blob: 99729dcd916bdd7f16e6b93a4bc84e528dd94a91 [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>
Josh Gao70adac62018-02-22 11:38:33 -080023#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070024#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070025#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070026#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070027
28#include <chrono>
29#include <regex>
30#include <thread>
31
Josh Gaobf06a402018-08-27 16:34:01 -070032#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080033#include <android/set_abort_message.h>
34
Josh Gao5f87bbd2019-01-09 17:01:49 -080035#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070036#include <android-base/file.h>
37#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070038#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070039#include <android-base/parseint.h>
40#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070041#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070042#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070043#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070044#include <android-base/unique_fd.h>
45#include <cutils/sockets.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070046#include <gtest/gtest.h>
47
Josh Gaoe04ca272018-01-16 15:38:17 -080048#include <libminijail.h>
49#include <scoped_minijail.h>
50
Narayan Kamath2d377cd2017-05-10 10:58:59 +010051#include "debuggerd/handler.h"
52#include "protocol.h"
53#include "tombstoned/tombstoned.h"
54#include "util.h"
55
Josh Gaocbe70cb2016-10-18 18:17:52 -070056using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080057
58using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070059using android::base::unique_fd;
60
61#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070062#define ARCH_SUFFIX "64"
63#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070064#define ARCH_SUFFIX ""
65#endif
66
67constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
68
69#define TIMEOUT(seconds, expr) \
70 [&]() { \
71 struct sigaction old_sigaction; \
72 struct sigaction new_sigaction = {}; \
73 new_sigaction.sa_handler = [](int) {}; \
74 if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
75 err(1, "sigaction failed"); \
76 } \
77 alarm(seconds); \
78 auto value = expr; \
79 int saved_errno = errno; \
80 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
81 err(1, "sigaction failed"); \
82 } \
83 alarm(0); \
84 errno = saved_errno; \
85 return value; \
86 }()
87
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -070088// Backtrace frame dump could contain:
89// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
90// or
91// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -080092#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -070093 ASSERT_MATCH(result, \
94 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +090095
Narayan Kamatha73df602017-05-24 15:07:25 +010096static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +010097 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -070098 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
99 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
100 if (intercept_fd->get() == -1) {
101 FAIL() << "failed to contact tombstoned: " << strerror(errno);
102 }
103
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700104 InterceptRequest req = {
105 .dump_type = intercept_type,
106 .pid = target_pid,
107 };
Josh Gao460b3362017-03-30 16:40:47 -0700108
109 unique_fd output_pipe_write;
110 if (!Pipe(output_fd, &output_pipe_write)) {
111 FAIL() << "failed to create output pipe: " << strerror(errno);
112 }
113
114 std::string pipe_size_str;
115 int pipe_buffer_size;
116 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
117 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
118 }
119
120 pipe_size_str = android::base::Trim(pipe_size_str);
121
122 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
123 FAIL() << "failed to parse pipe max size";
124 }
125
126 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
127 FAIL() << "failed to set pipe size: " << strerror(errno);
128 }
129
Josh Gao5675f3c2017-06-01 12:19:53 -0700130 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
131
Josh Gao5f87bbd2019-01-09 17:01:49 -0800132 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
133 output_pipe_write.reset();
134 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700135 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
136 }
137
138 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800139 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700140 if (rc == -1) {
141 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
142 } else if (rc == 0) {
143 FAIL() << "failed to read response from tombstoned (EOF)";
144 } else if (rc != sizeof(response)) {
145 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
146 << ", received " << rc;
147 }
148
Narayan Kamathca5e9082017-06-02 15:42:06 +0100149 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700150}
151
Josh Gaocbe70cb2016-10-18 18:17:52 -0700152class CrasherTest : public ::testing::Test {
153 public:
154 pid_t crasher_pid = -1;
155 bool previous_wait_for_gdb;
156 unique_fd crasher_pipe;
157 unique_fd intercept_fd;
158
159 CrasherTest();
160 ~CrasherTest();
161
Narayan Kamatha73df602017-05-24 15:07:25 +0100162 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700163
164 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
165 void FinishIntercept(int* result);
166
Josh Gao2e7b8e22017-05-04 17:12:57 -0700167 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700168 void StartCrasher(const std::string& crash_type);
169 void FinishCrasher();
170 void AssertDeath(int signo);
171};
172
173CrasherTest::CrasherTest() {
174 previous_wait_for_gdb = android::base::GetBoolProperty(kWaitForGdbKey, false);
175 android::base::SetProperty(kWaitForGdbKey, "0");
176}
177
178CrasherTest::~CrasherTest() {
179 if (crasher_pid != -1) {
180 kill(crasher_pid, SIGKILL);
181 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700182 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700183 }
184
185 android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
186}
187
Narayan Kamatha73df602017-05-24 15:07:25 +0100188void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700189 if (crasher_pid == -1) {
190 FAIL() << "crasher hasn't been started";
191 }
192
Narayan Kamathca5e9082017-06-02 15:42:06 +0100193 InterceptStatus status;
194 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
195 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700196}
197
198void CrasherTest::FinishIntercept(int* result) {
199 InterceptResponse response;
200
Christopher Ferris11555f02019-09-20 14:18:55 -0700201 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700202 if (rc == -1) {
203 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
204 } else if (rc == 0) {
205 *result = -1;
206 } else if (rc != sizeof(response)) {
207 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
208 << ", received " << rc;
209 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700210 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700211 }
212}
213
Josh Gao2e7b8e22017-05-04 17:12:57 -0700214void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800215 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700216 unique_fd crasher_read_pipe;
217 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
218 FAIL() << "failed to create pipe: " << strerror(errno);
219 }
220
Josh Gao2e7b8e22017-05-04 17:12:57 -0700221 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222 if (crasher_pid == -1) {
223 FAIL() << "fork failed: " << strerror(errno);
224 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800225 char dummy;
226 crasher_pipe.reset();
227 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800228 function();
229 _exit(0);
230 }
231}
232
Josh Gaocbe70cb2016-10-18 18:17:52 -0700233void CrasherTest::FinishCrasher() {
234 if (crasher_pipe == -1) {
235 FAIL() << "crasher pipe uninitialized";
236 }
237
Christopher Ferris172b0a02019-09-18 17:48:30 -0700238 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700239 if (rc == -1) {
240 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
241 } else if (rc == 0) {
242 FAIL() << "crasher pipe was closed";
243 }
244}
245
246void CrasherTest::AssertDeath(int signo) {
247 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700248 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700249 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700250 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
251 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700252 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700253 FAIL() << "failed to wait for crasher: " << strerror(errno);
254 }
255
Josh Gaoe06f2a42017-04-27 16:50:38 -0700256 if (signo == 0) {
257 ASSERT_TRUE(WIFEXITED(status));
258 ASSERT_EQ(0, WEXITSTATUS(signo));
259 } else {
260 ASSERT_FALSE(WIFEXITED(status));
261 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
262 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700263 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700264 crasher_pid = -1;
265}
266
267static void ConsumeFd(unique_fd fd, std::string* output) {
268 constexpr size_t read_length = PAGE_SIZE;
269 std::string result;
270
271 while (true) {
272 size_t offset = result.size();
273 result.resize(result.size() + PAGE_SIZE);
274 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
275 if (rc == -1) {
276 FAIL() << "read failed: " << strerror(errno);
277 } else if (rc == 0) {
278 result.resize(result.size() - PAGE_SIZE);
279 break;
280 }
281
282 result.resize(result.size() - PAGE_SIZE + rc);
283 }
284
285 *output = std::move(result);
286}
287
288TEST_F(CrasherTest, smoke) {
289 int intercept_result;
290 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800291 StartProcess([]() {
292 *reinterpret_cast<volatile char*>(0xdead) = '1';
293 });
294
Josh Gaocbe70cb2016-10-18 18:17:52 -0700295 StartIntercept(&output_fd);
296 FinishCrasher();
297 AssertDeath(SIGSEGV);
298 FinishIntercept(&intercept_result);
299
300 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
301
302 std::string result;
303 ConsumeFd(std::move(output_fd), &result);
304 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
305}
306
Josh Gaocdea7502017-11-01 15:00:40 -0700307TEST_F(CrasherTest, LD_PRELOAD) {
308 int intercept_result;
309 unique_fd output_fd;
310 StartProcess([]() {
311 setenv("LD_PRELOAD", "nonexistent.so", 1);
312 *reinterpret_cast<volatile char*>(0xdead) = '1';
313 });
314
315 StartIntercept(&output_fd);
316 FinishCrasher();
317 AssertDeath(SIGSEGV);
318 FinishIntercept(&intercept_result);
319
320 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
321
322 std::string result;
323 ConsumeFd(std::move(output_fd), &result);
324 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
325}
326
Josh Gaocbe70cb2016-10-18 18:17:52 -0700327TEST_F(CrasherTest, abort) {
328 int intercept_result;
329 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800330 StartProcess([]() {
331 abort();
332 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700333 StartIntercept(&output_fd);
334 FinishCrasher();
335 AssertDeath(SIGABRT);
336 FinishIntercept(&intercept_result);
337
338 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
339
340 std::string result;
341 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700342 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700343}
344
345TEST_F(CrasherTest, signal) {
346 int intercept_result;
347 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800348 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700349 while (true) {
350 sleep(1);
351 }
Josh Gao502cfd22017-02-17 01:39:15 -0800352 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700353 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700354 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700355 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
356
357 AssertDeath(SIGSEGV);
358 FinishIntercept(&intercept_result);
359
360 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
361
362 std::string result;
363 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700364 ASSERT_MATCH(
365 result,
366 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700367 ASSERT_MATCH(result, R"(backtrace:)");
368}
369
370TEST_F(CrasherTest, abort_message) {
371 int intercept_result;
372 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800373 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800374 // Arrived at experimentally;
375 // logd truncates at 4062.
376 // strlen("Abort message: ''") is 17.
377 // That's 4045, but we also want a NUL.
378 char buf[4045 + 1];
379 memset(buf, 'x', sizeof(buf));
380 buf[sizeof(buf) - 1] = '\0';
381 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800382 abort();
383 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700384 StartIntercept(&output_fd);
385 FinishCrasher();
386 AssertDeath(SIGABRT);
387 FinishIntercept(&intercept_result);
388
389 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
390
391 std::string result;
392 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800393 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700394}
395
Josh Gaoe06f2a42017-04-27 16:50:38 -0700396TEST_F(CrasherTest, abort_message_backtrace) {
397 int intercept_result;
398 unique_fd output_fd;
399 StartProcess([]() {
400 android_set_abort_message("not actually aborting");
401 raise(DEBUGGER_SIGNAL);
402 exit(0);
403 });
404 StartIntercept(&output_fd);
405 FinishCrasher();
406 AssertDeath(0);
407 FinishIntercept(&intercept_result);
408
409 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
410
411 std::string result;
412 ConsumeFd(std::move(output_fd), &result);
413 ASSERT_NOT_MATCH(result, R"(Abort message:)");
414}
415
Josh Gaocbe70cb2016-10-18 18:17:52 -0700416TEST_F(CrasherTest, intercept_timeout) {
417 int intercept_result;
418 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800419 StartProcess([]() {
420 abort();
421 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700422 StartIntercept(&output_fd);
423
424 // Don't let crasher finish until we timeout.
425 FinishIntercept(&intercept_result);
426
427 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
428 << intercept_result << ")";
429
430 FinishCrasher();
431 AssertDeath(SIGABRT);
432}
433
434TEST_F(CrasherTest, wait_for_gdb) {
435 if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
436 FAIL() << "failed to enable wait_for_gdb";
437 }
438 sleep(1);
439
Josh Gao502cfd22017-02-17 01:39:15 -0800440 StartProcess([]() {
441 abort();
442 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700443 FinishCrasher();
444
445 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700446 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700447 ASSERT_TRUE(WIFSTOPPED(status));
448 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
449
450 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
451
452 AssertDeath(SIGABRT);
453}
454
Josh Gaocbe70cb2016-10-18 18:17:52 -0700455TEST_F(CrasherTest, backtrace) {
456 std::string result;
457 int intercept_result;
458 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800459
460 StartProcess([]() {
461 abort();
462 });
Narayan Kamatha73df602017-05-24 15:07:25 +0100463 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700464
465 std::this_thread::sleep_for(500ms);
466
467 sigval val;
468 val.sival_int = 1;
469 ASSERT_EQ(0, sigqueue(crasher_pid, DEBUGGER_SIGNAL, val)) << strerror(errno);
470 FinishIntercept(&intercept_result);
471 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
472 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +0900473 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700474
475 int status;
476 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
477
478 StartIntercept(&output_fd);
479 FinishCrasher();
480 AssertDeath(SIGABRT);
481 FinishIntercept(&intercept_result);
482 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
483 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700484 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700485}
Josh Gaofca7ca32017-01-23 12:05:35 -0800486
487TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -0800488 int intercept_result;
489 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -0800490 StartProcess([]() {
491 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -0800492 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -0800493 });
Josh Gao502cfd22017-02-17 01:39:15 -0800494
495 StartIntercept(&output_fd);
496 FinishCrasher();
497 AssertDeath(SIGABRT);
498 FinishIntercept(&intercept_result);
499
500 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
501
502 std::string result;
503 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700504 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -0800505}
506
Josh Gao502cfd22017-02-17 01:39:15 -0800507TEST_F(CrasherTest, capabilities) {
508 ASSERT_EQ(0U, getuid()) << "capability test requires root";
509
Josh Gaofca7ca32017-01-23 12:05:35 -0800510 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -0800511 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
512 err(1, "failed to set PR_SET_KEEPCAPS");
513 }
514
515 if (setresuid(1, 1, 1) != 0) {
516 err(1, "setresuid failed");
517 }
518
519 __user_cap_header_struct capheader;
520 __user_cap_data_struct capdata[2];
521 memset(&capheader, 0, sizeof(capheader));
522 memset(&capdata, 0, sizeof(capdata));
523
524 capheader.version = _LINUX_CAPABILITY_VERSION_3;
525 capheader.pid = 0;
526
527 // Turn on every third capability.
528 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
529 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
530 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
531 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
532 }
533
534 // Make sure CAP_SYS_PTRACE is off.
535 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
536 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
537
538 if (capset(&capheader, &capdata[0]) != 0) {
539 err(1, "capset failed");
540 }
541
542 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
543 err(1, "failed to drop ambient capabilities");
544 }
545
Josh Gaoa5199a92017-04-03 13:18:34 -0700546 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -0800547 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -0800548 });
Josh Gao502cfd22017-02-17 01:39:15 -0800549
550 unique_fd output_fd;
551 StartIntercept(&output_fd);
552 FinishCrasher();
553 AssertDeath(SIGSYS);
554
555 std::string result;
556 int intercept_result;
557 FinishIntercept(&intercept_result);
558 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
559 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -0700560 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900561 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -0800562}
Josh Gaoc3c8c022017-02-13 16:36:18 -0800563
Josh Gao2e7b8e22017-05-04 17:12:57 -0700564TEST_F(CrasherTest, fake_pid) {
565 int intercept_result;
566 unique_fd output_fd;
567
568 // Prime the getpid/gettid caches.
569 UNUSED(getpid());
570 UNUSED(gettid());
571
572 std::function<pid_t()> clone_fn = []() {
573 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
574 };
575 StartProcess(
576 []() {
577 ASSERT_NE(getpid(), syscall(__NR_getpid));
578 ASSERT_NE(gettid(), syscall(__NR_gettid));
579 raise(SIGSEGV);
580 },
581 clone_fn);
582
583 StartIntercept(&output_fd);
584 FinishCrasher();
585 AssertDeath(SIGSEGV);
586 FinishIntercept(&intercept_result);
587
588 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
589
590 std::string result;
591 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +0900592 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -0700593}
594
Josh Gaoe04ca272018-01-16 15:38:17 -0800595static const char* const kDebuggerdSeccompPolicy =
596 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
597
Josh Gao70adac62018-02-22 11:38:33 -0800598static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -0700599 std::string policy;
600 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
601 PLOG(FATAL) << "failed to read policy file";
602 }
603
604 // Allow a bunch of syscalls used by the tests.
605 policy += "\nclone: 1";
606 policy += "\nsigaltstack: 1";
607 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -0700608 policy += "\ngetrlimit: 1";
609 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -0700610
611 FILE* tmp_file = tmpfile();
612 if (!tmp_file) {
613 PLOG(FATAL) << "tmpfile failed";
614 }
615
Christopher Ferris172b0a02019-09-18 17:48:30 -0700616 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -0700617 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
618 PLOG(FATAL) << "failed to write policy to tmpfile";
619 }
620
621 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
622 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -0800623 }
624
625 ScopedMinijail jail{minijail_new()};
626 if (!jail) {
627 LOG(FATAL) << "failed to create minijail";
628 }
629
630 minijail_no_new_privs(jail.get());
631 minijail_log_seccomp_filter_failures(jail.get());
632 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -0700633 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -0800634
635 pid_t result = fork();
636 if (result == -1) {
637 return result;
638 } else if (result != 0) {
639 return result;
640 }
641
642 // Spawn and detach a thread that spins forever.
643 std::atomic<bool> thread_ready(false);
644 std::thread thread([&jail, &thread_ready]() {
645 minijail_enter(jail.get());
646 thread_ready = true;
647 for (;;)
648 ;
649 });
650 thread.detach();
651
652 while (!thread_ready) {
653 continue;
654 }
655
Josh Gao70adac62018-02-22 11:38:33 -0800656 if (prejail) {
657 prejail();
658 }
659
Josh Gaoe04ca272018-01-16 15:38:17 -0800660 minijail_enter(jail.get());
661 return result;
662}
663
Josh Gao70adac62018-02-22 11:38:33 -0800664static pid_t seccomp_fork() {
665 return seccomp_fork_impl(nullptr);
666}
667
Josh Gaoe04ca272018-01-16 15:38:17 -0800668TEST_F(CrasherTest, seccomp_crash) {
669 int intercept_result;
670 unique_fd output_fd;
671
672 StartProcess([]() { abort(); }, &seccomp_fork);
673
674 StartIntercept(&output_fd);
675 FinishCrasher();
676 AssertDeath(SIGABRT);
677 FinishIntercept(&intercept_result);
678 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
679
680 std::string result;
681 ConsumeFd(std::move(output_fd), &result);
682 ASSERT_BACKTRACE_FRAME(result, "abort");
683}
684
Josh Gao70adac62018-02-22 11:38:33 -0800685static pid_t seccomp_fork_rlimit() {
686 return seccomp_fork_impl([]() {
687 struct rlimit rlim = {
688 .rlim_cur = 512 * 1024 * 1024,
689 .rlim_max = 512 * 1024 * 1024,
690 };
691
692 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
693 raise(SIGINT);
694 }
695 });
696}
697
698TEST_F(CrasherTest, seccomp_crash_oom) {
699 int intercept_result;
700 unique_fd output_fd;
701
702 StartProcess(
703 []() {
704 std::vector<void*> vec;
705 for (int i = 0; i < 512; ++i) {
706 char* buf = static_cast<char*>(malloc(1024 * 1024));
707 if (!buf) {
708 abort();
709 }
710 memset(buf, 0xff, 1024 * 1024);
711 vec.push_back(buf);
712 }
713 },
714 &seccomp_fork_rlimit);
715
716 StartIntercept(&output_fd);
717 FinishCrasher();
718 AssertDeath(SIGABRT);
719 FinishIntercept(&intercept_result);
720 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
721
722 // We can't actually generate a backtrace, just make sure that the process terminates.
723}
724
Josh Gaoe04ca272018-01-16 15:38:17 -0800725__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
726 siginfo_t siginfo;
727 siginfo.si_code = SI_QUEUE;
728 siginfo.si_pid = getpid();
729 siginfo.si_uid = getuid();
730
731 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
732 PLOG(FATAL) << "invalid dump type";
733 }
734
735 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
736
737 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
738 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
739 return false;
740 }
741
742 return true;
743}
744
745TEST_F(CrasherTest, seccomp_tombstone) {
746 int intercept_result;
747 unique_fd output_fd;
748
749 static const auto dump_type = kDebuggerdTombstone;
750 StartProcess(
751 []() {
752 raise_debugger_signal(dump_type);
753 _exit(0);
754 },
755 &seccomp_fork);
756
757 StartIntercept(&output_fd, dump_type);
758 FinishCrasher();
759 AssertDeath(0);
760 FinishIntercept(&intercept_result);
761 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
762
763 std::string result;
764 ConsumeFd(std::move(output_fd), &result);
765 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
766}
767
Josh Gao6f9eeec2018-09-12 13:55:47 -0700768extern "C" void foo() {
769 LOG(INFO) << "foo";
770 std::this_thread::sleep_for(1s);
771}
772
773extern "C" void bar() {
774 LOG(INFO) << "bar";
775 std::this_thread::sleep_for(1s);
776}
777
Josh Gaoe04ca272018-01-16 15:38:17 -0800778TEST_F(CrasherTest, seccomp_backtrace) {
779 int intercept_result;
780 unique_fd output_fd;
781
782 static const auto dump_type = kDebuggerdNativeBacktrace;
783 StartProcess(
784 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -0700785 std::thread a(foo);
786 std::thread b(bar);
787
788 std::this_thread::sleep_for(100ms);
789
Josh Gaoe04ca272018-01-16 15:38:17 -0800790 raise_debugger_signal(dump_type);
791 _exit(0);
792 },
793 &seccomp_fork);
794
795 StartIntercept(&output_fd, dump_type);
796 FinishCrasher();
797 AssertDeath(0);
798 FinishIntercept(&intercept_result);
799 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
800
801 std::string result;
802 ConsumeFd(std::move(output_fd), &result);
803 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -0700804 ASSERT_BACKTRACE_FRAME(result, "foo");
805 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -0800806}
807
808TEST_F(CrasherTest, seccomp_crash_logcat) {
809 StartProcess([]() { abort(); }, &seccomp_fork);
810 FinishCrasher();
811
812 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
813 AssertDeath(SIGABRT);
814}
815
Josh Gaofd13bf02017-08-18 15:37:26 -0700816TEST_F(CrasherTest, competing_tracer) {
817 int intercept_result;
818 unique_fd output_fd;
819 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700820 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -0700821 });
822
823 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -0700824
825 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700826 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -0700827
828 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700829 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -0700830 ASSERT_TRUE(WIFSTOPPED(status));
831 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
832
833 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
834 FinishIntercept(&intercept_result);
835 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
836
837 std::string result;
838 ConsumeFd(std::move(output_fd), &result);
839 std::string regex = R"(failed to attach to thread \d+, already traced by )";
840 regex += std::to_string(gettid());
841 regex += R"( \(.+debuggerd_test)";
842 ASSERT_MATCH(result, regex.c_str());
843
Christopher Ferris172b0a02019-09-18 17:48:30 -0700844 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700845 ASSERT_TRUE(WIFSTOPPED(status));
846 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
847
Josh Gaofd13bf02017-08-18 15:37:26 -0700848 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
849 AssertDeath(SIGABRT);
850}
851
Josh Gaobf06a402018-08-27 16:34:01 -0700852TEST_F(CrasherTest, fdsan_warning_abort_message) {
853 int intercept_result;
854 unique_fd output_fd;
855
856 StartProcess([]() {
857 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -0700858 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -0700859 if (fd == -1) {
860 abort();
861 }
862 close(fd.get());
863 _exit(0);
864 });
865
866 StartIntercept(&output_fd);
867 FinishCrasher();
868 AssertDeath(0);
869 FinishIntercept(&intercept_result);
870 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
871
872 std::string result;
873 ConsumeFd(std::move(output_fd), &result);
874 ASSERT_MATCH(result, "Abort message: 'attempted to close");
875}
876
Josh Gaoc3c8c022017-02-13 16:36:18 -0800877TEST(crash_dump, zombie) {
878 pid_t forkpid = fork();
879
Josh Gaoc3c8c022017-02-13 16:36:18 -0800880 pid_t rc;
881 int status;
882
883 if (forkpid == 0) {
884 errno = 0;
885 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
886 if (rc != -1 || errno != ECHILD) {
887 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
888 }
889
890 raise(DEBUGGER_SIGNAL);
891
892 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700893 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -0800894 if (rc != -1 || errno != ECHILD) {
895 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
896 }
897 _exit(0);
898 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -0700899 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -0800900 ASSERT_EQ(forkpid, rc);
901 ASSERT_TRUE(WIFEXITED(status));
902 ASSERT_EQ(0, WEXITSTATUS(status));
903 }
904}
Josh Gao352a8452017-03-30 16:46:21 -0700905
906TEST(tombstoned, no_notify) {
907 // Do this a few times.
908 for (int i = 0; i < 3; ++i) {
909 pid_t pid = 123'456'789 + i;
910
911 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100912 InterceptStatus status;
913 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
914 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700915
916 {
917 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100918 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -0700919 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
920 }
921
922 pid_t read_pid;
923 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
924 ASSERT_EQ(read_pid, pid);
925 }
926}
927
928TEST(tombstoned, stress) {
929 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
930 static constexpr int kDumpCount = 100;
931
932 std::atomic<bool> start(false);
933 std::vector<std::thread> threads;
934 threads.emplace_back([&start]() {
935 while (!start) {
936 continue;
937 }
938
939 // Use a way out of range pid, to avoid stomping on an actual process.
940 pid_t pid_base = 1'000'000;
941
942 for (int dump = 0; dump < kDumpCount; ++dump) {
943 pid_t pid = pid_base + dump;
944
945 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100946 InterceptStatus status;
947 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
948 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700949
950 // Pretend to crash, and then immediately close the socket.
951 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
952 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
953 if (sockfd == -1) {
954 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
955 }
956 TombstonedCrashPacket packet = {};
957 packet.packet_type = CrashPacketType::kDumpRequest;
958 packet.packet.dump_request.pid = pid;
959 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
960 FAIL() << "failed to write to tombstoned: " << strerror(errno);
961 }
962
963 continue;
964 }
965 });
966
967 threads.emplace_back([&start]() {
968 while (!start) {
969 continue;
970 }
971
972 // Use a way out of range pid, to avoid stomping on an actual process.
973 pid_t pid_base = 2'000'000;
974
975 for (int dump = 0; dump < kDumpCount; ++dump) {
976 pid_t pid = pid_base + dump;
977
978 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +0100979 InterceptStatus status;
980 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
981 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -0700982
983 {
984 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100985 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -0700986 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
987 tombstoned_notify_completion(tombstoned_socket.get());
988 }
989
990 // TODO: Fix the race that requires this sleep.
991 std::this_thread::sleep_for(50ms);
992
993 pid_t read_pid;
994 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
995 ASSERT_EQ(read_pid, pid);
996 }
997 });
998
999 start = true;
1000
1001 for (std::thread& thread : threads) {
1002 thread.join();
1003 }
1004}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001005
1006TEST(tombstoned, java_trace_intercept_smoke) {
1007 // Using a "real" PID is a little dangerous here - if the test fails
1008 // or crashes, we might end up getting a bogus / unreliable stack
1009 // trace.
1010 const pid_t self = getpid();
1011
1012 unique_fd intercept_fd, output_fd;
1013 InterceptStatus status;
1014 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1015 ASSERT_EQ(InterceptStatus::kRegistered, status);
1016
1017 // First connect to tombstoned requesting a native backtrace. This
1018 // should result in a "regular" FD and not the installed intercept.
1019 const char native[] = "native";
1020 unique_fd tombstoned_socket, input_fd;
1021 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdNativeBacktrace));
1022 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1023 tombstoned_notify_completion(tombstoned_socket.get());
1024
1025 // Then, connect to tombstoned asking for a java backtrace. This *should*
1026 // trigger the intercept.
1027 const char java[] = "java";
1028 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1029 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1030 tombstoned_notify_completion(tombstoned_socket.get());
1031
1032 char outbuf[sizeof(java)];
1033 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1034 ASSERT_STREQ("java", outbuf);
1035}
1036
1037TEST(tombstoned, multiple_intercepts) {
1038 const pid_t fake_pid = 1'234'567;
1039 unique_fd intercept_fd, output_fd;
1040 InterceptStatus status;
1041 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1042 ASSERT_EQ(InterceptStatus::kRegistered, status);
1043
1044 unique_fd intercept_fd_2, output_fd_2;
1045 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1046 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1047}
1048
1049TEST(tombstoned, intercept_any) {
1050 const pid_t fake_pid = 1'234'567;
1051
1052 unique_fd intercept_fd, output_fd;
1053 InterceptStatus status;
1054 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1055 ASSERT_EQ(InterceptStatus::kRegistered, status);
1056
1057 const char any[] = "any";
1058 unique_fd tombstoned_socket, input_fd;
1059 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1060 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1061 tombstoned_notify_completion(tombstoned_socket.get());
1062
1063 char outbuf[sizeof(any)];
1064 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1065 ASSERT_STREQ("any", outbuf);
1066}
Josh Gao2b22ae12018-09-12 14:51:03 -07001067
1068TEST(tombstoned, interceptless_backtrace) {
1069 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1070 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1071 std::map<int, time_t> result;
1072 for (int i = 0; i < 99; ++i) {
1073 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1074 struct stat st;
1075 if (stat(path.c_str(), &st) == 0) {
1076 result[i] = st.st_mtim.tv_sec;
1077 }
1078 }
1079 return result;
1080 };
1081
1082 auto before = get_tombstone_timestamps();
1083 for (int i = 0; i < 50; ++i) {
1084 raise_debugger_signal(kDebuggerdNativeBacktrace);
1085 }
1086 auto after = get_tombstone_timestamps();
1087
1088 int diff = 0;
1089 for (int i = 0; i < 99; ++i) {
1090 if (after.count(i) == 0) {
1091 continue;
1092 }
1093 if (before.count(i) == 0) {
1094 ++diff;
1095 continue;
1096 }
1097 if (before[i] != after[i]) {
1098 ++diff;
1099 }
1100 }
1101
1102 // We can't be sure that nothing's crash looping in the background.
1103 // This should be good enough, though...
1104 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1105}
Christopher Ferris481e8372019-07-15 17:13:24 -07001106
1107static __attribute__((__noinline__)) void overflow_stack(void* p) {
1108 void* buf[1];
1109 buf[0] = p;
1110 static volatile void* global = buf;
1111 if (global) {
1112 global = buf;
1113 overflow_stack(&buf);
1114 }
1115}
1116
1117TEST_F(CrasherTest, stack_overflow) {
1118 int intercept_result;
1119 unique_fd output_fd;
1120 StartProcess([]() { overflow_stack(nullptr); });
1121
1122 StartIntercept(&output_fd);
1123 FinishCrasher();
1124 AssertDeath(SIGSEGV);
1125 FinishIntercept(&intercept_result);
1126
1127 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1128
1129 std::string result;
1130 ConsumeFd(std::move(output_fd), &result);
1131 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1132}