blob: c0522aa9d2e94d059ff04d9814e71638beb5b623 [file] [log] [blame]
Josh Gaocbe70cb2016-10-18 18:17:52 -07001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Christopher Ferris35da2882021-02-17 15:39:06 -080017#include <dirent.h>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070018#include <dlfcn.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070019#include <err.h>
20#include <fcntl.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000021#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080022#include <malloc.h>
Christopher Ferrisbda10642023-04-24 18:14:53 -070023#include <pthread.h>
Josh Gaocdea7502017-11-01 15:00:40 -070024#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080025#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070026#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080027#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070028#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080029#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070030#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070031#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070032#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070033
34#include <chrono>
35#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000036#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070037#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070038#include <thread>
39
Christopher Ferris22035cc2023-01-31 17:50:22 -080040#include <android/dlext.h>
Josh Gaobf06a402018-08-27 16:34:01 -070041#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080042#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080043#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070044#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080045#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080046
Josh Gao5f87bbd2019-01-09 17:01:49 -080047#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070048#include <android-base/file.h>
49#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070050#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070051#include <android-base/parseint.h>
52#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070053#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070055#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070056#include <android-base/unique_fd.h>
57#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070058#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070059#include <gtest/gtest.h>
60
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000061#include <unwindstack/Elf.h>
62#include <unwindstack/Memory.h>
63
Josh Gaoe04ca272018-01-16 15:38:17 -080064#include <libminijail.h>
65#include <scoped_minijail.h>
66
Christopher Ferris2038cc72021-09-15 03:57:10 +000067#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010068#include "debuggerd/handler.h"
Mitch Phillips18ce5422023-01-19 14:23:49 -080069#include "gtest/gtest.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070070#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010071#include "protocol.h"
72#include "tombstoned/tombstoned.h"
73#include "util.h"
74
Josh Gaocbe70cb2016-10-18 18:17:52 -070075using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080076
77using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070078using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070079using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070080
81#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070082#define ARCH_SUFFIX "64"
83#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070084#define ARCH_SUFFIX ""
85#endif
86
Elliott Hughese4781d52021-03-17 09:15:15 -070087constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070088
89#define TIMEOUT(seconds, expr) \
90 [&]() { \
91 struct sigaction old_sigaction; \
92 struct sigaction new_sigaction = {}; \
93 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080094 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070095 err(1, "sigaction failed"); \
96 } \
Mattias Simonsson38ab0452023-11-08 12:02:46 +000097 alarm(seconds * android::base::HwTimeoutMultiplier()); \
Josh Gaocbe70cb2016-10-18 18:17:52 -070098 auto value = expr; \
99 int saved_errno = errno; \
100 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
101 err(1, "sigaction failed"); \
102 } \
103 alarm(0); \
104 errno = saved_errno; \
105 return value; \
106 }()
107
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700108// Backtrace frame dump could contain:
109// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
110// or
111// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800112#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700113 ASSERT_MATCH(result, \
114 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900115
Narayan Kamatha73df602017-05-24 15:07:25 +0100116static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700117 InterceptResponse* response, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700118 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
119 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
120 if (intercept_fd->get() == -1) {
121 FAIL() << "failed to contact tombstoned: " << strerror(errno);
122 }
123
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700124 InterceptRequest req = {
125 .dump_type = intercept_type,
126 .pid = target_pid,
127 };
Josh Gao460b3362017-03-30 16:40:47 -0700128
129 unique_fd output_pipe_write;
130 if (!Pipe(output_fd, &output_pipe_write)) {
131 FAIL() << "failed to create output pipe: " << strerror(errno);
132 }
133
134 std::string pipe_size_str;
135 int pipe_buffer_size;
136 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
137 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
138 }
139
140 pipe_size_str = android::base::Trim(pipe_size_str);
141
142 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
143 FAIL() << "failed to parse pipe max size";
144 }
145
146 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
147 FAIL() << "failed to set pipe size: " << strerror(errno);
148 }
149
Josh Gao5675f3c2017-06-01 12:19:53 -0700150 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
151
Josh Gao5f87bbd2019-01-09 17:01:49 -0800152 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
153 output_pipe_write.reset();
154 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700155 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
156 }
157
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700158 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), response, sizeof(*response)));
Josh Gao460b3362017-03-30 16:40:47 -0700159 if (rc == -1) {
160 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
161 } else if (rc == 0) {
162 FAIL() << "failed to read response from tombstoned (EOF)";
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700163 } else if (rc != sizeof(*response)) {
164 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(*response)
Josh Gao460b3362017-03-30 16:40:47 -0700165 << ", received " << rc;
166 }
Josh Gao460b3362017-03-30 16:40:47 -0700167}
168
Elliott Hughesd13ea522022-01-13 09:20:26 -0800169static bool pac_supported() {
170#if defined(__aarch64__)
171 return getauxval(AT_HWCAP) & HWCAP_PACA;
172#else
173 return false;
174#endif
175}
176
Josh Gaocbe70cb2016-10-18 18:17:52 -0700177class CrasherTest : public ::testing::Test {
178 public:
179 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700180 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700181 unique_fd crasher_pipe;
182 unique_fd intercept_fd;
183
184 CrasherTest();
185 ~CrasherTest();
186
Narayan Kamatha73df602017-05-24 15:07:25 +0100187 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700188
189 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
190 void FinishIntercept(int* result);
191
Josh Gao2e7b8e22017-05-04 17:12:57 -0700192 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700193 void StartCrasher(const std::string& crash_type);
194 void FinishCrasher();
195 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700196
197 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700198};
199
200CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700201 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
202 android::base::SetProperty(kWaitForDebuggerKey, "0");
203
204 // Clear the old property too, just in case someone's been using it
205 // on this device. (We only document the new name, but we still support
206 // the old name so we don't break anyone's existing setups.)
207 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700208}
209
210CrasherTest::~CrasherTest() {
211 if (crasher_pid != -1) {
212 kill(crasher_pid, SIGKILL);
213 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700214 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700215 }
216
Elliott Hughese4781d52021-03-17 09:15:15 -0700217 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700218}
219
Narayan Kamatha73df602017-05-24 15:07:25 +0100220void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221 if (crasher_pid == -1) {
222 FAIL() << "crasher hasn't been started";
223 }
224
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700225 InterceptResponse response = {};
226 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &response, intercept_type);
227 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
228 << "Error message: " << response.error_message;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700229}
230
231void CrasherTest::FinishIntercept(int* result) {
232 InterceptResponse response;
233
Christopher Ferris11555f02019-09-20 14:18:55 -0700234 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700235 if (rc == -1) {
236 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
237 } else if (rc == 0) {
238 *result = -1;
239 } else if (rc != sizeof(response)) {
240 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
241 << ", received " << rc;
242 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700243 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700244 }
245}
246
Josh Gao2e7b8e22017-05-04 17:12:57 -0700247void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800248 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700249 unique_fd crasher_read_pipe;
250 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
251 FAIL() << "failed to create pipe: " << strerror(errno);
252 }
253
Josh Gao2e7b8e22017-05-04 17:12:57 -0700254 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700255 if (crasher_pid == -1) {
256 FAIL() << "fork failed: " << strerror(errno);
257 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800258 char dummy;
259 crasher_pipe.reset();
260 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800261 function();
262 _exit(0);
263 }
264}
265
Josh Gaocbe70cb2016-10-18 18:17:52 -0700266void CrasherTest::FinishCrasher() {
267 if (crasher_pipe == -1) {
268 FAIL() << "crasher pipe uninitialized";
269 }
270
Christopher Ferris172b0a02019-09-18 17:48:30 -0700271 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700272 if (rc == -1) {
273 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
274 } else if (rc == 0) {
275 FAIL() << "crasher pipe was closed";
276 }
277}
278
279void CrasherTest::AssertDeath(int signo) {
280 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700281 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700282 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700283 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
284 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700285 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700286 FAIL() << "failed to wait for crasher: " << strerror(errno);
287 }
288
Josh Gaoe06f2a42017-04-27 16:50:38 -0700289 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700290 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700291 ASSERT_EQ(0, WEXITSTATUS(signo));
292 } else {
293 ASSERT_FALSE(WIFEXITED(status));
294 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
295 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700296 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700297 crasher_pid = -1;
298}
299
300static void ConsumeFd(unique_fd fd, std::string* output) {
Kelvin Zhang786dac32023-06-15 16:23:56 -0700301 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700302}
303
Mitch Phillips78f06702021-06-01 14:35:43 -0700304class LogcatCollector {
305 public:
306 LogcatCollector() { system("logcat -c"); }
307
308 void Collect(std::string* output) {
309 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
310 ASSERT_NE(cmd_stdout, nullptr);
311 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
312 ConsumeFd(std::move(tmp_fd), output);
313 pclose(cmd_stdout);
314 }
315};
316
Josh Gaocbe70cb2016-10-18 18:17:52 -0700317TEST_F(CrasherTest, smoke) {
318 int intercept_result;
319 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800320 StartProcess([]() {
321 *reinterpret_cast<volatile char*>(0xdead) = '1';
322 });
323
Josh Gaocbe70cb2016-10-18 18:17:52 -0700324 StartIntercept(&output_fd);
325 FinishCrasher();
326 AssertDeath(SIGSEGV);
327 FinishIntercept(&intercept_result);
328
329 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
330
331 std::string result;
332 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800333#ifdef __LP64__
334 ASSERT_MATCH(result,
335 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
336#else
337 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
338#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700339
340 if (mte_supported()) {
341 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700342 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
343 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700344 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800345
346 if (pac_supported()) {
347 // Test that the default PAC_ENABLED_KEYS value is set.
348 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
349 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
350 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700351}
352
Peter Collingbournef03af882020-03-20 18:09:00 -0700353TEST_F(CrasherTest, tagged_fault_addr) {
354#if !defined(__aarch64__)
355 GTEST_SKIP() << "Requires aarch64";
356#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700357 // HWASan crashes with SIGABRT on tag mismatch.
358 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700359 int intercept_result;
360 unique_fd output_fd;
361 StartProcess([]() {
362 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
363 });
364
365 StartIntercept(&output_fd);
366 FinishCrasher();
367 AssertDeath(SIGSEGV);
368 FinishIntercept(&intercept_result);
369
370 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
371
372 std::string result;
373 ConsumeFd(std::move(output_fd), &result);
374
375 // The address can either be tagged (new kernels) or untagged (old kernels).
376 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800377 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700378}
379
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700380void CrasherTest::Trap(void* ptr) {
381 void (*volatile f)(void*) = nullptr;
382 __asm__ __volatile__("" : : "r"(f) : "memory");
383 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700384}
385
386TEST_F(CrasherTest, heap_addr_in_register) {
387#if defined(__i386__)
388 GTEST_SKIP() << "architecture does not pass arguments in registers";
389#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700390 // The memory dump in HWASan crashes sadly shows the memory near the registers
391 // in the HWASan dump function, rather the faulting context. This is a known
392 // issue.
393 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700394 int intercept_result;
395 unique_fd output_fd;
396 StartProcess([]() {
397 // Crash with a heap pointer in the first argument register.
398 Trap(malloc(1));
399 });
400
401 StartIntercept(&output_fd);
402 FinishCrasher();
403 int status;
404 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
405 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
406 // Don't test the signal number because different architectures use different signals for
407 // __builtin_trap().
408 FinishIntercept(&intercept_result);
409
410 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
411
412 std::string result;
413 ConsumeFd(std::move(output_fd), &result);
414
415#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800416 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700417#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800418 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800419#elif defined(__riscv)
420 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700421#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800422 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700423#else
424 ASSERT_TRUE(false) << "unsupported architecture";
425#endif
426}
427
Peter Collingbournecd278072020-12-21 14:08:38 -0800428#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700429static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800430 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700431 abort();
432 }
433}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800434
435static void SetTagCheckingLevelAsync() {
436 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
437 abort();
438 }
439}
Peter Collingbournef8622522020-04-07 14:07:32 -0700440#endif
441
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800442struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
443
Peter Collingbourneaa544792021-05-13 13:53:37 -0700444INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800445
446TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800447#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700448 if (!mte_supported()) {
449 GTEST_SKIP() << "Requires MTE";
450 }
451
Peter Collingbourneaa544792021-05-13 13:53:37 -0700452 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
453 if (GetParam() == 0) {
454 return;
455 }
456
Mitch Phillips78f06702021-06-01 14:35:43 -0700457 LogcatCollector logcat_collector;
458
Peter Collingbournef8622522020-04-07 14:07:32 -0700459 int intercept_result;
460 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800461 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700462 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800463 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700464 free((void *)p);
465 p[0] = 42;
466 });
467
468 StartIntercept(&output_fd);
469 FinishCrasher();
470 AssertDeath(SIGSEGV);
471 FinishIntercept(&intercept_result);
472
473 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
474
Mitch Phillips78f06702021-06-01 14:35:43 -0700475 std::vector<std::string> log_sources(2);
476 ConsumeFd(std::move(output_fd), &log_sources[0]);
477 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700478 // Tag dump only available in the tombstone, not logcat.
479 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700480
Mitch Phillips78f06702021-06-01 14:35:43 -0700481 for (const auto& result : log_sources) {
482 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
483 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
484 std::to_string(GetParam()) + R"(-byte allocation)");
485 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
486 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
487 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700488#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800489 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700490#endif
491}
492
Peter Collingbournedc476342021-05-12 15:56:43 -0700493TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
494#if defined(__aarch64__)
495 if (!mte_supported()) {
496 GTEST_SKIP() << "Requires MTE";
497 }
498
499 int intercept_result;
500 unique_fd output_fd;
501 StartProcess([&]() {
502 SetTagCheckingLevelSync();
503 volatile int* p = (volatile int*)malloc(GetParam());
504 free((void *)p);
505 p[-1] = 42;
506 });
507
508 StartIntercept(&output_fd);
509 FinishCrasher();
510 AssertDeath(SIGSEGV);
511 FinishIntercept(&intercept_result);
512
513 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
514
515 std::string result;
516 ConsumeFd(std::move(output_fd), &result);
517
518 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
519 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
520#else
521 GTEST_SKIP() << "Requires aarch64";
522#endif
523}
524
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800525TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800526#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700527 if (!mte_supported()) {
528 GTEST_SKIP() << "Requires MTE";
529 }
530
Mitch Phillips78f06702021-06-01 14:35:43 -0700531 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700532 int intercept_result;
533 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800534 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700535 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800536 volatile char* p = (volatile char*)malloc(GetParam());
537 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700538 });
539
540 StartIntercept(&output_fd);
541 FinishCrasher();
542 AssertDeath(SIGSEGV);
543 FinishIntercept(&intercept_result);
544
545 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
546
Mitch Phillips78f06702021-06-01 14:35:43 -0700547 std::vector<std::string> log_sources(2);
548 ConsumeFd(std::move(output_fd), &log_sources[0]);
549 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700550
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700551 // Tag dump only in tombstone, not logcat, and tagging is not used for
552 // overflow protection in the scudo secondary (guard pages are used instead).
553 if (GetParam() < 0x10000) {
554 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
555 }
556
Mitch Phillips78f06702021-06-01 14:35:43 -0700557 for (const auto& result : log_sources) {
558 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
559 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
560 std::to_string(GetParam()) + R"(-byte allocation)");
561 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
562 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700563#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800564 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700565#endif
566}
567
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800568TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800569#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700570 if (!mte_supported()) {
571 GTEST_SKIP() << "Requires MTE";
572 }
573
574 int intercept_result;
575 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800576 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700577 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800578 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700579 p[-1] = 42;
580 });
581
582 StartIntercept(&output_fd);
583 FinishCrasher();
584 AssertDeath(SIGSEGV);
585 FinishIntercept(&intercept_result);
586
587 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
588
589 std::string result;
590 ConsumeFd(std::move(output_fd), &result);
591
592 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800593 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800594 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700595 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700596 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700597 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700598#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800599 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700600#endif
601}
602
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800603TEST_F(CrasherTest, mte_async) {
604#if defined(__aarch64__)
605 if (!mte_supported()) {
606 GTEST_SKIP() << "Requires MTE";
607 }
608
609 int intercept_result;
610 unique_fd output_fd;
611 StartProcess([&]() {
612 SetTagCheckingLevelAsync();
613 volatile int* p = (volatile int*)malloc(16);
614 p[-1] = 42;
615 });
616
617 StartIntercept(&output_fd);
618 FinishCrasher();
619 AssertDeath(SIGSEGV);
620 FinishIntercept(&intercept_result);
621
622 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
623
624 std::string result;
625 ConsumeFd(std::move(output_fd), &result);
626
Peter Collingbourne91e816a2023-03-07 21:24:47 -0800627 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800628#else
629 GTEST_SKIP() << "Requires aarch64";
630#endif
631}
632
Peter Collingbournef8622522020-04-07 14:07:32 -0700633TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800634#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700635 if (!mte_supported()) {
636 GTEST_SKIP() << "Requires MTE";
637 }
638
Mitch Phillips78f06702021-06-01 14:35:43 -0700639 LogcatCollector logcat_collector;
640
Peter Collingbournef8622522020-04-07 14:07:32 -0700641 int intercept_result;
642 unique_fd output_fd;
643 StartProcess([]() {
644 SetTagCheckingLevelSync();
645
646 // Make two allocations with the same tag and close to one another. Check for both properties
647 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
648 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
649 // (some non-zero value << 56) apart.
650 //
651 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
652 // other.
653 std::set<uintptr_t> allocs;
654 for (int i = 0; i != 4096; ++i) {
655 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
656 auto it = allocs.insert(alloc).first;
657 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
658 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
659 }
660 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
661 *reinterpret_cast<int*>(alloc + 16) = 42;
662 }
663 }
664 });
665
666 StartIntercept(&output_fd);
667 FinishCrasher();
668 AssertDeath(SIGSEGV);
669 FinishIntercept(&intercept_result);
670
671 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
672
Mitch Phillips78f06702021-06-01 14:35:43 -0700673 std::vector<std::string> log_sources(2);
674 ConsumeFd(std::move(output_fd), &log_sources[0]);
675 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700676
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700677 // Tag dump only in the tombstone, not logcat.
678 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
679
Mitch Phillips78f06702021-06-01 14:35:43 -0700680 for (const auto& result : log_sources) {
681 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
682 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800683 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700684 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
685 // overflows), so we can't match explicitly for an underflow message.
686 ASSERT_MATCH(result,
687 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
688 // Ensure there's at least two allocation traces (one for each cause).
689 ASSERT_MATCH(
690 result,
691 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
692 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700693#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800694 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700695#endif
696}
697
Peter Collingbournecd278072020-12-21 14:08:38 -0800698#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700699static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700700 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
701 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
702 size_t page_size = getpagesize();
703 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
704 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
705 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700706 return 0;
707 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700708 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
709 PROT_READ | PROT_WRITE | PROT_MTE);
710 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
711 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
712 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
713 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
714 }
715 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700716}
717#endif
718
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700719TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800720#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700721 if (!mte_supported()) {
722 GTEST_SKIP() << "Requires MTE";
723 }
724
725 int intercept_result;
726 unique_fd output_fd;
727 StartProcess([&]() {
728 SetTagCheckingLevelSync();
729 Trap(reinterpret_cast<void *>(CreateTagMapping()));
730 });
731
732 StartIntercept(&output_fd);
733 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700734 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700735 FinishIntercept(&intercept_result);
736
737 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
738
739 std::string result;
740 ConsumeFd(std::move(output_fd), &result);
741
742 ASSERT_MATCH(result, R"(memory near x0:
743.*
744.*
745 01.............0 0000000000000000 0000000000000000 ................
746 00.............0)");
747#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800748 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700749#endif
750}
751
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700752TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
753#if defined(__aarch64__)
754 if (!mte_supported()) {
755 GTEST_SKIP() << "Requires MTE";
756 }
757
758 int intercept_result;
759 unique_fd output_fd;
760 StartProcess([&]() {
761 SetTagCheckingLevelSync();
762 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
763 p[0] = 0; // Untagged pointer, tagged memory.
764 });
765
766 StartIntercept(&output_fd);
767 FinishCrasher();
768 AssertDeath(SIGSEGV);
769 FinishIntercept(&intercept_result);
770
771 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
772
773 std::string result;
774 ConsumeFd(std::move(output_fd), &result);
775
776 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
777\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
778#else
779 GTEST_SKIP() << "Requires aarch64";
780#endif
781}
782
783TEST_F(CrasherTest, mte_fault_tag_dump) {
784#if defined(__aarch64__)
785 if (!mte_supported()) {
786 GTEST_SKIP() << "Requires MTE";
787 }
788
789 int intercept_result;
790 unique_fd output_fd;
791 StartProcess([&]() {
792 SetTagCheckingLevelSync();
793 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
794 p[320] = 0; // Untagged pointer, tagged memory.
795 });
796
797 StartIntercept(&output_fd);
798 FinishCrasher();
799 AssertDeath(SIGSEGV);
800 FinishIntercept(&intercept_result);
801
802 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
803
804 std::string result;
805 ConsumeFd(std::move(output_fd), &result);
806
807 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
808\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
809\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
810\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
811)");
812#else
813 GTEST_SKIP() << "Requires aarch64";
814#endif
815}
816
817TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
818#if defined(__aarch64__)
819 if (!mte_supported()) {
820 GTEST_SKIP() << "Requires MTE";
821 }
822
823 int intercept_result;
824 unique_fd output_fd;
825 StartProcess([&]() {
826 SetTagCheckingLevelSync();
827 size_t page_size = getpagesize();
828 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
829 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
830 });
831
832 StartIntercept(&output_fd);
833 FinishCrasher();
834 AssertDeath(SIGSEGV);
835 FinishIntercept(&intercept_result);
836
837 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
838
839 std::string result;
840 ConsumeFd(std::move(output_fd), &result);
841
842 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
843 ASSERT_MATCH(result,
844 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
845\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
846
847)"); // Ensure truncation happened and there's a newline after the tag fault.
848#else
849 GTEST_SKIP() << "Requires aarch64";
850#endif
851}
852
Josh Gaocdea7502017-11-01 15:00:40 -0700853TEST_F(CrasherTest, LD_PRELOAD) {
854 int intercept_result;
855 unique_fd output_fd;
856 StartProcess([]() {
857 setenv("LD_PRELOAD", "nonexistent.so", 1);
858 *reinterpret_cast<volatile char*>(0xdead) = '1';
859 });
860
861 StartIntercept(&output_fd);
862 FinishCrasher();
863 AssertDeath(SIGSEGV);
864 FinishIntercept(&intercept_result);
865
866 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
867
868 std::string result;
869 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800870 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700871}
872
Josh Gaocbe70cb2016-10-18 18:17:52 -0700873TEST_F(CrasherTest, abort) {
874 int intercept_result;
875 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800876 StartProcess([]() {
877 abort();
878 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700879 StartIntercept(&output_fd);
880 FinishCrasher();
881 AssertDeath(SIGABRT);
882 FinishIntercept(&intercept_result);
883
884 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
885
886 std::string result;
887 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700888 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700889}
890
891TEST_F(CrasherTest, signal) {
892 int intercept_result;
893 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800894 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700895 while (true) {
896 sleep(1);
897 }
Josh Gao502cfd22017-02-17 01:39:15 -0800898 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700899 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700900 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700901 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
902
903 AssertDeath(SIGSEGV);
904 FinishIntercept(&intercept_result);
905
906 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
907
908 std::string result;
909 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700910 ASSERT_MATCH(
911 result,
912 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700913 ASSERT_MATCH(result, R"(backtrace:)");
914}
915
916TEST_F(CrasherTest, abort_message) {
917 int intercept_result;
918 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800919 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800920 // Arrived at experimentally;
921 // logd truncates at 4062.
922 // strlen("Abort message: ''") is 17.
923 // That's 4045, but we also want a NUL.
924 char buf[4045 + 1];
925 memset(buf, 'x', sizeof(buf));
926 buf[sizeof(buf) - 1] = '\0';
927 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800928 abort();
929 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700930 StartIntercept(&output_fd);
931 FinishCrasher();
932 AssertDeath(SIGABRT);
933 FinishIntercept(&intercept_result);
934
935 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
936
937 std::string result;
938 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800939 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700940}
941
Christopher Ferrise8891452021-08-17 17:34:53 -0700942TEST_F(CrasherTest, abort_message_newline_trimmed) {
943 int intercept_result;
944 unique_fd output_fd;
945 StartProcess([]() {
946 android_set_abort_message("Message with a newline.\n");
947 abort();
948 });
949 StartIntercept(&output_fd);
950 FinishCrasher();
951 AssertDeath(SIGABRT);
952 FinishIntercept(&intercept_result);
953
954 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
955
956 std::string result;
957 ConsumeFd(std::move(output_fd), &result);
958 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
959}
960
961TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
962 int intercept_result;
963 unique_fd output_fd;
964 StartProcess([]() {
965 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
966 abort();
967 });
968 StartIntercept(&output_fd);
969 FinishCrasher();
970 AssertDeath(SIGABRT);
971 FinishIntercept(&intercept_result);
972
973 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
974
975 std::string result;
976 ConsumeFd(std::move(output_fd), &result);
977 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
978}
979
Josh Gaoe06f2a42017-04-27 16:50:38 -0700980TEST_F(CrasherTest, abort_message_backtrace) {
981 int intercept_result;
982 unique_fd output_fd;
983 StartProcess([]() {
984 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -0800985 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700986 exit(0);
987 });
988 StartIntercept(&output_fd);
989 FinishCrasher();
990 AssertDeath(0);
991 FinishIntercept(&intercept_result);
992
993 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
994
995 std::string result;
996 ConsumeFd(std::move(output_fd), &result);
997 ASSERT_NOT_MATCH(result, R"(Abort message:)");
998}
999
Josh Gaocbe70cb2016-10-18 18:17:52 -07001000TEST_F(CrasherTest, intercept_timeout) {
1001 int intercept_result;
1002 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001003 StartProcess([]() {
1004 abort();
1005 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001006 StartIntercept(&output_fd);
1007
1008 // Don't let crasher finish until we timeout.
1009 FinishIntercept(&intercept_result);
1010
1011 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1012 << intercept_result << ")";
1013
1014 FinishCrasher();
1015 AssertDeath(SIGABRT);
1016}
1017
Elliott Hughese4781d52021-03-17 09:15:15 -07001018TEST_F(CrasherTest, wait_for_debugger) {
1019 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1020 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001021 }
1022 sleep(1);
1023
Josh Gao502cfd22017-02-17 01:39:15 -08001024 StartProcess([]() {
1025 abort();
1026 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001027 FinishCrasher();
1028
1029 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001030 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001031 ASSERT_TRUE(WIFSTOPPED(status));
1032 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1033
1034 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1035
1036 AssertDeath(SIGABRT);
1037}
1038
Josh Gaocbe70cb2016-10-18 18:17:52 -07001039TEST_F(CrasherTest, backtrace) {
1040 std::string result;
1041 int intercept_result;
1042 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001043
1044 StartProcess([]() {
1045 abort();
1046 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001047 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001048
1049 std::this_thread::sleep_for(500ms);
1050
1051 sigval val;
1052 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001053 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001054 FinishIntercept(&intercept_result);
1055 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1056 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001057 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001058
1059 int status;
1060 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1061
1062 StartIntercept(&output_fd);
1063 FinishCrasher();
1064 AssertDeath(SIGABRT);
1065 FinishIntercept(&intercept_result);
1066 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1067 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001068 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001069}
Josh Gaofca7ca32017-01-23 12:05:35 -08001070
1071TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001072 int intercept_result;
1073 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001074 StartProcess([]() {
1075 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001076 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001077 });
Josh Gao502cfd22017-02-17 01:39:15 -08001078
1079 StartIntercept(&output_fd);
1080 FinishCrasher();
1081 AssertDeath(SIGABRT);
1082 FinishIntercept(&intercept_result);
1083
1084 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1085
1086 std::string result;
1087 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001088 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001089}
1090
Josh Gao502cfd22017-02-17 01:39:15 -08001091TEST_F(CrasherTest, capabilities) {
1092 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1093
Josh Gaofca7ca32017-01-23 12:05:35 -08001094 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001095 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1096 err(1, "failed to set PR_SET_KEEPCAPS");
1097 }
1098
1099 if (setresuid(1, 1, 1) != 0) {
1100 err(1, "setresuid failed");
1101 }
1102
1103 __user_cap_header_struct capheader;
1104 __user_cap_data_struct capdata[2];
1105 memset(&capheader, 0, sizeof(capheader));
1106 memset(&capdata, 0, sizeof(capdata));
1107
1108 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1109 capheader.pid = 0;
1110
1111 // Turn on every third capability.
1112 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1113 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1114 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1115 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1116 }
1117
1118 // Make sure CAP_SYS_PTRACE is off.
1119 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1120 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1121
1122 if (capset(&capheader, &capdata[0]) != 0) {
1123 err(1, "capset failed");
1124 }
1125
1126 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1127 err(1, "failed to drop ambient capabilities");
1128 }
1129
Josh Gaoa5199a92017-04-03 13:18:34 -07001130 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001131 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001132 });
Josh Gao502cfd22017-02-17 01:39:15 -08001133
1134 unique_fd output_fd;
1135 StartIntercept(&output_fd);
1136 FinishCrasher();
1137 AssertDeath(SIGSYS);
1138
1139 std::string result;
1140 int intercept_result;
1141 FinishIntercept(&intercept_result);
1142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1143 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001144 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001145 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001146}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001147
Josh Gao2e7b8e22017-05-04 17:12:57 -07001148TEST_F(CrasherTest, fake_pid) {
1149 int intercept_result;
1150 unique_fd output_fd;
1151
1152 // Prime the getpid/gettid caches.
1153 UNUSED(getpid());
1154 UNUSED(gettid());
1155
1156 std::function<pid_t()> clone_fn = []() {
1157 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1158 };
1159 StartProcess(
1160 []() {
1161 ASSERT_NE(getpid(), syscall(__NR_getpid));
1162 ASSERT_NE(gettid(), syscall(__NR_gettid));
1163 raise(SIGSEGV);
1164 },
1165 clone_fn);
1166
1167 StartIntercept(&output_fd);
1168 FinishCrasher();
1169 AssertDeath(SIGSEGV);
1170 FinishIntercept(&intercept_result);
1171
1172 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1173
1174 std::string result;
1175 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001176 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001177}
1178
Josh Gaoe04ca272018-01-16 15:38:17 -08001179static const char* const kDebuggerdSeccompPolicy =
1180 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1181
Mitch Phillips18ce5422023-01-19 14:23:49 -08001182static void setup_jail(minijail* jail) {
1183 if (!jail) {
1184 LOG(FATAL) << "failed to create minijail";
1185 }
1186
Josh Gao6f9eeec2018-09-12 13:55:47 -07001187 std::string policy;
1188 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1189 PLOG(FATAL) << "failed to read policy file";
1190 }
1191
1192 // Allow a bunch of syscalls used by the tests.
1193 policy += "\nclone: 1";
1194 policy += "\nsigaltstack: 1";
1195 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001196 policy += "\ngetrlimit: 1";
1197 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001198
1199 FILE* tmp_file = tmpfile();
1200 if (!tmp_file) {
1201 PLOG(FATAL) << "tmpfile failed";
1202 }
1203
Christopher Ferris172b0a02019-09-18 17:48:30 -07001204 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001205 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1206 PLOG(FATAL) << "failed to write policy to tmpfile";
1207 }
1208
1209 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1210 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001211 }
1212
Mitch Phillips18ce5422023-01-19 14:23:49 -08001213 minijail_no_new_privs(jail);
1214 minijail_log_seccomp_filter_failures(jail);
1215 minijail_use_seccomp_filter(jail);
1216 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1217}
Josh Gaoe04ca272018-01-16 15:38:17 -08001218
Mitch Phillips18ce5422023-01-19 14:23:49 -08001219static pid_t seccomp_fork_impl(void (*prejail)()) {
1220 ScopedMinijail jail{minijail_new()};
1221 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001222
1223 pid_t result = fork();
1224 if (result == -1) {
1225 return result;
1226 } else if (result != 0) {
1227 return result;
1228 }
1229
1230 // Spawn and detach a thread that spins forever.
1231 std::atomic<bool> thread_ready(false);
1232 std::thread thread([&jail, &thread_ready]() {
1233 minijail_enter(jail.get());
1234 thread_ready = true;
1235 for (;;)
1236 ;
1237 });
1238 thread.detach();
1239
1240 while (!thread_ready) {
1241 continue;
1242 }
1243
Josh Gao70adac62018-02-22 11:38:33 -08001244 if (prejail) {
1245 prejail();
1246 }
1247
Josh Gaoe04ca272018-01-16 15:38:17 -08001248 minijail_enter(jail.get());
1249 return result;
1250}
1251
Josh Gao70adac62018-02-22 11:38:33 -08001252static pid_t seccomp_fork() {
1253 return seccomp_fork_impl(nullptr);
1254}
1255
Josh Gaoe04ca272018-01-16 15:38:17 -08001256TEST_F(CrasherTest, seccomp_crash) {
1257 int intercept_result;
1258 unique_fd output_fd;
1259
1260 StartProcess([]() { abort(); }, &seccomp_fork);
1261
1262 StartIntercept(&output_fd);
1263 FinishCrasher();
1264 AssertDeath(SIGABRT);
1265 FinishIntercept(&intercept_result);
1266 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1267
1268 std::string result;
1269 ConsumeFd(std::move(output_fd), &result);
1270 ASSERT_BACKTRACE_FRAME(result, "abort");
1271}
1272
Josh Gao70adac62018-02-22 11:38:33 -08001273static pid_t seccomp_fork_rlimit() {
1274 return seccomp_fork_impl([]() {
1275 struct rlimit rlim = {
1276 .rlim_cur = 512 * 1024 * 1024,
1277 .rlim_max = 512 * 1024 * 1024,
1278 };
1279
1280 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1281 raise(SIGINT);
1282 }
1283 });
1284}
1285
1286TEST_F(CrasherTest, seccomp_crash_oom) {
1287 int intercept_result;
1288 unique_fd output_fd;
1289
1290 StartProcess(
1291 []() {
1292 std::vector<void*> vec;
1293 for (int i = 0; i < 512; ++i) {
1294 char* buf = static_cast<char*>(malloc(1024 * 1024));
1295 if (!buf) {
1296 abort();
1297 }
1298 memset(buf, 0xff, 1024 * 1024);
1299 vec.push_back(buf);
1300 }
1301 },
1302 &seccomp_fork_rlimit);
1303
1304 StartIntercept(&output_fd);
1305 FinishCrasher();
1306 AssertDeath(SIGABRT);
1307 FinishIntercept(&intercept_result);
1308 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1309
1310 // We can't actually generate a backtrace, just make sure that the process terminates.
1311}
1312
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001313__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001314 siginfo_t siginfo;
1315 siginfo.si_code = SI_QUEUE;
1316 siginfo.si_pid = getpid();
1317 siginfo.si_uid = getuid();
1318
1319 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1320 PLOG(FATAL) << "invalid dump type";
1321 }
1322
1323 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1324
Josh Gaoa48b41b2019-12-13 14:11:04 -08001325 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001326 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1327 return false;
1328 }
1329
1330 return true;
1331}
1332
Christopher Ferrisb999b822022-02-09 17:57:21 -08001333extern "C" void foo() {
1334 LOG(INFO) << "foo";
1335 std::this_thread::sleep_for(1s);
1336}
1337
1338extern "C" void bar() {
1339 LOG(INFO) << "bar";
1340 std::this_thread::sleep_for(1s);
1341}
1342
Josh Gaoe04ca272018-01-16 15:38:17 -08001343TEST_F(CrasherTest, seccomp_tombstone) {
1344 int intercept_result;
1345 unique_fd output_fd;
1346
1347 static const auto dump_type = kDebuggerdTombstone;
1348 StartProcess(
1349 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001350 std::thread a(foo);
1351 std::thread b(bar);
1352
1353 std::this_thread::sleep_for(100ms);
1354
Josh Gaoe04ca272018-01-16 15:38:17 -08001355 raise_debugger_signal(dump_type);
1356 _exit(0);
1357 },
1358 &seccomp_fork);
1359
1360 StartIntercept(&output_fd, dump_type);
1361 FinishCrasher();
1362 AssertDeath(0);
1363 FinishIntercept(&intercept_result);
1364 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1365
1366 std::string result;
1367 ConsumeFd(std::move(output_fd), &result);
1368 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001369 ASSERT_BACKTRACE_FRAME(result, "foo");
1370 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001371}
1372
Christopher Ferris303c6be2022-05-24 17:08:33 -07001373TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1374 int intercept_result;
1375 unique_fd output_fd;
1376
1377 static const auto dump_type = kDebuggerdTombstone;
1378 StartProcess(
1379 []() {
1380 std::thread abort_thread([] { abort(); });
1381 abort_thread.join();
1382 },
1383 &seccomp_fork);
1384
1385 StartIntercept(&output_fd, dump_type);
1386 FinishCrasher();
1387 AssertDeath(SIGABRT);
1388 FinishIntercept(&intercept_result);
1389 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1390
1391 std::string result;
1392 ConsumeFd(std::move(output_fd), &result);
1393 ASSERT_BACKTRACE_FRAME(result, "abort");
1394}
1395
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001396TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1397 int intercept_result;
1398 unique_fd output_fd;
1399
1400 static const auto dump_type = kDebuggerdTombstone;
1401 StartProcess(
1402 []() {
1403 std::thread a(foo);
1404 std::thread b(bar);
1405
1406 std::this_thread::sleep_for(100ms);
1407
1408 std::thread abort_thread([] { abort(); });
1409 abort_thread.join();
1410 },
1411 &seccomp_fork);
1412
1413 StartIntercept(&output_fd, dump_type);
1414 FinishCrasher();
1415 AssertDeath(SIGABRT);
1416 FinishIntercept(&intercept_result);
1417 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1418
1419 std::string result;
1420 ConsumeFd(std::move(output_fd), &result);
1421 ASSERT_BACKTRACE_FRAME(result, "abort");
1422 ASSERT_BACKTRACE_FRAME(result, "foo");
1423 ASSERT_BACKTRACE_FRAME(result, "bar");
1424 ASSERT_BACKTRACE_FRAME(result, "main");
1425}
1426
Josh Gaoe04ca272018-01-16 15:38:17 -08001427TEST_F(CrasherTest, seccomp_backtrace) {
1428 int intercept_result;
1429 unique_fd output_fd;
1430
1431 static const auto dump_type = kDebuggerdNativeBacktrace;
1432 StartProcess(
1433 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001434 std::thread a(foo);
1435 std::thread b(bar);
1436
1437 std::this_thread::sleep_for(100ms);
1438
Josh Gaoe04ca272018-01-16 15:38:17 -08001439 raise_debugger_signal(dump_type);
1440 _exit(0);
1441 },
1442 &seccomp_fork);
1443
1444 StartIntercept(&output_fd, dump_type);
1445 FinishCrasher();
1446 AssertDeath(0);
1447 FinishIntercept(&intercept_result);
1448 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1449
1450 std::string result;
1451 ConsumeFd(std::move(output_fd), &result);
1452 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001453 ASSERT_BACKTRACE_FRAME(result, "foo");
1454 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001455}
1456
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001457TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1458 int intercept_result;
1459 unique_fd output_fd;
1460
1461 static const auto dump_type = kDebuggerdNativeBacktrace;
1462 StartProcess(
1463 []() {
1464 std::thread a(foo);
1465 std::thread b(bar);
1466
1467 std::this_thread::sleep_for(100ms);
1468
1469 std::thread raise_thread([] {
1470 raise_debugger_signal(dump_type);
1471 _exit(0);
1472 });
1473 raise_thread.join();
1474 },
1475 &seccomp_fork);
1476
1477 StartIntercept(&output_fd, dump_type);
1478 FinishCrasher();
1479 AssertDeath(0);
1480 FinishIntercept(&intercept_result);
1481 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1482
1483 std::string result;
1484 ConsumeFd(std::move(output_fd), &result);
1485 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1486 ASSERT_BACKTRACE_FRAME(result, "foo");
1487 ASSERT_BACKTRACE_FRAME(result, "bar");
1488 ASSERT_BACKTRACE_FRAME(result, "main");
1489}
1490
Josh Gaoe04ca272018-01-16 15:38:17 -08001491TEST_F(CrasherTest, seccomp_crash_logcat) {
1492 StartProcess([]() { abort(); }, &seccomp_fork);
1493 FinishCrasher();
1494
1495 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1496 AssertDeath(SIGABRT);
1497}
1498
Josh Gaofd13bf02017-08-18 15:37:26 -07001499TEST_F(CrasherTest, competing_tracer) {
1500 int intercept_result;
1501 unique_fd output_fd;
1502 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001503 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001504 });
1505
1506 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001507
1508 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001509 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001510
1511 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001512 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001513 ASSERT_TRUE(WIFSTOPPED(status));
1514 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1515
1516 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1517 FinishIntercept(&intercept_result);
1518 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1519
1520 std::string result;
1521 ConsumeFd(std::move(output_fd), &result);
1522 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1523 regex += std::to_string(gettid());
1524 regex += R"( \(.+debuggerd_test)";
1525 ASSERT_MATCH(result, regex.c_str());
1526
Christopher Ferris172b0a02019-09-18 17:48:30 -07001527 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001528 ASSERT_TRUE(WIFSTOPPED(status));
1529 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1530
Josh Gaofd13bf02017-08-18 15:37:26 -07001531 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1532 AssertDeath(SIGABRT);
1533}
1534
Mitch Phillips18ce5422023-01-19 14:23:49 -08001535struct GwpAsanTestParameters {
1536 size_t alloc_size;
1537 bool free_before_access;
1538 int access_offset;
1539 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1540};
1541
1542struct GwpAsanCrasherTest
1543 : CrasherTest,
1544 testing::WithParamInterface<
1545 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1546
1547GwpAsanTestParameters gwp_asan_tests[] = {
1548 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1549 "Use After Free, 0 bytes into a 7-byte allocation"},
1550 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1551 "Use After Free, 1 byte into a 15-byte allocation"},
1552 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1553 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1554 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1555 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1556};
1557
1558INSTANTIATE_TEST_SUITE_P(
1559 GwpAsanTests, GwpAsanCrasherTest,
1560 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1561 /* recoverable */ testing::Bool(),
1562 /* seccomp */ testing::Bool()),
1563 [](const testing::TestParamInfo<
1564 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1565 const GwpAsanTestParameters& params = std::get<0>(info.param);
1566 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1567 name += testing::PrintToString(params.alloc_size);
1568 name += "Alloc";
1569 if (params.access_offset < 0) {
1570 name += "Left";
1571 name += testing::PrintToString(params.access_offset * -1);
1572 } else {
1573 name += "Right";
1574 name += testing::PrintToString(params.access_offset);
1575 }
1576 name += "Bytes";
1577 if (std::get<1>(info.param)) name += "Recoverable";
1578 if (std::get<2>(info.param)) name += "Seccomp";
1579 return name;
1580 });
1581
1582TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1583 if (mte_supported()) {
1584 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1585 // instead of GWP-ASan.
1586 GTEST_SKIP() << "Skipped on MTE.";
1587 }
1588 // Skip this test on HWASan, which will reliably catch test errors as well.
1589 SKIP_WITH_HWASAN;
1590
1591 GwpAsanTestParameters params = std::get<0>(GetParam());
1592 bool recoverable = std::get<1>(GetParam());
1593 LogcatCollector logcat_collector;
1594
1595 int intercept_result;
1596 unique_fd output_fd;
1597 StartProcess([&recoverable]() {
1598 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1599 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1600 if (recoverable) {
1601 env[3] = "GWP_ASAN_RECOVERABLE=true";
1602 }
1603 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1604 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1605 "DISABLED_run_gwp_asan_test");
1606 std::string test_filter = "--gtest_filter=*";
1607 test_filter += test_name;
1608 std::string this_binary = android::base::GetExecutablePath();
1609 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1610 test_filter.c_str(), nullptr};
1611 // We check the crash report from a debuggerd handler and from logcat. The
1612 // echo from stdout/stderr of the subprocess trips up atest, because it
1613 // doesn't like that two tests started in a row without the first one
1614 // finishing (even though the second one is in a subprocess).
1615 close(STDOUT_FILENO);
1616 close(STDERR_FILENO);
1617 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1618 });
1619
1620 StartIntercept(&output_fd);
1621 FinishCrasher();
1622 if (recoverable) {
1623 AssertDeath(0);
1624 } else {
1625 AssertDeath(SIGSEGV);
1626 }
1627 FinishIntercept(&intercept_result);
1628
1629 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1630
1631 std::vector<std::string> log_sources(2);
1632 ConsumeFd(std::move(output_fd), &log_sources[0]);
1633 logcat_collector.Collect(&log_sources[1]);
1634
1635 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1636 // information. Make sure the recovery still works, but the report won't be
1637 // hugely useful, it looks like a regular SEGV.
1638 bool seccomp = std::get<2>(GetParam());
1639 if (!seccomp) {
1640 for (const auto& result : log_sources) {
1641 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1642 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1643 if (params.free_before_access) {
1644 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1645 }
1646 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1647 }
1648 }
1649}
1650
1651TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1652 GwpAsanTestParameters params = std::get<0>(GetParam());
1653 bool seccomp = std::get<2>(GetParam());
1654 if (seccomp) {
1655 ScopedMinijail jail{minijail_new()};
1656 setup_jail(jail.get());
1657 minijail_enter(jail.get());
1658 }
1659
1660 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1661 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1662 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1663 p[params.access_offset] = 42;
1664 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001665
1666 bool recoverable = std::get<1>(GetParam());
1667 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1668
1669 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1670 // we end with at least one in a different slot), make sure the process still
1671 // doesn't crash.
1672 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1673 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1674 free(static_cast<void*>(const_cast<char*>(p)));
1675 free(static_cast<void*>(const_cast<char*>(p2)));
1676 *p = 42;
1677 *p2 = 42;
1678
1679 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1680 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1681 // coverage does. Thus, skip the atexit handlers.
1682 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001683}
1684
Josh Gaobf06a402018-08-27 16:34:01 -07001685TEST_F(CrasherTest, fdsan_warning_abort_message) {
1686 int intercept_result;
1687 unique_fd output_fd;
1688
1689 StartProcess([]() {
1690 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001691 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001692 if (fd == -1) {
1693 abort();
1694 }
1695 close(fd.get());
1696 _exit(0);
1697 });
1698
1699 StartIntercept(&output_fd);
1700 FinishCrasher();
1701 AssertDeath(0);
1702 FinishIntercept(&intercept_result);
1703 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1704
1705 std::string result;
1706 ConsumeFd(std::move(output_fd), &result);
1707 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1708}
1709
Josh Gaoc3c8c022017-02-13 16:36:18 -08001710TEST(crash_dump, zombie) {
1711 pid_t forkpid = fork();
1712
Josh Gaoc3c8c022017-02-13 16:36:18 -08001713 pid_t rc;
1714 int status;
1715
1716 if (forkpid == 0) {
1717 errno = 0;
1718 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1719 if (rc != -1 || errno != ECHILD) {
1720 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1721 }
1722
Josh Gaoa48b41b2019-12-13 14:11:04 -08001723 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001724
1725 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001726 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001727 if (rc != -1 || errno != ECHILD) {
1728 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1729 }
1730 _exit(0);
1731 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001732 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001733 ASSERT_EQ(forkpid, rc);
1734 ASSERT_TRUE(WIFEXITED(status));
1735 ASSERT_EQ(0, WEXITSTATUS(status));
1736 }
1737}
Josh Gao352a8452017-03-30 16:46:21 -07001738
1739TEST(tombstoned, no_notify) {
1740 // Do this a few times.
1741 for (int i = 0; i < 3; ++i) {
1742 pid_t pid = 123'456'789 + i;
1743
1744 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001745 InterceptResponse response = {};
1746 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1747 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1748 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001749
1750 {
1751 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001752 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001753 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1754 }
1755
1756 pid_t read_pid;
1757 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1758 ASSERT_EQ(read_pid, pid);
1759 }
1760}
1761
1762TEST(tombstoned, stress) {
1763 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1764 static constexpr int kDumpCount = 100;
1765
1766 std::atomic<bool> start(false);
1767 std::vector<std::thread> threads;
1768 threads.emplace_back([&start]() {
1769 while (!start) {
1770 continue;
1771 }
1772
1773 // Use a way out of range pid, to avoid stomping on an actual process.
1774 pid_t pid_base = 1'000'000;
1775
1776 for (int dump = 0; dump < kDumpCount; ++dump) {
1777 pid_t pid = pid_base + dump;
1778
1779 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001780 InterceptResponse response = {};
1781 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1782 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1783 << "Error messeage: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001784
1785 // Pretend to crash, and then immediately close the socket.
1786 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1787 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1788 if (sockfd == -1) {
1789 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1790 }
1791 TombstonedCrashPacket packet = {};
1792 packet.packet_type = CrashPacketType::kDumpRequest;
1793 packet.packet.dump_request.pid = pid;
1794 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1795 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1796 }
1797
1798 continue;
1799 }
1800 });
1801
1802 threads.emplace_back([&start]() {
1803 while (!start) {
1804 continue;
1805 }
1806
1807 // Use a way out of range pid, to avoid stomping on an actual process.
1808 pid_t pid_base = 2'000'000;
1809
1810 for (int dump = 0; dump < kDumpCount; ++dump) {
1811 pid_t pid = pid_base + dump;
1812
1813 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001814 InterceptResponse response = {};
1815 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1816 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1817 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001818
1819 {
1820 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001821 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001822 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1823 tombstoned_notify_completion(tombstoned_socket.get());
1824 }
1825
1826 // TODO: Fix the race that requires this sleep.
1827 std::this_thread::sleep_for(50ms);
1828
1829 pid_t read_pid;
1830 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1831 ASSERT_EQ(read_pid, pid);
1832 }
1833 });
1834
1835 start = true;
1836
1837 for (std::thread& thread : threads) {
1838 thread.join();
1839 }
1840}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001841
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001842TEST(tombstoned, intercept_java_trace_smoke) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01001843 // Using a "real" PID is a little dangerous here - if the test fails
1844 // or crashes, we might end up getting a bogus / unreliable stack
1845 // trace.
1846 const pid_t self = getpid();
1847
1848 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001849 InterceptResponse response = {};
1850 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
1851 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1852 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001853
Josh Gao76e1e302021-01-26 15:53:11 -08001854 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001855 // should result in a "regular" FD and not the installed intercept.
1856 const char native[] = "native";
1857 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001858 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001859 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1860 tombstoned_notify_completion(tombstoned_socket.get());
1861
1862 // Then, connect to tombstoned asking for a java backtrace. This *should*
1863 // trigger the intercept.
1864 const char java[] = "java";
1865 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1866 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1867 tombstoned_notify_completion(tombstoned_socket.get());
1868
1869 char outbuf[sizeof(java)];
1870 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1871 ASSERT_STREQ("java", outbuf);
1872}
1873
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001874TEST(tombstoned, intercept_multiple_dump_types) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01001875 const pid_t fake_pid = 1'234'567;
1876 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001877 InterceptResponse response = {};
1878 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
1879 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1880 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001881
1882 unique_fd intercept_fd_2, output_fd_2;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001883 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
1884 kDebuggerdNativeBacktrace);
1885 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1886 << "Error message: " << response.error_message;
1887}
1888
1889TEST(tombstoned, intercept_bad_pid) {
1890 const pid_t fake_pid = -1;
1891 unique_fd intercept_fd, output_fd;
1892 InterceptResponse response = {};
1893 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
1894 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1895 << "Error message: " << response.error_message;
1896 ASSERT_MATCH(response.error_message, "bad pid");
1897}
1898
1899TEST(tombstoned, intercept_bad_dump_types) {
1900 const pid_t fake_pid = 1'234'567;
1901 unique_fd intercept_fd, output_fd;
1902 InterceptResponse response = {};
1903 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
1904 static_cast<DebuggerdDumpType>(20));
1905 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1906 << "Error message: " << response.error_message;
1907 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
1908
1909 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
1910 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1911 << "Error message: " << response.error_message;
1912 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
1913
1914 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
1915 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1916 << "Error message: " << response.error_message;
1917 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
1918}
1919
1920TEST(tombstoned, intercept_already_registered) {
1921 const pid_t fake_pid = 1'234'567;
1922 unique_fd intercept_fd1, output_fd1;
1923 InterceptResponse response = {};
1924 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
1925 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1926 << "Error message: " << response.error_message;
1927
1928 unique_fd intercept_fd2, output_fd2;
1929 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
1930 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
1931 << "Error message: " << response.error_message;
1932 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
1933}
1934
1935TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
1936 const pid_t fake_pid = 1'234'567;
1937
1938 unique_fd intercept_fd, output_fd;
1939 InterceptResponse response = {};
1940 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1941 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1942 << "Error message: " << response.error_message;
1943
1944 const char data[] = "tombstone_proto";
1945 unique_fd tombstoned_socket, input_fd;
1946 ASSERT_TRUE(
1947 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
1948 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
1949 tombstoned_notify_completion(tombstoned_socket.get());
1950
1951 char outbuf[sizeof(data)];
1952 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1953 ASSERT_STREQ("tombstone_proto", outbuf);
Narayan Kamathca5e9082017-06-02 15:42:06 +01001954}
1955
1956TEST(tombstoned, intercept_any) {
1957 const pid_t fake_pid = 1'234'567;
1958
1959 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001960 InterceptResponse response = {};
1961 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
1962 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1963 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001964
1965 const char any[] = "any";
1966 unique_fd tombstoned_socket, input_fd;
1967 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1968 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1969 tombstoned_notify_completion(tombstoned_socket.get());
1970
1971 char outbuf[sizeof(any)];
1972 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1973 ASSERT_STREQ("any", outbuf);
1974}
Josh Gao2b22ae12018-09-12 14:51:03 -07001975
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001976TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
1977 const pid_t fake_pid = 1'234'567;
1978
1979 InterceptResponse response = {};
1980 unique_fd intercept_fd1, output_fd1;
1981 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
1982 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1983 << "Error message: " << response.error_message;
1984
1985 unique_fd intercept_fd2, output_fd2;
1986 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
1987 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1988 << "Error message: " << response.error_message;
1989
1990 unique_fd tombstoned_socket, input_fd;
1991 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1992}
1993
1994TEST(tombstoned, intercept_multiple_verify_intercept) {
1995 // Need to use our pid for java since that will verify the pid.
1996 const pid_t fake_pid = getpid();
1997
1998 InterceptResponse response = {};
1999 unique_fd intercept_fd1, output_fd1;
2000 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2001 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2002 << "Error message: " << response.error_message;
2003
2004 unique_fd intercept_fd2, output_fd2;
2005 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2006 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2007 << "Error message: " << response.error_message;
2008
2009 unique_fd intercept_fd3, output_fd3;
2010 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2011 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2012 << "Error message: " << response.error_message;
2013
2014 const char native_data[] = "native";
2015 unique_fd tombstoned_socket1, input_fd1;
2016 ASSERT_TRUE(
2017 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2018 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2019 tombstoned_notify_completion(tombstoned_socket1.get());
2020
2021 char native_outbuf[sizeof(native_data)];
2022 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2023 ASSERT_STREQ("native", native_outbuf);
2024
2025 const char java_data[] = "java";
2026 unique_fd tombstoned_socket2, input_fd2;
2027 ASSERT_TRUE(
2028 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2029 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2030 tombstoned_notify_completion(tombstoned_socket2.get());
2031
2032 char java_outbuf[sizeof(java_data)];
2033 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2034 ASSERT_STREQ("java", java_outbuf);
2035
2036 const char tomb_data[] = "tombstone";
2037 unique_fd tombstoned_socket3, input_fd3;
2038 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2039 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2040 tombstoned_notify_completion(tombstoned_socket3.get());
2041
2042 char tomb_outbuf[sizeof(tomb_data)];
2043 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2044 ASSERT_STREQ("tombstone", tomb_outbuf);
2045}
2046
Josh Gao2b22ae12018-09-12 14:51:03 -07002047TEST(tombstoned, interceptless_backtrace) {
2048 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2049 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2050 std::map<int, time_t> result;
2051 for (int i = 0; i < 99; ++i) {
2052 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2053 struct stat st;
2054 if (stat(path.c_str(), &st) == 0) {
2055 result[i] = st.st_mtim.tv_sec;
2056 }
2057 }
2058 return result;
2059 };
2060
2061 auto before = get_tombstone_timestamps();
2062 for (int i = 0; i < 50; ++i) {
2063 raise_debugger_signal(kDebuggerdNativeBacktrace);
2064 }
2065 auto after = get_tombstone_timestamps();
2066
2067 int diff = 0;
2068 for (int i = 0; i < 99; ++i) {
2069 if (after.count(i) == 0) {
2070 continue;
2071 }
2072 if (before.count(i) == 0) {
2073 ++diff;
2074 continue;
2075 }
2076 if (before[i] != after[i]) {
2077 ++diff;
2078 }
2079 }
2080
2081 // We can't be sure that nothing's crash looping in the background.
2082 // This should be good enough, though...
2083 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2084}
Christopher Ferris481e8372019-07-15 17:13:24 -07002085
2086static __attribute__((__noinline__)) void overflow_stack(void* p) {
2087 void* buf[1];
2088 buf[0] = p;
2089 static volatile void* global = buf;
2090 if (global) {
2091 global = buf;
2092 overflow_stack(&buf);
2093 }
2094}
2095
2096TEST_F(CrasherTest, stack_overflow) {
2097 int intercept_result;
2098 unique_fd output_fd;
2099 StartProcess([]() { overflow_stack(nullptr); });
2100
2101 StartIntercept(&output_fd);
2102 FinishCrasher();
2103 AssertDeath(SIGSEGV);
2104 FinishIntercept(&intercept_result);
2105
2106 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2107
2108 std::string result;
2109 ConsumeFd(std::move(output_fd), &result);
2110 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2111}
Josh Gao76e1e302021-01-26 15:53:11 -08002112
Christopher Ferris22035cc2023-01-31 17:50:22 -08002113static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002114 std::string test_lib(testing::internal::GetArgvs()[0]);
2115 auto const value = test_lib.find_last_of('/');
2116 if (value == std::string::npos) {
2117 test_lib = "./";
2118 } else {
2119 test_lib = test_lib.substr(0, value + 1) + "./";
2120 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08002121 return test_lib + "libcrash_test.so";
2122}
2123
2124static void CreateEmbeddedLibrary(int out_fd) {
2125 std::string test_lib(GetTestLibraryPath());
2126 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2127 ASSERT_NE(fd.get(), -1);
2128 off_t file_size = lseek(fd, 0, SEEK_END);
2129 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2130 std::vector<uint8_t> contents(file_size);
2131 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2132
2133 // Put the shared library data at a pagesize() offset.
2134 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2135 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2136}
2137
2138TEST_F(CrasherTest, non_zero_offset_in_library) {
2139 int intercept_result;
2140 unique_fd output_fd;
2141 TemporaryFile tf;
2142 CreateEmbeddedLibrary(tf.fd);
2143 StartProcess([&tf]() {
2144 android_dlextinfo extinfo{};
2145 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2146 extinfo.library_fd = tf.fd;
2147 extinfo.library_fd_offset = 4 * getpagesize();
2148 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2149 if (handle == nullptr) {
2150 _exit(1);
2151 }
2152 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2153 if (crash_func == nullptr) {
2154 _exit(1);
2155 }
2156 crash_func();
2157 });
2158
2159 StartIntercept(&output_fd);
2160 FinishCrasher();
2161 AssertDeath(SIGSEGV);
2162 FinishIntercept(&intercept_result);
2163
2164 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2165
2166 std::string result;
2167 ConsumeFd(std::move(output_fd), &result);
2168
2169 // Verify the crash includes an offset value in the backtrace.
2170 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2171 tf.path, 4 * getpagesize());
2172 ASSERT_MATCH(result, match_str);
2173}
2174
2175static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2176 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002177
2178 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2179 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2180
2181 // Copy the shared so to a tempory directory.
2182 return system(cp_cmd.c_str()) == 0;
2183}
2184
2185TEST_F(CrasherTest, unreadable_elf) {
2186 int intercept_result;
2187 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002188 std::string tmp_so_name;
2189 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002190 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002191 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2192 _exit(1);
2193 }
2194 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2195 if (handle == nullptr) {
2196 _exit(1);
2197 }
2198 // Delete the original shared library so that we get the warning
2199 // about unreadable elf files.
2200 if (unlink(tmp_so_name.c_str()) == -1) {
2201 _exit(1);
2202 }
2203 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2204 if (crash_func == nullptr) {
2205 _exit(1);
2206 }
2207 crash_func();
2208 });
2209
2210 StartIntercept(&output_fd);
2211 FinishCrasher();
2212 AssertDeath(SIGSEGV);
2213 FinishIntercept(&intercept_result);
2214
2215 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2216
2217 std::string result;
2218 ConsumeFd(std::move(output_fd), &result);
2219 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002220 std::string match_str = "NOTE: " + tmp_so_name;
2221 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002222}
2223
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002224void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
2225 static std::regex tombstone_re("tombstone_\\d+");
Christopher Ferris35da2882021-02-17 15:39:06 -08002226 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2227 ASSERT_TRUE(dir_h != nullptr);
Christopher Ferris35da2882021-02-17 15:39:06 -08002228 dirent* entry;
2229 while ((entry = readdir(dir_h.get())) != nullptr) {
2230 if (!std::regex_match(entry->d_name, tombstone_re)) {
2231 continue;
2232 }
2233 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002234
2235 struct stat st;
2236 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2237 continue;
2238 }
2239
2240 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002241 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002242 break;
2243 }
2244 }
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002245}
Josh Gao76e1e302021-01-26 15:53:11 -08002246
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002247TEST(tombstoned, proto) {
2248 const pid_t self = getpid();
2249 unique_fd tombstoned_socket, text_fd, proto_fd;
2250 ASSERT_TRUE(
2251 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2252
2253 tombstoned_notify_completion(tombstoned_socket.get());
2254
2255 ASSERT_NE(-1, text_fd.get());
2256 ASSERT_NE(-1, proto_fd.get());
2257
2258 struct stat text_st;
2259 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2260
2261 std::optional<std::string> tombstone_file;
2262 // Allow up to 5 seconds for the tombstone to be written to the system.
2263 const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
2264 const auto start = std::chrono::high_resolution_clock::now();
2265 while (true) {
2266 std::this_thread::sleep_for(100ms);
2267 CheckForTombstone(text_st, tombstone_file);
2268 if (tombstone_file) {
2269 break;
2270 }
2271 if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
2272 break;
2273 }
2274 }
2275
2276 ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
Christopher Ferris35da2882021-02-17 15:39:06 -08002277 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002278
2279 struct stat proto_fd_st;
2280 struct stat proto_file_st;
2281 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2282 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2283
2284 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2285 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2286}
2287
2288TEST(tombstoned, proto_intercept) {
2289 const pid_t self = getpid();
2290 unique_fd intercept_fd, output_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002291
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002292 InterceptResponse response = {};
2293 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2294 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2295 << "Error message: " << response.error_message;
Josh Gao76e1e302021-01-26 15:53:11 -08002296
2297 unique_fd tombstoned_socket, text_fd, proto_fd;
2298 ASSERT_TRUE(
2299 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2300 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2301 tombstoned_notify_completion(tombstoned_socket.get());
2302
2303 text_fd.reset();
2304
2305 std::string output;
2306 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2307 ASSERT_EQ("foo", output);
2308}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002309
2310// Verify that when an intercept is present for the main thread, and the signal
2311// is received on a different thread, the intercept still works.
2312TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2313 StartProcess([]() {
2314 std::thread thread([]() {
2315 // Raise the signal on the side thread.
2316 raise_debugger_signal(kDebuggerdNativeBacktrace);
2317 });
2318 thread.join();
2319 _exit(0);
2320 });
2321
2322 unique_fd output_fd;
2323 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2324 FinishCrasher();
2325 AssertDeath(0);
2326
2327 int intercept_result;
2328 FinishIntercept(&intercept_result);
2329 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2330
2331 std::string result;
2332 ConsumeFd(std::move(output_fd), &result);
2333 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2334}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002335
2336static std::string format_pointer(uintptr_t ptr) {
2337#if defined(__LP64__)
2338 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2339 static_cast<uint32_t>(ptr & 0xffffffff));
2340#else
2341 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2342#endif
2343}
2344
2345static std::string format_pointer(void* ptr) {
2346 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2347}
2348
2349static std::string format_full_pointer(uintptr_t ptr) {
2350#if defined(__LP64__)
2351 return android::base::StringPrintf("%016" PRIx64, ptr);
2352#else
2353 return android::base::StringPrintf("%08x", ptr);
2354#endif
2355}
2356
2357static std::string format_full_pointer(void* ptr) {
2358 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2359}
2360
2361__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2362 int* crash_ptr = reinterpret_cast<int*>(ptr);
2363 *crash_ptr = 1;
2364 return *crash_ptr;
2365}
2366
2367// Verify that a fault address before the first map is properly handled.
2368TEST_F(CrasherTest, fault_address_before_first_map) {
2369 StartProcess([]() {
2370 ASSERT_EQ(0, crash_call(0x1024));
2371 _exit(0);
2372 });
2373
2374 unique_fd output_fd;
2375 StartIntercept(&output_fd);
2376 FinishCrasher();
2377 AssertDeath(SIGSEGV);
2378
2379 int intercept_result;
2380 FinishIntercept(&intercept_result);
2381 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2382
2383 std::string result;
2384 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002385 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002386
2387 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2388
2389 std::string match_str = android::base::StringPrintf(
2390 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2391 format_pointer(0x1024).c_str());
2392 ASSERT_MATCH(result, match_str);
2393}
2394
2395// Verify that a fault address after the last map is properly handled.
2396TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002397 // This makes assumptions about the memory layout that are not true in HWASan
2398 // processes.
2399 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002400 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2401 StartProcess([crash_uptr]() {
2402 ASSERT_EQ(0, crash_call(crash_uptr));
2403 _exit(0);
2404 });
2405
2406 unique_fd output_fd;
2407 StartIntercept(&output_fd);
2408 FinishCrasher();
2409 AssertDeath(SIGSEGV);
2410
2411 int intercept_result;
2412 FinishIntercept(&intercept_result);
2413 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2414
2415 std::string result;
2416 ConsumeFd(std::move(output_fd), &result);
2417
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002418 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2419 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002420 ASSERT_MATCH(result, match_str);
2421
2422 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2423
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002424 // Verifies that the fault address error message is at the end of the
2425 // maps section. To do this, the check below looks for the start of the
2426 // open files section or the start of the log file section. It's possible
2427 // for either of these sections to be present after the maps section right
2428 // now.
2429 // If the sections move around, this check might need to be modified.
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002430 match_str = android::base::StringPrintf(
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002431 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002432 format_pointer(crash_uptr).c_str());
2433 ASSERT_MATCH(result, match_str);
2434}
2435
2436// Verify that a fault address between maps is properly handled.
2437TEST_F(CrasherTest, fault_address_between_maps) {
2438 // Create a map before the fork so it will be present in the child.
2439 void* start_ptr =
2440 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2441 ASSERT_NE(MAP_FAILED, start_ptr);
2442 // Unmap the page in the middle.
2443 void* middle_ptr =
2444 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2445 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2446
2447 StartProcess([middle_ptr]() {
2448 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2449 _exit(0);
2450 });
2451
2452 // Unmap the two maps.
2453 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2454 void* end_ptr =
2455 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2456 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2457
2458 unique_fd output_fd;
2459 StartIntercept(&output_fd);
2460 FinishCrasher();
2461 AssertDeath(SIGSEGV);
2462
2463 int intercept_result;
2464 FinishIntercept(&intercept_result);
2465 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2466
2467 std::string result;
2468 ConsumeFd(std::move(output_fd), &result);
2469
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002470 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2471 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002472 ASSERT_MATCH(result, match_str);
2473
2474 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2475
2476 match_str = android::base::StringPrintf(
2477 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2478 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2479 format_pointer(end_ptr).c_str());
2480 ASSERT_MATCH(result, match_str);
2481}
2482
2483// Verify that a fault address happens in the correct map.
2484TEST_F(CrasherTest, fault_address_in_map) {
2485 // Create a map before the fork so it will be present in the child.
2486 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2487 ASSERT_NE(MAP_FAILED, ptr);
2488
2489 StartProcess([ptr]() {
2490 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2491 _exit(0);
2492 });
2493
2494 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2495
2496 unique_fd output_fd;
2497 StartIntercept(&output_fd);
2498 FinishCrasher();
2499 AssertDeath(SIGSEGV);
2500
2501 int intercept_result;
2502 FinishIntercept(&intercept_result);
2503 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2504
2505 std::string result;
2506 ConsumeFd(std::move(output_fd), &result);
2507
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002508 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2509 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002510 ASSERT_MATCH(result, match_str);
2511
2512 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2513
2514 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2515 ASSERT_MATCH(result, match_str);
2516}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002517
2518static constexpr uint32_t kDexData[] = {
2519 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2520 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2521 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2522 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2523 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2524 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2525 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2526 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2527 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2528 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2529 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2530 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2531 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2532 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2533 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2534 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2535 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2536};
2537
2538TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2539 StartProcess([]() {
2540 TemporaryDir td;
2541 std::string tmp_so_name;
2542 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2543 _exit(1);
2544 }
2545
2546 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2547 // move the library to which has a basename of libart.so.
2548 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2549 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2550 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2551 if (handle == nullptr) {
2552 _exit(1);
2553 }
2554
2555 void* ptr =
2556 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2557 ASSERT_TRUE(ptr != MAP_FAILED);
2558 memcpy(ptr, kDexData, sizeof(kDexData));
2559 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2560
2561 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2562 .symfile_size = sizeof(kDexData)};
2563
2564 JITDescriptor* dex_debug =
2565 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2566 ASSERT_TRUE(dex_debug != nullptr);
2567 dex_debug->version = 1;
2568 dex_debug->action_flag = 0;
2569 dex_debug->relevant_entry = 0;
2570 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2571
2572 // This sets the magic dex pc value for register 0, using the value
2573 // of register 1 + 0x102.
2574 asm(".cfi_escape "
2575 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2576 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2577 "0x13 /* DW_OP_drop */,"
2578 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2579
2580 // For each different architecture, set register one to the dex ptr mmap
2581 // created above. Then do a nullptr dereference to force a crash.
2582#if defined(__arm__)
2583 asm volatile(
2584 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002585 "mov r2, #0\n"
2586 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002587 : [base] "+r"(ptr)
2588 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002589 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002590#elif defined(__aarch64__)
2591 asm volatile(
2592 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002593 "mov x2, #0\n"
2594 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002595 : [base] "+r"(ptr)
2596 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002597 : "x1", "x2", "memory");
2598#elif defined(__riscv)
2599 // TODO: x1 is ra (the link register) on riscv64, so this might have
2600 // unintended consequences, but we'll need to change the .cfi_escape if so.
2601 asm volatile(
2602 "mv x1, %[base]\n"
2603 "sw zero, 0(zero)\n"
2604 : [base] "+r"(ptr)
2605 :
2606 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002607#elif defined(__i386__)
2608 asm volatile(
2609 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002610 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002611 : [base] "+r"(ptr)
2612 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002613 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002614#elif defined(__x86_64__)
2615 asm volatile(
2616 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002617 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002618 : [base] "+r"(ptr)
2619 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002620 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002621#else
2622#error "Unsupported architecture"
2623#endif
2624 _exit(0);
2625 });
2626
2627 unique_fd output_fd;
2628 StartIntercept(&output_fd);
2629 FinishCrasher();
2630 AssertDeath(SIGSEGV);
2631
2632 int intercept_result;
2633 FinishIntercept(&intercept_result);
2634 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2635
2636 std::string result;
2637 ConsumeFd(std::move(output_fd), &result);
2638
2639 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002640 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002641
2642 // Now verify that the dex_pc frame includes a proper function name.
2643 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2644}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002645
2646static std::string format_map_pointer(uintptr_t ptr) {
2647#if defined(__LP64__)
2648 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2649 static_cast<uint32_t>(ptr & 0xffffffff));
2650#else
2651 return android::base::StringPrintf("%08x", ptr);
2652#endif
2653}
2654
2655// Verify that map data is properly formatted.
2656TEST_F(CrasherTest, verify_map_format) {
2657 // Create multiple maps to make sure that the map data is formatted properly.
2658 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2659 ASSERT_NE(MAP_FAILED, none_map);
2660 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2661 ASSERT_NE(MAP_FAILED, r_map);
2662 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2663 ASSERT_NE(MAP_FAILED, w_map);
2664 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2665 ASSERT_NE(MAP_FAILED, x_map);
2666
2667 TemporaryFile tf;
2668 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2669 char c = 'f';
2670 ASSERT_EQ(1, write(tf.fd, &c, 1));
2671 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2672 ASSERT_EQ(1, write(tf.fd, &c, 1));
2673 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2674 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2675 ASSERT_NE(MAP_FAILED, file_map);
2676
2677 StartProcess([]() { abort(); });
2678
2679 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2680 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2681 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2682 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2683 ASSERT_EQ(0, munmap(file_map, 0x3001));
2684
2685 unique_fd output_fd;
2686 StartIntercept(&output_fd);
2687 FinishCrasher();
2688 AssertDeath(SIGABRT);
2689 int intercept_result;
2690 FinishIntercept(&intercept_result);
2691
2692 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2693
2694 std::string result;
2695 ConsumeFd(std::move(output_fd), &result);
2696
2697 std::string match_str;
2698 // Verify none.
2699 match_str = android::base::StringPrintf(
2700 " %s-%s --- 0 1000\\n",
2701 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2702 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2703 ASSERT_MATCH(result, match_str);
2704
2705 // Verify read-only.
2706 match_str = android::base::StringPrintf(
2707 " %s-%s r-- 0 1000\\n",
2708 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2709 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2710 ASSERT_MATCH(result, match_str);
2711
2712 // Verify write-only.
2713 match_str = android::base::StringPrintf(
2714 " %s-%s -w- 0 1000\\n",
2715 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2716 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2717 ASSERT_MATCH(result, match_str);
2718
2719 // Verify exec-only.
2720 match_str = android::base::StringPrintf(
2721 " %s-%s --x 0 1000\\n",
2722 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2723 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2724 ASSERT_MATCH(result, match_str);
2725
2726 // Verify file map with non-zero offset and a name.
2727 match_str = android::base::StringPrintf(
2728 " %s-%s r-- 2000 4000 %s\\n",
2729 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2730 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2731 ASSERT_MATCH(result, match_str);
2732}
2733
2734// Verify that the tombstone map data is correct.
2735TEST_F(CrasherTest, verify_header) {
2736 StartProcess([]() { abort(); });
2737
2738 unique_fd output_fd;
2739 StartIntercept(&output_fd);
2740 FinishCrasher();
2741 AssertDeath(SIGABRT);
2742 int intercept_result;
2743 FinishIntercept(&intercept_result);
2744
2745 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2746
2747 std::string result;
2748 ConsumeFd(std::move(output_fd), &result);
2749
2750 std::string match_str = android::base::StringPrintf(
2751 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2752 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2753 android::base::GetProperty("ro.revision", "unknown").c_str());
2754 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2755 ASSERT_MATCH(result, match_str);
2756}
2757
2758// Verify that the thread header is formatted properly.
2759TEST_F(CrasherTest, verify_thread_header) {
2760 void* shared_map =
2761 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2762 ASSERT_NE(MAP_FAILED, shared_map);
2763 memset(shared_map, 0, sizeof(pid_t));
2764
2765 StartProcess([&shared_map]() {
2766 std::atomic_bool tid_written;
2767 std::thread thread([&tid_written, &shared_map]() {
2768 pid_t tid = gettid();
2769 memcpy(shared_map, &tid, sizeof(pid_t));
2770 tid_written = true;
2771 volatile bool done = false;
2772 while (!done)
2773 ;
2774 });
2775 thread.detach();
2776 while (!tid_written.load(std::memory_order_acquire))
2777 ;
2778 abort();
2779 });
2780
2781 pid_t primary_pid = crasher_pid;
2782
2783 unique_fd output_fd;
2784 StartIntercept(&output_fd);
2785 FinishCrasher();
2786 AssertDeath(SIGABRT);
2787 int intercept_result;
2788 FinishIntercept(&intercept_result);
2789 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2790
2791 // Read the tid data out.
2792 pid_t tid;
2793 memcpy(&tid, shared_map, sizeof(pid_t));
2794 ASSERT_NE(0, tid);
2795
2796 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2797
2798 std::string result;
2799 ConsumeFd(std::move(output_fd), &result);
2800
2801 // Verify that there are two headers, one where the tid is "primary_pid"
2802 // and the other where the tid is "tid".
2803 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2804 primary_pid, primary_pid);
2805 ASSERT_MATCH(result, match_str);
2806
2807 match_str =
2808 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2809 ASSERT_MATCH(result, match_str);
2810}
2811
2812// Verify that there is a BuildID present in the map section and set properly.
2813TEST_F(CrasherTest, verify_build_id) {
2814 StartProcess([]() { abort(); });
2815
2816 unique_fd output_fd;
2817 StartIntercept(&output_fd);
2818 FinishCrasher();
2819 AssertDeath(SIGABRT);
2820 int intercept_result;
2821 FinishIntercept(&intercept_result);
2822 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2823
2824 std::string result;
2825 ConsumeFd(std::move(output_fd), &result);
2826
2827 // Find every /system or /apex lib and verify the BuildID is displayed
2828 // properly.
2829 bool found_valid_elf = false;
2830 std::smatch match;
2831 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2832 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2833 result = match.suffix()) {
2834 if (prev_file == match[1]) {
2835 // Already checked this file.
2836 continue;
2837 }
2838
2839 prev_file = match[1];
Christopher Ferris15038902023-11-10 00:05:49 -08002840 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
2841 unwindstack::Elf elf(elf_memory);
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002842 if (!elf.Init() || !elf.valid()) {
2843 // Skipping invalid elf files.
2844 continue;
2845 }
2846 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2847
2848 found_valid_elf = true;
2849 }
2850 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2851}
Christopher Ferrisbda10642023-04-24 18:14:53 -07002852
2853const char kLogMessage[] = "Should not see this log message.";
2854
2855// Verify that the logd process does not read the log.
2856TEST_F(CrasherTest, logd_skips_reading_logs) {
2857 StartProcess([]() {
2858 pthread_setname_np(pthread_self(), "logd");
2859 LOG(INFO) << kLogMessage;
2860 abort();
2861 });
2862
2863 unique_fd output_fd;
2864 StartIntercept(&output_fd);
2865 FinishCrasher();
2866 AssertDeath(SIGABRT);
2867 int intercept_result;
2868 FinishIntercept(&intercept_result);
2869 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2870
2871 std::string result;
2872 ConsumeFd(std::move(output_fd), &result);
2873 // logd should not contain our log message.
2874 ASSERT_NOT_MATCH(result, kLogMessage);
2875}
2876
2877// Verify that the logd process does not read the log when the non-main
2878// thread crashes.
2879TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
2880 StartProcess([]() {
2881 pthread_setname_np(pthread_self(), "logd");
2882 LOG(INFO) << kLogMessage;
2883
2884 std::thread thread([]() {
2885 pthread_setname_np(pthread_self(), "not_logd_thread");
2886 // Raise the signal on the side thread.
2887 raise_debugger_signal(kDebuggerdTombstone);
2888 });
2889 thread.join();
2890 _exit(0);
2891 });
2892
2893 unique_fd output_fd;
2894 StartIntercept(&output_fd, kDebuggerdTombstone);
2895 FinishCrasher();
2896 AssertDeath(0);
2897
2898 int intercept_result;
2899 FinishIntercept(&intercept_result);
2900 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2901
2902 std::string result;
2903 ConsumeFd(std::move(output_fd), &result);
2904 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2905 ASSERT_NOT_MATCH(result, kLogMessage);
2906}
Christopher Ferris98d62422023-05-24 20:01:10 +00002907
2908// Disable this test since there is a high liklihood that this would
2909// be flaky since it requires 500 messages being in the log.
2910TEST_F(CrasherTest, DISABLED_max_log_messages) {
2911 StartProcess([]() {
2912 for (size_t i = 0; i < 600; i++) {
2913 LOG(INFO) << "Message number " << i;
2914 }
2915 abort();
2916 });
2917
2918 unique_fd output_fd;
2919 StartIntercept(&output_fd);
2920 FinishCrasher();
2921 AssertDeath(SIGABRT);
2922 int intercept_result;
2923 FinishIntercept(&intercept_result);
2924 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2925
2926 std::string result;
2927 ConsumeFd(std::move(output_fd), &result);
2928 ASSERT_NOT_MATCH(result, "Message number 99");
2929 ASSERT_MATCH(result, "Message number 100");
2930 ASSERT_MATCH(result, "Message number 599");
2931}
2932
2933TEST_F(CrasherTest, log_with_newline) {
2934 StartProcess([]() {
2935 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
2936 abort();
2937 });
2938
2939 unique_fd output_fd;
2940 StartIntercept(&output_fd);
2941 FinishCrasher();
2942 AssertDeath(SIGABRT);
2943 int intercept_result;
2944 FinishIntercept(&intercept_result);
2945 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2946
2947 std::string result;
2948 ConsumeFd(std::move(output_fd), &result);
2949 ASSERT_MATCH(result, ":\\s*This line has a newline.");
2950 ASSERT_MATCH(result, ":\\s*This is on the next line.");
2951}