blob: 45e768dbc01ef685c8cd75e7cfdd7c7e12ce7851 [file] [log] [blame]
Josh Gaocbe70cb2016-10-18 18:17:52 -07001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <err.h>
18#include <fcntl.h>
Josh Gao502cfd22017-02-17 01:39:15 -080019#include <sys/capability.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080020#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070021#include <sys/ptrace.h>
Dan Albertc38057a2017-10-11 11:35:40 -070022#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070023#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070024#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070025
26#include <chrono>
27#include <regex>
28#include <thread>
29
Josh Gao502cfd22017-02-17 01:39:15 -080030#include <android/set_abort_message.h>
31
Josh Gaocbe70cb2016-10-18 18:17:52 -070032#include <android-base/file.h>
33#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070034#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070035#include <android-base/parseint.h>
36#include <android-base/properties.h>
37#include <android-base/strings.h>
38#include <android-base/unique_fd.h>
39#include <cutils/sockets.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070040#include <gtest/gtest.h>
41
Narayan Kamath2d377cd2017-05-10 10:58:59 +010042#include "debuggerd/handler.h"
43#include "protocol.h"
44#include "tombstoned/tombstoned.h"
45#include "util.h"
46
Josh Gaocbe70cb2016-10-18 18:17:52 -070047using namespace std::chrono_literals;
48using android::base::unique_fd;
49
50#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070051#define ARCH_SUFFIX "64"
52#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070053#define ARCH_SUFFIX ""
54#endif
55
56constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
57
58#define TIMEOUT(seconds, expr) \
59 [&]() { \
60 struct sigaction old_sigaction; \
61 struct sigaction new_sigaction = {}; \
62 new_sigaction.sa_handler = [](int) {}; \
63 if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
64 err(1, "sigaction failed"); \
65 } \
66 alarm(seconds); \
67 auto value = expr; \
68 int saved_errno = errno; \
69 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
70 err(1, "sigaction failed"); \
71 } \
72 alarm(0); \
73 errno = saved_errno; \
74 return value; \
75 }()
76
77#define ASSERT_MATCH(str, pattern) \
78 do { \
79 std::regex r((pattern)); \
80 if (!std::regex_search((str), r)) { \
81 FAIL() << "regex mismatch: expected " << (pattern) << " in: \n" << (str); \
82 } \
83 } while (0)
84
Josh Gaoe06f2a42017-04-27 16:50:38 -070085#define ASSERT_NOT_MATCH(str, pattern) \
86 do { \
87 std::regex r((pattern)); \
88 if (std::regex_search((str), r)) { \
89 FAIL() << "regex mismatch: expected to not find " << (pattern) << " in: \n" << (str); \
90 } \
91 } while (0)
92
Jaesung Chung58778e12017-06-15 18:20:34 +090093#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
94 ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
95 R"(/libc.so \()" frame_name R"(\+)")
96
Narayan Kamatha73df602017-05-24 15:07:25 +010097static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +010098 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -070099 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
100 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
101 if (intercept_fd->get() == -1) {
102 FAIL() << "failed to contact tombstoned: " << strerror(errno);
103 }
104
Narayan Kamatha73df602017-05-24 15:07:25 +0100105 InterceptRequest req = {.pid = target_pid, .dump_type = intercept_type};
Josh Gao460b3362017-03-30 16:40:47 -0700106
107 unique_fd output_pipe_write;
108 if (!Pipe(output_fd, &output_pipe_write)) {
109 FAIL() << "failed to create output pipe: " << strerror(errno);
110 }
111
112 std::string pipe_size_str;
113 int pipe_buffer_size;
114 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
115 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
116 }
117
118 pipe_size_str = android::base::Trim(pipe_size_str);
119
120 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
121 FAIL() << "failed to parse pipe max size";
122 }
123
124 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
125 FAIL() << "failed to set pipe size: " << strerror(errno);
126 }
127
Josh Gao5675f3c2017-06-01 12:19:53 -0700128 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
129
Josh Gao460b3362017-03-30 16:40:47 -0700130 if (send_fd(intercept_fd->get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
131 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
132 }
133
134 InterceptResponse response;
135 ssize_t rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
136 if (rc == -1) {
137 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
138 } else if (rc == 0) {
139 FAIL() << "failed to read response from tombstoned (EOF)";
140 } else if (rc != sizeof(response)) {
141 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
142 << ", received " << rc;
143 }
144
Narayan Kamathca5e9082017-06-02 15:42:06 +0100145 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700146}
147
Josh Gaocbe70cb2016-10-18 18:17:52 -0700148class CrasherTest : public ::testing::Test {
149 public:
150 pid_t crasher_pid = -1;
151 bool previous_wait_for_gdb;
152 unique_fd crasher_pipe;
153 unique_fd intercept_fd;
154
155 CrasherTest();
156 ~CrasherTest();
157
Narayan Kamatha73df602017-05-24 15:07:25 +0100158 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700159
160 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
161 void FinishIntercept(int* result);
162
Josh Gao2e7b8e22017-05-04 17:12:57 -0700163 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700164 void StartCrasher(const std::string& crash_type);
165 void FinishCrasher();
166 void AssertDeath(int signo);
167};
168
169CrasherTest::CrasherTest() {
170 previous_wait_for_gdb = android::base::GetBoolProperty(kWaitForGdbKey, false);
171 android::base::SetProperty(kWaitForGdbKey, "0");
172}
173
174CrasherTest::~CrasherTest() {
175 if (crasher_pid != -1) {
176 kill(crasher_pid, SIGKILL);
177 int status;
178 waitpid(crasher_pid, &status, WUNTRACED);
179 }
180
181 android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
182}
183
Narayan Kamatha73df602017-05-24 15:07:25 +0100184void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700185 if (crasher_pid == -1) {
186 FAIL() << "crasher hasn't been started";
187 }
188
Narayan Kamathca5e9082017-06-02 15:42:06 +0100189 InterceptStatus status;
190 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
191 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700192}
193
194void CrasherTest::FinishIntercept(int* result) {
195 InterceptResponse response;
196
197 // Timeout for tombstoned intercept is 10 seconds.
198 ssize_t rc = TIMEOUT(20, read(intercept_fd.get(), &response, sizeof(response)));
199 if (rc == -1) {
200 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
201 } else if (rc == 0) {
202 *result = -1;
203 } else if (rc != sizeof(response)) {
204 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
205 << ", received " << rc;
206 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700207 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700208 }
209}
210
Josh Gao2e7b8e22017-05-04 17:12:57 -0700211void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800212 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700213 unique_fd crasher_read_pipe;
214 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
215 FAIL() << "failed to create pipe: " << strerror(errno);
216 }
217
Josh Gao2e7b8e22017-05-04 17:12:57 -0700218 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700219 if (crasher_pid == -1) {
220 FAIL() << "fork failed: " << strerror(errno);
221 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800222 char dummy;
223 crasher_pipe.reset();
224 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800225 function();
226 _exit(0);
227 }
228}
229
Josh Gaocbe70cb2016-10-18 18:17:52 -0700230void CrasherTest::FinishCrasher() {
231 if (crasher_pipe == -1) {
232 FAIL() << "crasher pipe uninitialized";
233 }
234
235 ssize_t rc = write(crasher_pipe.get(), "\n", 1);
236 if (rc == -1) {
237 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
238 } else if (rc == 0) {
239 FAIL() << "crasher pipe was closed";
240 }
241}
242
243void CrasherTest::AssertDeath(int signo) {
244 int status;
245 pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0));
246 if (pid != crasher_pid) {
247 FAIL() << "failed to wait for crasher: " << strerror(errno);
248 }
249
Josh Gaoe06f2a42017-04-27 16:50:38 -0700250 if (signo == 0) {
251 ASSERT_TRUE(WIFEXITED(status));
252 ASSERT_EQ(0, WEXITSTATUS(signo));
253 } else {
254 ASSERT_FALSE(WIFEXITED(status));
255 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
256 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700257 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700258 crasher_pid = -1;
259}
260
261static void ConsumeFd(unique_fd fd, std::string* output) {
262 constexpr size_t read_length = PAGE_SIZE;
263 std::string result;
264
265 while (true) {
266 size_t offset = result.size();
267 result.resize(result.size() + PAGE_SIZE);
268 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
269 if (rc == -1) {
270 FAIL() << "read failed: " << strerror(errno);
271 } else if (rc == 0) {
272 result.resize(result.size() - PAGE_SIZE);
273 break;
274 }
275
276 result.resize(result.size() - PAGE_SIZE + rc);
277 }
278
279 *output = std::move(result);
280}
281
282TEST_F(CrasherTest, smoke) {
283 int intercept_result;
284 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800285 StartProcess([]() {
286 *reinterpret_cast<volatile char*>(0xdead) = '1';
287 });
288
Josh Gaocbe70cb2016-10-18 18:17:52 -0700289 StartIntercept(&output_fd);
290 FinishCrasher();
291 AssertDeath(SIGSEGV);
292 FinishIntercept(&intercept_result);
293
294 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
295
296 std::string result;
297 ConsumeFd(std::move(output_fd), &result);
298 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
299}
300
301TEST_F(CrasherTest, abort) {
302 int intercept_result;
303 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800304 StartProcess([]() {
305 abort();
306 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700307 StartIntercept(&output_fd);
308 FinishCrasher();
309 AssertDeath(SIGABRT);
310 FinishIntercept(&intercept_result);
311
312 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
313
314 std::string result;
315 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700316 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700317}
318
319TEST_F(CrasherTest, signal) {
320 int intercept_result;
321 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800322 StartProcess([]() {
323 abort();
324 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700325 StartIntercept(&output_fd);
326
327 // Wait for a bit, or we might end up killing the process before the signal
328 // handler even gets a chance to be registered.
329 std::this_thread::sleep_for(100ms);
330 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
331
332 AssertDeath(SIGSEGV);
333 FinishIntercept(&intercept_result);
334
335 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
336
337 std::string result;
338 ConsumeFd(std::move(output_fd), &result);
339 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER\), fault addr --------)");
340 ASSERT_MATCH(result, R"(backtrace:)");
341}
342
343TEST_F(CrasherTest, abort_message) {
344 int intercept_result;
345 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800346 StartProcess([]() {
347 android_set_abort_message("abort message goes here");
348 abort();
349 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700350 StartIntercept(&output_fd);
351 FinishCrasher();
352 AssertDeath(SIGABRT);
353 FinishIntercept(&intercept_result);
354
355 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
356
357 std::string result;
358 ConsumeFd(std::move(output_fd), &result);
Josh Gao502cfd22017-02-17 01:39:15 -0800359 ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700360}
361
Josh Gaoe06f2a42017-04-27 16:50:38 -0700362TEST_F(CrasherTest, abort_message_backtrace) {
363 int intercept_result;
364 unique_fd output_fd;
365 StartProcess([]() {
366 android_set_abort_message("not actually aborting");
367 raise(DEBUGGER_SIGNAL);
368 exit(0);
369 });
370 StartIntercept(&output_fd);
371 FinishCrasher();
372 AssertDeath(0);
373 FinishIntercept(&intercept_result);
374
375 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
376
377 std::string result;
378 ConsumeFd(std::move(output_fd), &result);
379 ASSERT_NOT_MATCH(result, R"(Abort message:)");
380}
381
Josh Gaocbe70cb2016-10-18 18:17:52 -0700382TEST_F(CrasherTest, intercept_timeout) {
383 int intercept_result;
384 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800385 StartProcess([]() {
386 abort();
387 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700388 StartIntercept(&output_fd);
389
390 // Don't let crasher finish until we timeout.
391 FinishIntercept(&intercept_result);
392
393 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
394 << intercept_result << ")";
395
396 FinishCrasher();
397 AssertDeath(SIGABRT);
398}
399
400TEST_F(CrasherTest, wait_for_gdb) {
401 if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
402 FAIL() << "failed to enable wait_for_gdb";
403 }
404 sleep(1);
405
Josh Gao502cfd22017-02-17 01:39:15 -0800406 StartProcess([]() {
407 abort();
408 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700409 FinishCrasher();
410
411 int status;
412 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, WUNTRACED));
413 ASSERT_TRUE(WIFSTOPPED(status));
414 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
415
416 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
417
418 AssertDeath(SIGABRT);
419}
420
Josh Gao7c6e3132017-01-22 17:59:02 -0800421// wait_for_gdb shouldn't trigger on manually sent signals.
Josh Gaocbe70cb2016-10-18 18:17:52 -0700422TEST_F(CrasherTest, wait_for_gdb_signal) {
423 if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
424 FAIL() << "failed to enable wait_for_gdb";
425 }
426
Josh Gao502cfd22017-02-17 01:39:15 -0800427 StartProcess([]() {
428 abort();
429 });
Josh Gao7c6e3132017-01-22 17:59:02 -0800430 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
431 AssertDeath(SIGSEGV);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700432}
433
434TEST_F(CrasherTest, backtrace) {
435 std::string result;
436 int intercept_result;
437 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800438
439 StartProcess([]() {
440 abort();
441 });
Narayan Kamatha73df602017-05-24 15:07:25 +0100442 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700443
444 std::this_thread::sleep_for(500ms);
445
446 sigval val;
447 val.sival_int = 1;
448 ASSERT_EQ(0, sigqueue(crasher_pid, DEBUGGER_SIGNAL, val)) << strerror(errno);
449 FinishIntercept(&intercept_result);
450 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
451 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +0900452 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700453
454 int status;
455 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
456
457 StartIntercept(&output_fd);
458 FinishCrasher();
459 AssertDeath(SIGABRT);
460 FinishIntercept(&intercept_result);
461 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
462 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700463 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700464}
Josh Gaofca7ca32017-01-23 12:05:35 -0800465
466TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -0800467 int intercept_result;
468 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -0800469 StartProcess([]() {
470 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -0800471 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -0800472 });
Josh Gao502cfd22017-02-17 01:39:15 -0800473
474 StartIntercept(&output_fd);
475 FinishCrasher();
476 AssertDeath(SIGABRT);
477 FinishIntercept(&intercept_result);
478
479 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
480
481 std::string result;
482 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700483 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -0800484}
485
Josh Gao502cfd22017-02-17 01:39:15 -0800486TEST_F(CrasherTest, capabilities) {
487 ASSERT_EQ(0U, getuid()) << "capability test requires root";
488
Josh Gaofca7ca32017-01-23 12:05:35 -0800489 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -0800490 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
491 err(1, "failed to set PR_SET_KEEPCAPS");
492 }
493
494 if (setresuid(1, 1, 1) != 0) {
495 err(1, "setresuid failed");
496 }
497
498 __user_cap_header_struct capheader;
499 __user_cap_data_struct capdata[2];
500 memset(&capheader, 0, sizeof(capheader));
501 memset(&capdata, 0, sizeof(capdata));
502
503 capheader.version = _LINUX_CAPABILITY_VERSION_3;
504 capheader.pid = 0;
505
506 // Turn on every third capability.
507 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
508 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
509 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
510 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
511 }
512
513 // Make sure CAP_SYS_PTRACE is off.
514 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
515 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
516
517 if (capset(&capheader, &capdata[0]) != 0) {
518 err(1, "capset failed");
519 }
520
521 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
522 err(1, "failed to drop ambient capabilities");
523 }
524
Josh Gaoa5199a92017-04-03 13:18:34 -0700525 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -0800526 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -0800527 });
Josh Gao502cfd22017-02-17 01:39:15 -0800528
529 unique_fd output_fd;
530 StartIntercept(&output_fd);
531 FinishCrasher();
532 AssertDeath(SIGSYS);
533
534 std::string result;
535 int intercept_result;
536 FinishIntercept(&intercept_result);
537 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
538 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -0700539 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900540 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -0800541}
Josh Gaoc3c8c022017-02-13 16:36:18 -0800542
Josh Gao2e7b8e22017-05-04 17:12:57 -0700543TEST_F(CrasherTest, fake_pid) {
544 int intercept_result;
545 unique_fd output_fd;
546
547 // Prime the getpid/gettid caches.
548 UNUSED(getpid());
549 UNUSED(gettid());
550
551 std::function<pid_t()> clone_fn = []() {
552 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
553 };
554 StartProcess(
555 []() {
556 ASSERT_NE(getpid(), syscall(__NR_getpid));
557 ASSERT_NE(gettid(), syscall(__NR_gettid));
558 raise(SIGSEGV);
559 },
560 clone_fn);
561
562 StartIntercept(&output_fd);
563 FinishCrasher();
564 AssertDeath(SIGSEGV);
565 FinishIntercept(&intercept_result);
566
567 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
568
569 std::string result;
570 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +0900571 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -0700572}
573
Josh Gaofd13bf02017-08-18 15:37:26 -0700574TEST_F(CrasherTest, competing_tracer) {
575 int intercept_result;
576 unique_fd output_fd;
577 StartProcess([]() {
578 while (true) {
579 }
580 });
581
582 StartIntercept(&output_fd);
583 FinishCrasher();
584
585 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
586 ASSERT_EQ(0, kill(crasher_pid, SIGABRT));
587
588 int status;
589 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
590 ASSERT_TRUE(WIFSTOPPED(status));
591 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
592
593 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
594 FinishIntercept(&intercept_result);
595 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
596
597 std::string result;
598 ConsumeFd(std::move(output_fd), &result);
599 std::string regex = R"(failed to attach to thread \d+, already traced by )";
600 regex += std::to_string(gettid());
601 regex += R"( \(.+debuggerd_test)";
602 ASSERT_MATCH(result, regex.c_str());
603
604 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
605 AssertDeath(SIGABRT);
606}
607
Josh Gaoc3c8c022017-02-13 16:36:18 -0800608TEST(crash_dump, zombie) {
609 pid_t forkpid = fork();
610
Josh Gaoc3c8c022017-02-13 16:36:18 -0800611 pid_t rc;
612 int status;
613
614 if (forkpid == 0) {
615 errno = 0;
616 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
617 if (rc != -1 || errno != ECHILD) {
618 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
619 }
620
621 raise(DEBUGGER_SIGNAL);
622
623 errno = 0;
624 rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
625 if (rc != -1 || errno != ECHILD) {
626 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
627 }
628 _exit(0);
629 } else {
630 rc = waitpid(forkpid, &status, 0);
631 ASSERT_EQ(forkpid, rc);
632 ASSERT_TRUE(WIFEXITED(status));
633 ASSERT_EQ(0, WEXITSTATUS(status));
634 }
635}
Josh Gao352a8452017-03-30 16:46:21 -0700636
637TEST(tombstoned, no_notify) {
638 // Do this a few times.
639 for (int i = 0; i < 3; ++i) {
640 pid_t pid = 123'456'789 + i;
641
642 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100643 InterceptStatus status;
644 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
645 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700646
647 {
648 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100649 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -0700650 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
651 }
652
653 pid_t read_pid;
654 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
655 ASSERT_EQ(read_pid, pid);
656 }
657}
658
659TEST(tombstoned, stress) {
660 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
661 static constexpr int kDumpCount = 100;
662
663 std::atomic<bool> start(false);
664 std::vector<std::thread> threads;
665 threads.emplace_back([&start]() {
666 while (!start) {
667 continue;
668 }
669
670 // Use a way out of range pid, to avoid stomping on an actual process.
671 pid_t pid_base = 1'000'000;
672
673 for (int dump = 0; dump < kDumpCount; ++dump) {
674 pid_t pid = pid_base + dump;
675
676 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100677 InterceptStatus status;
678 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
679 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700680
681 // Pretend to crash, and then immediately close the socket.
682 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
683 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
684 if (sockfd == -1) {
685 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
686 }
687 TombstonedCrashPacket packet = {};
688 packet.packet_type = CrashPacketType::kDumpRequest;
689 packet.packet.dump_request.pid = pid;
690 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
691 FAIL() << "failed to write to tombstoned: " << strerror(errno);
692 }
693
694 continue;
695 }
696 });
697
698 threads.emplace_back([&start]() {
699 while (!start) {
700 continue;
701 }
702
703 // Use a way out of range pid, to avoid stomping on an actual process.
704 pid_t pid_base = 2'000'000;
705
706 for (int dump = 0; dump < kDumpCount; ++dump) {
707 pid_t pid = pid_base + dump;
708
709 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100710 InterceptStatus status;
711 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
712 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700713
714 {
715 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100716 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -0700717 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
718 tombstoned_notify_completion(tombstoned_socket.get());
719 }
720
721 // TODO: Fix the race that requires this sleep.
722 std::this_thread::sleep_for(50ms);
723
724 pid_t read_pid;
725 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
726 ASSERT_EQ(read_pid, pid);
727 }
728 });
729
730 start = true;
731
732 for (std::thread& thread : threads) {
733 thread.join();
734 }
735}
Narayan Kamathca5e9082017-06-02 15:42:06 +0100736
737TEST(tombstoned, java_trace_intercept_smoke) {
738 // Using a "real" PID is a little dangerous here - if the test fails
739 // or crashes, we might end up getting a bogus / unreliable stack
740 // trace.
741 const pid_t self = getpid();
742
743 unique_fd intercept_fd, output_fd;
744 InterceptStatus status;
745 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
746 ASSERT_EQ(InterceptStatus::kRegistered, status);
747
748 // First connect to tombstoned requesting a native backtrace. This
749 // should result in a "regular" FD and not the installed intercept.
750 const char native[] = "native";
751 unique_fd tombstoned_socket, input_fd;
752 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
753 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
754 tombstoned_notify_completion(tombstoned_socket.get());
755
756 // Then, connect to tombstoned asking for a java backtrace. This *should*
757 // trigger the intercept.
758 const char java[] = "java";
759 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
760 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
761 tombstoned_notify_completion(tombstoned_socket.get());
762
763 char outbuf[sizeof(java)];
764 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
765 ASSERT_STREQ("java", outbuf);
766}
767
768TEST(tombstoned, multiple_intercepts) {
769 const pid_t fake_pid = 1'234'567;
770 unique_fd intercept_fd, output_fd;
771 InterceptStatus status;
772 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
773 ASSERT_EQ(InterceptStatus::kRegistered, status);
774
775 unique_fd intercept_fd_2, output_fd_2;
776 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
777 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
778}
779
780TEST(tombstoned, intercept_any) {
781 const pid_t fake_pid = 1'234'567;
782
783 unique_fd intercept_fd, output_fd;
784 InterceptStatus status;
785 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
786 ASSERT_EQ(InterceptStatus::kRegistered, status);
787
788 const char any[] = "any";
789 unique_fd tombstoned_socket, input_fd;
790 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
791 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
792 tombstoned_notify_completion(tombstoned_socket.get());
793
794 char outbuf[sizeof(any)];
795 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
796 ASSERT_STREQ("any", outbuf);
797}