blob: 52c1c255458d1c8cba38439ba7b364d1a7fac4cf [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
Christopher Ferris35da2882021-02-17 15:39:06 -080017#include <dirent.h>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070018#include <dlfcn.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070019#include <err.h>
20#include <fcntl.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000021#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080022#include <malloc.h>
Christopher Ferrisbda10642023-04-24 18:14:53 -070023#include <pthread.h>
Josh Gaocdea7502017-11-01 15:00:40 -070024#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080025#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070026#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080027#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070028#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080029#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070030#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070031#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070032#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070033
34#include <chrono>
35#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000036#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070037#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070038#include <thread>
39
Christopher Ferris22035cc2023-01-31 17:50:22 -080040#include <android/dlext.h>
Josh Gaobf06a402018-08-27 16:34:01 -070041#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080042#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080043#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070044#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080045#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080046
Josh Gao5f87bbd2019-01-09 17:01:49 -080047#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070048#include <android-base/file.h>
49#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070050#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070051#include <android-base/parseint.h>
52#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070053#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070055#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070056#include <android-base/unique_fd.h>
57#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070058#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070059#include <gtest/gtest.h>
60
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000061#include <unwindstack/Elf.h>
62#include <unwindstack/Memory.h>
63
Josh Gaoe04ca272018-01-16 15:38:17 -080064#include <libminijail.h>
65#include <scoped_minijail.h>
66
Christopher Ferris2038cc72021-09-15 03:57:10 +000067#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010068#include "debuggerd/handler.h"
Mitch Phillips18ce5422023-01-19 14:23:49 -080069#include "gtest/gtest.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070070#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010071#include "protocol.h"
72#include "tombstoned/tombstoned.h"
73#include "util.h"
74
Josh Gaocbe70cb2016-10-18 18:17:52 -070075using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080076
77using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070078using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070079using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070080
81#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070082#define ARCH_SUFFIX "64"
83#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070084#define ARCH_SUFFIX ""
85#endif
86
Elliott Hughese4781d52021-03-17 09:15:15 -070087constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070088
89#define TIMEOUT(seconds, expr) \
90 [&]() { \
91 struct sigaction old_sigaction; \
92 struct sigaction new_sigaction = {}; \
93 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080094 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070095 err(1, "sigaction failed"); \
96 } \
97 alarm(seconds); \
98 auto value = expr; \
99 int saved_errno = errno; \
100 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
101 err(1, "sigaction failed"); \
102 } \
103 alarm(0); \
104 errno = saved_errno; \
105 return value; \
106 }()
107
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700108// Backtrace frame dump could contain:
109// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
110// or
111// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800112#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700113 ASSERT_MATCH(result, \
114 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900115
Narayan Kamatha73df602017-05-24 15:07:25 +0100116static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100117 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700118 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
119 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
120 if (intercept_fd->get() == -1) {
121 FAIL() << "failed to contact tombstoned: " << strerror(errno);
122 }
123
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700124 InterceptRequest req = {
125 .dump_type = intercept_type,
126 .pid = target_pid,
127 };
Josh Gao460b3362017-03-30 16:40:47 -0700128
129 unique_fd output_pipe_write;
130 if (!Pipe(output_fd, &output_pipe_write)) {
131 FAIL() << "failed to create output pipe: " << strerror(errno);
132 }
133
134 std::string pipe_size_str;
135 int pipe_buffer_size;
136 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
137 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
138 }
139
140 pipe_size_str = android::base::Trim(pipe_size_str);
141
142 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
143 FAIL() << "failed to parse pipe max size";
144 }
145
146 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
147 FAIL() << "failed to set pipe size: " << strerror(errno);
148 }
149
Josh Gao5675f3c2017-06-01 12:19:53 -0700150 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
151
Josh Gao5f87bbd2019-01-09 17:01:49 -0800152 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
153 output_pipe_write.reset();
154 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700155 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
156 }
157
158 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800159 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700160 if (rc == -1) {
161 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
162 } else if (rc == 0) {
163 FAIL() << "failed to read response from tombstoned (EOF)";
164 } else if (rc != sizeof(response)) {
165 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
166 << ", received " << rc;
167 }
168
Narayan Kamathca5e9082017-06-02 15:42:06 +0100169 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700170}
171
Elliott Hughesd13ea522022-01-13 09:20:26 -0800172static bool pac_supported() {
173#if defined(__aarch64__)
174 return getauxval(AT_HWCAP) & HWCAP_PACA;
175#else
176 return false;
177#endif
178}
179
Josh Gaocbe70cb2016-10-18 18:17:52 -0700180class CrasherTest : public ::testing::Test {
181 public:
182 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700183 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700184 unique_fd crasher_pipe;
185 unique_fd intercept_fd;
186
187 CrasherTest();
188 ~CrasherTest();
189
Narayan Kamatha73df602017-05-24 15:07:25 +0100190 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700191
192 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
193 void FinishIntercept(int* result);
194
Josh Gao2e7b8e22017-05-04 17:12:57 -0700195 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700196 void StartCrasher(const std::string& crash_type);
197 void FinishCrasher();
198 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700199
200 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700201};
202
203CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700204 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
205 android::base::SetProperty(kWaitForDebuggerKey, "0");
206
207 // Clear the old property too, just in case someone's been using it
208 // on this device. (We only document the new name, but we still support
209 // the old name so we don't break anyone's existing setups.)
210 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700211}
212
213CrasherTest::~CrasherTest() {
214 if (crasher_pid != -1) {
215 kill(crasher_pid, SIGKILL);
216 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700217 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700218 }
219
Elliott Hughese4781d52021-03-17 09:15:15 -0700220 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221}
222
Narayan Kamatha73df602017-05-24 15:07:25 +0100223void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700224 if (crasher_pid == -1) {
225 FAIL() << "crasher hasn't been started";
226 }
227
Narayan Kamathca5e9082017-06-02 15:42:06 +0100228 InterceptStatus status;
229 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
230 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700231}
232
233void CrasherTest::FinishIntercept(int* result) {
234 InterceptResponse response;
235
Christopher Ferris11555f02019-09-20 14:18:55 -0700236 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700237 if (rc == -1) {
238 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
239 } else if (rc == 0) {
240 *result = -1;
241 } else if (rc != sizeof(response)) {
242 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
243 << ", received " << rc;
244 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700245 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700246 }
247}
248
Josh Gao2e7b8e22017-05-04 17:12:57 -0700249void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800250 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700251 unique_fd crasher_read_pipe;
252 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
253 FAIL() << "failed to create pipe: " << strerror(errno);
254 }
255
Josh Gao2e7b8e22017-05-04 17:12:57 -0700256 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700257 if (crasher_pid == -1) {
258 FAIL() << "fork failed: " << strerror(errno);
259 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800260 char dummy;
261 crasher_pipe.reset();
262 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800263 function();
264 _exit(0);
265 }
266}
267
Josh Gaocbe70cb2016-10-18 18:17:52 -0700268void CrasherTest::FinishCrasher() {
269 if (crasher_pipe == -1) {
270 FAIL() << "crasher pipe uninitialized";
271 }
272
Christopher Ferris172b0a02019-09-18 17:48:30 -0700273 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700274 if (rc == -1) {
275 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
276 } else if (rc == 0) {
277 FAIL() << "crasher pipe was closed";
278 }
279}
280
281void CrasherTest::AssertDeath(int signo) {
282 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700283 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700284 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700285 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
286 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700287 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700288 FAIL() << "failed to wait for crasher: " << strerror(errno);
289 }
290
Josh Gaoe06f2a42017-04-27 16:50:38 -0700291 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700292 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700293 ASSERT_EQ(0, WEXITSTATUS(signo));
294 } else {
295 ASSERT_FALSE(WIFEXITED(status));
296 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
297 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700299 crasher_pid = -1;
300}
301
302static void ConsumeFd(unique_fd fd, std::string* output) {
Kelvin Zhang786dac32023-06-15 16:23:56 -0700303 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700304}
305
Mitch Phillips78f06702021-06-01 14:35:43 -0700306class LogcatCollector {
307 public:
308 LogcatCollector() { system("logcat -c"); }
309
310 void Collect(std::string* output) {
311 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
312 ASSERT_NE(cmd_stdout, nullptr);
313 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
314 ConsumeFd(std::move(tmp_fd), output);
315 pclose(cmd_stdout);
316 }
317};
318
Josh Gaocbe70cb2016-10-18 18:17:52 -0700319TEST_F(CrasherTest, smoke) {
320 int intercept_result;
321 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800322 StartProcess([]() {
323 *reinterpret_cast<volatile char*>(0xdead) = '1';
324 });
325
Josh Gaocbe70cb2016-10-18 18:17:52 -0700326 StartIntercept(&output_fd);
327 FinishCrasher();
328 AssertDeath(SIGSEGV);
329 FinishIntercept(&intercept_result);
330
331 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
332
333 std::string result;
334 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800335#ifdef __LP64__
336 ASSERT_MATCH(result,
337 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
338#else
339 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
340#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700341
342 if (mte_supported()) {
343 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700344 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
345 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700346 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800347
348 if (pac_supported()) {
349 // Test that the default PAC_ENABLED_KEYS value is set.
350 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
351 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
352 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700353}
354
Peter Collingbournef03af882020-03-20 18:09:00 -0700355TEST_F(CrasherTest, tagged_fault_addr) {
356#if !defined(__aarch64__)
357 GTEST_SKIP() << "Requires aarch64";
358#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700359 // HWASan crashes with SIGABRT on tag mismatch.
360 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700361 int intercept_result;
362 unique_fd output_fd;
363 StartProcess([]() {
364 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
365 });
366
367 StartIntercept(&output_fd);
368 FinishCrasher();
369 AssertDeath(SIGSEGV);
370 FinishIntercept(&intercept_result);
371
372 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
373
374 std::string result;
375 ConsumeFd(std::move(output_fd), &result);
376
377 // The address can either be tagged (new kernels) or untagged (old kernels).
378 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800379 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700380}
381
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700382void CrasherTest::Trap(void* ptr) {
383 void (*volatile f)(void*) = nullptr;
384 __asm__ __volatile__("" : : "r"(f) : "memory");
385 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700386}
387
388TEST_F(CrasherTest, heap_addr_in_register) {
389#if defined(__i386__)
390 GTEST_SKIP() << "architecture does not pass arguments in registers";
391#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700392 // The memory dump in HWASan crashes sadly shows the memory near the registers
393 // in the HWASan dump function, rather the faulting context. This is a known
394 // issue.
395 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700396 int intercept_result;
397 unique_fd output_fd;
398 StartProcess([]() {
399 // Crash with a heap pointer in the first argument register.
400 Trap(malloc(1));
401 });
402
403 StartIntercept(&output_fd);
404 FinishCrasher();
405 int status;
406 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
407 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
408 // Don't test the signal number because different architectures use different signals for
409 // __builtin_trap().
410 FinishIntercept(&intercept_result);
411
412 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
413
414 std::string result;
415 ConsumeFd(std::move(output_fd), &result);
416
417#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800418 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700419#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800420 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800421#elif defined(__riscv)
422 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700423#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800424 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700425#else
426 ASSERT_TRUE(false) << "unsupported architecture";
427#endif
428}
429
Peter Collingbournecd278072020-12-21 14:08:38 -0800430#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700431static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800432 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700433 abort();
434 }
435}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800436
437static void SetTagCheckingLevelAsync() {
438 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
439 abort();
440 }
441}
Peter Collingbournef8622522020-04-07 14:07:32 -0700442#endif
443
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800444struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
445
Peter Collingbourneaa544792021-05-13 13:53:37 -0700446INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800447
448TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800449#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700450 if (!mte_supported()) {
451 GTEST_SKIP() << "Requires MTE";
452 }
453
Peter Collingbourneaa544792021-05-13 13:53:37 -0700454 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
455 if (GetParam() == 0) {
456 return;
457 }
458
Mitch Phillips78f06702021-06-01 14:35:43 -0700459 LogcatCollector logcat_collector;
460
Peter Collingbournef8622522020-04-07 14:07:32 -0700461 int intercept_result;
462 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800463 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700464 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800465 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700466 free((void *)p);
467 p[0] = 42;
468 });
469
470 StartIntercept(&output_fd);
471 FinishCrasher();
472 AssertDeath(SIGSEGV);
473 FinishIntercept(&intercept_result);
474
475 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
476
Mitch Phillips78f06702021-06-01 14:35:43 -0700477 std::vector<std::string> log_sources(2);
478 ConsumeFd(std::move(output_fd), &log_sources[0]);
479 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700480 // Tag dump only available in the tombstone, not logcat.
481 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700482
Mitch Phillips78f06702021-06-01 14:35:43 -0700483 for (const auto& result : log_sources) {
484 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
485 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
486 std::to_string(GetParam()) + R"(-byte allocation)");
487 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
488 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
489 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700490#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800491 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700492#endif
493}
494
Peter Collingbournedc476342021-05-12 15:56:43 -0700495TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
496#if defined(__aarch64__)
497 if (!mte_supported()) {
498 GTEST_SKIP() << "Requires MTE";
499 }
500
501 int intercept_result;
502 unique_fd output_fd;
503 StartProcess([&]() {
504 SetTagCheckingLevelSync();
505 volatile int* p = (volatile int*)malloc(GetParam());
506 free((void *)p);
507 p[-1] = 42;
508 });
509
510 StartIntercept(&output_fd);
511 FinishCrasher();
512 AssertDeath(SIGSEGV);
513 FinishIntercept(&intercept_result);
514
515 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
516
517 std::string result;
518 ConsumeFd(std::move(output_fd), &result);
519
520 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
521 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
522#else
523 GTEST_SKIP() << "Requires aarch64";
524#endif
525}
526
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800527TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800528#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700529 if (!mte_supported()) {
530 GTEST_SKIP() << "Requires MTE";
531 }
532
Mitch Phillips78f06702021-06-01 14:35:43 -0700533 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700534 int intercept_result;
535 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800536 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700537 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800538 volatile char* p = (volatile char*)malloc(GetParam());
539 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700540 });
541
542 StartIntercept(&output_fd);
543 FinishCrasher();
544 AssertDeath(SIGSEGV);
545 FinishIntercept(&intercept_result);
546
547 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
548
Mitch Phillips78f06702021-06-01 14:35:43 -0700549 std::vector<std::string> log_sources(2);
550 ConsumeFd(std::move(output_fd), &log_sources[0]);
551 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700552
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700553 // Tag dump only in tombstone, not logcat, and tagging is not used for
554 // overflow protection in the scudo secondary (guard pages are used instead).
555 if (GetParam() < 0x10000) {
556 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
557 }
558
Mitch Phillips78f06702021-06-01 14:35:43 -0700559 for (const auto& result : log_sources) {
560 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
561 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
562 std::to_string(GetParam()) + R"(-byte allocation)");
563 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
564 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700565#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800566 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700567#endif
568}
569
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800570TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800571#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700572 if (!mte_supported()) {
573 GTEST_SKIP() << "Requires MTE";
574 }
575
576 int intercept_result;
577 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800578 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700579 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800580 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700581 p[-1] = 42;
582 });
583
584 StartIntercept(&output_fd);
585 FinishCrasher();
586 AssertDeath(SIGSEGV);
587 FinishIntercept(&intercept_result);
588
589 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
590
591 std::string result;
592 ConsumeFd(std::move(output_fd), &result);
593
594 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800595 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800596 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700597 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700598 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700599 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700600#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800601 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700602#endif
603}
604
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800605TEST_F(CrasherTest, mte_async) {
606#if defined(__aarch64__)
607 if (!mte_supported()) {
608 GTEST_SKIP() << "Requires MTE";
609 }
610
611 int intercept_result;
612 unique_fd output_fd;
613 StartProcess([&]() {
614 SetTagCheckingLevelAsync();
615 volatile int* p = (volatile int*)malloc(16);
616 p[-1] = 42;
617 });
618
619 StartIntercept(&output_fd);
620 FinishCrasher();
621 AssertDeath(SIGSEGV);
622 FinishIntercept(&intercept_result);
623
624 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
625
626 std::string result;
627 ConsumeFd(std::move(output_fd), &result);
628
Peter Collingbourne91e816a2023-03-07 21:24:47 -0800629 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800630#else
631 GTEST_SKIP() << "Requires aarch64";
632#endif
633}
634
Peter Collingbournef8622522020-04-07 14:07:32 -0700635TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800636#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700637 if (!mte_supported()) {
638 GTEST_SKIP() << "Requires MTE";
639 }
640
Mitch Phillips78f06702021-06-01 14:35:43 -0700641 LogcatCollector logcat_collector;
642
Peter Collingbournef8622522020-04-07 14:07:32 -0700643 int intercept_result;
644 unique_fd output_fd;
645 StartProcess([]() {
646 SetTagCheckingLevelSync();
647
648 // Make two allocations with the same tag and close to one another. Check for both properties
649 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
650 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
651 // (some non-zero value << 56) apart.
652 //
653 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
654 // other.
655 std::set<uintptr_t> allocs;
656 for (int i = 0; i != 4096; ++i) {
657 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
658 auto it = allocs.insert(alloc).first;
659 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
660 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
661 }
662 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
663 *reinterpret_cast<int*>(alloc + 16) = 42;
664 }
665 }
666 });
667
668 StartIntercept(&output_fd);
669 FinishCrasher();
670 AssertDeath(SIGSEGV);
671 FinishIntercept(&intercept_result);
672
673 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
674
Mitch Phillips78f06702021-06-01 14:35:43 -0700675 std::vector<std::string> log_sources(2);
676 ConsumeFd(std::move(output_fd), &log_sources[0]);
677 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700678
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700679 // Tag dump only in the tombstone, not logcat.
680 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
681
Mitch Phillips78f06702021-06-01 14:35:43 -0700682 for (const auto& result : log_sources) {
683 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
684 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800685 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700686 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
687 // overflows), so we can't match explicitly for an underflow message.
688 ASSERT_MATCH(result,
689 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
690 // Ensure there's at least two allocation traces (one for each cause).
691 ASSERT_MATCH(
692 result,
693 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
694 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700695#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800696 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700697#endif
698}
699
Peter Collingbournecd278072020-12-21 14:08:38 -0800700#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700701static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700702 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
703 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
704 size_t page_size = getpagesize();
705 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
706 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
707 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700708 return 0;
709 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700710 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
711 PROT_READ | PROT_WRITE | PROT_MTE);
712 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
713 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
714 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
715 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
716 }
717 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700718}
719#endif
720
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700721TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800722#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700723 if (!mte_supported()) {
724 GTEST_SKIP() << "Requires MTE";
725 }
726
727 int intercept_result;
728 unique_fd output_fd;
729 StartProcess([&]() {
730 SetTagCheckingLevelSync();
731 Trap(reinterpret_cast<void *>(CreateTagMapping()));
732 });
733
734 StartIntercept(&output_fd);
735 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700736 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700737 FinishIntercept(&intercept_result);
738
739 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
740
741 std::string result;
742 ConsumeFd(std::move(output_fd), &result);
743
744 ASSERT_MATCH(result, R"(memory near x0:
745.*
746.*
747 01.............0 0000000000000000 0000000000000000 ................
748 00.............0)");
749#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800750 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700751#endif
752}
753
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700754TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
755#if defined(__aarch64__)
756 if (!mte_supported()) {
757 GTEST_SKIP() << "Requires MTE";
758 }
759
760 int intercept_result;
761 unique_fd output_fd;
762 StartProcess([&]() {
763 SetTagCheckingLevelSync();
764 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
765 p[0] = 0; // Untagged pointer, tagged memory.
766 });
767
768 StartIntercept(&output_fd);
769 FinishCrasher();
770 AssertDeath(SIGSEGV);
771 FinishIntercept(&intercept_result);
772
773 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
774
775 std::string result;
776 ConsumeFd(std::move(output_fd), &result);
777
778 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
779\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
780#else
781 GTEST_SKIP() << "Requires aarch64";
782#endif
783}
784
785TEST_F(CrasherTest, mte_fault_tag_dump) {
786#if defined(__aarch64__)
787 if (!mte_supported()) {
788 GTEST_SKIP() << "Requires MTE";
789 }
790
791 int intercept_result;
792 unique_fd output_fd;
793 StartProcess([&]() {
794 SetTagCheckingLevelSync();
795 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
796 p[320] = 0; // Untagged pointer, tagged memory.
797 });
798
799 StartIntercept(&output_fd);
800 FinishCrasher();
801 AssertDeath(SIGSEGV);
802 FinishIntercept(&intercept_result);
803
804 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
805
806 std::string result;
807 ConsumeFd(std::move(output_fd), &result);
808
809 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
810\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
811\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
812\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
813)");
814#else
815 GTEST_SKIP() << "Requires aarch64";
816#endif
817}
818
819TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
820#if defined(__aarch64__)
821 if (!mte_supported()) {
822 GTEST_SKIP() << "Requires MTE";
823 }
824
825 int intercept_result;
826 unique_fd output_fd;
827 StartProcess([&]() {
828 SetTagCheckingLevelSync();
829 size_t page_size = getpagesize();
830 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
831 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
832 });
833
834 StartIntercept(&output_fd);
835 FinishCrasher();
836 AssertDeath(SIGSEGV);
837 FinishIntercept(&intercept_result);
838
839 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
840
841 std::string result;
842 ConsumeFd(std::move(output_fd), &result);
843
844 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
845 ASSERT_MATCH(result,
846 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
847\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
848
849)"); // Ensure truncation happened and there's a newline after the tag fault.
850#else
851 GTEST_SKIP() << "Requires aarch64";
852#endif
853}
854
Josh Gaocdea7502017-11-01 15:00:40 -0700855TEST_F(CrasherTest, LD_PRELOAD) {
856 int intercept_result;
857 unique_fd output_fd;
858 StartProcess([]() {
859 setenv("LD_PRELOAD", "nonexistent.so", 1);
860 *reinterpret_cast<volatile char*>(0xdead) = '1';
861 });
862
863 StartIntercept(&output_fd);
864 FinishCrasher();
865 AssertDeath(SIGSEGV);
866 FinishIntercept(&intercept_result);
867
868 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
869
870 std::string result;
871 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800872 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700873}
874
Josh Gaocbe70cb2016-10-18 18:17:52 -0700875TEST_F(CrasherTest, abort) {
876 int intercept_result;
877 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800878 StartProcess([]() {
879 abort();
880 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700881 StartIntercept(&output_fd);
882 FinishCrasher();
883 AssertDeath(SIGABRT);
884 FinishIntercept(&intercept_result);
885
886 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
887
888 std::string result;
889 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700890 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700891}
892
893TEST_F(CrasherTest, signal) {
894 int intercept_result;
895 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800896 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700897 while (true) {
898 sleep(1);
899 }
Josh Gao502cfd22017-02-17 01:39:15 -0800900 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700901 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700902 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700903 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
904
905 AssertDeath(SIGSEGV);
906 FinishIntercept(&intercept_result);
907
908 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
909
910 std::string result;
911 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700912 ASSERT_MATCH(
913 result,
914 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700915 ASSERT_MATCH(result, R"(backtrace:)");
916}
917
918TEST_F(CrasherTest, abort_message) {
919 int intercept_result;
920 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800921 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800922 // Arrived at experimentally;
923 // logd truncates at 4062.
924 // strlen("Abort message: ''") is 17.
925 // That's 4045, but we also want a NUL.
926 char buf[4045 + 1];
927 memset(buf, 'x', sizeof(buf));
928 buf[sizeof(buf) - 1] = '\0';
929 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800930 abort();
931 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700932 StartIntercept(&output_fd);
933 FinishCrasher();
934 AssertDeath(SIGABRT);
935 FinishIntercept(&intercept_result);
936
937 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
938
939 std::string result;
940 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800941 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700942}
943
Christopher Ferrise8891452021-08-17 17:34:53 -0700944TEST_F(CrasherTest, abort_message_newline_trimmed) {
945 int intercept_result;
946 unique_fd output_fd;
947 StartProcess([]() {
948 android_set_abort_message("Message with a newline.\n");
949 abort();
950 });
951 StartIntercept(&output_fd);
952 FinishCrasher();
953 AssertDeath(SIGABRT);
954 FinishIntercept(&intercept_result);
955
956 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
957
958 std::string result;
959 ConsumeFd(std::move(output_fd), &result);
960 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
961}
962
963TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
964 int intercept_result;
965 unique_fd output_fd;
966 StartProcess([]() {
967 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
968 abort();
969 });
970 StartIntercept(&output_fd);
971 FinishCrasher();
972 AssertDeath(SIGABRT);
973 FinishIntercept(&intercept_result);
974
975 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
976
977 std::string result;
978 ConsumeFd(std::move(output_fd), &result);
979 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
980}
981
Josh Gaoe06f2a42017-04-27 16:50:38 -0700982TEST_F(CrasherTest, abort_message_backtrace) {
983 int intercept_result;
984 unique_fd output_fd;
985 StartProcess([]() {
986 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -0800987 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700988 exit(0);
989 });
990 StartIntercept(&output_fd);
991 FinishCrasher();
992 AssertDeath(0);
993 FinishIntercept(&intercept_result);
994
995 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
996
997 std::string result;
998 ConsumeFd(std::move(output_fd), &result);
999 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1000}
1001
Josh Gaocbe70cb2016-10-18 18:17:52 -07001002TEST_F(CrasherTest, intercept_timeout) {
1003 int intercept_result;
1004 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001005 StartProcess([]() {
1006 abort();
1007 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001008 StartIntercept(&output_fd);
1009
1010 // Don't let crasher finish until we timeout.
1011 FinishIntercept(&intercept_result);
1012
1013 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1014 << intercept_result << ")";
1015
1016 FinishCrasher();
1017 AssertDeath(SIGABRT);
1018}
1019
Elliott Hughese4781d52021-03-17 09:15:15 -07001020TEST_F(CrasherTest, wait_for_debugger) {
1021 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1022 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001023 }
1024 sleep(1);
1025
Josh Gao502cfd22017-02-17 01:39:15 -08001026 StartProcess([]() {
1027 abort();
1028 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001029 FinishCrasher();
1030
1031 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001032 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001033 ASSERT_TRUE(WIFSTOPPED(status));
1034 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1035
1036 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1037
1038 AssertDeath(SIGABRT);
1039}
1040
Josh Gaocbe70cb2016-10-18 18:17:52 -07001041TEST_F(CrasherTest, backtrace) {
1042 std::string result;
1043 int intercept_result;
1044 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001045
1046 StartProcess([]() {
1047 abort();
1048 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001049 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001050
1051 std::this_thread::sleep_for(500ms);
1052
1053 sigval val;
1054 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001055 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001056 FinishIntercept(&intercept_result);
1057 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1058 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001059 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001060
1061 int status;
1062 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1063
1064 StartIntercept(&output_fd);
1065 FinishCrasher();
1066 AssertDeath(SIGABRT);
1067 FinishIntercept(&intercept_result);
1068 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1069 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001070 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001071}
Josh Gaofca7ca32017-01-23 12:05:35 -08001072
1073TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001074 int intercept_result;
1075 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001076 StartProcess([]() {
1077 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001078 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001079 });
Josh Gao502cfd22017-02-17 01:39:15 -08001080
1081 StartIntercept(&output_fd);
1082 FinishCrasher();
1083 AssertDeath(SIGABRT);
1084 FinishIntercept(&intercept_result);
1085
1086 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1087
1088 std::string result;
1089 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001090 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001091}
1092
Josh Gao502cfd22017-02-17 01:39:15 -08001093TEST_F(CrasherTest, capabilities) {
1094 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1095
Josh Gaofca7ca32017-01-23 12:05:35 -08001096 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001097 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1098 err(1, "failed to set PR_SET_KEEPCAPS");
1099 }
1100
1101 if (setresuid(1, 1, 1) != 0) {
1102 err(1, "setresuid failed");
1103 }
1104
1105 __user_cap_header_struct capheader;
1106 __user_cap_data_struct capdata[2];
1107 memset(&capheader, 0, sizeof(capheader));
1108 memset(&capdata, 0, sizeof(capdata));
1109
1110 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1111 capheader.pid = 0;
1112
1113 // Turn on every third capability.
1114 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1115 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1116 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1117 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1118 }
1119
1120 // Make sure CAP_SYS_PTRACE is off.
1121 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1122 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1123
1124 if (capset(&capheader, &capdata[0]) != 0) {
1125 err(1, "capset failed");
1126 }
1127
1128 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1129 err(1, "failed to drop ambient capabilities");
1130 }
1131
Josh Gaoa5199a92017-04-03 13:18:34 -07001132 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001133 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001134 });
Josh Gao502cfd22017-02-17 01:39:15 -08001135
1136 unique_fd output_fd;
1137 StartIntercept(&output_fd);
1138 FinishCrasher();
1139 AssertDeath(SIGSYS);
1140
1141 std::string result;
1142 int intercept_result;
1143 FinishIntercept(&intercept_result);
1144 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1145 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001146 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001147 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001148}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001149
Josh Gao2e7b8e22017-05-04 17:12:57 -07001150TEST_F(CrasherTest, fake_pid) {
1151 int intercept_result;
1152 unique_fd output_fd;
1153
1154 // Prime the getpid/gettid caches.
1155 UNUSED(getpid());
1156 UNUSED(gettid());
1157
1158 std::function<pid_t()> clone_fn = []() {
1159 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1160 };
1161 StartProcess(
1162 []() {
1163 ASSERT_NE(getpid(), syscall(__NR_getpid));
1164 ASSERT_NE(gettid(), syscall(__NR_gettid));
1165 raise(SIGSEGV);
1166 },
1167 clone_fn);
1168
1169 StartIntercept(&output_fd);
1170 FinishCrasher();
1171 AssertDeath(SIGSEGV);
1172 FinishIntercept(&intercept_result);
1173
1174 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1175
1176 std::string result;
1177 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001178 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001179}
1180
Josh Gaoe04ca272018-01-16 15:38:17 -08001181static const char* const kDebuggerdSeccompPolicy =
1182 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1183
Mitch Phillips18ce5422023-01-19 14:23:49 -08001184static void setup_jail(minijail* jail) {
1185 if (!jail) {
1186 LOG(FATAL) << "failed to create minijail";
1187 }
1188
Josh Gao6f9eeec2018-09-12 13:55:47 -07001189 std::string policy;
1190 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1191 PLOG(FATAL) << "failed to read policy file";
1192 }
1193
1194 // Allow a bunch of syscalls used by the tests.
1195 policy += "\nclone: 1";
1196 policy += "\nsigaltstack: 1";
1197 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001198 policy += "\ngetrlimit: 1";
1199 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001200
1201 FILE* tmp_file = tmpfile();
1202 if (!tmp_file) {
1203 PLOG(FATAL) << "tmpfile failed";
1204 }
1205
Christopher Ferris172b0a02019-09-18 17:48:30 -07001206 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001207 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1208 PLOG(FATAL) << "failed to write policy to tmpfile";
1209 }
1210
1211 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1212 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001213 }
1214
Mitch Phillips18ce5422023-01-19 14:23:49 -08001215 minijail_no_new_privs(jail);
1216 minijail_log_seccomp_filter_failures(jail);
1217 minijail_use_seccomp_filter(jail);
1218 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1219}
Josh Gaoe04ca272018-01-16 15:38:17 -08001220
Mitch Phillips18ce5422023-01-19 14:23:49 -08001221static pid_t seccomp_fork_impl(void (*prejail)()) {
1222 ScopedMinijail jail{minijail_new()};
1223 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001224
1225 pid_t result = fork();
1226 if (result == -1) {
1227 return result;
1228 } else if (result != 0) {
1229 return result;
1230 }
1231
1232 // Spawn and detach a thread that spins forever.
1233 std::atomic<bool> thread_ready(false);
1234 std::thread thread([&jail, &thread_ready]() {
1235 minijail_enter(jail.get());
1236 thread_ready = true;
1237 for (;;)
1238 ;
1239 });
1240 thread.detach();
1241
1242 while (!thread_ready) {
1243 continue;
1244 }
1245
Josh Gao70adac62018-02-22 11:38:33 -08001246 if (prejail) {
1247 prejail();
1248 }
1249
Josh Gaoe04ca272018-01-16 15:38:17 -08001250 minijail_enter(jail.get());
1251 return result;
1252}
1253
Josh Gao70adac62018-02-22 11:38:33 -08001254static pid_t seccomp_fork() {
1255 return seccomp_fork_impl(nullptr);
1256}
1257
Josh Gaoe04ca272018-01-16 15:38:17 -08001258TEST_F(CrasherTest, seccomp_crash) {
1259 int intercept_result;
1260 unique_fd output_fd;
1261
1262 StartProcess([]() { abort(); }, &seccomp_fork);
1263
1264 StartIntercept(&output_fd);
1265 FinishCrasher();
1266 AssertDeath(SIGABRT);
1267 FinishIntercept(&intercept_result);
1268 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1269
1270 std::string result;
1271 ConsumeFd(std::move(output_fd), &result);
1272 ASSERT_BACKTRACE_FRAME(result, "abort");
1273}
1274
Josh Gao70adac62018-02-22 11:38:33 -08001275static pid_t seccomp_fork_rlimit() {
1276 return seccomp_fork_impl([]() {
1277 struct rlimit rlim = {
1278 .rlim_cur = 512 * 1024 * 1024,
1279 .rlim_max = 512 * 1024 * 1024,
1280 };
1281
1282 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1283 raise(SIGINT);
1284 }
1285 });
1286}
1287
1288TEST_F(CrasherTest, seccomp_crash_oom) {
1289 int intercept_result;
1290 unique_fd output_fd;
1291
1292 StartProcess(
1293 []() {
1294 std::vector<void*> vec;
1295 for (int i = 0; i < 512; ++i) {
1296 char* buf = static_cast<char*>(malloc(1024 * 1024));
1297 if (!buf) {
1298 abort();
1299 }
1300 memset(buf, 0xff, 1024 * 1024);
1301 vec.push_back(buf);
1302 }
1303 },
1304 &seccomp_fork_rlimit);
1305
1306 StartIntercept(&output_fd);
1307 FinishCrasher();
1308 AssertDeath(SIGABRT);
1309 FinishIntercept(&intercept_result);
1310 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1311
1312 // We can't actually generate a backtrace, just make sure that the process terminates.
1313}
1314
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001315__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001316 siginfo_t siginfo;
1317 siginfo.si_code = SI_QUEUE;
1318 siginfo.si_pid = getpid();
1319 siginfo.si_uid = getuid();
1320
1321 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1322 PLOG(FATAL) << "invalid dump type";
1323 }
1324
1325 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1326
Josh Gaoa48b41b2019-12-13 14:11:04 -08001327 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001328 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1329 return false;
1330 }
1331
1332 return true;
1333}
1334
Christopher Ferrisb999b822022-02-09 17:57:21 -08001335extern "C" void foo() {
1336 LOG(INFO) << "foo";
1337 std::this_thread::sleep_for(1s);
1338}
1339
1340extern "C" void bar() {
1341 LOG(INFO) << "bar";
1342 std::this_thread::sleep_for(1s);
1343}
1344
Josh Gaoe04ca272018-01-16 15:38:17 -08001345TEST_F(CrasherTest, seccomp_tombstone) {
1346 int intercept_result;
1347 unique_fd output_fd;
1348
1349 static const auto dump_type = kDebuggerdTombstone;
1350 StartProcess(
1351 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001352 std::thread a(foo);
1353 std::thread b(bar);
1354
1355 std::this_thread::sleep_for(100ms);
1356
Josh Gaoe04ca272018-01-16 15:38:17 -08001357 raise_debugger_signal(dump_type);
1358 _exit(0);
1359 },
1360 &seccomp_fork);
1361
1362 StartIntercept(&output_fd, dump_type);
1363 FinishCrasher();
1364 AssertDeath(0);
1365 FinishIntercept(&intercept_result);
1366 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1367
1368 std::string result;
1369 ConsumeFd(std::move(output_fd), &result);
1370 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001371 ASSERT_BACKTRACE_FRAME(result, "foo");
1372 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001373}
1374
Christopher Ferris303c6be2022-05-24 17:08:33 -07001375TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1376 int intercept_result;
1377 unique_fd output_fd;
1378
1379 static const auto dump_type = kDebuggerdTombstone;
1380 StartProcess(
1381 []() {
1382 std::thread abort_thread([] { abort(); });
1383 abort_thread.join();
1384 },
1385 &seccomp_fork);
1386
1387 StartIntercept(&output_fd, dump_type);
1388 FinishCrasher();
1389 AssertDeath(SIGABRT);
1390 FinishIntercept(&intercept_result);
1391 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1392
1393 std::string result;
1394 ConsumeFd(std::move(output_fd), &result);
1395 ASSERT_BACKTRACE_FRAME(result, "abort");
1396}
1397
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001398TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1399 int intercept_result;
1400 unique_fd output_fd;
1401
1402 static const auto dump_type = kDebuggerdTombstone;
1403 StartProcess(
1404 []() {
1405 std::thread a(foo);
1406 std::thread b(bar);
1407
1408 std::this_thread::sleep_for(100ms);
1409
1410 std::thread abort_thread([] { abort(); });
1411 abort_thread.join();
1412 },
1413 &seccomp_fork);
1414
1415 StartIntercept(&output_fd, dump_type);
1416 FinishCrasher();
1417 AssertDeath(SIGABRT);
1418 FinishIntercept(&intercept_result);
1419 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1420
1421 std::string result;
1422 ConsumeFd(std::move(output_fd), &result);
1423 ASSERT_BACKTRACE_FRAME(result, "abort");
1424 ASSERT_BACKTRACE_FRAME(result, "foo");
1425 ASSERT_BACKTRACE_FRAME(result, "bar");
1426 ASSERT_BACKTRACE_FRAME(result, "main");
1427}
1428
Josh Gaoe04ca272018-01-16 15:38:17 -08001429TEST_F(CrasherTest, seccomp_backtrace) {
1430 int intercept_result;
1431 unique_fd output_fd;
1432
1433 static const auto dump_type = kDebuggerdNativeBacktrace;
1434 StartProcess(
1435 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001436 std::thread a(foo);
1437 std::thread b(bar);
1438
1439 std::this_thread::sleep_for(100ms);
1440
Josh Gaoe04ca272018-01-16 15:38:17 -08001441 raise_debugger_signal(dump_type);
1442 _exit(0);
1443 },
1444 &seccomp_fork);
1445
1446 StartIntercept(&output_fd, dump_type);
1447 FinishCrasher();
1448 AssertDeath(0);
1449 FinishIntercept(&intercept_result);
1450 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1451
1452 std::string result;
1453 ConsumeFd(std::move(output_fd), &result);
1454 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001455 ASSERT_BACKTRACE_FRAME(result, "foo");
1456 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001457}
1458
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001459TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1460 int intercept_result;
1461 unique_fd output_fd;
1462
1463 static const auto dump_type = kDebuggerdNativeBacktrace;
1464 StartProcess(
1465 []() {
1466 std::thread a(foo);
1467 std::thread b(bar);
1468
1469 std::this_thread::sleep_for(100ms);
1470
1471 std::thread raise_thread([] {
1472 raise_debugger_signal(dump_type);
1473 _exit(0);
1474 });
1475 raise_thread.join();
1476 },
1477 &seccomp_fork);
1478
1479 StartIntercept(&output_fd, dump_type);
1480 FinishCrasher();
1481 AssertDeath(0);
1482 FinishIntercept(&intercept_result);
1483 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1484
1485 std::string result;
1486 ConsumeFd(std::move(output_fd), &result);
1487 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1488 ASSERT_BACKTRACE_FRAME(result, "foo");
1489 ASSERT_BACKTRACE_FRAME(result, "bar");
1490 ASSERT_BACKTRACE_FRAME(result, "main");
1491}
1492
Josh Gaoe04ca272018-01-16 15:38:17 -08001493TEST_F(CrasherTest, seccomp_crash_logcat) {
1494 StartProcess([]() { abort(); }, &seccomp_fork);
1495 FinishCrasher();
1496
1497 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1498 AssertDeath(SIGABRT);
1499}
1500
Josh Gaofd13bf02017-08-18 15:37:26 -07001501TEST_F(CrasherTest, competing_tracer) {
1502 int intercept_result;
1503 unique_fd output_fd;
1504 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001505 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001506 });
1507
1508 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001509
1510 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001511 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001512
1513 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001514 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001515 ASSERT_TRUE(WIFSTOPPED(status));
1516 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1517
1518 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1519 FinishIntercept(&intercept_result);
1520 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1521
1522 std::string result;
1523 ConsumeFd(std::move(output_fd), &result);
1524 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1525 regex += std::to_string(gettid());
1526 regex += R"( \(.+debuggerd_test)";
1527 ASSERT_MATCH(result, regex.c_str());
1528
Christopher Ferris172b0a02019-09-18 17:48:30 -07001529 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001530 ASSERT_TRUE(WIFSTOPPED(status));
1531 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1532
Josh Gaofd13bf02017-08-18 15:37:26 -07001533 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1534 AssertDeath(SIGABRT);
1535}
1536
Mitch Phillips18ce5422023-01-19 14:23:49 -08001537struct GwpAsanTestParameters {
1538 size_t alloc_size;
1539 bool free_before_access;
1540 int access_offset;
1541 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1542};
1543
1544struct GwpAsanCrasherTest
1545 : CrasherTest,
1546 testing::WithParamInterface<
1547 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1548
1549GwpAsanTestParameters gwp_asan_tests[] = {
1550 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1551 "Use After Free, 0 bytes into a 7-byte allocation"},
1552 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1553 "Use After Free, 1 byte into a 15-byte allocation"},
1554 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1555 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1556 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1557 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1558};
1559
1560INSTANTIATE_TEST_SUITE_P(
1561 GwpAsanTests, GwpAsanCrasherTest,
1562 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1563 /* recoverable */ testing::Bool(),
1564 /* seccomp */ testing::Bool()),
1565 [](const testing::TestParamInfo<
1566 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1567 const GwpAsanTestParameters& params = std::get<0>(info.param);
1568 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1569 name += testing::PrintToString(params.alloc_size);
1570 name += "Alloc";
1571 if (params.access_offset < 0) {
1572 name += "Left";
1573 name += testing::PrintToString(params.access_offset * -1);
1574 } else {
1575 name += "Right";
1576 name += testing::PrintToString(params.access_offset);
1577 }
1578 name += "Bytes";
1579 if (std::get<1>(info.param)) name += "Recoverable";
1580 if (std::get<2>(info.param)) name += "Seccomp";
1581 return name;
1582 });
1583
1584TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1585 if (mte_supported()) {
1586 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1587 // instead of GWP-ASan.
1588 GTEST_SKIP() << "Skipped on MTE.";
1589 }
1590 // Skip this test on HWASan, which will reliably catch test errors as well.
1591 SKIP_WITH_HWASAN;
1592
1593 GwpAsanTestParameters params = std::get<0>(GetParam());
1594 bool recoverable = std::get<1>(GetParam());
1595 LogcatCollector logcat_collector;
1596
1597 int intercept_result;
1598 unique_fd output_fd;
1599 StartProcess([&recoverable]() {
1600 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1601 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1602 if (recoverable) {
1603 env[3] = "GWP_ASAN_RECOVERABLE=true";
1604 }
1605 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1606 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1607 "DISABLED_run_gwp_asan_test");
1608 std::string test_filter = "--gtest_filter=*";
1609 test_filter += test_name;
1610 std::string this_binary = android::base::GetExecutablePath();
1611 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1612 test_filter.c_str(), nullptr};
1613 // We check the crash report from a debuggerd handler and from logcat. The
1614 // echo from stdout/stderr of the subprocess trips up atest, because it
1615 // doesn't like that two tests started in a row without the first one
1616 // finishing (even though the second one is in a subprocess).
1617 close(STDOUT_FILENO);
1618 close(STDERR_FILENO);
1619 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1620 });
1621
1622 StartIntercept(&output_fd);
1623 FinishCrasher();
1624 if (recoverable) {
1625 AssertDeath(0);
1626 } else {
1627 AssertDeath(SIGSEGV);
1628 }
1629 FinishIntercept(&intercept_result);
1630
1631 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1632
1633 std::vector<std::string> log_sources(2);
1634 ConsumeFd(std::move(output_fd), &log_sources[0]);
1635 logcat_collector.Collect(&log_sources[1]);
1636
1637 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1638 // information. Make sure the recovery still works, but the report won't be
1639 // hugely useful, it looks like a regular SEGV.
1640 bool seccomp = std::get<2>(GetParam());
1641 if (!seccomp) {
1642 for (const auto& result : log_sources) {
1643 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1644 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1645 if (params.free_before_access) {
1646 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1647 }
1648 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1649 }
1650 }
1651}
1652
1653TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1654 GwpAsanTestParameters params = std::get<0>(GetParam());
1655 bool seccomp = std::get<2>(GetParam());
1656 if (seccomp) {
1657 ScopedMinijail jail{minijail_new()};
1658 setup_jail(jail.get());
1659 minijail_enter(jail.get());
1660 }
1661
1662 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1663 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1664 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1665 p[params.access_offset] = 42;
1666 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001667
1668 bool recoverable = std::get<1>(GetParam());
1669 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1670
1671 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1672 // we end with at least one in a different slot), make sure the process still
1673 // doesn't crash.
1674 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1675 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1676 free(static_cast<void*>(const_cast<char*>(p)));
1677 free(static_cast<void*>(const_cast<char*>(p2)));
1678 *p = 42;
1679 *p2 = 42;
1680
1681 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1682 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1683 // coverage does. Thus, skip the atexit handlers.
1684 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001685}
1686
Josh Gaobf06a402018-08-27 16:34:01 -07001687TEST_F(CrasherTest, fdsan_warning_abort_message) {
1688 int intercept_result;
1689 unique_fd output_fd;
1690
1691 StartProcess([]() {
1692 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001693 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001694 if (fd == -1) {
1695 abort();
1696 }
1697 close(fd.get());
1698 _exit(0);
1699 });
1700
1701 StartIntercept(&output_fd);
1702 FinishCrasher();
1703 AssertDeath(0);
1704 FinishIntercept(&intercept_result);
1705 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1706
1707 std::string result;
1708 ConsumeFd(std::move(output_fd), &result);
1709 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1710}
1711
Josh Gaoc3c8c022017-02-13 16:36:18 -08001712TEST(crash_dump, zombie) {
1713 pid_t forkpid = fork();
1714
Josh Gaoc3c8c022017-02-13 16:36:18 -08001715 pid_t rc;
1716 int status;
1717
1718 if (forkpid == 0) {
1719 errno = 0;
1720 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1721 if (rc != -1 || errno != ECHILD) {
1722 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1723 }
1724
Josh Gaoa48b41b2019-12-13 14:11:04 -08001725 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001726
1727 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001728 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001729 if (rc != -1 || errno != ECHILD) {
1730 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1731 }
1732 _exit(0);
1733 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001734 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001735 ASSERT_EQ(forkpid, rc);
1736 ASSERT_TRUE(WIFEXITED(status));
1737 ASSERT_EQ(0, WEXITSTATUS(status));
1738 }
1739}
Josh Gao352a8452017-03-30 16:46:21 -07001740
1741TEST(tombstoned, no_notify) {
1742 // Do this a few times.
1743 for (int i = 0; i < 3; ++i) {
1744 pid_t pid = 123'456'789 + i;
1745
1746 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001747 InterceptStatus status;
1748 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1749 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001750
1751 {
1752 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001753 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001754 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1755 }
1756
1757 pid_t read_pid;
1758 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1759 ASSERT_EQ(read_pid, pid);
1760 }
1761}
1762
1763TEST(tombstoned, stress) {
1764 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1765 static constexpr int kDumpCount = 100;
1766
1767 std::atomic<bool> start(false);
1768 std::vector<std::thread> threads;
1769 threads.emplace_back([&start]() {
1770 while (!start) {
1771 continue;
1772 }
1773
1774 // Use a way out of range pid, to avoid stomping on an actual process.
1775 pid_t pid_base = 1'000'000;
1776
1777 for (int dump = 0; dump < kDumpCount; ++dump) {
1778 pid_t pid = pid_base + dump;
1779
1780 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001781 InterceptStatus status;
1782 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1783 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001784
1785 // Pretend to crash, and then immediately close the socket.
1786 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1787 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1788 if (sockfd == -1) {
1789 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1790 }
1791 TombstonedCrashPacket packet = {};
1792 packet.packet_type = CrashPacketType::kDumpRequest;
1793 packet.packet.dump_request.pid = pid;
1794 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1795 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1796 }
1797
1798 continue;
1799 }
1800 });
1801
1802 threads.emplace_back([&start]() {
1803 while (!start) {
1804 continue;
1805 }
1806
1807 // Use a way out of range pid, to avoid stomping on an actual process.
1808 pid_t pid_base = 2'000'000;
1809
1810 for (int dump = 0; dump < kDumpCount; ++dump) {
1811 pid_t pid = pid_base + dump;
1812
1813 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001814 InterceptStatus status;
1815 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1816 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001817
1818 {
1819 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001820 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001821 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1822 tombstoned_notify_completion(tombstoned_socket.get());
1823 }
1824
1825 // TODO: Fix the race that requires this sleep.
1826 std::this_thread::sleep_for(50ms);
1827
1828 pid_t read_pid;
1829 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1830 ASSERT_EQ(read_pid, pid);
1831 }
1832 });
1833
1834 start = true;
1835
1836 for (std::thread& thread : threads) {
1837 thread.join();
1838 }
1839}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001840
1841TEST(tombstoned, java_trace_intercept_smoke) {
1842 // Using a "real" PID is a little dangerous here - if the test fails
1843 // or crashes, we might end up getting a bogus / unreliable stack
1844 // trace.
1845 const pid_t self = getpid();
1846
1847 unique_fd intercept_fd, output_fd;
1848 InterceptStatus status;
1849 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1850 ASSERT_EQ(InterceptStatus::kRegistered, status);
1851
Josh Gao76e1e302021-01-26 15:53:11 -08001852 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001853 // should result in a "regular" FD and not the installed intercept.
1854 const char native[] = "native";
1855 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001856 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001857 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1858 tombstoned_notify_completion(tombstoned_socket.get());
1859
1860 // Then, connect to tombstoned asking for a java backtrace. This *should*
1861 // trigger the intercept.
1862 const char java[] = "java";
1863 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1864 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1865 tombstoned_notify_completion(tombstoned_socket.get());
1866
1867 char outbuf[sizeof(java)];
1868 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1869 ASSERT_STREQ("java", outbuf);
1870}
1871
1872TEST(tombstoned, multiple_intercepts) {
1873 const pid_t fake_pid = 1'234'567;
1874 unique_fd intercept_fd, output_fd;
1875 InterceptStatus status;
1876 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1877 ASSERT_EQ(InterceptStatus::kRegistered, status);
1878
1879 unique_fd intercept_fd_2, output_fd_2;
1880 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1881 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1882}
1883
1884TEST(tombstoned, intercept_any) {
1885 const pid_t fake_pid = 1'234'567;
1886
1887 unique_fd intercept_fd, output_fd;
1888 InterceptStatus status;
1889 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1890 ASSERT_EQ(InterceptStatus::kRegistered, status);
1891
1892 const char any[] = "any";
1893 unique_fd tombstoned_socket, input_fd;
1894 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1895 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1896 tombstoned_notify_completion(tombstoned_socket.get());
1897
1898 char outbuf[sizeof(any)];
1899 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1900 ASSERT_STREQ("any", outbuf);
1901}
Josh Gao2b22ae12018-09-12 14:51:03 -07001902
1903TEST(tombstoned, interceptless_backtrace) {
1904 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1905 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1906 std::map<int, time_t> result;
1907 for (int i = 0; i < 99; ++i) {
1908 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1909 struct stat st;
1910 if (stat(path.c_str(), &st) == 0) {
1911 result[i] = st.st_mtim.tv_sec;
1912 }
1913 }
1914 return result;
1915 };
1916
1917 auto before = get_tombstone_timestamps();
1918 for (int i = 0; i < 50; ++i) {
1919 raise_debugger_signal(kDebuggerdNativeBacktrace);
1920 }
1921 auto after = get_tombstone_timestamps();
1922
1923 int diff = 0;
1924 for (int i = 0; i < 99; ++i) {
1925 if (after.count(i) == 0) {
1926 continue;
1927 }
1928 if (before.count(i) == 0) {
1929 ++diff;
1930 continue;
1931 }
1932 if (before[i] != after[i]) {
1933 ++diff;
1934 }
1935 }
1936
1937 // We can't be sure that nothing's crash looping in the background.
1938 // This should be good enough, though...
1939 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1940}
Christopher Ferris481e8372019-07-15 17:13:24 -07001941
1942static __attribute__((__noinline__)) void overflow_stack(void* p) {
1943 void* buf[1];
1944 buf[0] = p;
1945 static volatile void* global = buf;
1946 if (global) {
1947 global = buf;
1948 overflow_stack(&buf);
1949 }
1950}
1951
1952TEST_F(CrasherTest, stack_overflow) {
1953 int intercept_result;
1954 unique_fd output_fd;
1955 StartProcess([]() { overflow_stack(nullptr); });
1956
1957 StartIntercept(&output_fd);
1958 FinishCrasher();
1959 AssertDeath(SIGSEGV);
1960 FinishIntercept(&intercept_result);
1961
1962 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1963
1964 std::string result;
1965 ConsumeFd(std::move(output_fd), &result);
1966 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1967}
Josh Gao76e1e302021-01-26 15:53:11 -08001968
Christopher Ferris22035cc2023-01-31 17:50:22 -08001969static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001970 std::string test_lib(testing::internal::GetArgvs()[0]);
1971 auto const value = test_lib.find_last_of('/');
1972 if (value == std::string::npos) {
1973 test_lib = "./";
1974 } else {
1975 test_lib = test_lib.substr(0, value + 1) + "./";
1976 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08001977 return test_lib + "libcrash_test.so";
1978}
1979
1980static void CreateEmbeddedLibrary(int out_fd) {
1981 std::string test_lib(GetTestLibraryPath());
1982 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
1983 ASSERT_NE(fd.get(), -1);
1984 off_t file_size = lseek(fd, 0, SEEK_END);
1985 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
1986 std::vector<uint8_t> contents(file_size);
1987 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
1988
1989 // Put the shared library data at a pagesize() offset.
1990 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
1991 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
1992}
1993
1994TEST_F(CrasherTest, non_zero_offset_in_library) {
1995 int intercept_result;
1996 unique_fd output_fd;
1997 TemporaryFile tf;
1998 CreateEmbeddedLibrary(tf.fd);
1999 StartProcess([&tf]() {
2000 android_dlextinfo extinfo{};
2001 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2002 extinfo.library_fd = tf.fd;
2003 extinfo.library_fd_offset = 4 * getpagesize();
2004 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2005 if (handle == nullptr) {
2006 _exit(1);
2007 }
2008 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2009 if (crash_func == nullptr) {
2010 _exit(1);
2011 }
2012 crash_func();
2013 });
2014
2015 StartIntercept(&output_fd);
2016 FinishCrasher();
2017 AssertDeath(SIGSEGV);
2018 FinishIntercept(&intercept_result);
2019
2020 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2021
2022 std::string result;
2023 ConsumeFd(std::move(output_fd), &result);
2024
2025 // Verify the crash includes an offset value in the backtrace.
2026 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2027 tf.path, 4 * getpagesize());
2028 ASSERT_MATCH(result, match_str);
2029}
2030
2031static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2032 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002033
2034 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2035 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2036
2037 // Copy the shared so to a tempory directory.
2038 return system(cp_cmd.c_str()) == 0;
2039}
2040
2041TEST_F(CrasherTest, unreadable_elf) {
2042 int intercept_result;
2043 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002044 std::string tmp_so_name;
2045 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002046 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002047 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2048 _exit(1);
2049 }
2050 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2051 if (handle == nullptr) {
2052 _exit(1);
2053 }
2054 // Delete the original shared library so that we get the warning
2055 // about unreadable elf files.
2056 if (unlink(tmp_so_name.c_str()) == -1) {
2057 _exit(1);
2058 }
2059 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2060 if (crash_func == nullptr) {
2061 _exit(1);
2062 }
2063 crash_func();
2064 });
2065
2066 StartIntercept(&output_fd);
2067 FinishCrasher();
2068 AssertDeath(SIGSEGV);
2069 FinishIntercept(&intercept_result);
2070
2071 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2072
2073 std::string result;
2074 ConsumeFd(std::move(output_fd), &result);
2075 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002076 std::string match_str = "NOTE: " + tmp_so_name;
2077 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002078}
2079
Josh Gao76e1e302021-01-26 15:53:11 -08002080TEST(tombstoned, proto) {
2081 const pid_t self = getpid();
2082 unique_fd tombstoned_socket, text_fd, proto_fd;
2083 ASSERT_TRUE(
2084 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2085
2086 tombstoned_notify_completion(tombstoned_socket.get());
2087
2088 ASSERT_NE(-1, text_fd.get());
2089 ASSERT_NE(-1, proto_fd.get());
2090
2091 struct stat text_st;
2092 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2093
2094 // Give tombstoned some time to link the files into place.
2095 std::this_thread::sleep_for(100ms);
2096
2097 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08002098 std::optional<std::string> tombstone_file;
2099 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2100 ASSERT_TRUE(dir_h != nullptr);
2101 std::regex tombstone_re("tombstone_\\d+");
2102 dirent* entry;
2103 while ((entry = readdir(dir_h.get())) != nullptr) {
2104 if (!std::regex_match(entry->d_name, tombstone_re)) {
2105 continue;
2106 }
2107 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002108
2109 struct stat st;
2110 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2111 continue;
2112 }
2113
2114 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002115 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002116 break;
2117 }
2118 }
2119
Christopher Ferris35da2882021-02-17 15:39:06 -08002120 ASSERT_TRUE(tombstone_file);
2121 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002122
2123 struct stat proto_fd_st;
2124 struct stat proto_file_st;
2125 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2126 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2127
2128 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2129 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2130}
2131
2132TEST(tombstoned, proto_intercept) {
2133 const pid_t self = getpid();
2134 unique_fd intercept_fd, output_fd;
2135 InterceptStatus status;
2136
2137 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2138 ASSERT_EQ(InterceptStatus::kRegistered, status);
2139
2140 unique_fd tombstoned_socket, text_fd, proto_fd;
2141 ASSERT_TRUE(
2142 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2143 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2144 tombstoned_notify_completion(tombstoned_socket.get());
2145
2146 text_fd.reset();
2147
2148 std::string output;
2149 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2150 ASSERT_EQ("foo", output);
2151}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002152
2153// Verify that when an intercept is present for the main thread, and the signal
2154// is received on a different thread, the intercept still works.
2155TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2156 StartProcess([]() {
2157 std::thread thread([]() {
2158 // Raise the signal on the side thread.
2159 raise_debugger_signal(kDebuggerdNativeBacktrace);
2160 });
2161 thread.join();
2162 _exit(0);
2163 });
2164
2165 unique_fd output_fd;
2166 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2167 FinishCrasher();
2168 AssertDeath(0);
2169
2170 int intercept_result;
2171 FinishIntercept(&intercept_result);
2172 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2173
2174 std::string result;
2175 ConsumeFd(std::move(output_fd), &result);
2176 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2177}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002178
2179static std::string format_pointer(uintptr_t ptr) {
2180#if defined(__LP64__)
2181 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2182 static_cast<uint32_t>(ptr & 0xffffffff));
2183#else
2184 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2185#endif
2186}
2187
2188static std::string format_pointer(void* ptr) {
2189 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2190}
2191
2192static std::string format_full_pointer(uintptr_t ptr) {
2193#if defined(__LP64__)
2194 return android::base::StringPrintf("%016" PRIx64, ptr);
2195#else
2196 return android::base::StringPrintf("%08x", ptr);
2197#endif
2198}
2199
2200static std::string format_full_pointer(void* ptr) {
2201 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2202}
2203
2204__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2205 int* crash_ptr = reinterpret_cast<int*>(ptr);
2206 *crash_ptr = 1;
2207 return *crash_ptr;
2208}
2209
2210// Verify that a fault address before the first map is properly handled.
2211TEST_F(CrasherTest, fault_address_before_first_map) {
2212 StartProcess([]() {
2213 ASSERT_EQ(0, crash_call(0x1024));
2214 _exit(0);
2215 });
2216
2217 unique_fd output_fd;
2218 StartIntercept(&output_fd);
2219 FinishCrasher();
2220 AssertDeath(SIGSEGV);
2221
2222 int intercept_result;
2223 FinishIntercept(&intercept_result);
2224 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2225
2226 std::string result;
2227 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002228 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002229
2230 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2231
2232 std::string match_str = android::base::StringPrintf(
2233 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2234 format_pointer(0x1024).c_str());
2235 ASSERT_MATCH(result, match_str);
2236}
2237
2238// Verify that a fault address after the last map is properly handled.
2239TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002240 // This makes assumptions about the memory layout that are not true in HWASan
2241 // processes.
2242 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002243 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2244 StartProcess([crash_uptr]() {
2245 ASSERT_EQ(0, crash_call(crash_uptr));
2246 _exit(0);
2247 });
2248
2249 unique_fd output_fd;
2250 StartIntercept(&output_fd);
2251 FinishCrasher();
2252 AssertDeath(SIGSEGV);
2253
2254 int intercept_result;
2255 FinishIntercept(&intercept_result);
2256 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2257
2258 std::string result;
2259 ConsumeFd(std::move(output_fd), &result);
2260
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002261 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2262 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002263 ASSERT_MATCH(result, match_str);
2264
2265 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2266
2267 // Assumes that the open files section comes after the map section.
2268 // If that assumption changes, the regex below needs to change.
2269 match_str = android::base::StringPrintf(
2270 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2271 format_pointer(crash_uptr).c_str());
2272 ASSERT_MATCH(result, match_str);
2273}
2274
2275// Verify that a fault address between maps is properly handled.
2276TEST_F(CrasherTest, fault_address_between_maps) {
2277 // Create a map before the fork so it will be present in the child.
2278 void* start_ptr =
2279 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2280 ASSERT_NE(MAP_FAILED, start_ptr);
2281 // Unmap the page in the middle.
2282 void* middle_ptr =
2283 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2284 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2285
2286 StartProcess([middle_ptr]() {
2287 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2288 _exit(0);
2289 });
2290
2291 // Unmap the two maps.
2292 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2293 void* end_ptr =
2294 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2295 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2296
2297 unique_fd output_fd;
2298 StartIntercept(&output_fd);
2299 FinishCrasher();
2300 AssertDeath(SIGSEGV);
2301
2302 int intercept_result;
2303 FinishIntercept(&intercept_result);
2304 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2305
2306 std::string result;
2307 ConsumeFd(std::move(output_fd), &result);
2308
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002309 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2310 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002311 ASSERT_MATCH(result, match_str);
2312
2313 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2314
2315 match_str = android::base::StringPrintf(
2316 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2317 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2318 format_pointer(end_ptr).c_str());
2319 ASSERT_MATCH(result, match_str);
2320}
2321
2322// Verify that a fault address happens in the correct map.
2323TEST_F(CrasherTest, fault_address_in_map) {
2324 // Create a map before the fork so it will be present in the child.
2325 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2326 ASSERT_NE(MAP_FAILED, ptr);
2327
2328 StartProcess([ptr]() {
2329 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2330 _exit(0);
2331 });
2332
2333 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2334
2335 unique_fd output_fd;
2336 StartIntercept(&output_fd);
2337 FinishCrasher();
2338 AssertDeath(SIGSEGV);
2339
2340 int intercept_result;
2341 FinishIntercept(&intercept_result);
2342 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2343
2344 std::string result;
2345 ConsumeFd(std::move(output_fd), &result);
2346
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002347 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2348 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002349 ASSERT_MATCH(result, match_str);
2350
2351 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2352
2353 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2354 ASSERT_MATCH(result, match_str);
2355}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002356
2357static constexpr uint32_t kDexData[] = {
2358 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2359 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2360 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2361 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2362 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2363 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2364 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2365 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2366 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2367 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2368 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2369 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2370 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2371 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2372 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2373 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2374 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2375};
2376
2377TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2378 StartProcess([]() {
2379 TemporaryDir td;
2380 std::string tmp_so_name;
2381 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2382 _exit(1);
2383 }
2384
2385 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2386 // move the library to which has a basename of libart.so.
2387 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2388 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2389 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2390 if (handle == nullptr) {
2391 _exit(1);
2392 }
2393
2394 void* ptr =
2395 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2396 ASSERT_TRUE(ptr != MAP_FAILED);
2397 memcpy(ptr, kDexData, sizeof(kDexData));
2398 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2399
2400 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2401 .symfile_size = sizeof(kDexData)};
2402
2403 JITDescriptor* dex_debug =
2404 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2405 ASSERT_TRUE(dex_debug != nullptr);
2406 dex_debug->version = 1;
2407 dex_debug->action_flag = 0;
2408 dex_debug->relevant_entry = 0;
2409 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2410
2411 // This sets the magic dex pc value for register 0, using the value
2412 // of register 1 + 0x102.
2413 asm(".cfi_escape "
2414 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2415 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2416 "0x13 /* DW_OP_drop */,"
2417 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2418
2419 // For each different architecture, set register one to the dex ptr mmap
2420 // created above. Then do a nullptr dereference to force a crash.
2421#if defined(__arm__)
2422 asm volatile(
2423 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002424 "mov r2, #0\n"
2425 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002426 : [base] "+r"(ptr)
2427 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002428 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002429#elif defined(__aarch64__)
2430 asm volatile(
2431 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002432 "mov x2, #0\n"
2433 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002434 : [base] "+r"(ptr)
2435 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002436 : "x1", "x2", "memory");
2437#elif defined(__riscv)
2438 // TODO: x1 is ra (the link register) on riscv64, so this might have
2439 // unintended consequences, but we'll need to change the .cfi_escape if so.
2440 asm volatile(
2441 "mv x1, %[base]\n"
2442 "sw zero, 0(zero)\n"
2443 : [base] "+r"(ptr)
2444 :
2445 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002446#elif defined(__i386__)
2447 asm volatile(
2448 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002449 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002450 : [base] "+r"(ptr)
2451 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002452 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002453#elif defined(__x86_64__)
2454 asm volatile(
2455 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002456 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002457 : [base] "+r"(ptr)
2458 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002459 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002460#else
2461#error "Unsupported architecture"
2462#endif
2463 _exit(0);
2464 });
2465
2466 unique_fd output_fd;
2467 StartIntercept(&output_fd);
2468 FinishCrasher();
2469 AssertDeath(SIGSEGV);
2470
2471 int intercept_result;
2472 FinishIntercept(&intercept_result);
2473 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2474
2475 std::string result;
2476 ConsumeFd(std::move(output_fd), &result);
2477
2478 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002479 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002480
2481 // Now verify that the dex_pc frame includes a proper function name.
2482 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2483}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002484
2485static std::string format_map_pointer(uintptr_t ptr) {
2486#if defined(__LP64__)
2487 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2488 static_cast<uint32_t>(ptr & 0xffffffff));
2489#else
2490 return android::base::StringPrintf("%08x", ptr);
2491#endif
2492}
2493
2494// Verify that map data is properly formatted.
2495TEST_F(CrasherTest, verify_map_format) {
2496 // Create multiple maps to make sure that the map data is formatted properly.
2497 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2498 ASSERT_NE(MAP_FAILED, none_map);
2499 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2500 ASSERT_NE(MAP_FAILED, r_map);
2501 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2502 ASSERT_NE(MAP_FAILED, w_map);
2503 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2504 ASSERT_NE(MAP_FAILED, x_map);
2505
2506 TemporaryFile tf;
2507 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2508 char c = 'f';
2509 ASSERT_EQ(1, write(tf.fd, &c, 1));
2510 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2511 ASSERT_EQ(1, write(tf.fd, &c, 1));
2512 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2513 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2514 ASSERT_NE(MAP_FAILED, file_map);
2515
2516 StartProcess([]() { abort(); });
2517
2518 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2519 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2520 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2521 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2522 ASSERT_EQ(0, munmap(file_map, 0x3001));
2523
2524 unique_fd output_fd;
2525 StartIntercept(&output_fd);
2526 FinishCrasher();
2527 AssertDeath(SIGABRT);
2528 int intercept_result;
2529 FinishIntercept(&intercept_result);
2530
2531 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2532
2533 std::string result;
2534 ConsumeFd(std::move(output_fd), &result);
2535
2536 std::string match_str;
2537 // Verify none.
2538 match_str = android::base::StringPrintf(
2539 " %s-%s --- 0 1000\\n",
2540 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2541 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2542 ASSERT_MATCH(result, match_str);
2543
2544 // Verify read-only.
2545 match_str = android::base::StringPrintf(
2546 " %s-%s r-- 0 1000\\n",
2547 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2548 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2549 ASSERT_MATCH(result, match_str);
2550
2551 // Verify write-only.
2552 match_str = android::base::StringPrintf(
2553 " %s-%s -w- 0 1000\\n",
2554 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2555 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2556 ASSERT_MATCH(result, match_str);
2557
2558 // Verify exec-only.
2559 match_str = android::base::StringPrintf(
2560 " %s-%s --x 0 1000\\n",
2561 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2562 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2563 ASSERT_MATCH(result, match_str);
2564
2565 // Verify file map with non-zero offset and a name.
2566 match_str = android::base::StringPrintf(
2567 " %s-%s r-- 2000 4000 %s\\n",
2568 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2569 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2570 ASSERT_MATCH(result, match_str);
2571}
2572
2573// Verify that the tombstone map data is correct.
2574TEST_F(CrasherTest, verify_header) {
2575 StartProcess([]() { abort(); });
2576
2577 unique_fd output_fd;
2578 StartIntercept(&output_fd);
2579 FinishCrasher();
2580 AssertDeath(SIGABRT);
2581 int intercept_result;
2582 FinishIntercept(&intercept_result);
2583
2584 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2585
2586 std::string result;
2587 ConsumeFd(std::move(output_fd), &result);
2588
2589 std::string match_str = android::base::StringPrintf(
2590 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2591 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2592 android::base::GetProperty("ro.revision", "unknown").c_str());
2593 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2594 ASSERT_MATCH(result, match_str);
2595}
2596
2597// Verify that the thread header is formatted properly.
2598TEST_F(CrasherTest, verify_thread_header) {
2599 void* shared_map =
2600 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2601 ASSERT_NE(MAP_FAILED, shared_map);
2602 memset(shared_map, 0, sizeof(pid_t));
2603
2604 StartProcess([&shared_map]() {
2605 std::atomic_bool tid_written;
2606 std::thread thread([&tid_written, &shared_map]() {
2607 pid_t tid = gettid();
2608 memcpy(shared_map, &tid, sizeof(pid_t));
2609 tid_written = true;
2610 volatile bool done = false;
2611 while (!done)
2612 ;
2613 });
2614 thread.detach();
2615 while (!tid_written.load(std::memory_order_acquire))
2616 ;
2617 abort();
2618 });
2619
2620 pid_t primary_pid = crasher_pid;
2621
2622 unique_fd output_fd;
2623 StartIntercept(&output_fd);
2624 FinishCrasher();
2625 AssertDeath(SIGABRT);
2626 int intercept_result;
2627 FinishIntercept(&intercept_result);
2628 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2629
2630 // Read the tid data out.
2631 pid_t tid;
2632 memcpy(&tid, shared_map, sizeof(pid_t));
2633 ASSERT_NE(0, tid);
2634
2635 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2636
2637 std::string result;
2638 ConsumeFd(std::move(output_fd), &result);
2639
2640 // Verify that there are two headers, one where the tid is "primary_pid"
2641 // and the other where the tid is "tid".
2642 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2643 primary_pid, primary_pid);
2644 ASSERT_MATCH(result, match_str);
2645
2646 match_str =
2647 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2648 ASSERT_MATCH(result, match_str);
2649}
2650
2651// Verify that there is a BuildID present in the map section and set properly.
2652TEST_F(CrasherTest, verify_build_id) {
2653 StartProcess([]() { abort(); });
2654
2655 unique_fd output_fd;
2656 StartIntercept(&output_fd);
2657 FinishCrasher();
2658 AssertDeath(SIGABRT);
2659 int intercept_result;
2660 FinishIntercept(&intercept_result);
2661 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2662
2663 std::string result;
2664 ConsumeFd(std::move(output_fd), &result);
2665
2666 // Find every /system or /apex lib and verify the BuildID is displayed
2667 // properly.
2668 bool found_valid_elf = false;
2669 std::smatch match;
2670 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2671 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2672 result = match.suffix()) {
2673 if (prev_file == match[1]) {
2674 // Already checked this file.
2675 continue;
2676 }
2677
2678 prev_file = match[1];
2679 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2680 if (!elf.Init() || !elf.valid()) {
2681 // Skipping invalid elf files.
2682 continue;
2683 }
2684 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2685
2686 found_valid_elf = true;
2687 }
2688 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2689}
Christopher Ferrisbda10642023-04-24 18:14:53 -07002690
2691const char kLogMessage[] = "Should not see this log message.";
2692
2693// Verify that the logd process does not read the log.
2694TEST_F(CrasherTest, logd_skips_reading_logs) {
2695 StartProcess([]() {
2696 pthread_setname_np(pthread_self(), "logd");
2697 LOG(INFO) << kLogMessage;
2698 abort();
2699 });
2700
2701 unique_fd output_fd;
2702 StartIntercept(&output_fd);
2703 FinishCrasher();
2704 AssertDeath(SIGABRT);
2705 int intercept_result;
2706 FinishIntercept(&intercept_result);
2707 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2708
2709 std::string result;
2710 ConsumeFd(std::move(output_fd), &result);
2711 // logd should not contain our log message.
2712 ASSERT_NOT_MATCH(result, kLogMessage);
2713}
2714
2715// Verify that the logd process does not read the log when the non-main
2716// thread crashes.
2717TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
2718 StartProcess([]() {
2719 pthread_setname_np(pthread_self(), "logd");
2720 LOG(INFO) << kLogMessage;
2721
2722 std::thread thread([]() {
2723 pthread_setname_np(pthread_self(), "not_logd_thread");
2724 // Raise the signal on the side thread.
2725 raise_debugger_signal(kDebuggerdTombstone);
2726 });
2727 thread.join();
2728 _exit(0);
2729 });
2730
2731 unique_fd output_fd;
2732 StartIntercept(&output_fd, kDebuggerdTombstone);
2733 FinishCrasher();
2734 AssertDeath(0);
2735
2736 int intercept_result;
2737 FinishIntercept(&intercept_result);
2738 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2739
2740 std::string result;
2741 ConsumeFd(std::move(output_fd), &result);
2742 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2743 ASSERT_NOT_MATCH(result, kLogMessage);
2744}
Christopher Ferris98d62422023-05-24 20:01:10 +00002745
2746// Disable this test since there is a high liklihood that this would
2747// be flaky since it requires 500 messages being in the log.
2748TEST_F(CrasherTest, DISABLED_max_log_messages) {
2749 StartProcess([]() {
2750 for (size_t i = 0; i < 600; i++) {
2751 LOG(INFO) << "Message number " << i;
2752 }
2753 abort();
2754 });
2755
2756 unique_fd output_fd;
2757 StartIntercept(&output_fd);
2758 FinishCrasher();
2759 AssertDeath(SIGABRT);
2760 int intercept_result;
2761 FinishIntercept(&intercept_result);
2762 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2763
2764 std::string result;
2765 ConsumeFd(std::move(output_fd), &result);
2766 ASSERT_NOT_MATCH(result, "Message number 99");
2767 ASSERT_MATCH(result, "Message number 100");
2768 ASSERT_MATCH(result, "Message number 599");
2769}
2770
2771TEST_F(CrasherTest, log_with_newline) {
2772 StartProcess([]() {
2773 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
2774 abort();
2775 });
2776
2777 unique_fd output_fd;
2778 StartIntercept(&output_fd);
2779 FinishCrasher();
2780 AssertDeath(SIGABRT);
2781 int intercept_result;
2782 FinishIntercept(&intercept_result);
2783 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2784
2785 std::string result;
2786 ConsumeFd(std::move(output_fd), &result);
2787 ASSERT_MATCH(result, ":\\s*This line has a newline.");
2788 ASSERT_MATCH(result, ":\\s*This is on the next line.");
2789}