• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <err.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <sys/capability.h>
21 #include <sys/prctl.h>
22 #include <sys/types.h>
23 
24 #include <chrono>
25 #include <regex>
26 #include <thread>
27 
28 #include <android/set_abort_message.h>
29 
30 #include <android-base/file.h>
31 #include <android-base/logging.h>
32 #include <android-base/macros.h>
33 #include <android-base/parseint.h>
34 #include <android-base/properties.h>
35 #include <android-base/strings.h>
36 #include <android-base/unique_fd.h>
37 #include <cutils/sockets.h>
38 #include <gtest/gtest.h>
39 
40 #include "debuggerd/handler.h"
41 #include "protocol.h"
42 #include "tombstoned/tombstoned.h"
43 #include "util.h"
44 
45 using namespace std::chrono_literals;
46 using android::base::unique_fd;
47 
48 #if defined(__LP64__)
49 #define ARCH_SUFFIX "64"
50 #else
51 #define ARCH_SUFFIX ""
52 #endif
53 
54 constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
55 
56 #define TIMEOUT(seconds, expr)                                     \
57   [&]() {                                                          \
58     struct sigaction old_sigaction;                                \
59     struct sigaction new_sigaction = {};                           \
60     new_sigaction.sa_handler = [](int) {};                         \
61     if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
62       err(1, "sigaction failed");                                  \
63     }                                                              \
64     alarm(seconds);                                                \
65     auto value = expr;                                             \
66     int saved_errno = errno;                                       \
67     if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) {        \
68       err(1, "sigaction failed");                                  \
69     }                                                              \
70     alarm(0);                                                      \
71     errno = saved_errno;                                           \
72     return value;                                                  \
73   }()
74 
75 #define ASSERT_MATCH(str, pattern)                                              \
76   do {                                                                          \
77     std::regex r((pattern));                                                    \
78     if (!std::regex_search((str), r)) {                                         \
79       FAIL() << "regex mismatch: expected " << (pattern) << " in: \n" << (str); \
80     }                                                                           \
81   } while (0)
82 
83 #define ASSERT_NOT_MATCH(str, pattern)                                                      \
84   do {                                                                                      \
85     std::regex r((pattern));                                                                \
86     if (std::regex_search((str), r)) {                                                      \
87       FAIL() << "regex mismatch: expected to not find " << (pattern) << " in: \n" << (str); \
88     }                                                                                       \
89   } while (0)
90 
91 #define ASSERT_BACKTRACE_FRAME(result, frame_name)                        \
92   ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
93                        R"(/libc.so \()" frame_name R"(\+)")
94 
tombstoned_intercept(pid_t target_pid,unique_fd * intercept_fd,unique_fd * output_fd,InterceptStatus * status,DebuggerdDumpType intercept_type)95 static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
96                                  InterceptStatus* status, DebuggerdDumpType intercept_type) {
97   intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
98                                           ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
99   if (intercept_fd->get() == -1) {
100     FAIL() << "failed to contact tombstoned: " << strerror(errno);
101   }
102 
103   InterceptRequest req = {.pid = target_pid, .dump_type = intercept_type};
104 
105   unique_fd output_pipe_write;
106   if (!Pipe(output_fd, &output_pipe_write)) {
107     FAIL() << "failed to create output pipe: " << strerror(errno);
108   }
109 
110   std::string pipe_size_str;
111   int pipe_buffer_size;
112   if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
113     FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
114   }
115 
116   pipe_size_str = android::base::Trim(pipe_size_str);
117 
118   if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
119     FAIL() << "failed to parse pipe max size";
120   }
121 
122   if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
123     FAIL() << "failed to set pipe size: " << strerror(errno);
124   }
125 
126   ASSERT_GE(pipe_buffer_size, 1024 * 1024);
127 
128   if (send_fd(intercept_fd->get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
129     FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
130   }
131 
132   InterceptResponse response;
133   ssize_t rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
134   if (rc == -1) {
135     FAIL() << "failed to read response from tombstoned: " << strerror(errno);
136   } else if (rc == 0) {
137     FAIL() << "failed to read response from tombstoned (EOF)";
138   } else if (rc != sizeof(response)) {
139     FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
140            << ", received " << rc;
141   }
142 
143   *status = response.status;
144 }
145 
146 class CrasherTest : public ::testing::Test {
147  public:
148   pid_t crasher_pid = -1;
149   bool previous_wait_for_gdb;
150   unique_fd crasher_pipe;
151   unique_fd intercept_fd;
152 
153   CrasherTest();
154   ~CrasherTest();
155 
156   void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
157 
158   // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
159   void FinishIntercept(int* result);
160 
161   void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
162   void StartCrasher(const std::string& crash_type);
163   void FinishCrasher();
164   void AssertDeath(int signo);
165 };
166 
CrasherTest()167 CrasherTest::CrasherTest() {
168   previous_wait_for_gdb = android::base::GetBoolProperty(kWaitForGdbKey, false);
169   android::base::SetProperty(kWaitForGdbKey, "0");
170 }
171 
~CrasherTest()172 CrasherTest::~CrasherTest() {
173   if (crasher_pid != -1) {
174     kill(crasher_pid, SIGKILL);
175     int status;
176     waitpid(crasher_pid, &status, WUNTRACED);
177   }
178 
179   android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
180 }
181 
StartIntercept(unique_fd * output_fd,DebuggerdDumpType intercept_type)182 void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
183   if (crasher_pid == -1) {
184     FAIL() << "crasher hasn't been started";
185   }
186 
187   InterceptStatus status;
188   tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
189   ASSERT_EQ(InterceptStatus::kRegistered, status);
190 }
191 
FinishIntercept(int * result)192 void CrasherTest::FinishIntercept(int* result) {
193   InterceptResponse response;
194 
195   // Timeout for tombstoned intercept is 10 seconds.
196   ssize_t rc = TIMEOUT(20, read(intercept_fd.get(), &response, sizeof(response)));
197   if (rc == -1) {
198     FAIL() << "failed to read response from tombstoned: " << strerror(errno);
199   } else if (rc == 0) {
200     *result = -1;
201   } else if (rc != sizeof(response)) {
202     FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
203            << ", received " << rc;
204   } else {
205     *result = response.status == InterceptStatus::kStarted ? 1 : 0;
206   }
207 }
208 
StartProcess(std::function<void ()> function,std::function<pid_t ()> forker)209 void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
210   unique_fd read_pipe;
211   unique_fd crasher_read_pipe;
212   if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
213     FAIL() << "failed to create pipe: " << strerror(errno);
214   }
215 
216   crasher_pid = forker();
217   if (crasher_pid == -1) {
218     FAIL() << "fork failed: " << strerror(errno);
219   } else if (crasher_pid == 0) {
220     char dummy;
221     crasher_pipe.reset();
222     TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
223     function();
224     _exit(0);
225   }
226 }
227 
FinishCrasher()228 void CrasherTest::FinishCrasher() {
229   if (crasher_pipe == -1) {
230     FAIL() << "crasher pipe uninitialized";
231   }
232 
233   ssize_t rc = write(crasher_pipe.get(), "\n", 1);
234   if (rc == -1) {
235     FAIL() << "failed to write to crasher pipe: " << strerror(errno);
236   } else if (rc == 0) {
237     FAIL() << "crasher pipe was closed";
238   }
239 }
240 
AssertDeath(int signo)241 void CrasherTest::AssertDeath(int signo) {
242   int status;
243   pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0));
244   if (pid != crasher_pid) {
245     FAIL() << "failed to wait for crasher: " << strerror(errno);
246   }
247 
248   if (signo == 0) {
249     ASSERT_TRUE(WIFEXITED(status));
250     ASSERT_EQ(0, WEXITSTATUS(signo));
251   } else {
252     ASSERT_FALSE(WIFEXITED(status));
253     ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
254     ASSERT_EQ(signo, WTERMSIG(status));
255   }
256   crasher_pid = -1;
257 }
258 
ConsumeFd(unique_fd fd,std::string * output)259 static void ConsumeFd(unique_fd fd, std::string* output) {
260   constexpr size_t read_length = PAGE_SIZE;
261   std::string result;
262 
263   while (true) {
264     size_t offset = result.size();
265     result.resize(result.size() + PAGE_SIZE);
266     ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
267     if (rc == -1) {
268       FAIL() << "read failed: " << strerror(errno);
269     } else if (rc == 0) {
270       result.resize(result.size() - PAGE_SIZE);
271       break;
272     }
273 
274     result.resize(result.size() - PAGE_SIZE + rc);
275   }
276 
277   *output = std::move(result);
278 }
279 
TEST_F(CrasherTest,smoke)280 TEST_F(CrasherTest, smoke) {
281   int intercept_result;
282   unique_fd output_fd;
283   StartProcess([]() {
284     *reinterpret_cast<volatile char*>(0xdead) = '1';
285   });
286 
287   StartIntercept(&output_fd);
288   FinishCrasher();
289   AssertDeath(SIGSEGV);
290   FinishIntercept(&intercept_result);
291 
292   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
293 
294   std::string result;
295   ConsumeFd(std::move(output_fd), &result);
296   ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
297 }
298 
TEST_F(CrasherTest,abort)299 TEST_F(CrasherTest, abort) {
300   int intercept_result;
301   unique_fd output_fd;
302   StartProcess([]() {
303     abort();
304   });
305   StartIntercept(&output_fd);
306   FinishCrasher();
307   AssertDeath(SIGABRT);
308   FinishIntercept(&intercept_result);
309 
310   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
311 
312   std::string result;
313   ConsumeFd(std::move(output_fd), &result);
314   ASSERT_BACKTRACE_FRAME(result, "abort");
315 }
316 
TEST_F(CrasherTest,signal)317 TEST_F(CrasherTest, signal) {
318   int intercept_result;
319   unique_fd output_fd;
320   StartProcess([]() {
321     abort();
322   });
323   StartIntercept(&output_fd);
324 
325   // Wait for a bit, or we might end up killing the process before the signal
326   // handler even gets a chance to be registered.
327   std::this_thread::sleep_for(100ms);
328   ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
329 
330   AssertDeath(SIGSEGV);
331   FinishIntercept(&intercept_result);
332 
333   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
334 
335   std::string result;
336   ConsumeFd(std::move(output_fd), &result);
337   ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER\), fault addr --------)");
338   ASSERT_MATCH(result, R"(backtrace:)");
339 }
340 
TEST_F(CrasherTest,abort_message)341 TEST_F(CrasherTest, abort_message) {
342   int intercept_result;
343   unique_fd output_fd;
344   StartProcess([]() {
345     android_set_abort_message("abort message goes here");
346     abort();
347   });
348   StartIntercept(&output_fd);
349   FinishCrasher();
350   AssertDeath(SIGABRT);
351   FinishIntercept(&intercept_result);
352 
353   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
354 
355   std::string result;
356   ConsumeFd(std::move(output_fd), &result);
357   ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
358 }
359 
TEST_F(CrasherTest,abort_message_backtrace)360 TEST_F(CrasherTest, abort_message_backtrace) {
361   int intercept_result;
362   unique_fd output_fd;
363   StartProcess([]() {
364     android_set_abort_message("not actually aborting");
365     raise(DEBUGGER_SIGNAL);
366     exit(0);
367   });
368   StartIntercept(&output_fd);
369   FinishCrasher();
370   AssertDeath(0);
371   FinishIntercept(&intercept_result);
372 
373   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
374 
375   std::string result;
376   ConsumeFd(std::move(output_fd), &result);
377   ASSERT_NOT_MATCH(result, R"(Abort message:)");
378 }
379 
TEST_F(CrasherTest,intercept_timeout)380 TEST_F(CrasherTest, intercept_timeout) {
381   int intercept_result;
382   unique_fd output_fd;
383   StartProcess([]() {
384     abort();
385   });
386   StartIntercept(&output_fd);
387 
388   // Don't let crasher finish until we timeout.
389   FinishIntercept(&intercept_result);
390 
391   ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
392                                  << intercept_result << ")";
393 
394   FinishCrasher();
395   AssertDeath(SIGABRT);
396 }
397 
TEST_F(CrasherTest,wait_for_gdb)398 TEST_F(CrasherTest, wait_for_gdb) {
399   if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
400     FAIL() << "failed to enable wait_for_gdb";
401   }
402   sleep(1);
403 
404   StartProcess([]() {
405     abort();
406   });
407   FinishCrasher();
408 
409   int status;
410   ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, WUNTRACED));
411   ASSERT_TRUE(WIFSTOPPED(status));
412   ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
413 
414   ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
415 
416   AssertDeath(SIGABRT);
417 }
418 
419 // wait_for_gdb shouldn't trigger on manually sent signals.
TEST_F(CrasherTest,wait_for_gdb_signal)420 TEST_F(CrasherTest, wait_for_gdb_signal) {
421   if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
422     FAIL() << "failed to enable wait_for_gdb";
423   }
424 
425   StartProcess([]() {
426     abort();
427   });
428   ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
429   AssertDeath(SIGSEGV);
430 }
431 
TEST_F(CrasherTest,backtrace)432 TEST_F(CrasherTest, backtrace) {
433   std::string result;
434   int intercept_result;
435   unique_fd output_fd;
436 
437   StartProcess([]() {
438     abort();
439   });
440   StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
441 
442   std::this_thread::sleep_for(500ms);
443 
444   sigval val;
445   val.sival_int = 1;
446   ASSERT_EQ(0, sigqueue(crasher_pid, DEBUGGER_SIGNAL, val)) << strerror(errno);
447   FinishIntercept(&intercept_result);
448   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
449   ConsumeFd(std::move(output_fd), &result);
450   ASSERT_BACKTRACE_FRAME(result, "read");
451 
452   int status;
453   ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
454 
455   StartIntercept(&output_fd);
456   FinishCrasher();
457   AssertDeath(SIGABRT);
458   FinishIntercept(&intercept_result);
459   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
460   ConsumeFd(std::move(output_fd), &result);
461   ASSERT_BACKTRACE_FRAME(result, "abort");
462 }
463 
TEST_F(CrasherTest,PR_SET_DUMPABLE_0_crash)464 TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
465   int intercept_result;
466   unique_fd output_fd;
467   StartProcess([]() {
468     prctl(PR_SET_DUMPABLE, 0);
469     abort();
470   });
471 
472   StartIntercept(&output_fd);
473   FinishCrasher();
474   AssertDeath(SIGABRT);
475   FinishIntercept(&intercept_result);
476 
477   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
478 
479   std::string result;
480   ConsumeFd(std::move(output_fd), &result);
481   ASSERT_BACKTRACE_FRAME(result, "abort");
482 }
483 
TEST_F(CrasherTest,capabilities)484 TEST_F(CrasherTest, capabilities) {
485   ASSERT_EQ(0U, getuid()) << "capability test requires root";
486 
487   StartProcess([]() {
488     if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
489       err(1, "failed to set PR_SET_KEEPCAPS");
490     }
491 
492     if (setresuid(1, 1, 1) != 0) {
493       err(1, "setresuid failed");
494     }
495 
496     __user_cap_header_struct capheader;
497     __user_cap_data_struct capdata[2];
498     memset(&capheader, 0, sizeof(capheader));
499     memset(&capdata, 0, sizeof(capdata));
500 
501     capheader.version = _LINUX_CAPABILITY_VERSION_3;
502     capheader.pid = 0;
503 
504     // Turn on every third capability.
505     static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
506     for (int i = 0; i < CAP_LAST_CAP; i += 3) {
507       capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
508       capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
509     }
510 
511     // Make sure CAP_SYS_PTRACE is off.
512     capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
513     capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
514 
515     if (capset(&capheader, &capdata[0]) != 0) {
516       err(1, "capset failed");
517     }
518 
519     if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
520       err(1, "failed to drop ambient capabilities");
521     }
522 
523     pthread_setname_np(pthread_self(), "thread_name");
524     raise(SIGSYS);
525   });
526 
527   unique_fd output_fd;
528   StartIntercept(&output_fd);
529   FinishCrasher();
530   AssertDeath(SIGSYS);
531 
532   std::string result;
533   int intercept_result;
534   FinishIntercept(&intercept_result);
535   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
536   ConsumeFd(std::move(output_fd), &result);
537   ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
538   ASSERT_BACKTRACE_FRAME(result, "tgkill");
539 }
540 
TEST_F(CrasherTest,fake_pid)541 TEST_F(CrasherTest, fake_pid) {
542   int intercept_result;
543   unique_fd output_fd;
544 
545   // Prime the getpid/gettid caches.
546   UNUSED(getpid());
547   UNUSED(gettid());
548 
549   std::function<pid_t()> clone_fn = []() {
550     return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
551   };
552   StartProcess(
553       []() {
554         ASSERT_NE(getpid(), syscall(__NR_getpid));
555         ASSERT_NE(gettid(), syscall(__NR_gettid));
556         raise(SIGSEGV);
557       },
558       clone_fn);
559 
560   StartIntercept(&output_fd);
561   FinishCrasher();
562   AssertDeath(SIGSEGV);
563   FinishIntercept(&intercept_result);
564 
565   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
566 
567   std::string result;
568   ConsumeFd(std::move(output_fd), &result);
569   ASSERT_BACKTRACE_FRAME(result, "tgkill");
570 }
571 
TEST(crash_dump,zombie)572 TEST(crash_dump, zombie) {
573   pid_t forkpid = fork();
574 
575   pid_t rc;
576   int status;
577 
578   if (forkpid == 0) {
579     errno = 0;
580     rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
581     if (rc != -1 || errno != ECHILD) {
582       errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
583     }
584 
585     raise(DEBUGGER_SIGNAL);
586 
587     errno = 0;
588     rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
589     if (rc != -1 || errno != ECHILD) {
590       errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
591     }
592     _exit(0);
593   } else {
594     rc = waitpid(forkpid, &status, 0);
595     ASSERT_EQ(forkpid, rc);
596     ASSERT_TRUE(WIFEXITED(status));
597     ASSERT_EQ(0, WEXITSTATUS(status));
598   }
599 }
600 
TEST(tombstoned,no_notify)601 TEST(tombstoned, no_notify) {
602   // Do this a few times.
603   for (int i = 0; i < 3; ++i) {
604     pid_t pid = 123'456'789 + i;
605 
606     unique_fd intercept_fd, output_fd;
607     InterceptStatus status;
608     tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
609     ASSERT_EQ(InterceptStatus::kRegistered, status);
610 
611     {
612       unique_fd tombstoned_socket, input_fd;
613       ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
614       ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
615     }
616 
617     pid_t read_pid;
618     ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
619     ASSERT_EQ(read_pid, pid);
620   }
621 }
622 
TEST(tombstoned,stress)623 TEST(tombstoned, stress) {
624   // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
625   static constexpr int kDumpCount = 100;
626 
627   std::atomic<bool> start(false);
628   std::vector<std::thread> threads;
629   threads.emplace_back([&start]() {
630     while (!start) {
631       continue;
632     }
633 
634     // Use a way out of range pid, to avoid stomping on an actual process.
635     pid_t pid_base = 1'000'000;
636 
637     for (int dump = 0; dump < kDumpCount; ++dump) {
638       pid_t pid = pid_base + dump;
639 
640       unique_fd intercept_fd, output_fd;
641       InterceptStatus status;
642       tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
643       ASSERT_EQ(InterceptStatus::kRegistered, status);
644 
645       // Pretend to crash, and then immediately close the socket.
646       unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
647                                            ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
648       if (sockfd == -1) {
649         FAIL() << "failed to connect to tombstoned: " << strerror(errno);
650       }
651       TombstonedCrashPacket packet = {};
652       packet.packet_type = CrashPacketType::kDumpRequest;
653       packet.packet.dump_request.pid = pid;
654       if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
655         FAIL() << "failed to write to tombstoned: " << strerror(errno);
656       }
657 
658       continue;
659     }
660   });
661 
662   threads.emplace_back([&start]() {
663     while (!start) {
664       continue;
665     }
666 
667     // Use a way out of range pid, to avoid stomping on an actual process.
668     pid_t pid_base = 2'000'000;
669 
670     for (int dump = 0; dump < kDumpCount; ++dump) {
671       pid_t pid = pid_base + dump;
672 
673       unique_fd intercept_fd, output_fd;
674       InterceptStatus status;
675       tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
676       ASSERT_EQ(InterceptStatus::kRegistered, status);
677 
678       {
679         unique_fd tombstoned_socket, input_fd;
680         ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
681         ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
682         tombstoned_notify_completion(tombstoned_socket.get());
683       }
684 
685       // TODO: Fix the race that requires this sleep.
686       std::this_thread::sleep_for(50ms);
687 
688       pid_t read_pid;
689       ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
690       ASSERT_EQ(read_pid, pid);
691     }
692   });
693 
694   start = true;
695 
696   for (std::thread& thread : threads) {
697     thread.join();
698   }
699 }
700 
TEST(tombstoned,java_trace_intercept_smoke)701 TEST(tombstoned, java_trace_intercept_smoke) {
702   // Using a "real" PID is a little dangerous here - if the test fails
703   // or crashes, we might end up getting a bogus / unreliable stack
704   // trace.
705   const pid_t self = getpid();
706 
707   unique_fd intercept_fd, output_fd;
708   InterceptStatus status;
709   tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
710   ASSERT_EQ(InterceptStatus::kRegistered, status);
711 
712   // First connect to tombstoned requesting a native backtrace. This
713   // should result in a "regular" FD and not the installed intercept.
714   const char native[] = "native";
715   unique_fd tombstoned_socket, input_fd;
716   ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
717   ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
718   tombstoned_notify_completion(tombstoned_socket.get());
719 
720   // Then, connect to tombstoned asking for a java backtrace. This *should*
721   // trigger the intercept.
722   const char java[] = "java";
723   ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
724   ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
725   tombstoned_notify_completion(tombstoned_socket.get());
726 
727   char outbuf[sizeof(java)];
728   ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
729   ASSERT_STREQ("java", outbuf);
730 }
731 
TEST(tombstoned,multiple_intercepts)732 TEST(tombstoned, multiple_intercepts) {
733   const pid_t fake_pid = 1'234'567;
734   unique_fd intercept_fd, output_fd;
735   InterceptStatus status;
736   tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
737   ASSERT_EQ(InterceptStatus::kRegistered, status);
738 
739   unique_fd intercept_fd_2, output_fd_2;
740   tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
741   ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
742 }
743 
TEST(tombstoned,intercept_any)744 TEST(tombstoned, intercept_any) {
745   const pid_t fake_pid = 1'234'567;
746 
747   unique_fd intercept_fd, output_fd;
748   InterceptStatus status;
749   tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
750   ASSERT_EQ(InterceptStatus::kRegistered, status);
751 
752   const char any[] = "any";
753   unique_fd tombstoned_socket, input_fd;
754   ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
755   ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
756   tombstoned_notify_completion(tombstoned_socket.get());
757 
758   char outbuf[sizeof(any)];
759   ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
760   ASSERT_STREQ("any", outbuf);
761 }
762