blob: 0d17a3b5c2563dba1abb4c4b58a7f1627e3ef5c3 [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 Gaocdea7502017-11-01 15:00:40 -070019#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080020#include <sys/capability.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080021#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070022#include <sys/ptrace.h>
Dan Albertc38057a2017-10-11 11:35:40 -070023#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070024#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070025#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070026
27#include <chrono>
28#include <regex>
29#include <thread>
30
Josh Gao502cfd22017-02-17 01:39:15 -080031#include <android/set_abort_message.h>
32
Josh Gaocbe70cb2016-10-18 18:17:52 -070033#include <android-base/file.h>
34#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070035#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070036#include <android-base/parseint.h>
37#include <android-base/properties.h>
38#include <android-base/strings.h>
39#include <android-base/unique_fd.h>
40#include <cutils/sockets.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070041#include <gtest/gtest.h>
42
Narayan Kamath2d377cd2017-05-10 10:58:59 +010043#include "debuggerd/handler.h"
44#include "protocol.h"
45#include "tombstoned/tombstoned.h"
46#include "util.h"
47
Josh Gaocbe70cb2016-10-18 18:17:52 -070048using namespace std::chrono_literals;
49using android::base::unique_fd;
50
51#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#define ARCH_SUFFIX "64"
53#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#define ARCH_SUFFIX ""
55#endif
56
57constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
58
59#define TIMEOUT(seconds, expr) \
60 [&]() { \
61 struct sigaction old_sigaction; \
62 struct sigaction new_sigaction = {}; \
63 new_sigaction.sa_handler = [](int) {}; \
64 if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
65 err(1, "sigaction failed"); \
66 } \
67 alarm(seconds); \
68 auto value = expr; \
69 int saved_errno = errno; \
70 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
71 err(1, "sigaction failed"); \
72 } \
73 alarm(0); \
74 errno = saved_errno; \
75 return value; \
76 }()
77
78#define ASSERT_MATCH(str, pattern) \
79 do { \
80 std::regex r((pattern)); \
81 if (!std::regex_search((str), r)) { \
82 FAIL() << "regex mismatch: expected " << (pattern) << " in: \n" << (str); \
83 } \
84 } while (0)
85
Josh Gaoe06f2a42017-04-27 16:50:38 -070086#define ASSERT_NOT_MATCH(str, pattern) \
87 do { \
88 std::regex r((pattern)); \
89 if (std::regex_search((str), r)) { \
90 FAIL() << "regex mismatch: expected to not find " << (pattern) << " in: \n" << (str); \
91 } \
92 } while (0)
93
Jaesung Chung58778e12017-06-15 18:20:34 +090094#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
95 ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
96 R"(/libc.so \()" frame_name R"(\+)")
97
Narayan Kamatha73df602017-05-24 15:07:25 +010098static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +010099 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700100 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
101 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
102 if (intercept_fd->get() == -1) {
103 FAIL() << "failed to contact tombstoned: " << strerror(errno);
104 }
105
Narayan Kamatha73df602017-05-24 15:07:25 +0100106 InterceptRequest req = {.pid = target_pid, .dump_type = intercept_type};
Josh Gao460b3362017-03-30 16:40:47 -0700107
108 unique_fd output_pipe_write;
109 if (!Pipe(output_fd, &output_pipe_write)) {
110 FAIL() << "failed to create output pipe: " << strerror(errno);
111 }
112
113 std::string pipe_size_str;
114 int pipe_buffer_size;
115 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
116 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
117 }
118
119 pipe_size_str = android::base::Trim(pipe_size_str);
120
121 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
122 FAIL() << "failed to parse pipe max size";
123 }
124
125 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
126 FAIL() << "failed to set pipe size: " << strerror(errno);
127 }
128
Josh Gao5675f3c2017-06-01 12:19:53 -0700129 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
130
Josh Gao460b3362017-03-30 16:40:47 -0700131 if (send_fd(intercept_fd->get(), &req, sizeof(req), std::move(output_pipe_write)) != sizeof(req)) {
132 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
133 }
134
135 InterceptResponse response;
136 ssize_t rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
137 if (rc == -1) {
138 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
139 } else if (rc == 0) {
140 FAIL() << "failed to read response from tombstoned (EOF)";
141 } else if (rc != sizeof(response)) {
142 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
143 << ", received " << rc;
144 }
145
Narayan Kamathca5e9082017-06-02 15:42:06 +0100146 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700147}
148
Josh Gaocbe70cb2016-10-18 18:17:52 -0700149class CrasherTest : public ::testing::Test {
150 public:
151 pid_t crasher_pid = -1;
152 bool previous_wait_for_gdb;
153 unique_fd crasher_pipe;
154 unique_fd intercept_fd;
155
156 CrasherTest();
157 ~CrasherTest();
158
Narayan Kamatha73df602017-05-24 15:07:25 +0100159 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700160
161 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
162 void FinishIntercept(int* result);
163
Josh Gao2e7b8e22017-05-04 17:12:57 -0700164 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700165 void StartCrasher(const std::string& crash_type);
166 void FinishCrasher();
167 void AssertDeath(int signo);
168};
169
170CrasherTest::CrasherTest() {
171 previous_wait_for_gdb = android::base::GetBoolProperty(kWaitForGdbKey, false);
172 android::base::SetProperty(kWaitForGdbKey, "0");
173}
174
175CrasherTest::~CrasherTest() {
176 if (crasher_pid != -1) {
177 kill(crasher_pid, SIGKILL);
178 int status;
179 waitpid(crasher_pid, &status, WUNTRACED);
180 }
181
182 android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
183}
184
Narayan Kamatha73df602017-05-24 15:07:25 +0100185void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700186 if (crasher_pid == -1) {
187 FAIL() << "crasher hasn't been started";
188 }
189
Narayan Kamathca5e9082017-06-02 15:42:06 +0100190 InterceptStatus status;
191 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
192 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700193}
194
195void CrasherTest::FinishIntercept(int* result) {
196 InterceptResponse response;
197
198 // Timeout for tombstoned intercept is 10 seconds.
199 ssize_t rc = TIMEOUT(20, read(intercept_fd.get(), &response, sizeof(response)));
200 if (rc == -1) {
201 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
202 } else if (rc == 0) {
203 *result = -1;
204 } else if (rc != sizeof(response)) {
205 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
206 << ", received " << rc;
207 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700208 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700209 }
210}
211
Josh Gao2e7b8e22017-05-04 17:12:57 -0700212void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800213 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700214 unique_fd crasher_read_pipe;
215 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
216 FAIL() << "failed to create pipe: " << strerror(errno);
217 }
218
Josh Gao2e7b8e22017-05-04 17:12:57 -0700219 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700220 if (crasher_pid == -1) {
221 FAIL() << "fork failed: " << strerror(errno);
222 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800223 char dummy;
224 crasher_pipe.reset();
225 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800226 function();
227 _exit(0);
228 }
229}
230
Josh Gaocbe70cb2016-10-18 18:17:52 -0700231void CrasherTest::FinishCrasher() {
232 if (crasher_pipe == -1) {
233 FAIL() << "crasher pipe uninitialized";
234 }
235
236 ssize_t rc = write(crasher_pipe.get(), "\n", 1);
237 if (rc == -1) {
238 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
239 } else if (rc == 0) {
240 FAIL() << "crasher pipe was closed";
241 }
242}
243
244void CrasherTest::AssertDeath(int signo) {
245 int status;
246 pid_t pid = TIMEOUT(5, waitpid(crasher_pid, &status, 0));
247 if (pid != crasher_pid) {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700248 printf("failed to wait for crasher (pid %d)\n", crasher_pid);
249 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700250 FAIL() << "failed to wait for crasher: " << strerror(errno);
251 }
252
Josh Gaoe06f2a42017-04-27 16:50:38 -0700253 if (signo == 0) {
254 ASSERT_TRUE(WIFEXITED(status));
255 ASSERT_EQ(0, WEXITSTATUS(signo));
256 } else {
257 ASSERT_FALSE(WIFEXITED(status));
258 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
259 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700260 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 crasher_pid = -1;
262}
263
264static void ConsumeFd(unique_fd fd, std::string* output) {
265 constexpr size_t read_length = PAGE_SIZE;
266 std::string result;
267
268 while (true) {
269 size_t offset = result.size();
270 result.resize(result.size() + PAGE_SIZE);
271 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
272 if (rc == -1) {
273 FAIL() << "read failed: " << strerror(errno);
274 } else if (rc == 0) {
275 result.resize(result.size() - PAGE_SIZE);
276 break;
277 }
278
279 result.resize(result.size() - PAGE_SIZE + rc);
280 }
281
282 *output = std::move(result);
283}
284
285TEST_F(CrasherTest, smoke) {
286 int intercept_result;
287 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800288 StartProcess([]() {
289 *reinterpret_cast<volatile char*>(0xdead) = '1';
290 });
291
Josh Gaocbe70cb2016-10-18 18:17:52 -0700292 StartIntercept(&output_fd);
293 FinishCrasher();
294 AssertDeath(SIGSEGV);
295 FinishIntercept(&intercept_result);
296
297 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
298
299 std::string result;
300 ConsumeFd(std::move(output_fd), &result);
301 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
302}
303
Josh Gaocdea7502017-11-01 15:00:40 -0700304TEST_F(CrasherTest, LD_PRELOAD) {
305 int intercept_result;
306 unique_fd output_fd;
307 StartProcess([]() {
308 setenv("LD_PRELOAD", "nonexistent.so", 1);
309 *reinterpret_cast<volatile char*>(0xdead) = '1';
310 });
311
312 StartIntercept(&output_fd);
313 FinishCrasher();
314 AssertDeath(SIGSEGV);
315 FinishIntercept(&intercept_result);
316
317 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
318
319 std::string result;
320 ConsumeFd(std::move(output_fd), &result);
321 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
322}
323
Josh Gaocbe70cb2016-10-18 18:17:52 -0700324TEST_F(CrasherTest, abort) {
325 int intercept_result;
326 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800327 StartProcess([]() {
328 abort();
329 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700330 StartIntercept(&output_fd);
331 FinishCrasher();
332 AssertDeath(SIGABRT);
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);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700339 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700340}
341
342TEST_F(CrasherTest, signal) {
343 int intercept_result;
344 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800345 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700346 while (true) {
347 sleep(1);
348 }
Josh Gao502cfd22017-02-17 01:39:15 -0800349 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700350 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700351 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700352 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
353
354 AssertDeath(SIGSEGV);
355 FinishIntercept(&intercept_result);
356
357 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
358
359 std::string result;
360 ConsumeFd(std::move(output_fd), &result);
361 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER\), fault addr --------)");
362 ASSERT_MATCH(result, R"(backtrace:)");
363}
364
365TEST_F(CrasherTest, abort_message) {
366 int intercept_result;
367 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800368 StartProcess([]() {
369 android_set_abort_message("abort message goes here");
370 abort();
371 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700372 StartIntercept(&output_fd);
373 FinishCrasher();
374 AssertDeath(SIGABRT);
375 FinishIntercept(&intercept_result);
376
377 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
378
379 std::string result;
380 ConsumeFd(std::move(output_fd), &result);
Josh Gao502cfd22017-02-17 01:39:15 -0800381 ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700382}
383
Josh Gaoe06f2a42017-04-27 16:50:38 -0700384TEST_F(CrasherTest, abort_message_backtrace) {
385 int intercept_result;
386 unique_fd output_fd;
387 StartProcess([]() {
388 android_set_abort_message("not actually aborting");
389 raise(DEBUGGER_SIGNAL);
390 exit(0);
391 });
392 StartIntercept(&output_fd);
393 FinishCrasher();
394 AssertDeath(0);
395 FinishIntercept(&intercept_result);
396
397 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
398
399 std::string result;
400 ConsumeFd(std::move(output_fd), &result);
401 ASSERT_NOT_MATCH(result, R"(Abort message:)");
402}
403
Josh Gaocbe70cb2016-10-18 18:17:52 -0700404TEST_F(CrasherTest, intercept_timeout) {
405 int intercept_result;
406 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800407 StartProcess([]() {
408 abort();
409 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700410 StartIntercept(&output_fd);
411
412 // Don't let crasher finish until we timeout.
413 FinishIntercept(&intercept_result);
414
415 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
416 << intercept_result << ")";
417
418 FinishCrasher();
419 AssertDeath(SIGABRT);
420}
421
422TEST_F(CrasherTest, wait_for_gdb) {
423 if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
424 FAIL() << "failed to enable wait_for_gdb";
425 }
426 sleep(1);
427
Josh Gao502cfd22017-02-17 01:39:15 -0800428 StartProcess([]() {
429 abort();
430 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700431 FinishCrasher();
432
433 int status;
434 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, WUNTRACED));
435 ASSERT_TRUE(WIFSTOPPED(status));
436 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
437
438 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
439
440 AssertDeath(SIGABRT);
441}
442
Josh Gaocbe70cb2016-10-18 18:17:52 -0700443TEST_F(CrasherTest, backtrace) {
444 std::string result;
445 int intercept_result;
446 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800447
448 StartProcess([]() {
449 abort();
450 });
Narayan Kamatha73df602017-05-24 15:07:25 +0100451 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700452
453 std::this_thread::sleep_for(500ms);
454
455 sigval val;
456 val.sival_int = 1;
457 ASSERT_EQ(0, sigqueue(crasher_pid, DEBUGGER_SIGNAL, val)) << strerror(errno);
458 FinishIntercept(&intercept_result);
459 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
460 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +0900461 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700462
463 int status;
464 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
465
466 StartIntercept(&output_fd);
467 FinishCrasher();
468 AssertDeath(SIGABRT);
469 FinishIntercept(&intercept_result);
470 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
471 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700472 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700473}
Josh Gaofca7ca32017-01-23 12:05:35 -0800474
475TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -0800476 int intercept_result;
477 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -0800478 StartProcess([]() {
479 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -0800480 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -0800481 });
Josh Gao502cfd22017-02-17 01:39:15 -0800482
483 StartIntercept(&output_fd);
484 FinishCrasher();
485 AssertDeath(SIGABRT);
486 FinishIntercept(&intercept_result);
487
488 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
489
490 std::string result;
491 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700492 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -0800493}
494
Josh Gao502cfd22017-02-17 01:39:15 -0800495TEST_F(CrasherTest, capabilities) {
496 ASSERT_EQ(0U, getuid()) << "capability test requires root";
497
Josh Gaofca7ca32017-01-23 12:05:35 -0800498 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -0800499 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
500 err(1, "failed to set PR_SET_KEEPCAPS");
501 }
502
503 if (setresuid(1, 1, 1) != 0) {
504 err(1, "setresuid failed");
505 }
506
507 __user_cap_header_struct capheader;
508 __user_cap_data_struct capdata[2];
509 memset(&capheader, 0, sizeof(capheader));
510 memset(&capdata, 0, sizeof(capdata));
511
512 capheader.version = _LINUX_CAPABILITY_VERSION_3;
513 capheader.pid = 0;
514
515 // Turn on every third capability.
516 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
517 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
518 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
519 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
520 }
521
522 // Make sure CAP_SYS_PTRACE is off.
523 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
524 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
525
526 if (capset(&capheader, &capdata[0]) != 0) {
527 err(1, "capset failed");
528 }
529
530 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
531 err(1, "failed to drop ambient capabilities");
532 }
533
Josh Gaoa5199a92017-04-03 13:18:34 -0700534 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -0800535 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -0800536 });
Josh Gao502cfd22017-02-17 01:39:15 -0800537
538 unique_fd output_fd;
539 StartIntercept(&output_fd);
540 FinishCrasher();
541 AssertDeath(SIGSYS);
542
543 std::string result;
544 int intercept_result;
545 FinishIntercept(&intercept_result);
546 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
547 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -0700548 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900549 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -0800550}
Josh Gaoc3c8c022017-02-13 16:36:18 -0800551
Josh Gao2e7b8e22017-05-04 17:12:57 -0700552TEST_F(CrasherTest, fake_pid) {
553 int intercept_result;
554 unique_fd output_fd;
555
556 // Prime the getpid/gettid caches.
557 UNUSED(getpid());
558 UNUSED(gettid());
559
560 std::function<pid_t()> clone_fn = []() {
561 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
562 };
563 StartProcess(
564 []() {
565 ASSERT_NE(getpid(), syscall(__NR_getpid));
566 ASSERT_NE(gettid(), syscall(__NR_gettid));
567 raise(SIGSEGV);
568 },
569 clone_fn);
570
571 StartIntercept(&output_fd);
572 FinishCrasher();
573 AssertDeath(SIGSEGV);
574 FinishIntercept(&intercept_result);
575
576 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
577
578 std::string result;
579 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +0900580 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -0700581}
582
Josh Gaofd13bf02017-08-18 15:37:26 -0700583TEST_F(CrasherTest, competing_tracer) {
584 int intercept_result;
585 unique_fd output_fd;
586 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700587 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -0700588 });
589
590 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -0700591
592 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700593 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -0700594
595 int status;
596 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
597 ASSERT_TRUE(WIFSTOPPED(status));
598 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
599
600 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
601 FinishIntercept(&intercept_result);
602 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
603
604 std::string result;
605 ConsumeFd(std::move(output_fd), &result);
606 std::string regex = R"(failed to attach to thread \d+, already traced by )";
607 regex += std::to_string(gettid());
608 regex += R"( \(.+debuggerd_test)";
609 ASSERT_MATCH(result, regex.c_str());
610
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700611 ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
612 ASSERT_TRUE(WIFSTOPPED(status));
613 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
614
Josh Gaofd13bf02017-08-18 15:37:26 -0700615 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
616 AssertDeath(SIGABRT);
617}
618
Josh Gaoc3c8c022017-02-13 16:36:18 -0800619TEST(crash_dump, zombie) {
620 pid_t forkpid = fork();
621
Josh Gaoc3c8c022017-02-13 16:36:18 -0800622 pid_t rc;
623 int status;
624
625 if (forkpid == 0) {
626 errno = 0;
627 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
628 if (rc != -1 || errno != ECHILD) {
629 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
630 }
631
632 raise(DEBUGGER_SIGNAL);
633
634 errno = 0;
635 rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
636 if (rc != -1 || errno != ECHILD) {
637 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
638 }
639 _exit(0);
640 } else {
641 rc = waitpid(forkpid, &status, 0);
642 ASSERT_EQ(forkpid, rc);
643 ASSERT_TRUE(WIFEXITED(status));
644 ASSERT_EQ(0, WEXITSTATUS(status));
645 }
646}
Josh Gao352a8452017-03-30 16:46:21 -0700647
648TEST(tombstoned, no_notify) {
649 // Do this a few times.
650 for (int i = 0; i < 3; ++i) {
651 pid_t pid = 123'456'789 + i;
652
653 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100654 InterceptStatus status;
655 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
656 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700657
658 {
659 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100660 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -0700661 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
662 }
663
664 pid_t read_pid;
665 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
666 ASSERT_EQ(read_pid, pid);
667 }
668}
669
670TEST(tombstoned, stress) {
671 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
672 static constexpr int kDumpCount = 100;
673
674 std::atomic<bool> start(false);
675 std::vector<std::thread> threads;
676 threads.emplace_back([&start]() {
677 while (!start) {
678 continue;
679 }
680
681 // Use a way out of range pid, to avoid stomping on an actual process.
682 pid_t pid_base = 1'000'000;
683
684 for (int dump = 0; dump < kDumpCount; ++dump) {
685 pid_t pid = pid_base + dump;
686
687 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100688 InterceptStatus status;
689 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
690 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700691
692 // Pretend to crash, and then immediately close the socket.
693 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
694 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
695 if (sockfd == -1) {
696 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
697 }
698 TombstonedCrashPacket packet = {};
699 packet.packet_type = CrashPacketType::kDumpRequest;
700 packet.packet.dump_request.pid = pid;
701 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
702 FAIL() << "failed to write to tombstoned: " << strerror(errno);
703 }
704
705 continue;
706 }
707 });
708
709 threads.emplace_back([&start]() {
710 while (!start) {
711 continue;
712 }
713
714 // Use a way out of range pid, to avoid stomping on an actual process.
715 pid_t pid_base = 2'000'000;
716
717 for (int dump = 0; dump < kDumpCount; ++dump) {
718 pid_t pid = pid_base + dump;
719
720 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100721 InterceptStatus status;
722 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
723 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700724
725 {
726 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100727 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -0700728 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
729 tombstoned_notify_completion(tombstoned_socket.get());
730 }
731
732 // TODO: Fix the race that requires this sleep.
733 std::this_thread::sleep_for(50ms);
734
735 pid_t read_pid;
736 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
737 ASSERT_EQ(read_pid, pid);
738 }
739 });
740
741 start = true;
742
743 for (std::thread& thread : threads) {
744 thread.join();
745 }
746}
Narayan Kamathca5e9082017-06-02 15:42:06 +0100747
748TEST(tombstoned, java_trace_intercept_smoke) {
749 // Using a "real" PID is a little dangerous here - if the test fails
750 // or crashes, we might end up getting a bogus / unreliable stack
751 // trace.
752 const pid_t self = getpid();
753
754 unique_fd intercept_fd, output_fd;
755 InterceptStatus status;
756 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
757 ASSERT_EQ(InterceptStatus::kRegistered, status);
758
759 // First connect to tombstoned requesting a native backtrace. This
760 // should result in a "regular" FD and not the installed intercept.
761 const char native[] = "native";
762 unique_fd tombstoned_socket, input_fd;
763 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
764 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
765 tombstoned_notify_completion(tombstoned_socket.get());
766
767 // Then, connect to tombstoned asking for a java backtrace. This *should*
768 // trigger the intercept.
769 const char java[] = "java";
770 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
771 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
772 tombstoned_notify_completion(tombstoned_socket.get());
773
774 char outbuf[sizeof(java)];
775 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
776 ASSERT_STREQ("java", outbuf);
777}
778
779TEST(tombstoned, multiple_intercepts) {
780 const pid_t fake_pid = 1'234'567;
781 unique_fd intercept_fd, output_fd;
782 InterceptStatus status;
783 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
784 ASSERT_EQ(InterceptStatus::kRegistered, status);
785
786 unique_fd intercept_fd_2, output_fd_2;
787 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
788 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
789}
790
791TEST(tombstoned, intercept_any) {
792 const pid_t fake_pid = 1'234'567;
793
794 unique_fd intercept_fd, output_fd;
795 InterceptStatus status;
796 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
797 ASSERT_EQ(InterceptStatus::kRegistered, status);
798
799 const char any[] = "any";
800 unique_fd tombstoned_socket, input_fd;
801 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
802 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
803 tombstoned_notify_completion(tombstoned_socket.get());
804
805 char outbuf[sizeof(any)];
806 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
807 ASSERT_STREQ("any", outbuf);
808}