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