1 /*
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
17 #include <dirent.h>
18 #include <dlfcn.h>
19 #include <err.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <linux/prctl.h>
23 #include <malloc.h>
24 #include <pthread.h>
25 #include <setjmp.h>
26 #include <stdlib.h>
27 #include <sys/capability.h>
28 #include <sys/mman.h>
29 #include <sys/prctl.h>
30 #include <sys/ptrace.h>
31 #include <sys/resource.h>
32 #include <sys/syscall.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35
36 #include <chrono>
37 #include <regex>
38 #include <set>
39 #include <string>
40 #include <thread>
41
42 #include <android/crash_detail.h>
43 #include <android/dlext.h>
44 #include <android/fdsan.h>
45 #include <android/set_abort_message.h>
46 #include <bionic/malloc.h>
47 #include <bionic/mte.h>
48 #include <bionic/reserved_signals.h>
49
50 #include <android-base/cmsg.h>
51 #include <android-base/file.h>
52 #include <android-base/logging.h>
53 #include <android-base/macros.h>
54 #include <android-base/parseint.h>
55 #include <android-base/properties.h>
56 #include <android-base/stringprintf.h>
57 #include <android-base/strings.h>
58 #include <android-base/test_utils.h>
59 #include <android-base/unique_fd.h>
60 #include <cutils/sockets.h>
61 #include <gmock/gmock.h>
62 #include <gtest/gtest.h>
63
64 #include <unwindstack/Elf.h>
65 #include <unwindstack/Memory.h>
66
67 #include <libminijail.h>
68 #include <scoped_minijail.h>
69
70 #include "crash_test.h"
71 #include "debuggerd/handler.h"
72 #include "gtest/gtest.h"
73 #include "libdebuggerd/utility_host.h"
74 #include "protocol.h"
75 #include "tombstoned/tombstoned.h"
76 #include "util.h"
77
78 using namespace std::chrono_literals;
79
80 using android::base::SendFileDescriptors;
81 using android::base::unique_fd;
82 using ::testing::HasSubstr;
83
84 #if defined(__LP64__)
85 #define ARCH_SUFFIX "64"
86 #else
87 #define ARCH_SUFFIX ""
88 #endif
89
90 constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
91
92 #define TIMEOUT(seconds, expr) \
93 [&]() { \
94 struct sigaction old_sigaction; \
95 struct sigaction new_sigaction = {}; \
96 new_sigaction.sa_handler = [](int) {}; \
97 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
98 err(1, "sigaction failed"); \
99 } \
100 alarm(seconds * android::base::HwTimeoutMultiplier()); \
101 auto value = expr; \
102 int saved_errno = errno; \
103 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
104 err(1, "sigaction failed"); \
105 } \
106 alarm(0); \
107 errno = saved_errno; \
108 return value; \
109 }()
110
111 // Backtrace frame dump could contain:
112 // #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
113 // or
114 // #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
115 #define ASSERT_BACKTRACE_FRAME(result, frame_name) \
116 ASSERT_MATCH(result, \
117 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
118
tombstoned_intercept(pid_t target_pid,unique_fd * intercept_fd,unique_fd * output_fd,InterceptResponse * response,DebuggerdDumpType intercept_type)119 static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
120 InterceptResponse* response, DebuggerdDumpType intercept_type) {
121 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
122 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
123 if (intercept_fd->get() == -1) {
124 FAIL() << "failed to contact tombstoned: " << strerror(errno);
125 }
126
127 InterceptRequest req = {
128 .dump_type = intercept_type,
129 .pid = target_pid,
130 };
131
132 unique_fd output_pipe_write;
133 if (!Pipe(output_fd, &output_pipe_write)) {
134 FAIL() << "failed to create output pipe: " << strerror(errno);
135 }
136
137 std::string pipe_size_str;
138 int pipe_buffer_size;
139 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
140 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
141 }
142
143 pipe_size_str = android::base::Trim(pipe_size_str);
144
145 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
146 FAIL() << "failed to parse pipe max size";
147 }
148
149 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
150 FAIL() << "failed to set pipe size: " << strerror(errno);
151 }
152
153 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
154
155 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
156 output_pipe_write.reset();
157 if (rc != sizeof(req)) {
158 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
159 }
160
161 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), response, sizeof(*response)));
162 if (rc == -1) {
163 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
164 } else if (rc == 0) {
165 FAIL() << "failed to read response from tombstoned (EOF)";
166 } else if (rc != sizeof(*response)) {
167 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(*response)
168 << ", received " << rc;
169 }
170 }
171
pac_supported()172 static bool pac_supported() {
173 #if defined(__aarch64__)
174 return getauxval(AT_HWCAP) & HWCAP_PACA;
175 #else
176 return false;
177 #endif
178 }
179
180 class CrasherTest : public ::testing::Test {
181 public:
182 pid_t crasher_pid = -1;
183 bool previous_wait_for_debugger;
184 unique_fd crasher_pipe;
185 unique_fd intercept_fd;
186
187 CrasherTest();
188 ~CrasherTest();
189
190 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
191
192 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
193 void FinishIntercept(int* result);
194
195 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
196 void StartCrasher(const std::string& crash_type);
197 void FinishCrasher();
198 void AssertDeath(int signo);
199
200 static void Trap(void* ptr);
201 };
202
CrasherTest()203 CrasherTest::CrasherTest() {
204 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
205 android::base::SetProperty(kWaitForDebuggerKey, "0");
206
207 // Clear the old property too, just in case someone's been using it
208 // on this device. (We only document the new name, but we still support
209 // the old name so we don't break anyone's existing setups.)
210 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
211 }
212
~CrasherTest()213 CrasherTest::~CrasherTest() {
214 if (crasher_pid != -1) {
215 kill(crasher_pid, SIGKILL);
216 int status;
217 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
218 }
219
220 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
221 }
222
StartIntercept(unique_fd * output_fd,DebuggerdDumpType intercept_type)223 void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
224 if (crasher_pid == -1) {
225 FAIL() << "crasher hasn't been started";
226 }
227
228 InterceptResponse response = {};
229 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &response, intercept_type);
230 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
231 << "Error message: " << response.error_message;
232 }
233
FinishIntercept(int * result)234 void CrasherTest::FinishIntercept(int* result) {
235 InterceptResponse response;
236
237 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
238 if (rc == -1) {
239 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
240 } else if (rc == 0) {
241 *result = -1;
242 } else if (rc != sizeof(response)) {
243 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
244 << ", received " << rc;
245 } else {
246 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
247 }
248 }
249
StartProcess(std::function<void ()> function,std::function<pid_t ()> forker)250 void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
251 unique_fd read_pipe;
252 unique_fd crasher_read_pipe;
253 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
254 FAIL() << "failed to create pipe: " << strerror(errno);
255 }
256
257 crasher_pid = forker();
258 if (crasher_pid == -1) {
259 FAIL() << "fork failed: " << strerror(errno);
260 } else if (crasher_pid == 0) {
261 char dummy;
262 crasher_pipe.reset();
263 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
264 function();
265 _exit(0);
266 }
267 }
268
FinishCrasher()269 void CrasherTest::FinishCrasher() {
270 if (crasher_pipe == -1) {
271 FAIL() << "crasher pipe uninitialized";
272 }
273
274 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
275 if (rc == -1) {
276 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
277 } else if (rc == 0) {
278 FAIL() << "crasher pipe was closed";
279 }
280 }
281
AssertDeath(int signo)282 void CrasherTest::AssertDeath(int signo) {
283 int status;
284 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
285 if (pid != crasher_pid) {
286 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
287 strerror(errno));
288 sleep(100);
289 FAIL() << "failed to wait for crasher: " << strerror(errno);
290 }
291
292 if (signo == 0) {
293 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
294 ASSERT_EQ(0, WEXITSTATUS(signo));
295 } else {
296 ASSERT_FALSE(WIFEXITED(status));
297 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
298 ASSERT_EQ(signo, WTERMSIG(status));
299 }
300 crasher_pid = -1;
301 }
302
ConsumeFd(unique_fd fd,std::string * output)303 static void ConsumeFd(unique_fd fd, std::string* output) {
304 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
305 }
306
307 class LogcatCollector {
308 public:
LogcatCollector()309 LogcatCollector() { system("logcat -c"); }
310
Collect(std::string * output)311 void Collect(std::string* output) {
312 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
313 ASSERT_NE(cmd_stdout, nullptr);
314 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
315 ConsumeFd(std::move(tmp_fd), output);
316 pclose(cmd_stdout);
317 }
318 };
319
TEST_F(CrasherTest,smoke)320 TEST_F(CrasherTest, smoke) {
321 int intercept_result;
322 unique_fd output_fd;
323 StartProcess([]() {
324 *reinterpret_cast<volatile char*>(0xdead) = '1';
325 });
326
327 StartIntercept(&output_fd);
328 FinishCrasher();
329 AssertDeath(SIGSEGV);
330 FinishIntercept(&intercept_result);
331
332 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
333
334 std::string result;
335 ConsumeFd(std::move(output_fd), &result);
336 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
337
338 if (mte_supported()) {
339 // Test that the default TAGGED_ADDR_CTRL value is set.
340 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
341 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
342 }
343
344 if (pac_supported()) {
345 // Test that the default PAC_ENABLED_KEYS value is set.
346 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
347 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
348 }
349 }
350
TEST_F(CrasherTest,tagged_fault_addr)351 TEST_F(CrasherTest, tagged_fault_addr) {
352 #if !defined(__aarch64__)
353 GTEST_SKIP() << "Requires aarch64";
354 #endif
355 // HWASan crashes with SIGABRT on tag mismatch.
356 SKIP_WITH_HWASAN;
357 int intercept_result;
358 unique_fd output_fd;
359 StartProcess([]() {
360 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
361 });
362
363 StartIntercept(&output_fd);
364 FinishCrasher();
365 AssertDeath(SIGSEGV);
366 FinishIntercept(&intercept_result);
367
368 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
369
370 std::string result;
371 ConsumeFd(std::move(output_fd), &result);
372
373 // The address can either be tagged (new kernels) or untagged (old kernels).
374 ASSERT_MATCH(
375 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
376 }
377
Trap(void * ptr)378 void CrasherTest::Trap(void* ptr) {
379 void (*volatile f)(void*) = nullptr;
380 __asm__ __volatile__("" : : "r"(f) : "memory");
381 f(ptr);
382 }
383
TEST_F(CrasherTest,heap_addr_in_register)384 TEST_F(CrasherTest, heap_addr_in_register) {
385 #if defined(__i386__)
386 GTEST_SKIP() << "architecture does not pass arguments in registers";
387 #endif
388 // The memory dump in HWASan crashes sadly shows the memory near the registers
389 // in the HWASan dump function, rather the faulting context. This is a known
390 // issue.
391 SKIP_WITH_HWASAN;
392 int intercept_result;
393 unique_fd output_fd;
394 StartProcess([]() {
395 // Crash with a heap pointer in the first argument register.
396 Trap(malloc(1));
397 });
398
399 StartIntercept(&output_fd);
400 FinishCrasher();
401 int status;
402 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
403 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
404 // Don't test the signal number because different architectures use different signals for
405 // __builtin_trap().
406 FinishIntercept(&intercept_result);
407
408 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
409
410 std::string result;
411 ConsumeFd(std::move(output_fd), &result);
412
413 #if defined(__aarch64__)
414 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
415 #elif defined(__arm__)
416 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
417 #elif defined(__riscv)
418 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
419 #elif defined(__x86_64__)
420 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
421 #else
422 ASSERT_TRUE(false) << "unsupported architecture";
423 #endif
424 }
425
426 #if defined(__aarch64__)
SetTagCheckingLevelSync()427 static void SetTagCheckingLevelSync() {
428 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
429 abort();
430 }
431 }
432
SetTagCheckingLevelAsync()433 static void SetTagCheckingLevelAsync() {
434 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
435 abort();
436 }
437 }
438 #endif
439
440 struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
441
442 INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
443
TEST_P(SizeParamCrasherTest,mte_uaf)444 TEST_P(SizeParamCrasherTest, mte_uaf) {
445 #if defined(__aarch64__)
446 if (!mte_supported()) {
447 GTEST_SKIP() << "Requires MTE";
448 }
449
450 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
451 if (GetParam() == 0) {
452 return;
453 }
454
455 LogcatCollector logcat_collector;
456
457 int intercept_result;
458 unique_fd output_fd;
459 StartProcess([&]() {
460 SetTagCheckingLevelSync();
461 volatile int* p = (volatile int*)malloc(GetParam());
462 free((void *)p);
463 p[0] = 42;
464 });
465
466 StartIntercept(&output_fd);
467 FinishCrasher();
468 AssertDeath(SIGSEGV);
469 FinishIntercept(&intercept_result);
470
471 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
472
473 std::vector<std::string> log_sources(2);
474 ConsumeFd(std::move(output_fd), &log_sources[0]);
475 logcat_collector.Collect(&log_sources[1]);
476 // Tag dump only available in the tombstone, not logcat.
477 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
478
479 for (const auto& result : log_sources) {
480 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
481 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
482 std::to_string(GetParam()) + R"(-byte allocation)");
483 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
484 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
485 }
486 #else
487 GTEST_SKIP() << "Requires aarch64";
488 #endif
489 }
490
TEST_P(SizeParamCrasherTest,mte_oob_uaf)491 TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
492 #if defined(__aarch64__)
493 if (!mte_supported()) {
494 GTEST_SKIP() << "Requires MTE";
495 }
496
497 int intercept_result;
498 unique_fd output_fd;
499 StartProcess([&]() {
500 SetTagCheckingLevelSync();
501 volatile int* p = (volatile int*)malloc(GetParam());
502 free((void *)p);
503 p[-1] = 42;
504 });
505
506 StartIntercept(&output_fd);
507 FinishCrasher();
508 AssertDeath(SIGSEGV);
509 FinishIntercept(&intercept_result);
510
511 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
512
513 std::string result;
514 ConsumeFd(std::move(output_fd), &result);
515
516 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
517 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
518 #else
519 GTEST_SKIP() << "Requires aarch64";
520 #endif
521 }
522
TEST_P(SizeParamCrasherTest,mte_overflow)523 TEST_P(SizeParamCrasherTest, mte_overflow) {
524 #if defined(__aarch64__)
525 if (!mte_supported()) {
526 GTEST_SKIP() << "Requires MTE";
527 }
528
529 LogcatCollector logcat_collector;
530 int intercept_result;
531 unique_fd output_fd;
532 StartProcess([&]() {
533 SetTagCheckingLevelSync();
534 volatile char* p = (volatile char*)malloc(GetParam());
535 p[GetParam()] = 42;
536 });
537
538 StartIntercept(&output_fd);
539 FinishCrasher();
540 AssertDeath(SIGSEGV);
541 FinishIntercept(&intercept_result);
542
543 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
544
545 std::vector<std::string> log_sources(2);
546 ConsumeFd(std::move(output_fd), &log_sources[0]);
547 logcat_collector.Collect(&log_sources[1]);
548
549 // Tag dump only in tombstone, not logcat, and tagging is not used for
550 // overflow protection in the scudo secondary (guard pages are used instead).
551 if (GetParam() < 0x10000) {
552 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
553 }
554
555 for (const auto& result : log_sources) {
556 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
557 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
558 std::to_string(GetParam()) + R"(-byte allocation)");
559 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
560 }
561 #else
562 GTEST_SKIP() << "Requires aarch64";
563 #endif
564 }
565
TEST_P(SizeParamCrasherTest,mte_underflow)566 TEST_P(SizeParamCrasherTest, mte_underflow) {
567 #if defined(__aarch64__)
568 if (!mte_supported()) {
569 GTEST_SKIP() << "Requires MTE";
570 }
571
572 int intercept_result;
573 unique_fd output_fd;
574 StartProcess([&]() {
575 SetTagCheckingLevelSync();
576 volatile int* p = (volatile int*)malloc(GetParam());
577 p[-1] = 42;
578 });
579
580 StartIntercept(&output_fd);
581 FinishCrasher();
582 AssertDeath(SIGSEGV);
583 FinishIntercept(&intercept_result);
584
585 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
586
587 std::string result;
588 ConsumeFd(std::move(output_fd), &result);
589
590 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
591 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
592 std::to_string(GetParam()) + R"(-byte allocation)");
593 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
594 #00 pc)");
595 ASSERT_MATCH(result, "Memory tags around the fault address");
596 #else
597 GTEST_SKIP() << "Requires aarch64";
598 #endif
599 }
600
mte_illegal_setjmp_helper(jmp_buf & jump_buf)601 __attribute__((noinline)) void mte_illegal_setjmp_helper(jmp_buf& jump_buf) {
602 // This frame is at least 8 bytes for storing and restoring the LR before the
603 // setjmp below. So this can never get an empty stack frame, even if we omit
604 // the frame pointer. So, the SP of this is always less (numerically) than the
605 // calling function frame.
606 setjmp(jump_buf);
607 }
608
TEST_F(CrasherTest,DISABLED_mte_illegal_setjmp)609 TEST_F(CrasherTest, DISABLED_mte_illegal_setjmp) {
610 // This setjmp is illegal because it jumps back into a function that already returned.
611 // Quoting man 3 setjmp:
612 // If the function which called setjmp() returns before longjmp() is
613 // called, the behavior is undefined. Some kind of subtle or
614 // unsubtle chaos is sure to result.
615 // https://man7.org/linux/man-pages/man3/longjmp.3.html
616 #if defined(__aarch64__)
617 if (!mte_supported()) {
618 GTEST_SKIP() << "Requires MTE";
619 }
620
621 int intercept_result;
622 unique_fd output_fd;
623 StartProcess([&]() {
624 SetTagCheckingLevelSync();
625 jmp_buf jump_buf;
626 mte_illegal_setjmp_helper(jump_buf);
627 longjmp(jump_buf, 1);
628 });
629
630 StartIntercept(&output_fd);
631 FinishCrasher();
632 AssertDeath(SIGABRT);
633 FinishIntercept(&intercept_result);
634
635 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
636
637 std::string result;
638 ConsumeFd(std::move(output_fd), &result);
639
640 // In our test-case, we have a NEGATIVE stack adjustment, which is being
641 // interpreted as unsigned integer, and thus is "too large".
642 // TODO(fmayer): fix the error message for this
643 ASSERT_MATCH(result, R"(memtag_handle_longjmp: stack adjustment too large)");
644 #else
645 GTEST_SKIP() << "Requires aarch64";
646 #endif
647 }
648
TEST_F(CrasherTest,mte_async)649 TEST_F(CrasherTest, mte_async) {
650 #if defined(__aarch64__)
651 if (!mte_supported()) {
652 GTEST_SKIP() << "Requires MTE";
653 }
654
655 int intercept_result;
656 unique_fd output_fd;
657 StartProcess([&]() {
658 SetTagCheckingLevelAsync();
659 volatile int* p = (volatile int*)malloc(16);
660 p[-1] = 42;
661 });
662
663 StartIntercept(&output_fd);
664 FinishCrasher();
665 AssertDeath(SIGSEGV);
666 FinishIntercept(&intercept_result);
667
668 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
669
670 std::string result;
671 ConsumeFd(std::move(output_fd), &result);
672
673 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
674 #else
675 GTEST_SKIP() << "Requires aarch64";
676 #endif
677 }
678
TEST_F(CrasherTest,mte_multiple_causes)679 TEST_F(CrasherTest, mte_multiple_causes) {
680 #if defined(__aarch64__)
681 if (!mte_supported()) {
682 GTEST_SKIP() << "Requires MTE";
683 }
684
685 LogcatCollector logcat_collector;
686
687 int intercept_result;
688 unique_fd output_fd;
689 StartProcess([]() {
690 SetTagCheckingLevelSync();
691
692 // Make two allocations with the same tag and close to one another. Check for both properties
693 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
694 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
695 // (some non-zero value << 56) apart.
696 //
697 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
698 // other.
699 std::set<uintptr_t> allocs;
700 for (int i = 0; i != 4096; ++i) {
701 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
702 auto it = allocs.insert(alloc).first;
703 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
704 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
705 }
706 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
707 *reinterpret_cast<int*>(alloc + 16) = 42;
708 }
709 }
710 });
711
712 StartIntercept(&output_fd);
713 FinishCrasher();
714 AssertDeath(SIGSEGV);
715 FinishIntercept(&intercept_result);
716
717 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
718
719 std::vector<std::string> log_sources(2);
720 ConsumeFd(std::move(output_fd), &log_sources[0]);
721 logcat_collector.Collect(&log_sources[1]);
722
723 // Tag dump only in the tombstone, not logcat.
724 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
725
726 for (const auto& result : log_sources) {
727 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
728 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
729 "listing them in decreasing order of likelihood."));
730 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
731 // overflows), so we can't match explicitly for an underflow message.
732 ASSERT_MATCH(result,
733 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
734 // Ensure there's at least two allocation traces (one for each cause).
735 ASSERT_MATCH(
736 result,
737 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
738 }
739 #else
740 GTEST_SKIP() << "Requires aarch64";
741 #endif
742 }
743
744 #if defined(__aarch64__)
CreateTagMapping()745 static uintptr_t CreateTagMapping() {
746 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
747 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
748 size_t page_size = getpagesize();
749 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
750 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
751 if (mapping == MAP_FAILED) {
752 return 0;
753 }
754 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
755 PROT_READ | PROT_WRITE | PROT_MTE);
756 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
757 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
758 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
759 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
760 }
761 return mapping_uptr + page_size;
762 }
763 #endif
764
TEST_F(CrasherTest,mte_register_tag_dump)765 TEST_F(CrasherTest, mte_register_tag_dump) {
766 #if defined(__aarch64__)
767 if (!mte_supported()) {
768 GTEST_SKIP() << "Requires MTE";
769 }
770
771 int intercept_result;
772 unique_fd output_fd;
773 StartProcess([&]() {
774 SetTagCheckingLevelSync();
775 Trap(reinterpret_cast<void *>(CreateTagMapping()));
776 });
777
778 StartIntercept(&output_fd);
779 FinishCrasher();
780 AssertDeath(SIGSEGV);
781 FinishIntercept(&intercept_result);
782
783 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
784
785 std::string result;
786 ConsumeFd(std::move(output_fd), &result);
787
788 ASSERT_MATCH(result, R"(memory near x0:
789 .*
790 .*
791 01.............0 0000000000000000 0000000000000000 ................
792 00.............0)");
793 #else
794 GTEST_SKIP() << "Requires aarch64";
795 #endif
796 }
797
TEST_F(CrasherTest,mte_fault_tag_dump_front_truncated)798 TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
799 #if defined(__aarch64__)
800 if (!mte_supported()) {
801 GTEST_SKIP() << "Requires MTE";
802 }
803
804 int intercept_result;
805 unique_fd output_fd;
806 StartProcess([&]() {
807 SetTagCheckingLevelSync();
808 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
809 p[0] = 0; // Untagged pointer, tagged memory.
810 });
811
812 StartIntercept(&output_fd);
813 FinishCrasher();
814 AssertDeath(SIGSEGV);
815 FinishIntercept(&intercept_result);
816
817 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
818
819 std::string result;
820 ConsumeFd(std::move(output_fd), &result);
821
822 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
823 \s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
824 #else
825 GTEST_SKIP() << "Requires aarch64";
826 #endif
827 }
828
TEST_F(CrasherTest,mte_fault_tag_dump)829 TEST_F(CrasherTest, mte_fault_tag_dump) {
830 #if defined(__aarch64__)
831 if (!mte_supported()) {
832 GTEST_SKIP() << "Requires MTE";
833 }
834
835 int intercept_result;
836 unique_fd output_fd;
837 StartProcess([&]() {
838 SetTagCheckingLevelSync();
839 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
840 p[320] = 0; // Untagged pointer, tagged memory.
841 });
842
843 StartIntercept(&output_fd);
844 FinishCrasher();
845 AssertDeath(SIGSEGV);
846 FinishIntercept(&intercept_result);
847
848 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
849
850 std::string result;
851 ConsumeFd(std::move(output_fd), &result);
852
853 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
854 \s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
855 \s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
856 \s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
857 )");
858 #else
859 GTEST_SKIP() << "Requires aarch64";
860 #endif
861 }
862
TEST_F(CrasherTest,mte_fault_tag_dump_rear_truncated)863 TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
864 #if defined(__aarch64__)
865 if (!mte_supported()) {
866 GTEST_SKIP() << "Requires MTE";
867 }
868
869 int intercept_result;
870 unique_fd output_fd;
871 StartProcess([&]() {
872 SetTagCheckingLevelSync();
873 size_t page_size = getpagesize();
874 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
875 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
876 });
877
878 StartIntercept(&output_fd);
879 FinishCrasher();
880 AssertDeath(SIGSEGV);
881 FinishIntercept(&intercept_result);
882
883 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
884
885 std::string result;
886 ConsumeFd(std::move(output_fd), &result);
887
888 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
889 ASSERT_MATCH(result,
890 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
891 \s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
892
893 )"); // Ensure truncation happened and there's a newline after the tag fault.
894 #else
895 GTEST_SKIP() << "Requires aarch64";
896 #endif
897 }
898
TEST_F(CrasherTest,LD_PRELOAD)899 TEST_F(CrasherTest, LD_PRELOAD) {
900 int intercept_result;
901 unique_fd output_fd;
902 StartProcess([]() {
903 setenv("LD_PRELOAD", "nonexistent.so", 1);
904 *reinterpret_cast<volatile char*>(0xdead) = '1';
905 });
906
907 StartIntercept(&output_fd);
908 FinishCrasher();
909 AssertDeath(SIGSEGV);
910 FinishIntercept(&intercept_result);
911
912 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
913
914 std::string result;
915 ConsumeFd(std::move(output_fd), &result);
916 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
917 }
918
TEST_F(CrasherTest,abort)919 TEST_F(CrasherTest, abort) {
920 int intercept_result;
921 unique_fd output_fd;
922 StartProcess([]() {
923 abort();
924 });
925 StartIntercept(&output_fd);
926 FinishCrasher();
927 AssertDeath(SIGABRT);
928 FinishIntercept(&intercept_result);
929
930 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
931
932 std::string result;
933 ConsumeFd(std::move(output_fd), &result);
934 ASSERT_BACKTRACE_FRAME(result, "abort");
935 }
936
TEST_F(CrasherTest,signal)937 TEST_F(CrasherTest, signal) {
938 int intercept_result;
939 unique_fd output_fd;
940 StartProcess([]() {
941 while (true) {
942 sleep(1);
943 }
944 });
945 StartIntercept(&output_fd);
946 FinishCrasher();
947 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
948
949 AssertDeath(SIGSEGV);
950 FinishIntercept(&intercept_result);
951
952 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
953
954 std::string result;
955 ConsumeFd(std::move(output_fd), &result);
956 ASSERT_MATCH(
957 result,
958 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
959 ASSERT_MATCH(result, R"(backtrace:)");
960 }
961
TEST_F(CrasherTest,abort_message)962 TEST_F(CrasherTest, abort_message) {
963 int intercept_result;
964 unique_fd output_fd;
965 StartProcess([]() {
966 // Arrived at experimentally;
967 // logd truncates at 4062.
968 // strlen("Abort message: ''") is 17.
969 // That's 4045, but we also want a NUL.
970 char buf[4045 + 1];
971 memset(buf, 'x', sizeof(buf));
972 buf[sizeof(buf) - 1] = '\0';
973 android_set_abort_message(buf);
974 abort();
975 });
976 StartIntercept(&output_fd);
977 FinishCrasher();
978 AssertDeath(SIGABRT);
979 FinishIntercept(&intercept_result);
980
981 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
982
983 std::string result;
984 ConsumeFd(std::move(output_fd), &result);
985 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
986 }
987
988 static char g_crash_detail_value_changes[] = "crash_detail_value";
989 static char g_crash_detail_value[] = "crash_detail_value";
990 static char g_crash_detail_value2[] = "crash_detail_value2";
991
android_register_crash_detail_strs(const char * _Nonnull name,const char * _Nonnull data)992 inline crash_detail_t* _Nullable android_register_crash_detail_strs(const char* _Nonnull name,
993 const char* _Nonnull data) {
994 return android_crash_detail_register(name, strlen(name), data, strlen(data));
995 }
996
TEST_F(CrasherTest,crash_detail_single)997 TEST_F(CrasherTest, crash_detail_single) {
998 int intercept_result;
999 unique_fd output_fd;
1000 StartProcess([]() {
1001 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1002 abort();
1003 });
1004 StartIntercept(&output_fd);
1005 FinishCrasher();
1006 AssertDeath(SIGABRT);
1007 FinishIntercept(&intercept_result);
1008
1009 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1010
1011 std::string result;
1012 ConsumeFd(std::move(output_fd), &result);
1013 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1014 }
1015
TEST_F(CrasherTest,crash_detail_replace_data)1016 TEST_F(CrasherTest, crash_detail_replace_data) {
1017 int intercept_result;
1018 unique_fd output_fd;
1019 StartProcess([]() {
1020 auto *cd = android_register_crash_detail_strs("CRASH_DETAIL_NAME", "original_data");
1021 android_crash_detail_replace_data(cd, "new_data", strlen("new_data"));
1022 abort();
1023 });
1024 StartIntercept(&output_fd);
1025 FinishCrasher();
1026 AssertDeath(SIGABRT);
1027 FinishIntercept(&intercept_result);
1028
1029 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1030
1031 std::string result;
1032 ConsumeFd(std::move(output_fd), &result);
1033 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'new_data')");
1034 // Ensure the old one no longer shows up, i.e. that we actually replaced
1035 // it, not added a new one.
1036 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'original_data')");
1037 }
1038
TEST_F(CrasherTest,crash_detail_replace_name)1039 TEST_F(CrasherTest, crash_detail_replace_name) {
1040 int intercept_result;
1041 unique_fd output_fd;
1042 StartProcess([]() {
1043 auto *cd = android_register_crash_detail_strs("old_name", g_crash_detail_value);
1044 android_crash_detail_replace_name(cd, "new_name", strlen("new_name"));
1045 abort();
1046 });
1047 StartIntercept(&output_fd);
1048 FinishCrasher();
1049 AssertDeath(SIGABRT);
1050 FinishIntercept(&intercept_result);
1051
1052 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1053
1054 std::string result;
1055 ConsumeFd(std::move(output_fd), &result);
1056 ASSERT_MATCH(result, R"(new_name: 'crash_detail_value')");
1057 // Ensure the old one no longer shows up, i.e. that we actually replaced
1058 // it, not added a new one.
1059 ASSERT_NOT_MATCH(result, R"(old_name: 'crash_detail_value')");
1060 }
1061
TEST_F(CrasherTest,crash_detail_single_byte_name)1062 TEST_F(CrasherTest, crash_detail_single_byte_name) {
1063 int intercept_result;
1064 unique_fd output_fd;
1065 StartProcess([]() {
1066 android_register_crash_detail_strs("CRASH_DETAIL_NAME\1", g_crash_detail_value);
1067 abort();
1068 });
1069 StartIntercept(&output_fd);
1070 FinishCrasher();
1071 AssertDeath(SIGABRT);
1072 FinishIntercept(&intercept_result);
1073
1074 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1075
1076 std::string result;
1077 ConsumeFd(std::move(output_fd), &result);
1078 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME\\1: 'crash_detail_value')");
1079 }
1080
1081
TEST_F(CrasherTest,crash_detail_single_bytes)1082 TEST_F(CrasherTest, crash_detail_single_bytes) {
1083 int intercept_result;
1084 unique_fd output_fd;
1085 StartProcess([]() {
1086 android_crash_detail_register("CRASH_DETAIL_NAME", strlen("CRASH_DETAIL_NAME"), "\1",
1087 sizeof("\1"));
1088 abort();
1089 });
1090 StartIntercept(&output_fd);
1091 FinishCrasher();
1092 AssertDeath(SIGABRT);
1093 FinishIntercept(&intercept_result);
1094
1095 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1096
1097 std::string result;
1098 ConsumeFd(std::move(output_fd), &result);
1099 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: '\\1\\0')");
1100 }
1101
TEST_F(CrasherTest,crash_detail_mixed)1102 TEST_F(CrasherTest, crash_detail_mixed) {
1103 int intercept_result;
1104 unique_fd output_fd;
1105 StartProcess([]() {
1106 const char data[] = "helloworld\1\255\3";
1107 android_register_crash_detail_strs("CRASH_DETAIL_NAME", data);
1108 abort();
1109 });
1110 StartIntercept(&output_fd);
1111 FinishCrasher();
1112 AssertDeath(SIGABRT);
1113 FinishIntercept(&intercept_result);
1114
1115 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1116
1117 std::string result;
1118 ConsumeFd(std::move(output_fd), &result);
1119 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'helloworld\\1\\255\\3')");
1120 }
1121
TEST_F(CrasherTest,crash_detail_many)1122 TEST_F(CrasherTest, crash_detail_many) {
1123 int intercept_result;
1124 unique_fd output_fd;
1125 StartProcess([]() {
1126 for (int i = 0; i < 1000; ++i) {
1127 std::string name = "CRASH_DETAIL_NAME" + std::to_string(i);
1128 std::string value = "CRASH_DETAIL_VALUE" + std::to_string(i);
1129 auto* h = android_register_crash_detail_strs(name.data(), value.data());
1130 android_crash_detail_unregister(h);
1131 }
1132
1133 android_register_crash_detail_strs("FINAL_NAME", "FINAL_VALUE");
1134 android_register_crash_detail_strs("FINAL_NAME2", "FINAL_VALUE2");
1135 abort();
1136 });
1137 StartIntercept(&output_fd);
1138 FinishCrasher();
1139 AssertDeath(SIGABRT);
1140 FinishIntercept(&intercept_result);
1141
1142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1143
1144 std::string result;
1145 ConsumeFd(std::move(output_fd), &result);
1146 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_NAME");
1147 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_VALUE");
1148 ASSERT_MATCH(result, R"(FINAL_NAME: 'FINAL_VALUE')");
1149 ASSERT_MATCH(result, R"(FINAL_NAME2: 'FINAL_VALUE2')");
1150 }
1151
TEST_F(CrasherTest,crash_detail_single_changes)1152 TEST_F(CrasherTest, crash_detail_single_changes) {
1153 int intercept_result;
1154 unique_fd output_fd;
1155 StartProcess([]() {
1156 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value_changes);
1157 g_crash_detail_value_changes[0] = 'C';
1158 abort();
1159 });
1160 StartIntercept(&output_fd);
1161 FinishCrasher();
1162 AssertDeath(SIGABRT);
1163 FinishIntercept(&intercept_result);
1164
1165 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1166
1167 std::string result;
1168 ConsumeFd(std::move(output_fd), &result);
1169 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'Crash_detail_value')");
1170 }
1171
TEST_F(CrasherTest,crash_detail_multiple)1172 TEST_F(CrasherTest, crash_detail_multiple) {
1173 int intercept_result;
1174 unique_fd output_fd;
1175 StartProcess([]() {
1176 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1177 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1178 abort();
1179 });
1180 StartIntercept(&output_fd);
1181 FinishCrasher();
1182 AssertDeath(SIGABRT);
1183 FinishIntercept(&intercept_result);
1184
1185 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1186
1187 std::string result;
1188 ConsumeFd(std::move(output_fd), &result);
1189 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1190 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1191 }
1192
TEST_F(CrasherTest,crash_detail_remove)1193 TEST_F(CrasherTest, crash_detail_remove) {
1194 int intercept_result;
1195 unique_fd output_fd;
1196 StartProcess([]() {
1197 auto* detail1 = android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1198 android_crash_detail_unregister(detail1);
1199 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1200 abort();
1201 });
1202 StartIntercept(&output_fd);
1203 FinishCrasher();
1204 AssertDeath(SIGABRT);
1205 FinishIntercept(&intercept_result);
1206
1207 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1208
1209 std::string result;
1210 ConsumeFd(std::move(output_fd), &result);
1211 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1212 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1213 }
1214
TEST_F(CrasherTest,abort_message_newline_trimmed)1215 TEST_F(CrasherTest, abort_message_newline_trimmed) {
1216 int intercept_result;
1217 unique_fd output_fd;
1218 StartProcess([]() {
1219 android_set_abort_message("Message with a newline.\n");
1220 abort();
1221 });
1222 StartIntercept(&output_fd);
1223 FinishCrasher();
1224 AssertDeath(SIGABRT);
1225 FinishIntercept(&intercept_result);
1226
1227 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1228
1229 std::string result;
1230 ConsumeFd(std::move(output_fd), &result);
1231 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1232 }
1233
TEST_F(CrasherTest,abort_message_multiple_newlines_trimmed)1234 TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1235 int intercept_result;
1236 unique_fd output_fd;
1237 StartProcess([]() {
1238 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1239 abort();
1240 });
1241 StartIntercept(&output_fd);
1242 FinishCrasher();
1243 AssertDeath(SIGABRT);
1244 FinishIntercept(&intercept_result);
1245
1246 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1247
1248 std::string result;
1249 ConsumeFd(std::move(output_fd), &result);
1250 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1251 }
1252
TEST_F(CrasherTest,abort_message_backtrace)1253 TEST_F(CrasherTest, abort_message_backtrace) {
1254 int intercept_result;
1255 unique_fd output_fd;
1256 StartProcess([]() {
1257 android_set_abort_message("not actually aborting");
1258 raise(BIONIC_SIGNAL_DEBUGGER);
1259 exit(0);
1260 });
1261 StartIntercept(&output_fd);
1262 FinishCrasher();
1263 AssertDeath(0);
1264 FinishIntercept(&intercept_result);
1265
1266 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1267
1268 std::string result;
1269 ConsumeFd(std::move(output_fd), &result);
1270 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1271 }
1272
TEST_F(CrasherTest,intercept_timeout)1273 TEST_F(CrasherTest, intercept_timeout) {
1274 int intercept_result;
1275 unique_fd output_fd;
1276 StartProcess([]() {
1277 abort();
1278 });
1279 StartIntercept(&output_fd);
1280
1281 // Don't let crasher finish until we timeout.
1282 FinishIntercept(&intercept_result);
1283
1284 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1285 << intercept_result << ")";
1286
1287 FinishCrasher();
1288 AssertDeath(SIGABRT);
1289 }
1290
TEST_F(CrasherTest,wait_for_debugger)1291 TEST_F(CrasherTest, wait_for_debugger) {
1292 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1293 FAIL() << "failed to enable wait_for_debugger";
1294 }
1295 sleep(1);
1296
1297 StartProcess([]() {
1298 abort();
1299 });
1300 FinishCrasher();
1301
1302 int status;
1303 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
1304 ASSERT_TRUE(WIFSTOPPED(status));
1305 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1306
1307 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1308
1309 AssertDeath(SIGABRT);
1310 }
1311
TEST_F(CrasherTest,backtrace)1312 TEST_F(CrasherTest, backtrace) {
1313 std::string result;
1314 int intercept_result;
1315 unique_fd output_fd;
1316
1317 StartProcess([]() {
1318 abort();
1319 });
1320 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1321
1322 std::this_thread::sleep_for(500ms);
1323
1324 sigval val;
1325 val.sival_int = 1;
1326 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
1327 FinishIntercept(&intercept_result);
1328 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1329 ConsumeFd(std::move(output_fd), &result);
1330 ASSERT_BACKTRACE_FRAME(result, "read");
1331
1332 int status;
1333 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1334
1335 StartIntercept(&output_fd);
1336 FinishCrasher();
1337 AssertDeath(SIGABRT);
1338 FinishIntercept(&intercept_result);
1339 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1340 ConsumeFd(std::move(output_fd), &result);
1341 ASSERT_BACKTRACE_FRAME(result, "abort");
1342 }
1343
TEST_F(CrasherTest,PR_SET_DUMPABLE_0_crash)1344 TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
1345 int intercept_result;
1346 unique_fd output_fd;
1347 StartProcess([]() {
1348 prctl(PR_SET_DUMPABLE, 0);
1349 abort();
1350 });
1351
1352 StartIntercept(&output_fd);
1353 FinishCrasher();
1354 AssertDeath(SIGABRT);
1355 FinishIntercept(&intercept_result);
1356
1357 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1358
1359 std::string result;
1360 ConsumeFd(std::move(output_fd), &result);
1361 ASSERT_BACKTRACE_FRAME(result, "abort");
1362 }
1363
TEST_F(CrasherTest,capabilities)1364 TEST_F(CrasherTest, capabilities) {
1365 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1366
1367 StartProcess([]() {
1368 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1369 err(1, "failed to set PR_SET_KEEPCAPS");
1370 }
1371
1372 if (setresuid(1, 1, 1) != 0) {
1373 err(1, "setresuid failed");
1374 }
1375
1376 __user_cap_header_struct capheader;
1377 __user_cap_data_struct capdata[2];
1378 memset(&capheader, 0, sizeof(capheader));
1379 memset(&capdata, 0, sizeof(capdata));
1380
1381 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1382 capheader.pid = 0;
1383
1384 // Turn on every third capability.
1385 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1386 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1387 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1388 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1389 }
1390
1391 // Make sure CAP_SYS_PTRACE is off.
1392 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1393 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1394
1395 if (capset(&capheader, &capdata[0]) != 0) {
1396 err(1, "capset failed");
1397 }
1398
1399 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1400 err(1, "failed to drop ambient capabilities");
1401 }
1402
1403 pthread_setname_np(pthread_self(), "thread_name");
1404 raise(SIGSYS);
1405 });
1406
1407 unique_fd output_fd;
1408 StartIntercept(&output_fd);
1409 FinishCrasher();
1410 AssertDeath(SIGSYS);
1411
1412 std::string result;
1413 int intercept_result;
1414 FinishIntercept(&intercept_result);
1415 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1416 ConsumeFd(std::move(output_fd), &result);
1417 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
1418 ASSERT_BACKTRACE_FRAME(result, "tgkill");
1419 }
1420
TEST_F(CrasherTest,fake_pid)1421 TEST_F(CrasherTest, fake_pid) {
1422 int intercept_result;
1423 unique_fd output_fd;
1424
1425 // Prime the getpid/gettid caches.
1426 UNUSED(getpid());
1427 UNUSED(gettid());
1428
1429 std::function<pid_t()> clone_fn = []() {
1430 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1431 };
1432 StartProcess(
1433 []() {
1434 ASSERT_NE(getpid(), syscall(__NR_getpid));
1435 ASSERT_NE(gettid(), syscall(__NR_gettid));
1436 raise(SIGSEGV);
1437 },
1438 clone_fn);
1439
1440 StartIntercept(&output_fd);
1441 FinishCrasher();
1442 AssertDeath(SIGSEGV);
1443 FinishIntercept(&intercept_result);
1444
1445 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1446
1447 std::string result;
1448 ConsumeFd(std::move(output_fd), &result);
1449 ASSERT_BACKTRACE_FRAME(result, "tgkill");
1450 }
1451
1452 static const char* const kDebuggerdSeccompPolicy =
1453 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1454
setup_jail(minijail * jail)1455 static void setup_jail(minijail* jail) {
1456 if (!jail) {
1457 LOG(FATAL) << "failed to create minijail";
1458 }
1459
1460 std::string policy;
1461 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1462 PLOG(FATAL) << "failed to read policy file";
1463 }
1464
1465 // Allow a bunch of syscalls used by the tests.
1466 policy += "\nclone: 1";
1467 policy += "\nsigaltstack: 1";
1468 policy += "\nnanosleep: 1";
1469 policy += "\ngetrlimit: 1";
1470 policy += "\nugetrlimit: 1";
1471
1472 FILE* tmp_file = tmpfile();
1473 if (!tmp_file) {
1474 PLOG(FATAL) << "tmpfile failed";
1475 }
1476
1477 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
1478 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1479 PLOG(FATAL) << "failed to write policy to tmpfile";
1480 }
1481
1482 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1483 PLOG(FATAL) << "failed to seek tmp_fd";
1484 }
1485
1486 minijail_no_new_privs(jail);
1487 minijail_log_seccomp_filter_failures(jail);
1488 minijail_use_seccomp_filter(jail);
1489 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1490 }
1491
seccomp_fork_impl(void (* prejail)())1492 static pid_t seccomp_fork_impl(void (*prejail)()) {
1493 ScopedMinijail jail{minijail_new()};
1494 setup_jail(jail.get());
1495
1496 pid_t result = fork();
1497 if (result == -1) {
1498 return result;
1499 } else if (result != 0) {
1500 return result;
1501 }
1502
1503 // Spawn and detach a thread that spins forever.
1504 std::atomic<bool> thread_ready(false);
1505 std::thread thread([&jail, &thread_ready]() {
1506 minijail_enter(jail.get());
1507 thread_ready = true;
1508 for (;;)
1509 ;
1510 });
1511 thread.detach();
1512
1513 while (!thread_ready) {
1514 continue;
1515 }
1516
1517 if (prejail) {
1518 prejail();
1519 }
1520
1521 minijail_enter(jail.get());
1522 return result;
1523 }
1524
seccomp_fork()1525 static pid_t seccomp_fork() {
1526 return seccomp_fork_impl(nullptr);
1527 }
1528
TEST_F(CrasherTest,seccomp_crash)1529 TEST_F(CrasherTest, seccomp_crash) {
1530 int intercept_result;
1531 unique_fd output_fd;
1532
1533 StartProcess([]() { abort(); }, &seccomp_fork);
1534
1535 StartIntercept(&output_fd);
1536 FinishCrasher();
1537 AssertDeath(SIGABRT);
1538 FinishIntercept(&intercept_result);
1539 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1540
1541 std::string result;
1542 ConsumeFd(std::move(output_fd), &result);
1543 ASSERT_BACKTRACE_FRAME(result, "abort");
1544 }
1545
seccomp_fork_rlimit()1546 static pid_t seccomp_fork_rlimit() {
1547 return seccomp_fork_impl([]() {
1548 struct rlimit rlim = {
1549 .rlim_cur = 512 * 1024 * 1024,
1550 .rlim_max = 512 * 1024 * 1024,
1551 };
1552
1553 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1554 raise(SIGINT);
1555 }
1556 });
1557 }
1558
TEST_F(CrasherTest,seccomp_crash_oom)1559 TEST_F(CrasherTest, seccomp_crash_oom) {
1560 int intercept_result;
1561 unique_fd output_fd;
1562
1563 StartProcess(
1564 []() {
1565 std::vector<void*> vec;
1566 for (int i = 0; i < 512; ++i) {
1567 char* buf = static_cast<char*>(malloc(1024 * 1024));
1568 if (!buf) {
1569 abort();
1570 }
1571 memset(buf, 0xff, 1024 * 1024);
1572 vec.push_back(buf);
1573 }
1574 },
1575 &seccomp_fork_rlimit);
1576
1577 StartIntercept(&output_fd);
1578 FinishCrasher();
1579 AssertDeath(SIGABRT);
1580 FinishIntercept(&intercept_result);
1581 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1582
1583 // We can't actually generate a backtrace, just make sure that the process terminates.
1584 }
1585
raise_debugger_signal(DebuggerdDumpType dump_type)1586 __attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1587 siginfo_t siginfo;
1588 siginfo.si_code = SI_QUEUE;
1589 siginfo.si_pid = getpid();
1590 siginfo.si_uid = getuid();
1591
1592 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1593 PLOG(FATAL) << "invalid dump type";
1594 }
1595
1596 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1597
1598 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
1599 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1600 return false;
1601 }
1602
1603 return true;
1604 }
1605
foo()1606 extern "C" void foo() {
1607 LOG(INFO) << "foo";
1608 std::this_thread::sleep_for(1s);
1609 }
1610
bar()1611 extern "C" void bar() {
1612 LOG(INFO) << "bar";
1613 std::this_thread::sleep_for(1s);
1614 }
1615
TEST_F(CrasherTest,seccomp_tombstone)1616 TEST_F(CrasherTest, seccomp_tombstone) {
1617 int intercept_result;
1618 unique_fd output_fd;
1619
1620 static const auto dump_type = kDebuggerdTombstone;
1621 StartProcess(
1622 []() {
1623 std::thread a(foo);
1624 std::thread b(bar);
1625
1626 std::this_thread::sleep_for(100ms);
1627
1628 raise_debugger_signal(dump_type);
1629 _exit(0);
1630 },
1631 &seccomp_fork);
1632
1633 StartIntercept(&output_fd, dump_type);
1634 FinishCrasher();
1635 AssertDeath(0);
1636 FinishIntercept(&intercept_result);
1637 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1638
1639 std::string result;
1640 ConsumeFd(std::move(output_fd), &result);
1641 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1642 ASSERT_BACKTRACE_FRAME(result, "foo");
1643 ASSERT_BACKTRACE_FRAME(result, "bar");
1644 }
1645
TEST_F(CrasherTest,seccomp_tombstone_thread_abort)1646 TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1647 int intercept_result;
1648 unique_fd output_fd;
1649
1650 static const auto dump_type = kDebuggerdTombstone;
1651 StartProcess(
1652 []() {
1653 std::thread abort_thread([] { abort(); });
1654 abort_thread.join();
1655 },
1656 &seccomp_fork);
1657
1658 StartIntercept(&output_fd, dump_type);
1659 FinishCrasher();
1660 AssertDeath(SIGABRT);
1661 FinishIntercept(&intercept_result);
1662 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1663
1664 std::string result;
1665 ConsumeFd(std::move(output_fd), &result);
1666 ASSERT_MATCH(
1667 result,
1668 R"(signal 6 \(SIGABRT\))");
1669 ASSERT_BACKTRACE_FRAME(result, "abort");
1670 }
1671
TEST_F(CrasherTest,seccomp_tombstone_multiple_threads_abort)1672 TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1673 int intercept_result;
1674 unique_fd output_fd;
1675
1676 static const auto dump_type = kDebuggerdTombstone;
1677 StartProcess(
1678 []() {
1679 std::thread a(foo);
1680 std::thread b(bar);
1681
1682 std::this_thread::sleep_for(100ms);
1683
1684 std::thread abort_thread([] { abort(); });
1685 abort_thread.join();
1686 },
1687 &seccomp_fork);
1688
1689 StartIntercept(&output_fd, dump_type);
1690 FinishCrasher();
1691 AssertDeath(SIGABRT);
1692 FinishIntercept(&intercept_result);
1693 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1694
1695 std::string result;
1696 ConsumeFd(std::move(output_fd), &result);
1697 ASSERT_BACKTRACE_FRAME(result, "abort");
1698 ASSERT_BACKTRACE_FRAME(result, "foo");
1699 ASSERT_BACKTRACE_FRAME(result, "bar");
1700 ASSERT_BACKTRACE_FRAME(result, "main");
1701 }
1702
TEST_F(CrasherTest,seccomp_backtrace)1703 TEST_F(CrasherTest, seccomp_backtrace) {
1704 int intercept_result;
1705 unique_fd output_fd;
1706
1707 static const auto dump_type = kDebuggerdNativeBacktrace;
1708 StartProcess(
1709 []() {
1710 std::thread a(foo);
1711 std::thread b(bar);
1712
1713 std::this_thread::sleep_for(100ms);
1714
1715 raise_debugger_signal(dump_type);
1716 _exit(0);
1717 },
1718 &seccomp_fork);
1719
1720 StartIntercept(&output_fd, dump_type);
1721 FinishCrasher();
1722 AssertDeath(0);
1723 FinishIntercept(&intercept_result);
1724 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1725
1726 std::string result;
1727 ConsumeFd(std::move(output_fd), &result);
1728 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1729 ASSERT_BACKTRACE_FRAME(result, "foo");
1730 ASSERT_BACKTRACE_FRAME(result, "bar");
1731 }
1732
TEST_F(CrasherTest,seccomp_backtrace_from_thread)1733 TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1734 int intercept_result;
1735 unique_fd output_fd;
1736
1737 static const auto dump_type = kDebuggerdNativeBacktrace;
1738 StartProcess(
1739 []() {
1740 std::thread a(foo);
1741 std::thread b(bar);
1742
1743 std::this_thread::sleep_for(100ms);
1744
1745 std::thread raise_thread([] {
1746 raise_debugger_signal(dump_type);
1747 _exit(0);
1748 });
1749 raise_thread.join();
1750 },
1751 &seccomp_fork);
1752
1753 StartIntercept(&output_fd, dump_type);
1754 FinishCrasher();
1755 AssertDeath(0);
1756 FinishIntercept(&intercept_result);
1757 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1758
1759 std::string result;
1760 ConsumeFd(std::move(output_fd), &result);
1761 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1762 ASSERT_BACKTRACE_FRAME(result, "foo");
1763 ASSERT_BACKTRACE_FRAME(result, "bar");
1764 ASSERT_BACKTRACE_FRAME(result, "main");
1765 }
1766
TEST_F(CrasherTest,seccomp_crash_logcat)1767 TEST_F(CrasherTest, seccomp_crash_logcat) {
1768 StartProcess([]() { abort(); }, &seccomp_fork);
1769 FinishCrasher();
1770
1771 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1772 AssertDeath(SIGABRT);
1773 }
1774
1775 extern "C" void malloc_enable();
1776 extern "C" void malloc_disable();
1777
TEST_F(CrasherTest,seccomp_tombstone_no_allocation)1778 TEST_F(CrasherTest, seccomp_tombstone_no_allocation) {
1779 int intercept_result;
1780 unique_fd output_fd;
1781
1782 static const auto dump_type = kDebuggerdTombstone;
1783 StartProcess(
1784 []() {
1785 std::thread a(foo);
1786 std::thread b(bar);
1787
1788 std::this_thread::sleep_for(100ms);
1789
1790 // Disable allocations to verify that nothing in the fallback
1791 // signal handler does an allocation.
1792 malloc_disable();
1793 raise_debugger_signal(dump_type);
1794 _exit(0);
1795 },
1796 &seccomp_fork);
1797
1798 StartIntercept(&output_fd, dump_type);
1799 FinishCrasher();
1800 AssertDeath(0);
1801 FinishIntercept(&intercept_result);
1802 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1803
1804 std::string result;
1805 ConsumeFd(std::move(output_fd), &result);
1806 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1807 ASSERT_BACKTRACE_FRAME(result, "foo");
1808 ASSERT_BACKTRACE_FRAME(result, "bar");
1809 }
1810
TEST_F(CrasherTest,seccomp_backtrace_no_allocation)1811 TEST_F(CrasherTest, seccomp_backtrace_no_allocation) {
1812 int intercept_result;
1813 unique_fd output_fd;
1814
1815 static const auto dump_type = kDebuggerdNativeBacktrace;
1816 StartProcess(
1817 []() {
1818 std::thread a(foo);
1819 std::thread b(bar);
1820
1821 std::this_thread::sleep_for(100ms);
1822
1823 // Disable allocations to verify that nothing in the fallback
1824 // signal handler does an allocation.
1825 malloc_disable();
1826 raise_debugger_signal(dump_type);
1827 _exit(0);
1828 },
1829 &seccomp_fork);
1830
1831 StartIntercept(&output_fd, dump_type);
1832 FinishCrasher();
1833 AssertDeath(0);
1834 FinishIntercept(&intercept_result);
1835 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1836
1837 std::string result;
1838 ConsumeFd(std::move(output_fd), &result);
1839 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1840 ASSERT_BACKTRACE_FRAME(result, "foo");
1841 ASSERT_BACKTRACE_FRAME(result, "bar");
1842 }
1843
TEST_F(CrasherTest,competing_tracer)1844 TEST_F(CrasherTest, competing_tracer) {
1845 int intercept_result;
1846 unique_fd output_fd;
1847 StartProcess([]() {
1848 raise(SIGABRT);
1849 });
1850
1851 StartIntercept(&output_fd);
1852
1853 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
1854 FinishCrasher();
1855
1856 int status;
1857 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
1858 ASSERT_TRUE(WIFSTOPPED(status));
1859 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1860
1861 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1862 FinishIntercept(&intercept_result);
1863 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1864
1865 std::string result;
1866 ConsumeFd(std::move(output_fd), &result);
1867 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1868 regex += std::to_string(gettid());
1869 regex += R"( \(.+debuggerd_test)";
1870 ASSERT_MATCH(result, regex.c_str());
1871
1872 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
1873 ASSERT_TRUE(WIFSTOPPED(status));
1874 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1875
1876 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1877 AssertDeath(SIGABRT);
1878 }
1879
1880 struct GwpAsanTestParameters {
1881 size_t alloc_size;
1882 bool free_before_access;
1883 int access_offset;
1884 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1885 };
1886
1887 struct GwpAsanCrasherTest
1888 : CrasherTest,
1889 testing::WithParamInterface<
1890 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1891
1892 GwpAsanTestParameters gwp_asan_tests[] = {
1893 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1894 "Use After Free, 0 bytes into a 7-byte allocation"},
1895 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1896 "Use After Free, 1 byte into a 15-byte allocation"},
1897 {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
1898 /* access_offset */ getpagesize() + 2,
1899 android::base::StringPrintf("Buffer Overflow, 2 bytes right of a %d-byte allocation",
1900 getpagesize())},
1901 {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
1902 /* access_offset */ -1,
1903 android::base::StringPrintf("Buffer Underflow, 1 byte left of a %d-byte allocation",
1904 getpagesize())},
1905 };
1906
1907 INSTANTIATE_TEST_SUITE_P(
1908 GwpAsanTests, GwpAsanCrasherTest,
1909 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1910 /* recoverable */ testing::Bool(),
1911 /* seccomp */ testing::Bool()),
1912 [](const testing::TestParamInfo<
__anon5e2643523702(const testing::TestParamInfo< std::tuple<GwpAsanTestParameters, bool, bool>>& info) 1913 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1914 const GwpAsanTestParameters& params = std::get<0>(info.param);
1915 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1916 name += testing::PrintToString(params.alloc_size);
1917 name += "Alloc";
1918 if (params.access_offset < 0) {
1919 name += "Left";
1920 name += testing::PrintToString(params.access_offset * -1);
1921 } else {
1922 name += "Right";
1923 name += testing::PrintToString(params.access_offset);
1924 }
1925 name += "Bytes";
1926 if (std::get<1>(info.param)) name += "Recoverable";
1927 if (std::get<2>(info.param)) name += "Seccomp";
1928 return name;
1929 });
1930
TEST_P(GwpAsanCrasherTest,run_gwp_asan_test)1931 TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1932 if (mte_supported()) {
1933 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1934 // instead of GWP-ASan.
1935 GTEST_SKIP() << "Skipped on MTE.";
1936 }
1937 // Skip this test on HWASan, which will reliably catch test errors as well.
1938 SKIP_WITH_HWASAN;
1939
1940 GwpAsanTestParameters params = std::get<0>(GetParam());
1941 bool recoverable = std::get<1>(GetParam());
1942 LogcatCollector logcat_collector;
1943
1944 int intercept_result;
1945 unique_fd output_fd;
1946 StartProcess([&recoverable]() {
1947 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1948 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1949 if (!recoverable) {
1950 env[3] = "GWP_ASAN_RECOVERABLE=false";
1951 }
1952 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1953 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1954 "DISABLED_run_gwp_asan_test");
1955 std::string test_filter = "--gtest_filter=*";
1956 test_filter += test_name;
1957 std::string this_binary = android::base::GetExecutablePath();
1958 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1959 test_filter.c_str(), nullptr};
1960 // We check the crash report from a debuggerd handler and from logcat. The
1961 // echo from stdout/stderr of the subprocess trips up atest, because it
1962 // doesn't like that two tests started in a row without the first one
1963 // finishing (even though the second one is in a subprocess).
1964 close(STDOUT_FILENO);
1965 close(STDERR_FILENO);
1966 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1967 });
1968
1969 StartIntercept(&output_fd);
1970 FinishCrasher();
1971 if (recoverable) {
1972 AssertDeath(0);
1973 } else {
1974 AssertDeath(SIGSEGV);
1975 }
1976 FinishIntercept(&intercept_result);
1977
1978 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1979
1980 std::vector<std::string> log_sources(2);
1981 ConsumeFd(std::move(output_fd), &log_sources[0]);
1982 logcat_collector.Collect(&log_sources[1]);
1983
1984 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1985 // information. Make sure the recovery still works, but the report won't be
1986 // hugely useful, it looks like a regular SEGV.
1987 bool seccomp = std::get<2>(GetParam());
1988 if (!seccomp) {
1989 for (const auto& result : log_sources) {
1990 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1991 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1992 if (params.free_before_access) {
1993 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1994 }
1995 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1996 }
1997 }
1998 }
1999
TEST_P(GwpAsanCrasherTest,DISABLED_run_gwp_asan_test)2000 TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
2001 GwpAsanTestParameters params = std::get<0>(GetParam());
2002 bool seccomp = std::get<2>(GetParam());
2003 if (seccomp) {
2004 ScopedMinijail jail{minijail_new()};
2005 setup_jail(jail.get());
2006 minijail_enter(jail.get());
2007 }
2008
2009 // Use 'volatile' to prevent a very clever compiler eliminating the store.
2010 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
2011 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
2012 p[params.access_offset] = 42;
2013 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
2014
2015 bool recoverable = std::get<1>(GetParam());
2016 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
2017
2018 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
2019 // we end with at least one in a different slot), make sure the process still
2020 // doesn't crash.
2021 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
2022 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
2023 free(static_cast<void*>(const_cast<char*>(p)));
2024 free(static_cast<void*>(const_cast<char*>(p2)));
2025 *p = 42;
2026 *p2 = 42;
2027
2028 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
2029 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
2030 // coverage does. Thus, skip the atexit handlers.
2031 _exit(0);
2032 }
2033
TEST_F(CrasherTest,fdsan_warning_abort_message)2034 TEST_F(CrasherTest, fdsan_warning_abort_message) {
2035 int intercept_result;
2036 unique_fd output_fd;
2037
2038 StartProcess([]() {
2039 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
2040 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
2041 if (fd == -1) {
2042 abort();
2043 }
2044 close(fd.get());
2045 _exit(0);
2046 });
2047
2048 StartIntercept(&output_fd);
2049 FinishCrasher();
2050 AssertDeath(0);
2051 FinishIntercept(&intercept_result);
2052 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2053
2054 std::string result;
2055 ConsumeFd(std::move(output_fd), &result);
2056 ASSERT_MATCH(result, "Abort message: 'attempted to close");
2057 }
2058
TEST(crash_dump,zombie)2059 TEST(crash_dump, zombie) {
2060 pid_t forkpid = fork();
2061
2062 pid_t rc;
2063 int status;
2064
2065 if (forkpid == 0) {
2066 errno = 0;
2067 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
2068 if (rc != -1 || errno != ECHILD) {
2069 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
2070 }
2071
2072 raise(BIONIC_SIGNAL_DEBUGGER);
2073
2074 errno = 0;
2075 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
2076 if (rc != -1 || errno != ECHILD) {
2077 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
2078 }
2079 _exit(0);
2080 } else {
2081 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
2082 ASSERT_EQ(forkpid, rc);
2083 ASSERT_TRUE(WIFEXITED(status));
2084 ASSERT_EQ(0, WEXITSTATUS(status));
2085 }
2086 }
2087
TEST(tombstoned,no_notify)2088 TEST(tombstoned, no_notify) {
2089 // Do this a few times.
2090 for (int i = 0; i < 3; ++i) {
2091 pid_t pid = 123'456'789 + i;
2092
2093 unique_fd intercept_fd, output_fd;
2094 InterceptResponse response = {};
2095 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2096 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2097 << "Error message: " << response.error_message;
2098
2099 {
2100 unique_fd tombstoned_socket, input_fd;
2101 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
2102 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2103 }
2104
2105 pid_t read_pid;
2106 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2107 ASSERT_EQ(read_pid, pid);
2108 }
2109 }
2110
TEST(tombstoned,stress)2111 TEST(tombstoned, stress) {
2112 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
2113 static constexpr int kDumpCount = 100;
2114
2115 std::atomic<bool> start(false);
2116 std::vector<std::thread> threads;
2117 threads.emplace_back([&start]() {
2118 while (!start) {
2119 continue;
2120 }
2121
2122 // Use a way out of range pid, to avoid stomping on an actual process.
2123 pid_t pid_base = 1'000'000;
2124
2125 for (int dump = 0; dump < kDumpCount; ++dump) {
2126 pid_t pid = pid_base + dump;
2127
2128 unique_fd intercept_fd, output_fd;
2129 InterceptResponse response = {};
2130 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2131 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2132 << "Error messeage: " << response.error_message;
2133
2134 // Pretend to crash, and then immediately close the socket.
2135 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
2136 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
2137 if (sockfd == -1) {
2138 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
2139 }
2140 TombstonedCrashPacket packet = {};
2141 packet.packet_type = CrashPacketType::kDumpRequest;
2142 packet.packet.dump_request.pid = pid;
2143 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
2144 FAIL() << "failed to write to tombstoned: " << strerror(errno);
2145 }
2146
2147 continue;
2148 }
2149 });
2150
2151 threads.emplace_back([&start]() {
2152 while (!start) {
2153 continue;
2154 }
2155
2156 // Use a way out of range pid, to avoid stomping on an actual process.
2157 pid_t pid_base = 2'000'000;
2158
2159 for (int dump = 0; dump < kDumpCount; ++dump) {
2160 pid_t pid = pid_base + dump;
2161
2162 unique_fd intercept_fd, output_fd;
2163 InterceptResponse response = {};
2164 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2165 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2166 << "Error message: " << response.error_message;
2167
2168 {
2169 unique_fd tombstoned_socket, input_fd;
2170 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
2171 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2172 tombstoned_notify_completion(tombstoned_socket.get());
2173 }
2174
2175 // TODO: Fix the race that requires this sleep.
2176 std::this_thread::sleep_for(50ms);
2177
2178 pid_t read_pid;
2179 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2180 ASSERT_EQ(read_pid, pid);
2181 }
2182 });
2183
2184 start = true;
2185
2186 for (std::thread& thread : threads) {
2187 thread.join();
2188 }
2189 }
2190
TEST(tombstoned,intercept_java_trace_smoke)2191 TEST(tombstoned, intercept_java_trace_smoke) {
2192 // Using a "real" PID is a little dangerous here - if the test fails
2193 // or crashes, we might end up getting a bogus / unreliable stack
2194 // trace.
2195 const pid_t self = getpid();
2196
2197 unique_fd intercept_fd, output_fd;
2198 InterceptResponse response = {};
2199 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2200 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2201 << "Error message: " << response.error_message;
2202
2203 // First connect to tombstoned requesting a native tombstone. This
2204 // should result in a "regular" FD and not the installed intercept.
2205 const char native[] = "native";
2206 unique_fd tombstoned_socket, input_fd;
2207 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
2208 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
2209 tombstoned_notify_completion(tombstoned_socket.get());
2210
2211 // Then, connect to tombstoned asking for a java backtrace. This *should*
2212 // trigger the intercept.
2213 const char java[] = "java";
2214 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
2215 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
2216 tombstoned_notify_completion(tombstoned_socket.get());
2217
2218 char outbuf[sizeof(java)];
2219 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2220 ASSERT_STREQ("java", outbuf);
2221 }
2222
TEST(tombstoned,intercept_multiple_dump_types)2223 TEST(tombstoned, intercept_multiple_dump_types) {
2224 const pid_t fake_pid = 1'234'567;
2225 unique_fd intercept_fd, output_fd;
2226 InterceptResponse response = {};
2227 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2228 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2229 << "Error message: " << response.error_message;
2230
2231 unique_fd intercept_fd_2, output_fd_2;
2232 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
2233 kDebuggerdNativeBacktrace);
2234 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2235 << "Error message: " << response.error_message;
2236 }
2237
TEST(tombstoned,intercept_bad_pid)2238 TEST(tombstoned, intercept_bad_pid) {
2239 const pid_t fake_pid = -1;
2240 unique_fd intercept_fd, output_fd;
2241 InterceptResponse response = {};
2242 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2243 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2244 << "Error message: " << response.error_message;
2245 ASSERT_MATCH(response.error_message, "bad pid");
2246 }
2247
TEST(tombstoned,intercept_bad_dump_types)2248 TEST(tombstoned, intercept_bad_dump_types) {
2249 const pid_t fake_pid = 1'234'567;
2250 unique_fd intercept_fd, output_fd;
2251 InterceptResponse response = {};
2252 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
2253 static_cast<DebuggerdDumpType>(20));
2254 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2255 << "Error message: " << response.error_message;
2256 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
2257
2258 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
2259 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2260 << "Error message: " << response.error_message;
2261 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
2262
2263 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
2264 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2265 << "Error message: " << response.error_message;
2266 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
2267 }
2268
TEST(tombstoned,intercept_already_registered)2269 TEST(tombstoned, intercept_already_registered) {
2270 const pid_t fake_pid = 1'234'567;
2271 unique_fd intercept_fd1, output_fd1;
2272 InterceptResponse response = {};
2273 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
2274 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2275 << "Error message: " << response.error_message;
2276
2277 unique_fd intercept_fd2, output_fd2;
2278 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
2279 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
2280 << "Error message: " << response.error_message;
2281 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
2282 }
2283
TEST(tombstoned,intercept_tombstone_proto_matched_to_tombstone)2284 TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
2285 const pid_t fake_pid = 1'234'567;
2286
2287 unique_fd intercept_fd, output_fd;
2288 InterceptResponse response = {};
2289 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2290 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2291 << "Error message: " << response.error_message;
2292
2293 const char data[] = "tombstone_proto";
2294 unique_fd tombstoned_socket, input_fd;
2295 ASSERT_TRUE(
2296 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
2297 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
2298 tombstoned_notify_completion(tombstoned_socket.get());
2299
2300 char outbuf[sizeof(data)];
2301 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2302 ASSERT_STREQ("tombstone_proto", outbuf);
2303 }
2304
TEST(tombstoned,intercept_any)2305 TEST(tombstoned, intercept_any) {
2306 const pid_t fake_pid = 1'234'567;
2307
2308 unique_fd intercept_fd, output_fd;
2309 InterceptResponse response = {};
2310 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2311 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2312 << "Error message: " << response.error_message;
2313
2314 const char any[] = "any";
2315 unique_fd tombstoned_socket, input_fd;
2316 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2317 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
2318 tombstoned_notify_completion(tombstoned_socket.get());
2319
2320 char outbuf[sizeof(any)];
2321 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2322 ASSERT_STREQ("any", outbuf);
2323 }
2324
TEST(tombstoned,intercept_any_failed_with_multiple_intercepts)2325 TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
2326 const pid_t fake_pid = 1'234'567;
2327
2328 InterceptResponse response = {};
2329 unique_fd intercept_fd1, output_fd1;
2330 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2331 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2332 << "Error message: " << response.error_message;
2333
2334 unique_fd intercept_fd2, output_fd2;
2335 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2336 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2337 << "Error message: " << response.error_message;
2338
2339 unique_fd tombstoned_socket, input_fd;
2340 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2341 }
2342
TEST(tombstoned,intercept_multiple_verify_intercept)2343 TEST(tombstoned, intercept_multiple_verify_intercept) {
2344 // Need to use our pid for java since that will verify the pid.
2345 const pid_t fake_pid = getpid();
2346
2347 InterceptResponse response = {};
2348 unique_fd intercept_fd1, output_fd1;
2349 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2350 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2351 << "Error message: " << response.error_message;
2352
2353 unique_fd intercept_fd2, output_fd2;
2354 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2355 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2356 << "Error message: " << response.error_message;
2357
2358 unique_fd intercept_fd3, output_fd3;
2359 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2360 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2361 << "Error message: " << response.error_message;
2362
2363 const char native_data[] = "native";
2364 unique_fd tombstoned_socket1, input_fd1;
2365 ASSERT_TRUE(
2366 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2367 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2368 tombstoned_notify_completion(tombstoned_socket1.get());
2369
2370 char native_outbuf[sizeof(native_data)];
2371 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2372 ASSERT_STREQ("native", native_outbuf);
2373
2374 const char java_data[] = "java";
2375 unique_fd tombstoned_socket2, input_fd2;
2376 ASSERT_TRUE(
2377 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2378 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2379 tombstoned_notify_completion(tombstoned_socket2.get());
2380
2381 char java_outbuf[sizeof(java_data)];
2382 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2383 ASSERT_STREQ("java", java_outbuf);
2384
2385 const char tomb_data[] = "tombstone";
2386 unique_fd tombstoned_socket3, input_fd3;
2387 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2388 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2389 tombstoned_notify_completion(tombstoned_socket3.get());
2390
2391 char tomb_outbuf[sizeof(tomb_data)];
2392 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2393 ASSERT_STREQ("tombstone", tomb_outbuf);
2394 }
2395
TEST(tombstoned,interceptless_backtrace)2396 TEST(tombstoned, interceptless_backtrace) {
2397 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2398 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2399 std::map<int, time_t> result;
2400 for (int i = 0; i < 99; ++i) {
2401 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2402 struct stat st;
2403 if (stat(path.c_str(), &st) == 0) {
2404 result[i] = st.st_mtim.tv_sec;
2405 }
2406 }
2407 return result;
2408 };
2409
2410 auto before = get_tombstone_timestamps();
2411 for (int i = 0; i < 50; ++i) {
2412 raise_debugger_signal(kDebuggerdNativeBacktrace);
2413 }
2414 auto after = get_tombstone_timestamps();
2415
2416 int diff = 0;
2417 for (int i = 0; i < 99; ++i) {
2418 if (after.count(i) == 0) {
2419 continue;
2420 }
2421 if (before.count(i) == 0) {
2422 ++diff;
2423 continue;
2424 }
2425 if (before[i] != after[i]) {
2426 ++diff;
2427 }
2428 }
2429
2430 // We can't be sure that nothing's crash looping in the background.
2431 // This should be good enough, though...
2432 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2433 }
2434
overflow_stack(void * p)2435 static __attribute__((__noinline__)) void overflow_stack(void* p) {
2436 void* buf[1];
2437 buf[0] = p;
2438 static volatile void* global = buf;
2439 if (global) {
2440 global = buf;
2441 overflow_stack(&buf);
2442 }
2443 }
2444
TEST_F(CrasherTest,stack_overflow)2445 TEST_F(CrasherTest, stack_overflow) {
2446 int intercept_result;
2447 unique_fd output_fd;
2448 StartProcess([]() { overflow_stack(nullptr); });
2449
2450 StartIntercept(&output_fd);
2451 FinishCrasher();
2452 AssertDeath(SIGSEGV);
2453 FinishIntercept(&intercept_result);
2454
2455 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2456
2457 std::string result;
2458 ConsumeFd(std::move(output_fd), &result);
2459 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2460 }
2461
GetTestLibraryPath()2462 static std::string GetTestLibraryPath() {
2463 std::string test_lib(testing::internal::GetArgvs()[0]);
2464 auto const value = test_lib.find_last_of('/');
2465 if (value == std::string::npos) {
2466 test_lib = "./";
2467 } else {
2468 test_lib = test_lib.substr(0, value + 1) + "./";
2469 }
2470 return test_lib + "libcrash_test.so";
2471 }
2472
CreateEmbeddedLibrary(int out_fd)2473 static void CreateEmbeddedLibrary(int out_fd) {
2474 std::string test_lib(GetTestLibraryPath());
2475 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2476 ASSERT_NE(fd.get(), -1);
2477 off_t file_size = lseek(fd, 0, SEEK_END);
2478 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2479 std::vector<uint8_t> contents(file_size);
2480 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2481
2482 // Put the shared library data at a pagesize() offset.
2483 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2484 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2485 }
2486
TEST_F(CrasherTest,non_zero_offset_in_library)2487 TEST_F(CrasherTest, non_zero_offset_in_library) {
2488 int intercept_result;
2489 unique_fd output_fd;
2490 TemporaryFile tf;
2491 CreateEmbeddedLibrary(tf.fd);
2492 StartProcess([&tf]() {
2493 android_dlextinfo extinfo{};
2494 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2495 extinfo.library_fd = tf.fd;
2496 extinfo.library_fd_offset = 4 * getpagesize();
2497 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2498 if (handle == nullptr) {
2499 _exit(1);
2500 }
2501 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2502 if (crash_func == nullptr) {
2503 _exit(1);
2504 }
2505 crash_func();
2506 });
2507
2508 StartIntercept(&output_fd);
2509 FinishCrasher();
2510 AssertDeath(SIGSEGV);
2511 FinishIntercept(&intercept_result);
2512
2513 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2514
2515 std::string result;
2516 ConsumeFd(std::move(output_fd), &result);
2517
2518 // Verify the crash includes an offset value in the backtrace.
2519 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2520 tf.path, 4 * getpagesize());
2521 ASSERT_MATCH(result, match_str);
2522 }
2523
CopySharedLibrary(const char * tmp_dir,std::string * tmp_so_name)2524 static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2525 std::string test_lib(GetTestLibraryPath());
2526
2527 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2528 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2529
2530 // Copy the shared so to a tempory directory.
2531 return system(cp_cmd.c_str()) == 0;
2532 }
2533
TEST_F(CrasherTest,unreadable_elf)2534 TEST_F(CrasherTest, unreadable_elf) {
2535 int intercept_result;
2536 unique_fd output_fd;
2537 std::string tmp_so_name;
2538 StartProcess([&tmp_so_name]() {
2539 TemporaryDir td;
2540 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2541 _exit(1);
2542 }
2543 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2544 if (handle == nullptr) {
2545 _exit(1);
2546 }
2547 // Delete the original shared library so that we get the warning
2548 // about unreadable elf files.
2549 if (unlink(tmp_so_name.c_str()) == -1) {
2550 _exit(1);
2551 }
2552 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2553 if (crash_func == nullptr) {
2554 _exit(1);
2555 }
2556 crash_func();
2557 });
2558
2559 StartIntercept(&output_fd);
2560 FinishCrasher();
2561 AssertDeath(SIGSEGV);
2562 FinishIntercept(&intercept_result);
2563
2564 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2565
2566 std::string result;
2567 ConsumeFd(std::move(output_fd), &result);
2568 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
2569 std::string match_str = "NOTE: " + tmp_so_name;
2570 ASSERT_MATCH(result, match_str);
2571 }
2572
CheckForTombstone(const struct stat & text_st,std::optional<std::string> & tombstone_file)2573 void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
2574 static std::regex tombstone_re("tombstone_\\d+");
2575 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2576 ASSERT_TRUE(dir_h != nullptr);
2577 dirent* entry;
2578 while ((entry = readdir(dir_h.get())) != nullptr) {
2579 if (!std::regex_match(entry->d_name, tombstone_re)) {
2580 continue;
2581 }
2582 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
2583
2584 struct stat st;
2585 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2586 continue;
2587 }
2588
2589 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
2590 tombstone_file = path;
2591 break;
2592 }
2593 }
2594 }
2595
TEST(tombstoned,proto)2596 TEST(tombstoned, proto) {
2597 const pid_t self = getpid();
2598 unique_fd tombstoned_socket, text_fd, proto_fd;
2599 ASSERT_TRUE(
2600 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2601
2602 tombstoned_notify_completion(tombstoned_socket.get());
2603
2604 ASSERT_NE(-1, text_fd.get());
2605 ASSERT_NE(-1, proto_fd.get());
2606
2607 struct stat text_st;
2608 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2609
2610 std::optional<std::string> tombstone_file;
2611 // Allow up to 5 seconds for the tombstone to be written to the system.
2612 const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
2613 const auto start = std::chrono::high_resolution_clock::now();
2614 while (true) {
2615 std::this_thread::sleep_for(100ms);
2616 CheckForTombstone(text_st, tombstone_file);
2617 if (tombstone_file) {
2618 break;
2619 }
2620 if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
2621 break;
2622 }
2623 }
2624
2625 ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
2626 std::string proto_path = tombstone_file.value() + ".pb";
2627
2628 struct stat proto_fd_st;
2629 struct stat proto_file_st;
2630 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2631 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2632
2633 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2634 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2635 }
2636
TEST(tombstoned,proto_intercept)2637 TEST(tombstoned, proto_intercept) {
2638 const pid_t self = getpid();
2639 unique_fd intercept_fd, output_fd;
2640
2641 InterceptResponse response = {};
2642 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2643 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2644 << "Error message: " << response.error_message;
2645
2646 unique_fd tombstoned_socket, text_fd, proto_fd;
2647 ASSERT_TRUE(
2648 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2649 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2650 tombstoned_notify_completion(tombstoned_socket.get());
2651
2652 text_fd.reset();
2653
2654 std::string output;
2655 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2656 ASSERT_EQ("foo", output);
2657 }
2658
2659 // Verify that when an intercept is present for the main thread, and the signal
2660 // is received on a different thread, the intercept still works.
TEST_F(CrasherTest,intercept_for_main_thread_signal_on_side_thread)2661 TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2662 StartProcess([]() {
2663 std::thread thread([]() {
2664 // Raise the signal on the side thread.
2665 raise_debugger_signal(kDebuggerdNativeBacktrace);
2666 });
2667 thread.join();
2668 _exit(0);
2669 });
2670
2671 unique_fd output_fd;
2672 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2673 FinishCrasher();
2674 AssertDeath(0);
2675
2676 int intercept_result;
2677 FinishIntercept(&intercept_result);
2678 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2679
2680 std::string result;
2681 ConsumeFd(std::move(output_fd), &result);
2682 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2683 }
2684
format_pointer(uintptr_t ptr)2685 static std::string format_pointer(uintptr_t ptr) {
2686 #if defined(__LP64__)
2687 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2688 static_cast<uint32_t>(ptr & 0xffffffff));
2689 #else
2690 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2691 #endif
2692 }
2693
format_pointer(void * ptr)2694 static std::string format_pointer(void* ptr) {
2695 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2696 }
2697
format_full_pointer(uintptr_t ptr)2698 static std::string format_full_pointer(uintptr_t ptr) {
2699 #if defined(__LP64__)
2700 return android::base::StringPrintf("%016" PRIx64, ptr);
2701 #else
2702 return android::base::StringPrintf("%08x", ptr);
2703 #endif
2704 }
2705
format_full_pointer(void * ptr)2706 static std::string format_full_pointer(void* ptr) {
2707 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2708 }
2709
crash_call(uintptr_t ptr)2710 __attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2711 int* crash_ptr = reinterpret_cast<int*>(ptr);
2712 *crash_ptr = 1;
2713 return *crash_ptr;
2714 }
2715
2716 // Verify that a fault address before the first map is properly handled.
TEST_F(CrasherTest,fault_address_before_first_map)2717 TEST_F(CrasherTest, fault_address_before_first_map) {
2718 StartProcess([]() {
2719 ASSERT_EQ(0, crash_call(0x1024));
2720 _exit(0);
2721 });
2722
2723 unique_fd output_fd;
2724 StartIntercept(&output_fd);
2725 FinishCrasher();
2726 AssertDeath(SIGSEGV);
2727
2728 int intercept_result;
2729 FinishIntercept(&intercept_result);
2730 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2731
2732 std::string result;
2733 ConsumeFd(std::move(output_fd), &result);
2734 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
2735
2736 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2737
2738 std::string match_str = android::base::StringPrintf(
2739 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2740 format_pointer(0x1024).c_str());
2741 ASSERT_MATCH(result, match_str);
2742 }
2743
2744 // Verify that a fault address after the last map is properly handled.
TEST_F(CrasherTest,fault_address_after_last_map)2745 TEST_F(CrasherTest, fault_address_after_last_map) {
2746 // This makes assumptions about the memory layout that are not true in HWASan
2747 // processes.
2748 SKIP_WITH_HWASAN;
2749 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2750 StartProcess([crash_uptr]() {
2751 ASSERT_EQ(0, crash_call(crash_uptr));
2752 _exit(0);
2753 });
2754
2755 unique_fd output_fd;
2756 StartIntercept(&output_fd);
2757 FinishCrasher();
2758 AssertDeath(SIGSEGV);
2759
2760 int intercept_result;
2761 FinishIntercept(&intercept_result);
2762 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2763
2764 std::string result;
2765 ConsumeFd(std::move(output_fd), &result);
2766
2767 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2768 match_str += format_full_pointer(crash_uptr);
2769 ASSERT_MATCH(result, match_str);
2770
2771 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
2772
2773 // Verifies that the fault address error message is at the end of the
2774 // maps section. To do this, the check below looks for the start of the
2775 // open files section or the start of the log file section. It's possible
2776 // for either of these sections to be present after the maps section right
2777 // now.
2778 // If the sections move around, this check might need to be modified.
2779 match_str = android::base::StringPrintf(
2780 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
2781 format_pointer(crash_uptr).c_str());
2782 ASSERT_MATCH(result, match_str);
2783 }
2784
2785 // Verify that a fault address between maps is properly handled.
TEST_F(CrasherTest,fault_address_between_maps)2786 TEST_F(CrasherTest, fault_address_between_maps) {
2787 // Create a map before the fork so it will be present in the child.
2788 void* start_ptr =
2789 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2790 ASSERT_NE(MAP_FAILED, start_ptr);
2791 // Unmap the page in the middle.
2792 void* middle_ptr =
2793 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2794 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2795
2796 StartProcess([middle_ptr]() {
2797 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2798 _exit(0);
2799 });
2800
2801 // Unmap the two maps.
2802 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2803 void* end_ptr =
2804 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2805 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2806
2807 unique_fd output_fd;
2808 StartIntercept(&output_fd);
2809 FinishCrasher();
2810 AssertDeath(SIGSEGV);
2811
2812 int intercept_result;
2813 FinishIntercept(&intercept_result);
2814 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2815
2816 std::string result;
2817 ConsumeFd(std::move(output_fd), &result);
2818
2819 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2820 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
2821 ASSERT_MATCH(result, match_str);
2822
2823 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
2824
2825 match_str = android::base::StringPrintf(
2826 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2827 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2828 format_pointer(end_ptr).c_str());
2829 ASSERT_MATCH(result, match_str);
2830 }
2831
2832 // Verify that a fault address happens in the correct map.
TEST_F(CrasherTest,fault_address_in_map)2833 TEST_F(CrasherTest, fault_address_in_map) {
2834 // Create a map before the fork so it will be present in the child.
2835 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2836 ASSERT_NE(MAP_FAILED, ptr);
2837
2838 StartProcess([ptr]() {
2839 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2840 _exit(0);
2841 });
2842
2843 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2844
2845 unique_fd output_fd;
2846 StartIntercept(&output_fd);
2847 FinishCrasher();
2848 AssertDeath(SIGSEGV);
2849
2850 int intercept_result;
2851 FinishIntercept(&intercept_result);
2852 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2853
2854 std::string result;
2855 ConsumeFd(std::move(output_fd), &result);
2856
2857 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2858 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2859 ASSERT_MATCH(result, match_str);
2860
2861 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
2862
2863 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2864 ASSERT_MATCH(result, match_str);
2865 }
2866
2867 static constexpr uint32_t kDexData[] = {
2868 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2869 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2870 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2871 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2872 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2873 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2874 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2875 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2876 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2877 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2878 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2879 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2880 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2881 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2882 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2883 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2884 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2885 };
2886
TEST_F(CrasherTest,verify_dex_pc_with_function_name)2887 TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2888 StartProcess([]() {
2889 TemporaryDir td;
2890 std::string tmp_so_name;
2891 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2892 _exit(1);
2893 }
2894
2895 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2896 // move the library to which has a basename of libart.so.
2897 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2898 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2899 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2900 if (handle == nullptr) {
2901 _exit(1);
2902 }
2903
2904 void* ptr =
2905 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2906 ASSERT_TRUE(ptr != MAP_FAILED);
2907 memcpy(ptr, kDexData, sizeof(kDexData));
2908 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2909
2910 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2911 .symfile_size = sizeof(kDexData)};
2912
2913 JITDescriptor* dex_debug =
2914 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2915 ASSERT_TRUE(dex_debug != nullptr);
2916 dex_debug->version = 1;
2917 dex_debug->action_flag = 0;
2918 dex_debug->relevant_entry = 0;
2919 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2920
2921 // This sets the magic dex pc value for register 0, using the value
2922 // of register 1 + 0x102.
2923 asm(".cfi_escape "
2924 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2925 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2926 "0x13 /* DW_OP_drop */,"
2927 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2928
2929 // For each different architecture, set register one to the dex ptr mmap
2930 // created above. Then do a nullptr dereference to force a crash.
2931 #if defined(__arm__)
2932 asm volatile(
2933 "mov r1, %[base]\n"
2934 "mov r2, #0\n"
2935 "str r2, [r2]\n"
2936 : [base] "+r"(ptr)
2937 :
2938 : "r1", "r2", "memory");
2939 #elif defined(__aarch64__)
2940 asm volatile(
2941 "mov x1, %[base]\n"
2942 "mov x2, #0\n"
2943 "str xzr, [x2]\n"
2944 : [base] "+r"(ptr)
2945 :
2946 : "x1", "x2", "memory");
2947 #elif defined(__riscv)
2948 // TODO: x1 is ra (the link register) on riscv64, so this might have
2949 // unintended consequences, but we'll need to change the .cfi_escape if so.
2950 asm volatile(
2951 "mv x1, %[base]\n"
2952 "sw zero, 0(zero)\n"
2953 : [base] "+r"(ptr)
2954 :
2955 : "x1", "memory");
2956 #elif defined(__i386__)
2957 asm volatile(
2958 "mov %[base], %%ecx\n"
2959 "movl $0, 0\n"
2960 : [base] "+r"(ptr)
2961 :
2962 : "ecx", "memory");
2963 #elif defined(__x86_64__)
2964 asm volatile(
2965 "mov %[base], %%rdx\n"
2966 "movq $0, 0\n"
2967 : [base] "+r"(ptr)
2968 :
2969 : "rdx", "memory");
2970 #else
2971 #error "Unsupported architecture"
2972 #endif
2973 _exit(0);
2974 });
2975
2976 unique_fd output_fd;
2977 StartIntercept(&output_fd);
2978 FinishCrasher();
2979 AssertDeath(SIGSEGV);
2980
2981 int intercept_result;
2982 FinishIntercept(&intercept_result);
2983 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2984
2985 std::string result;
2986 ConsumeFd(std::move(output_fd), &result);
2987
2988 // Verify the process crashed properly.
2989 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
2990
2991 // Now verify that the dex_pc frame includes a proper function name.
2992 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2993 }
2994
format_map_pointer(uintptr_t ptr)2995 static std::string format_map_pointer(uintptr_t ptr) {
2996 #if defined(__LP64__)
2997 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2998 static_cast<uint32_t>(ptr & 0xffffffff));
2999 #else
3000 return android::base::StringPrintf("%08x", ptr);
3001 #endif
3002 }
3003
3004 // Verify that map data is properly formatted.
TEST_F(CrasherTest,verify_map_format)3005 TEST_F(CrasherTest, verify_map_format) {
3006 // Create multiple maps to make sure that the map data is formatted properly.
3007 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3008 ASSERT_NE(MAP_FAILED, none_map);
3009 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3010 ASSERT_NE(MAP_FAILED, r_map);
3011 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3012 ASSERT_NE(MAP_FAILED, w_map);
3013 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3014 ASSERT_NE(MAP_FAILED, x_map);
3015
3016 TemporaryFile tf;
3017 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
3018 char c = 'f';
3019 ASSERT_EQ(1, write(tf.fd, &c, 1));
3020 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
3021 ASSERT_EQ(1, write(tf.fd, &c, 1));
3022 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
3023 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
3024 ASSERT_NE(MAP_FAILED, file_map);
3025
3026 StartProcess([]() { abort(); });
3027
3028 ASSERT_EQ(0, munmap(none_map, getpagesize()));
3029 ASSERT_EQ(0, munmap(r_map, getpagesize()));
3030 ASSERT_EQ(0, munmap(w_map, getpagesize()));
3031 ASSERT_EQ(0, munmap(x_map, getpagesize()));
3032 ASSERT_EQ(0, munmap(file_map, 0x3001));
3033
3034 unique_fd output_fd;
3035 StartIntercept(&output_fd);
3036 FinishCrasher();
3037 AssertDeath(SIGABRT);
3038 int intercept_result;
3039 FinishIntercept(&intercept_result);
3040
3041 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3042
3043 std::string result;
3044 ConsumeFd(std::move(output_fd), &result);
3045
3046 std::string match_str;
3047 // Verify none.
3048 match_str = android::base::StringPrintf(
3049 " %s-%s --- 0 %x\\n",
3050 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
3051 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str(),
3052 getpagesize());
3053 ASSERT_MATCH(result, match_str);
3054
3055 // Verify read-only.
3056 match_str = android::base::StringPrintf(
3057 " %s-%s r-- 0 %x\\n",
3058 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
3059 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str(),
3060 getpagesize());
3061 ASSERT_MATCH(result, match_str);
3062
3063 // Verify write-only.
3064 match_str = android::base::StringPrintf(
3065 " %s-%s -w- 0 %x\\n",
3066 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
3067 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str(),
3068 getpagesize());
3069 ASSERT_MATCH(result, match_str);
3070
3071 // Verify exec-only.
3072 match_str = android::base::StringPrintf(
3073 " %s-%s --x 0 %x\\n",
3074 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
3075 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str(),
3076 getpagesize());
3077 ASSERT_MATCH(result, match_str);
3078
3079 // Verify file map with non-zero offset and a name.
3080 match_str = android::base::StringPrintf(
3081 " %s-%s r-- 2000 4000 %s\\n",
3082 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
3083 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
3084 ASSERT_MATCH(result, match_str);
3085 }
3086
3087 // Verify that the tombstone map data is correct.
TEST_F(CrasherTest,verify_header)3088 TEST_F(CrasherTest, verify_header) {
3089 StartProcess([]() { abort(); });
3090
3091 unique_fd output_fd;
3092 StartIntercept(&output_fd);
3093 FinishCrasher();
3094 AssertDeath(SIGABRT);
3095 int intercept_result;
3096 FinishIntercept(&intercept_result);
3097
3098 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3099
3100 std::string result;
3101 ConsumeFd(std::move(output_fd), &result);
3102
3103 std::string match_str = android::base::StringPrintf(
3104 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
3105 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
3106 android::base::GetProperty("ro.revision", "unknown").c_str());
3107 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
3108 ASSERT_MATCH(result, match_str);
3109 }
3110
3111 // Verify that the thread header is formatted properly.
TEST_F(CrasherTest,verify_thread_header)3112 TEST_F(CrasherTest, verify_thread_header) {
3113 void* shared_map =
3114 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
3115 ASSERT_NE(MAP_FAILED, shared_map);
3116 memset(shared_map, 0, sizeof(pid_t));
3117
3118 StartProcess([&shared_map]() {
3119 std::atomic_bool tid_written;
3120 std::thread thread([&tid_written, &shared_map]() {
3121 pid_t tid = gettid();
3122 memcpy(shared_map, &tid, sizeof(pid_t));
3123 tid_written = true;
3124 volatile bool done = false;
3125 while (!done)
3126 ;
3127 });
3128 thread.detach();
3129 while (!tid_written.load(std::memory_order_acquire))
3130 ;
3131 abort();
3132 });
3133
3134 pid_t primary_pid = crasher_pid;
3135
3136 unique_fd output_fd;
3137 StartIntercept(&output_fd);
3138 FinishCrasher();
3139 AssertDeath(SIGABRT);
3140 int intercept_result;
3141 FinishIntercept(&intercept_result);
3142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3143
3144 // Read the tid data out.
3145 pid_t tid;
3146 memcpy(&tid, shared_map, sizeof(pid_t));
3147 ASSERT_NE(0, tid);
3148
3149 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
3150
3151 std::string result;
3152 ConsumeFd(std::move(output_fd), &result);
3153
3154 // Verify that there are two headers, one where the tid is "primary_pid"
3155 // and the other where the tid is "tid".
3156 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
3157 primary_pid, primary_pid);
3158 ASSERT_MATCH(result, match_str);
3159
3160 match_str =
3161 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
3162 ASSERT_MATCH(result, match_str);
3163 }
3164
3165 // Verify that there is a BuildID present in the map section and set properly.
TEST_F(CrasherTest,verify_build_id)3166 TEST_F(CrasherTest, verify_build_id) {
3167 StartProcess([]() { abort(); });
3168
3169 unique_fd output_fd;
3170 StartIntercept(&output_fd);
3171 FinishCrasher();
3172 AssertDeath(SIGABRT);
3173 int intercept_result;
3174 FinishIntercept(&intercept_result);
3175 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3176
3177 std::string result;
3178 ConsumeFd(std::move(output_fd), &result);
3179
3180 // Find every /system or /apex lib and verify the BuildID is displayed
3181 // properly.
3182 bool found_valid_elf = false;
3183 std::smatch match;
3184 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
3185 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
3186 result = match.suffix()) {
3187 if (prev_file == match[1]) {
3188 // Already checked this file.
3189 continue;
3190 }
3191
3192 prev_file = match[1];
3193 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
3194 unwindstack::Elf elf(elf_memory);
3195 if (!elf.Init() || !elf.valid()) {
3196 // Skipping invalid elf files.
3197 continue;
3198 }
3199 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
3200
3201 found_valid_elf = true;
3202 }
3203 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
3204 }
3205
3206 const char kLogMessage[] = "Should not see this log message.";
3207
3208 // Verify that the logd process does not read the log.
TEST_F(CrasherTest,logd_skips_reading_logs)3209 TEST_F(CrasherTest, logd_skips_reading_logs) {
3210 StartProcess([]() {
3211 pthread_setname_np(pthread_self(), "logd");
3212 LOG(INFO) << kLogMessage;
3213 abort();
3214 });
3215
3216 unique_fd output_fd;
3217 StartIntercept(&output_fd);
3218 FinishCrasher();
3219 AssertDeath(SIGABRT);
3220 int intercept_result;
3221 FinishIntercept(&intercept_result);
3222 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3223
3224 std::string result;
3225 ConsumeFd(std::move(output_fd), &result);
3226 // logd should not contain our log message.
3227 ASSERT_NOT_MATCH(result, kLogMessage);
3228 }
3229
3230 // Verify that the logd process does not read the log when the non-main
3231 // thread crashes.
TEST_F(CrasherTest,logd_skips_reading_logs_not_main_thread)3232 TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
3233 StartProcess([]() {
3234 pthread_setname_np(pthread_self(), "logd");
3235 LOG(INFO) << kLogMessage;
3236
3237 std::thread thread([]() {
3238 pthread_setname_np(pthread_self(), "not_logd_thread");
3239 // Raise the signal on the side thread.
3240 raise_debugger_signal(kDebuggerdTombstone);
3241 });
3242 thread.join();
3243 _exit(0);
3244 });
3245
3246 unique_fd output_fd;
3247 StartIntercept(&output_fd, kDebuggerdTombstone);
3248 FinishCrasher();
3249 AssertDeath(0);
3250
3251 int intercept_result;
3252 FinishIntercept(&intercept_result);
3253 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3254
3255 std::string result;
3256 ConsumeFd(std::move(output_fd), &result);
3257 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
3258 ASSERT_NOT_MATCH(result, kLogMessage);
3259 }
3260
3261 // Disable this test since there is a high liklihood that this would
3262 // be flaky since it requires 500 messages being in the log.
TEST_F(CrasherTest,DISABLED_max_log_messages)3263 TEST_F(CrasherTest, DISABLED_max_log_messages) {
3264 StartProcess([]() {
3265 for (size_t i = 0; i < 600; i++) {
3266 LOG(INFO) << "Message number " << i;
3267 }
3268 abort();
3269 });
3270
3271 unique_fd output_fd;
3272 StartIntercept(&output_fd);
3273 FinishCrasher();
3274 AssertDeath(SIGABRT);
3275 int intercept_result;
3276 FinishIntercept(&intercept_result);
3277 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3278
3279 std::string result;
3280 ConsumeFd(std::move(output_fd), &result);
3281 ASSERT_NOT_MATCH(result, "Message number 99");
3282 ASSERT_MATCH(result, "Message number 100");
3283 ASSERT_MATCH(result, "Message number 599");
3284 }
3285
TEST_F(CrasherTest,log_with_newline)3286 TEST_F(CrasherTest, log_with_newline) {
3287 StartProcess([]() {
3288 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
3289 abort();
3290 });
3291
3292 unique_fd output_fd;
3293 StartIntercept(&output_fd);
3294 FinishCrasher();
3295 AssertDeath(SIGABRT);
3296 int intercept_result;
3297 FinishIntercept(&intercept_result);
3298 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3299
3300 std::string result;
3301 ConsumeFd(std::move(output_fd), &result);
3302 ASSERT_MATCH(result, ":\\s*This line has a newline.");
3303 ASSERT_MATCH(result, ":\\s*This is on the next line.");
3304 }
3305
TEST_F(CrasherTest,log_with_non_utf8)3306 TEST_F(CrasherTest, log_with_non_utf8) {
3307 StartProcess([]() { LOG(FATAL) << "Invalid UTF-8: \xA0\xB0\xC0\xD0 and some other data."; });
3308
3309 unique_fd output_fd;
3310 StartIntercept(&output_fd);
3311 FinishCrasher();
3312 AssertDeath(SIGABRT);
3313 int intercept_result;
3314 FinishIntercept(&intercept_result);
3315 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3316
3317 std::string result;
3318 ConsumeFd(std::move(output_fd), &result);
3319 // Verify the abort message is sanitized properly.
3320 size_t pos = result.find(
3321 "Abort message: 'Invalid UTF-8: "
3322 "\x5C\x32\x34\x30\x5C\x32\x36\x30\x5C\x33\x30\x30\x5C\x33\x32\x30 and some other data.'");
3323 EXPECT_TRUE(pos != std::string::npos) << "Couldn't find sanitized abort message: " << result;
3324
3325 // Make sure that the log message is sanitized properly too.
3326 EXPECT_TRUE(
3327 result.find("Invalid UTF-8: \x5C\x32\x34\x30\x5C\x32\x36\x30\x5C\x33\x30\x30\x5C\x33\x32\x30 "
3328 "and some other data.",
3329 pos + 30) != std::string::npos)
3330 << "Couldn't find sanitized log message: " << result;
3331 }
3332