blob: a6d8226e3f096856fa34282d98a982c08afefadf [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 } \
Mattias Simonsson38ab0452023-11-08 12:02:46 +000097 alarm(seconds * android::base::HwTimeoutMultiplier()); \
Josh Gaocbe70cb2016-10-18 18:17:52 -070098 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,
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700117 InterceptResponse* response, 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
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700158 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), response, sizeof(*response)));
Josh Gao460b3362017-03-30 16:40:47 -0700159 if (rc == -1) {
160 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
161 } else if (rc == 0) {
162 FAIL() << "failed to read response from tombstoned (EOF)";
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700163 } else if (rc != sizeof(*response)) {
164 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(*response)
Josh Gao460b3362017-03-30 16:40:47 -0700165 << ", received " << rc;
166 }
Josh Gao460b3362017-03-30 16:40:47 -0700167}
168
Elliott Hughesd13ea522022-01-13 09:20:26 -0800169static bool pac_supported() {
170#if defined(__aarch64__)
171 return getauxval(AT_HWCAP) & HWCAP_PACA;
172#else
173 return false;
174#endif
175}
176
Josh Gaocbe70cb2016-10-18 18:17:52 -0700177class CrasherTest : public ::testing::Test {
178 public:
179 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700180 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700181 unique_fd crasher_pipe;
182 unique_fd intercept_fd;
183
184 CrasherTest();
185 ~CrasherTest();
186
Narayan Kamatha73df602017-05-24 15:07:25 +0100187 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700188
189 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
190 void FinishIntercept(int* result);
191
Josh Gao2e7b8e22017-05-04 17:12:57 -0700192 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700193 void StartCrasher(const std::string& crash_type);
194 void FinishCrasher();
195 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700196
197 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700198};
199
200CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700201 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
202 android::base::SetProperty(kWaitForDebuggerKey, "0");
203
204 // Clear the old property too, just in case someone's been using it
205 // on this device. (We only document the new name, but we still support
206 // the old name so we don't break anyone's existing setups.)
207 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700208}
209
210CrasherTest::~CrasherTest() {
211 if (crasher_pid != -1) {
212 kill(crasher_pid, SIGKILL);
213 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700214 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700215 }
216
Elliott Hughese4781d52021-03-17 09:15:15 -0700217 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700218}
219
Narayan Kamatha73df602017-05-24 15:07:25 +0100220void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221 if (crasher_pid == -1) {
222 FAIL() << "crasher hasn't been started";
223 }
224
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700225 InterceptResponse response = {};
226 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &response, intercept_type);
227 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
228 << "Error message: " << response.error_message;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700229}
230
231void CrasherTest::FinishIntercept(int* result) {
232 InterceptResponse response;
233
Christopher Ferris11555f02019-09-20 14:18:55 -0700234 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700235 if (rc == -1) {
236 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
237 } else if (rc == 0) {
238 *result = -1;
239 } else if (rc != sizeof(response)) {
240 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
241 << ", received " << rc;
242 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700243 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700244 }
245}
246
Josh Gao2e7b8e22017-05-04 17:12:57 -0700247void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800248 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700249 unique_fd crasher_read_pipe;
250 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
251 FAIL() << "failed to create pipe: " << strerror(errno);
252 }
253
Josh Gao2e7b8e22017-05-04 17:12:57 -0700254 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700255 if (crasher_pid == -1) {
256 FAIL() << "fork failed: " << strerror(errno);
257 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800258 char dummy;
259 crasher_pipe.reset();
260 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800261 function();
262 _exit(0);
263 }
264}
265
Josh Gaocbe70cb2016-10-18 18:17:52 -0700266void CrasherTest::FinishCrasher() {
267 if (crasher_pipe == -1) {
268 FAIL() << "crasher pipe uninitialized";
269 }
270
Christopher Ferris172b0a02019-09-18 17:48:30 -0700271 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700272 if (rc == -1) {
273 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
274 } else if (rc == 0) {
275 FAIL() << "crasher pipe was closed";
276 }
277}
278
279void CrasherTest::AssertDeath(int signo) {
280 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700281 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700282 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700283 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
284 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700285 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700286 FAIL() << "failed to wait for crasher: " << strerror(errno);
287 }
288
Josh Gaoe06f2a42017-04-27 16:50:38 -0700289 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700290 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700291 ASSERT_EQ(0, WEXITSTATUS(signo));
292 } else {
293 ASSERT_FALSE(WIFEXITED(status));
294 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
295 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700296 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700297 crasher_pid = -1;
298}
299
300static void ConsumeFd(unique_fd fd, std::string* output) {
Kelvin Zhang786dac32023-06-15 16:23:56 -0700301 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700302}
303
Mitch Phillips78f06702021-06-01 14:35:43 -0700304class LogcatCollector {
305 public:
306 LogcatCollector() { system("logcat -c"); }
307
308 void Collect(std::string* output) {
309 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
310 ASSERT_NE(cmd_stdout, nullptr);
311 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
312 ConsumeFd(std::move(tmp_fd), output);
313 pclose(cmd_stdout);
314 }
315};
316
Josh Gaocbe70cb2016-10-18 18:17:52 -0700317TEST_F(CrasherTest, smoke) {
318 int intercept_result;
319 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800320 StartProcess([]() {
321 *reinterpret_cast<volatile char*>(0xdead) = '1';
322 });
323
Josh Gaocbe70cb2016-10-18 18:17:52 -0700324 StartIntercept(&output_fd);
325 FinishCrasher();
326 AssertDeath(SIGSEGV);
327 FinishIntercept(&intercept_result);
328
329 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
330
331 std::string result;
332 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800333#ifdef __LP64__
334 ASSERT_MATCH(result,
335 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
336#else
337 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
338#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700339
340 if (mte_supported()) {
341 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700342 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
343 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700344 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800345
346 if (pac_supported()) {
347 // Test that the default PAC_ENABLED_KEYS value is set.
348 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
349 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
350 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700351}
352
Peter Collingbournef03af882020-03-20 18:09:00 -0700353TEST_F(CrasherTest, tagged_fault_addr) {
354#if !defined(__aarch64__)
355 GTEST_SKIP() << "Requires aarch64";
356#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700357 // HWASan crashes with SIGABRT on tag mismatch.
358 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700359 int intercept_result;
360 unique_fd output_fd;
361 StartProcess([]() {
362 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
363 });
364
365 StartIntercept(&output_fd);
366 FinishCrasher();
367 AssertDeath(SIGSEGV);
368 FinishIntercept(&intercept_result);
369
370 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
371
372 std::string result;
373 ConsumeFd(std::move(output_fd), &result);
374
375 // The address can either be tagged (new kernels) or untagged (old kernels).
376 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800377 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700378}
379
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700380void CrasherTest::Trap(void* ptr) {
381 void (*volatile f)(void*) = nullptr;
382 __asm__ __volatile__("" : : "r"(f) : "memory");
383 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700384}
385
386TEST_F(CrasherTest, heap_addr_in_register) {
387#if defined(__i386__)
388 GTEST_SKIP() << "architecture does not pass arguments in registers";
389#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700390 // The memory dump in HWASan crashes sadly shows the memory near the registers
391 // in the HWASan dump function, rather the faulting context. This is a known
392 // issue.
393 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700394 int intercept_result;
395 unique_fd output_fd;
396 StartProcess([]() {
397 // Crash with a heap pointer in the first argument register.
398 Trap(malloc(1));
399 });
400
401 StartIntercept(&output_fd);
402 FinishCrasher();
403 int status;
404 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
405 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
406 // Don't test the signal number because different architectures use different signals for
407 // __builtin_trap().
408 FinishIntercept(&intercept_result);
409
410 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
411
412 std::string result;
413 ConsumeFd(std::move(output_fd), &result);
414
415#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800416 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700417#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800418 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800419#elif defined(__riscv)
420 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700421#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800422 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700423#else
424 ASSERT_TRUE(false) << "unsupported architecture";
425#endif
426}
427
Peter Collingbournecd278072020-12-21 14:08:38 -0800428#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700429static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800430 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700431 abort();
432 }
433}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800434
435static void SetTagCheckingLevelAsync() {
436 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
437 abort();
438 }
439}
Peter Collingbournef8622522020-04-07 14:07:32 -0700440#endif
441
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800442struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
443
Peter Collingbourneaa544792021-05-13 13:53:37 -0700444INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800445
446TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800447#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700448 if (!mte_supported()) {
449 GTEST_SKIP() << "Requires MTE";
450 }
451
Peter Collingbourneaa544792021-05-13 13:53:37 -0700452 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
453 if (GetParam() == 0) {
454 return;
455 }
456
Mitch Phillips78f06702021-06-01 14:35:43 -0700457 LogcatCollector logcat_collector;
458
Peter Collingbournef8622522020-04-07 14:07:32 -0700459 int intercept_result;
460 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800461 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700462 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800463 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700464 free((void *)p);
465 p[0] = 42;
466 });
467
468 StartIntercept(&output_fd);
469 FinishCrasher();
470 AssertDeath(SIGSEGV);
471 FinishIntercept(&intercept_result);
472
473 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
474
Mitch Phillips78f06702021-06-01 14:35:43 -0700475 std::vector<std::string> log_sources(2);
476 ConsumeFd(std::move(output_fd), &log_sources[0]);
477 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700478 // Tag dump only available in the tombstone, not logcat.
479 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700480
Mitch Phillips78f06702021-06-01 14:35:43 -0700481 for (const auto& result : log_sources) {
482 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
483 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
484 std::to_string(GetParam()) + R"(-byte allocation)");
485 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
486 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
487 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700488#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800489 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700490#endif
491}
492
Peter Collingbournedc476342021-05-12 15:56:43 -0700493TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
494#if defined(__aarch64__)
495 if (!mte_supported()) {
496 GTEST_SKIP() << "Requires MTE";
497 }
498
499 int intercept_result;
500 unique_fd output_fd;
501 StartProcess([&]() {
502 SetTagCheckingLevelSync();
503 volatile int* p = (volatile int*)malloc(GetParam());
504 free((void *)p);
505 p[-1] = 42;
506 });
507
508 StartIntercept(&output_fd);
509 FinishCrasher();
510 AssertDeath(SIGSEGV);
511 FinishIntercept(&intercept_result);
512
513 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
514
515 std::string result;
516 ConsumeFd(std::move(output_fd), &result);
517
518 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
519 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
520#else
521 GTEST_SKIP() << "Requires aarch64";
522#endif
523}
524
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800525TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800526#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700527 if (!mte_supported()) {
528 GTEST_SKIP() << "Requires MTE";
529 }
530
Mitch Phillips78f06702021-06-01 14:35:43 -0700531 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700532 int intercept_result;
533 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800534 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700535 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800536 volatile char* p = (volatile char*)malloc(GetParam());
537 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700538 });
539
540 StartIntercept(&output_fd);
541 FinishCrasher();
542 AssertDeath(SIGSEGV);
543 FinishIntercept(&intercept_result);
544
545 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
546
Mitch Phillips78f06702021-06-01 14:35:43 -0700547 std::vector<std::string> log_sources(2);
548 ConsumeFd(std::move(output_fd), &log_sources[0]);
549 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700550
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700551 // Tag dump only in tombstone, not logcat, and tagging is not used for
552 // overflow protection in the scudo secondary (guard pages are used instead).
553 if (GetParam() < 0x10000) {
554 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
555 }
556
Mitch Phillips78f06702021-06-01 14:35:43 -0700557 for (const auto& result : log_sources) {
558 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
559 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
560 std::to_string(GetParam()) + R"(-byte allocation)");
561 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
562 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700563#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800564 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700565#endif
566}
567
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800568TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800569#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700570 if (!mte_supported()) {
571 GTEST_SKIP() << "Requires MTE";
572 }
573
574 int intercept_result;
575 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800576 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700577 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800578 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700579 p[-1] = 42;
580 });
581
582 StartIntercept(&output_fd);
583 FinishCrasher();
584 AssertDeath(SIGSEGV);
585 FinishIntercept(&intercept_result);
586
587 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
588
589 std::string result;
590 ConsumeFd(std::move(output_fd), &result);
591
592 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800593 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800594 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700595 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700596 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700597 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700598#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800599 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700600#endif
601}
602
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800603TEST_F(CrasherTest, mte_async) {
604#if defined(__aarch64__)
605 if (!mte_supported()) {
606 GTEST_SKIP() << "Requires MTE";
607 }
608
609 int intercept_result;
610 unique_fd output_fd;
611 StartProcess([&]() {
612 SetTagCheckingLevelAsync();
613 volatile int* p = (volatile int*)malloc(16);
614 p[-1] = 42;
615 });
616
617 StartIntercept(&output_fd);
618 FinishCrasher();
619 AssertDeath(SIGSEGV);
620 FinishIntercept(&intercept_result);
621
622 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
623
624 std::string result;
625 ConsumeFd(std::move(output_fd), &result);
626
Peter Collingbourne91e816a2023-03-07 21:24:47 -0800627 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800628#else
629 GTEST_SKIP() << "Requires aarch64";
630#endif
631}
632
Peter Collingbournef8622522020-04-07 14:07:32 -0700633TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800634#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700635 if (!mte_supported()) {
636 GTEST_SKIP() << "Requires MTE";
637 }
638
Mitch Phillips78f06702021-06-01 14:35:43 -0700639 LogcatCollector logcat_collector;
640
Peter Collingbournef8622522020-04-07 14:07:32 -0700641 int intercept_result;
642 unique_fd output_fd;
643 StartProcess([]() {
644 SetTagCheckingLevelSync();
645
646 // Make two allocations with the same tag and close to one another. Check for both properties
647 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
648 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
649 // (some non-zero value << 56) apart.
650 //
651 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
652 // other.
653 std::set<uintptr_t> allocs;
654 for (int i = 0; i != 4096; ++i) {
655 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
656 auto it = allocs.insert(alloc).first;
657 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
658 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
659 }
660 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
661 *reinterpret_cast<int*>(alloc + 16) = 42;
662 }
663 }
664 });
665
666 StartIntercept(&output_fd);
667 FinishCrasher();
668 AssertDeath(SIGSEGV);
669 FinishIntercept(&intercept_result);
670
671 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
672
Mitch Phillips78f06702021-06-01 14:35:43 -0700673 std::vector<std::string> log_sources(2);
674 ConsumeFd(std::move(output_fd), &log_sources[0]);
675 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700676
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700677 // Tag dump only in the tombstone, not logcat.
678 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
679
Mitch Phillips78f06702021-06-01 14:35:43 -0700680 for (const auto& result : log_sources) {
681 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
682 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800683 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700684 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
685 // overflows), so we can't match explicitly for an underflow message.
686 ASSERT_MATCH(result,
687 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
688 // Ensure there's at least two allocation traces (one for each cause).
689 ASSERT_MATCH(
690 result,
691 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
692 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700693#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800694 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700695#endif
696}
697
Peter Collingbournecd278072020-12-21 14:08:38 -0800698#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700699static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700700 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
701 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
702 size_t page_size = getpagesize();
703 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
704 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
705 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700706 return 0;
707 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700708 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
709 PROT_READ | PROT_WRITE | PROT_MTE);
710 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
711 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
712 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
713 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
714 }
715 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700716}
717#endif
718
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700719TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800720#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700721 if (!mte_supported()) {
722 GTEST_SKIP() << "Requires MTE";
723 }
724
725 int intercept_result;
726 unique_fd output_fd;
727 StartProcess([&]() {
728 SetTagCheckingLevelSync();
729 Trap(reinterpret_cast<void *>(CreateTagMapping()));
730 });
731
732 StartIntercept(&output_fd);
733 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700734 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700735 FinishIntercept(&intercept_result);
736
737 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
738
739 std::string result;
740 ConsumeFd(std::move(output_fd), &result);
741
742 ASSERT_MATCH(result, R"(memory near x0:
743.*
744.*
745 01.............0 0000000000000000 0000000000000000 ................
746 00.............0)");
747#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800748 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700749#endif
750}
751
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700752TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
753#if defined(__aarch64__)
754 if (!mte_supported()) {
755 GTEST_SKIP() << "Requires MTE";
756 }
757
758 int intercept_result;
759 unique_fd output_fd;
760 StartProcess([&]() {
761 SetTagCheckingLevelSync();
762 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
763 p[0] = 0; // Untagged pointer, tagged memory.
764 });
765
766 StartIntercept(&output_fd);
767 FinishCrasher();
768 AssertDeath(SIGSEGV);
769 FinishIntercept(&intercept_result);
770
771 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
772
773 std::string result;
774 ConsumeFd(std::move(output_fd), &result);
775
776 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
777\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
778#else
779 GTEST_SKIP() << "Requires aarch64";
780#endif
781}
782
783TEST_F(CrasherTest, mte_fault_tag_dump) {
784#if defined(__aarch64__)
785 if (!mte_supported()) {
786 GTEST_SKIP() << "Requires MTE";
787 }
788
789 int intercept_result;
790 unique_fd output_fd;
791 StartProcess([&]() {
792 SetTagCheckingLevelSync();
793 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
794 p[320] = 0; // Untagged pointer, tagged memory.
795 });
796
797 StartIntercept(&output_fd);
798 FinishCrasher();
799 AssertDeath(SIGSEGV);
800 FinishIntercept(&intercept_result);
801
802 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
803
804 std::string result;
805 ConsumeFd(std::move(output_fd), &result);
806
807 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
808\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
809\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
810\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
811)");
812#else
813 GTEST_SKIP() << "Requires aarch64";
814#endif
815}
816
817TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
818#if defined(__aarch64__)
819 if (!mte_supported()) {
820 GTEST_SKIP() << "Requires MTE";
821 }
822
823 int intercept_result;
824 unique_fd output_fd;
825 StartProcess([&]() {
826 SetTagCheckingLevelSync();
827 size_t page_size = getpagesize();
828 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
829 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
830 });
831
832 StartIntercept(&output_fd);
833 FinishCrasher();
834 AssertDeath(SIGSEGV);
835 FinishIntercept(&intercept_result);
836
837 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
838
839 std::string result;
840 ConsumeFd(std::move(output_fd), &result);
841
842 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
843 ASSERT_MATCH(result,
844 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
845\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
846
847)"); // Ensure truncation happened and there's a newline after the tag fault.
848#else
849 GTEST_SKIP() << "Requires aarch64";
850#endif
851}
852
Josh Gaocdea7502017-11-01 15:00:40 -0700853TEST_F(CrasherTest, LD_PRELOAD) {
854 int intercept_result;
855 unique_fd output_fd;
856 StartProcess([]() {
857 setenv("LD_PRELOAD", "nonexistent.so", 1);
858 *reinterpret_cast<volatile char*>(0xdead) = '1';
859 });
860
861 StartIntercept(&output_fd);
862 FinishCrasher();
863 AssertDeath(SIGSEGV);
864 FinishIntercept(&intercept_result);
865
866 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
867
868 std::string result;
869 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800870 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700871}
872
Josh Gaocbe70cb2016-10-18 18:17:52 -0700873TEST_F(CrasherTest, abort) {
874 int intercept_result;
875 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800876 StartProcess([]() {
877 abort();
878 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700879 StartIntercept(&output_fd);
880 FinishCrasher();
881 AssertDeath(SIGABRT);
882 FinishIntercept(&intercept_result);
883
884 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
885
886 std::string result;
887 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700888 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700889}
890
891TEST_F(CrasherTest, signal) {
892 int intercept_result;
893 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800894 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700895 while (true) {
896 sleep(1);
897 }
Josh Gao502cfd22017-02-17 01:39:15 -0800898 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700899 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700900 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700901 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
902
903 AssertDeath(SIGSEGV);
904 FinishIntercept(&intercept_result);
905
906 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
907
908 std::string result;
909 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700910 ASSERT_MATCH(
911 result,
912 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700913 ASSERT_MATCH(result, R"(backtrace:)");
914}
915
916TEST_F(CrasherTest, abort_message) {
917 int intercept_result;
918 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800919 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800920 // Arrived at experimentally;
921 // logd truncates at 4062.
922 // strlen("Abort message: ''") is 17.
923 // That's 4045, but we also want a NUL.
924 char buf[4045 + 1];
925 memset(buf, 'x', sizeof(buf));
926 buf[sizeof(buf) - 1] = '\0';
927 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800928 abort();
929 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700930 StartIntercept(&output_fd);
931 FinishCrasher();
932 AssertDeath(SIGABRT);
933 FinishIntercept(&intercept_result);
934
935 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
936
937 std::string result;
938 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800939 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700940}
941
Christopher Ferrise8891452021-08-17 17:34:53 -0700942TEST_F(CrasherTest, abort_message_newline_trimmed) {
943 int intercept_result;
944 unique_fd output_fd;
945 StartProcess([]() {
946 android_set_abort_message("Message with a newline.\n");
947 abort();
948 });
949 StartIntercept(&output_fd);
950 FinishCrasher();
951 AssertDeath(SIGABRT);
952 FinishIntercept(&intercept_result);
953
954 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
955
956 std::string result;
957 ConsumeFd(std::move(output_fd), &result);
958 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
959}
960
961TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
962 int intercept_result;
963 unique_fd output_fd;
964 StartProcess([]() {
965 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
966 abort();
967 });
968 StartIntercept(&output_fd);
969 FinishCrasher();
970 AssertDeath(SIGABRT);
971 FinishIntercept(&intercept_result);
972
973 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
974
975 std::string result;
976 ConsumeFd(std::move(output_fd), &result);
977 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
978}
979
Josh Gaoe06f2a42017-04-27 16:50:38 -0700980TEST_F(CrasherTest, abort_message_backtrace) {
981 int intercept_result;
982 unique_fd output_fd;
983 StartProcess([]() {
984 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -0800985 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700986 exit(0);
987 });
988 StartIntercept(&output_fd);
989 FinishCrasher();
990 AssertDeath(0);
991 FinishIntercept(&intercept_result);
992
993 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
994
995 std::string result;
996 ConsumeFd(std::move(output_fd), &result);
997 ASSERT_NOT_MATCH(result, R"(Abort message:)");
998}
999
Josh Gaocbe70cb2016-10-18 18:17:52 -07001000TEST_F(CrasherTest, intercept_timeout) {
1001 int intercept_result;
1002 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001003 StartProcess([]() {
1004 abort();
1005 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001006 StartIntercept(&output_fd);
1007
1008 // Don't let crasher finish until we timeout.
1009 FinishIntercept(&intercept_result);
1010
1011 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1012 << intercept_result << ")";
1013
1014 FinishCrasher();
1015 AssertDeath(SIGABRT);
1016}
1017
Elliott Hughese4781d52021-03-17 09:15:15 -07001018TEST_F(CrasherTest, wait_for_debugger) {
1019 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1020 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001021 }
1022 sleep(1);
1023
Josh Gao502cfd22017-02-17 01:39:15 -08001024 StartProcess([]() {
1025 abort();
1026 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001027 FinishCrasher();
1028
1029 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001030 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001031 ASSERT_TRUE(WIFSTOPPED(status));
1032 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1033
1034 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1035
1036 AssertDeath(SIGABRT);
1037}
1038
Josh Gaocbe70cb2016-10-18 18:17:52 -07001039TEST_F(CrasherTest, backtrace) {
1040 std::string result;
1041 int intercept_result;
1042 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001043
1044 StartProcess([]() {
1045 abort();
1046 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001047 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001048
1049 std::this_thread::sleep_for(500ms);
1050
1051 sigval val;
1052 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001053 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001054 FinishIntercept(&intercept_result);
1055 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1056 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001057 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001058
1059 int status;
1060 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1061
1062 StartIntercept(&output_fd);
1063 FinishCrasher();
1064 AssertDeath(SIGABRT);
1065 FinishIntercept(&intercept_result);
1066 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1067 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001068 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001069}
Josh Gaofca7ca32017-01-23 12:05:35 -08001070
1071TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001072 int intercept_result;
1073 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001074 StartProcess([]() {
1075 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001076 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001077 });
Josh Gao502cfd22017-02-17 01:39:15 -08001078
1079 StartIntercept(&output_fd);
1080 FinishCrasher();
1081 AssertDeath(SIGABRT);
1082 FinishIntercept(&intercept_result);
1083
1084 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1085
1086 std::string result;
1087 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001088 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001089}
1090
Josh Gao502cfd22017-02-17 01:39:15 -08001091TEST_F(CrasherTest, capabilities) {
1092 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1093
Josh Gaofca7ca32017-01-23 12:05:35 -08001094 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001095 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1096 err(1, "failed to set PR_SET_KEEPCAPS");
1097 }
1098
1099 if (setresuid(1, 1, 1) != 0) {
1100 err(1, "setresuid failed");
1101 }
1102
1103 __user_cap_header_struct capheader;
1104 __user_cap_data_struct capdata[2];
1105 memset(&capheader, 0, sizeof(capheader));
1106 memset(&capdata, 0, sizeof(capdata));
1107
1108 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1109 capheader.pid = 0;
1110
1111 // Turn on every third capability.
1112 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1113 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1114 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1115 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1116 }
1117
1118 // Make sure CAP_SYS_PTRACE is off.
1119 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1120 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1121
1122 if (capset(&capheader, &capdata[0]) != 0) {
1123 err(1, "capset failed");
1124 }
1125
1126 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1127 err(1, "failed to drop ambient capabilities");
1128 }
1129
Josh Gaoa5199a92017-04-03 13:18:34 -07001130 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001131 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001132 });
Josh Gao502cfd22017-02-17 01:39:15 -08001133
1134 unique_fd output_fd;
1135 StartIntercept(&output_fd);
1136 FinishCrasher();
1137 AssertDeath(SIGSYS);
1138
1139 std::string result;
1140 int intercept_result;
1141 FinishIntercept(&intercept_result);
1142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1143 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001144 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001145 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001146}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001147
Josh Gao2e7b8e22017-05-04 17:12:57 -07001148TEST_F(CrasherTest, fake_pid) {
1149 int intercept_result;
1150 unique_fd output_fd;
1151
1152 // Prime the getpid/gettid caches.
1153 UNUSED(getpid());
1154 UNUSED(gettid());
1155
1156 std::function<pid_t()> clone_fn = []() {
1157 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1158 };
1159 StartProcess(
1160 []() {
1161 ASSERT_NE(getpid(), syscall(__NR_getpid));
1162 ASSERT_NE(gettid(), syscall(__NR_gettid));
1163 raise(SIGSEGV);
1164 },
1165 clone_fn);
1166
1167 StartIntercept(&output_fd);
1168 FinishCrasher();
1169 AssertDeath(SIGSEGV);
1170 FinishIntercept(&intercept_result);
1171
1172 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1173
1174 std::string result;
1175 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001176 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001177}
1178
Josh Gaoe04ca272018-01-16 15:38:17 -08001179static const char* const kDebuggerdSeccompPolicy =
1180 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1181
Mitch Phillips18ce5422023-01-19 14:23:49 -08001182static void setup_jail(minijail* jail) {
1183 if (!jail) {
1184 LOG(FATAL) << "failed to create minijail";
1185 }
1186
Josh Gao6f9eeec2018-09-12 13:55:47 -07001187 std::string policy;
1188 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1189 PLOG(FATAL) << "failed to read policy file";
1190 }
1191
1192 // Allow a bunch of syscalls used by the tests.
1193 policy += "\nclone: 1";
1194 policy += "\nsigaltstack: 1";
1195 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001196 policy += "\ngetrlimit: 1";
1197 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001198
1199 FILE* tmp_file = tmpfile();
1200 if (!tmp_file) {
1201 PLOG(FATAL) << "tmpfile failed";
1202 }
1203
Christopher Ferris172b0a02019-09-18 17:48:30 -07001204 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001205 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1206 PLOG(FATAL) << "failed to write policy to tmpfile";
1207 }
1208
1209 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1210 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001211 }
1212
Mitch Phillips18ce5422023-01-19 14:23:49 -08001213 minijail_no_new_privs(jail);
1214 minijail_log_seccomp_filter_failures(jail);
1215 minijail_use_seccomp_filter(jail);
1216 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1217}
Josh Gaoe04ca272018-01-16 15:38:17 -08001218
Mitch Phillips18ce5422023-01-19 14:23:49 -08001219static pid_t seccomp_fork_impl(void (*prejail)()) {
1220 ScopedMinijail jail{minijail_new()};
1221 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001222
1223 pid_t result = fork();
1224 if (result == -1) {
1225 return result;
1226 } else if (result != 0) {
1227 return result;
1228 }
1229
1230 // Spawn and detach a thread that spins forever.
1231 std::atomic<bool> thread_ready(false);
1232 std::thread thread([&jail, &thread_ready]() {
1233 minijail_enter(jail.get());
1234 thread_ready = true;
1235 for (;;)
1236 ;
1237 });
1238 thread.detach();
1239
1240 while (!thread_ready) {
1241 continue;
1242 }
1243
Josh Gao70adac62018-02-22 11:38:33 -08001244 if (prejail) {
1245 prejail();
1246 }
1247
Josh Gaoe04ca272018-01-16 15:38:17 -08001248 minijail_enter(jail.get());
1249 return result;
1250}
1251
Josh Gao70adac62018-02-22 11:38:33 -08001252static pid_t seccomp_fork() {
1253 return seccomp_fork_impl(nullptr);
1254}
1255
Josh Gaoe04ca272018-01-16 15:38:17 -08001256TEST_F(CrasherTest, seccomp_crash) {
1257 int intercept_result;
1258 unique_fd output_fd;
1259
1260 StartProcess([]() { abort(); }, &seccomp_fork);
1261
1262 StartIntercept(&output_fd);
1263 FinishCrasher();
1264 AssertDeath(SIGABRT);
1265 FinishIntercept(&intercept_result);
1266 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1267
1268 std::string result;
1269 ConsumeFd(std::move(output_fd), &result);
1270 ASSERT_BACKTRACE_FRAME(result, "abort");
1271}
1272
Josh Gao70adac62018-02-22 11:38:33 -08001273static pid_t seccomp_fork_rlimit() {
1274 return seccomp_fork_impl([]() {
1275 struct rlimit rlim = {
1276 .rlim_cur = 512 * 1024 * 1024,
1277 .rlim_max = 512 * 1024 * 1024,
1278 };
1279
1280 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1281 raise(SIGINT);
1282 }
1283 });
1284}
1285
1286TEST_F(CrasherTest, seccomp_crash_oom) {
1287 int intercept_result;
1288 unique_fd output_fd;
1289
1290 StartProcess(
1291 []() {
1292 std::vector<void*> vec;
1293 for (int i = 0; i < 512; ++i) {
1294 char* buf = static_cast<char*>(malloc(1024 * 1024));
1295 if (!buf) {
1296 abort();
1297 }
1298 memset(buf, 0xff, 1024 * 1024);
1299 vec.push_back(buf);
1300 }
1301 },
1302 &seccomp_fork_rlimit);
1303
1304 StartIntercept(&output_fd);
1305 FinishCrasher();
1306 AssertDeath(SIGABRT);
1307 FinishIntercept(&intercept_result);
1308 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1309
1310 // We can't actually generate a backtrace, just make sure that the process terminates.
1311}
1312
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001313__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001314 siginfo_t siginfo;
1315 siginfo.si_code = SI_QUEUE;
1316 siginfo.si_pid = getpid();
1317 siginfo.si_uid = getuid();
1318
1319 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1320 PLOG(FATAL) << "invalid dump type";
1321 }
1322
1323 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1324
Josh Gaoa48b41b2019-12-13 14:11:04 -08001325 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001326 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1327 return false;
1328 }
1329
1330 return true;
1331}
1332
Christopher Ferrisb999b822022-02-09 17:57:21 -08001333extern "C" void foo() {
1334 LOG(INFO) << "foo";
1335 std::this_thread::sleep_for(1s);
1336}
1337
1338extern "C" void bar() {
1339 LOG(INFO) << "bar";
1340 std::this_thread::sleep_for(1s);
1341}
1342
Josh Gaoe04ca272018-01-16 15:38:17 -08001343TEST_F(CrasherTest, seccomp_tombstone) {
1344 int intercept_result;
1345 unique_fd output_fd;
1346
1347 static const auto dump_type = kDebuggerdTombstone;
1348 StartProcess(
1349 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001350 std::thread a(foo);
1351 std::thread b(bar);
1352
1353 std::this_thread::sleep_for(100ms);
1354
Josh Gaoe04ca272018-01-16 15:38:17 -08001355 raise_debugger_signal(dump_type);
1356 _exit(0);
1357 },
1358 &seccomp_fork);
1359
1360 StartIntercept(&output_fd, dump_type);
1361 FinishCrasher();
1362 AssertDeath(0);
1363 FinishIntercept(&intercept_result);
1364 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1365
1366 std::string result;
1367 ConsumeFd(std::move(output_fd), &result);
1368 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001369 ASSERT_BACKTRACE_FRAME(result, "foo");
1370 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001371}
1372
Christopher Ferris303c6be2022-05-24 17:08:33 -07001373TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1374 int intercept_result;
1375 unique_fd output_fd;
1376
1377 static const auto dump_type = kDebuggerdTombstone;
1378 StartProcess(
1379 []() {
1380 std::thread abort_thread([] { abort(); });
1381 abort_thread.join();
1382 },
1383 &seccomp_fork);
1384
1385 StartIntercept(&output_fd, dump_type);
1386 FinishCrasher();
1387 AssertDeath(SIGABRT);
1388 FinishIntercept(&intercept_result);
1389 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1390
1391 std::string result;
1392 ConsumeFd(std::move(output_fd), &result);
1393 ASSERT_BACKTRACE_FRAME(result, "abort");
1394}
1395
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001396TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1397 int intercept_result;
1398 unique_fd output_fd;
1399
1400 static const auto dump_type = kDebuggerdTombstone;
1401 StartProcess(
1402 []() {
1403 std::thread a(foo);
1404 std::thread b(bar);
1405
1406 std::this_thread::sleep_for(100ms);
1407
1408 std::thread abort_thread([] { abort(); });
1409 abort_thread.join();
1410 },
1411 &seccomp_fork);
1412
1413 StartIntercept(&output_fd, dump_type);
1414 FinishCrasher();
1415 AssertDeath(SIGABRT);
1416 FinishIntercept(&intercept_result);
1417 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1418
1419 std::string result;
1420 ConsumeFd(std::move(output_fd), &result);
1421 ASSERT_BACKTRACE_FRAME(result, "abort");
1422 ASSERT_BACKTRACE_FRAME(result, "foo");
1423 ASSERT_BACKTRACE_FRAME(result, "bar");
1424 ASSERT_BACKTRACE_FRAME(result, "main");
1425}
1426
Josh Gaoe04ca272018-01-16 15:38:17 -08001427TEST_F(CrasherTest, seccomp_backtrace) {
1428 int intercept_result;
1429 unique_fd output_fd;
1430
1431 static const auto dump_type = kDebuggerdNativeBacktrace;
1432 StartProcess(
1433 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001434 std::thread a(foo);
1435 std::thread b(bar);
1436
1437 std::this_thread::sleep_for(100ms);
1438
Josh Gaoe04ca272018-01-16 15:38:17 -08001439 raise_debugger_signal(dump_type);
1440 _exit(0);
1441 },
1442 &seccomp_fork);
1443
1444 StartIntercept(&output_fd, dump_type);
1445 FinishCrasher();
1446 AssertDeath(0);
1447 FinishIntercept(&intercept_result);
1448 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1449
1450 std::string result;
1451 ConsumeFd(std::move(output_fd), &result);
1452 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001453 ASSERT_BACKTRACE_FRAME(result, "foo");
1454 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001455}
1456
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001457TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1458 int intercept_result;
1459 unique_fd output_fd;
1460
1461 static const auto dump_type = kDebuggerdNativeBacktrace;
1462 StartProcess(
1463 []() {
1464 std::thread a(foo);
1465 std::thread b(bar);
1466
1467 std::this_thread::sleep_for(100ms);
1468
1469 std::thread raise_thread([] {
1470 raise_debugger_signal(dump_type);
1471 _exit(0);
1472 });
1473 raise_thread.join();
1474 },
1475 &seccomp_fork);
1476
1477 StartIntercept(&output_fd, dump_type);
1478 FinishCrasher();
1479 AssertDeath(0);
1480 FinishIntercept(&intercept_result);
1481 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1482
1483 std::string result;
1484 ConsumeFd(std::move(output_fd), &result);
1485 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1486 ASSERT_BACKTRACE_FRAME(result, "foo");
1487 ASSERT_BACKTRACE_FRAME(result, "bar");
1488 ASSERT_BACKTRACE_FRAME(result, "main");
1489}
1490
Josh Gaoe04ca272018-01-16 15:38:17 -08001491TEST_F(CrasherTest, seccomp_crash_logcat) {
1492 StartProcess([]() { abort(); }, &seccomp_fork);
1493 FinishCrasher();
1494
1495 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1496 AssertDeath(SIGABRT);
1497}
1498
Josh Gaofd13bf02017-08-18 15:37:26 -07001499TEST_F(CrasherTest, competing_tracer) {
1500 int intercept_result;
1501 unique_fd output_fd;
1502 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001503 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001504 });
1505
1506 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001507
1508 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001509 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001510
1511 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001512 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001513 ASSERT_TRUE(WIFSTOPPED(status));
1514 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1515
1516 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1517 FinishIntercept(&intercept_result);
1518 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1519
1520 std::string result;
1521 ConsumeFd(std::move(output_fd), &result);
1522 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1523 regex += std::to_string(gettid());
1524 regex += R"( \(.+debuggerd_test)";
1525 ASSERT_MATCH(result, regex.c_str());
1526
Christopher Ferris172b0a02019-09-18 17:48:30 -07001527 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001528 ASSERT_TRUE(WIFSTOPPED(status));
1529 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1530
Josh Gaofd13bf02017-08-18 15:37:26 -07001531 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1532 AssertDeath(SIGABRT);
1533}
1534
Mitch Phillips18ce5422023-01-19 14:23:49 -08001535struct GwpAsanTestParameters {
1536 size_t alloc_size;
1537 bool free_before_access;
1538 int access_offset;
1539 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1540};
1541
1542struct GwpAsanCrasherTest
1543 : CrasherTest,
1544 testing::WithParamInterface<
1545 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1546
1547GwpAsanTestParameters gwp_asan_tests[] = {
1548 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1549 "Use After Free, 0 bytes into a 7-byte allocation"},
1550 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1551 "Use After Free, 1 byte into a 15-byte allocation"},
1552 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1553 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1554 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1555 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1556};
1557
1558INSTANTIATE_TEST_SUITE_P(
1559 GwpAsanTests, GwpAsanCrasherTest,
1560 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1561 /* recoverable */ testing::Bool(),
1562 /* seccomp */ testing::Bool()),
1563 [](const testing::TestParamInfo<
1564 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1565 const GwpAsanTestParameters& params = std::get<0>(info.param);
1566 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1567 name += testing::PrintToString(params.alloc_size);
1568 name += "Alloc";
1569 if (params.access_offset < 0) {
1570 name += "Left";
1571 name += testing::PrintToString(params.access_offset * -1);
1572 } else {
1573 name += "Right";
1574 name += testing::PrintToString(params.access_offset);
1575 }
1576 name += "Bytes";
1577 if (std::get<1>(info.param)) name += "Recoverable";
1578 if (std::get<2>(info.param)) name += "Seccomp";
1579 return name;
1580 });
1581
1582TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1583 if (mte_supported()) {
1584 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1585 // instead of GWP-ASan.
1586 GTEST_SKIP() << "Skipped on MTE.";
1587 }
1588 // Skip this test on HWASan, which will reliably catch test errors as well.
1589 SKIP_WITH_HWASAN;
1590
1591 GwpAsanTestParameters params = std::get<0>(GetParam());
1592 bool recoverable = std::get<1>(GetParam());
1593 LogcatCollector logcat_collector;
1594
1595 int intercept_result;
1596 unique_fd output_fd;
1597 StartProcess([&recoverable]() {
1598 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1599 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1600 if (recoverable) {
1601 env[3] = "GWP_ASAN_RECOVERABLE=true";
1602 }
1603 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1604 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1605 "DISABLED_run_gwp_asan_test");
1606 std::string test_filter = "--gtest_filter=*";
1607 test_filter += test_name;
1608 std::string this_binary = android::base::GetExecutablePath();
1609 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1610 test_filter.c_str(), nullptr};
1611 // We check the crash report from a debuggerd handler and from logcat. The
1612 // echo from stdout/stderr of the subprocess trips up atest, because it
1613 // doesn't like that two tests started in a row without the first one
1614 // finishing (even though the second one is in a subprocess).
1615 close(STDOUT_FILENO);
1616 close(STDERR_FILENO);
1617 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1618 });
1619
1620 StartIntercept(&output_fd);
1621 FinishCrasher();
1622 if (recoverable) {
1623 AssertDeath(0);
1624 } else {
1625 AssertDeath(SIGSEGV);
1626 }
1627 FinishIntercept(&intercept_result);
1628
1629 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1630
1631 std::vector<std::string> log_sources(2);
1632 ConsumeFd(std::move(output_fd), &log_sources[0]);
1633 logcat_collector.Collect(&log_sources[1]);
1634
1635 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1636 // information. Make sure the recovery still works, but the report won't be
1637 // hugely useful, it looks like a regular SEGV.
1638 bool seccomp = std::get<2>(GetParam());
1639 if (!seccomp) {
1640 for (const auto& result : log_sources) {
1641 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1642 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1643 if (params.free_before_access) {
1644 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1645 }
1646 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1647 }
1648 }
1649}
1650
1651TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1652 GwpAsanTestParameters params = std::get<0>(GetParam());
1653 bool seccomp = std::get<2>(GetParam());
1654 if (seccomp) {
1655 ScopedMinijail jail{minijail_new()};
1656 setup_jail(jail.get());
1657 minijail_enter(jail.get());
1658 }
1659
1660 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1661 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1662 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1663 p[params.access_offset] = 42;
1664 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001665
1666 bool recoverable = std::get<1>(GetParam());
1667 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1668
1669 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1670 // we end with at least one in a different slot), make sure the process still
1671 // doesn't crash.
1672 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1673 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1674 free(static_cast<void*>(const_cast<char*>(p)));
1675 free(static_cast<void*>(const_cast<char*>(p2)));
1676 *p = 42;
1677 *p2 = 42;
1678
1679 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1680 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1681 // coverage does. Thus, skip the atexit handlers.
1682 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001683}
1684
Josh Gaobf06a402018-08-27 16:34:01 -07001685TEST_F(CrasherTest, fdsan_warning_abort_message) {
1686 int intercept_result;
1687 unique_fd output_fd;
1688
1689 StartProcess([]() {
1690 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001691 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001692 if (fd == -1) {
1693 abort();
1694 }
1695 close(fd.get());
1696 _exit(0);
1697 });
1698
1699 StartIntercept(&output_fd);
1700 FinishCrasher();
1701 AssertDeath(0);
1702 FinishIntercept(&intercept_result);
1703 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1704
1705 std::string result;
1706 ConsumeFd(std::move(output_fd), &result);
1707 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1708}
1709
Josh Gaoc3c8c022017-02-13 16:36:18 -08001710TEST(crash_dump, zombie) {
1711 pid_t forkpid = fork();
1712
Josh Gaoc3c8c022017-02-13 16:36:18 -08001713 pid_t rc;
1714 int status;
1715
1716 if (forkpid == 0) {
1717 errno = 0;
1718 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1719 if (rc != -1 || errno != ECHILD) {
1720 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1721 }
1722
Josh Gaoa48b41b2019-12-13 14:11:04 -08001723 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001724
1725 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001726 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001727 if (rc != -1 || errno != ECHILD) {
1728 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1729 }
1730 _exit(0);
1731 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001732 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001733 ASSERT_EQ(forkpid, rc);
1734 ASSERT_TRUE(WIFEXITED(status));
1735 ASSERT_EQ(0, WEXITSTATUS(status));
1736 }
1737}
Josh Gao352a8452017-03-30 16:46:21 -07001738
1739TEST(tombstoned, no_notify) {
1740 // Do this a few times.
1741 for (int i = 0; i < 3; ++i) {
1742 pid_t pid = 123'456'789 + i;
1743
1744 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001745 InterceptResponse response = {};
1746 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1747 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1748 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001749
1750 {
1751 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001752 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001753 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1754 }
1755
1756 pid_t read_pid;
1757 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1758 ASSERT_EQ(read_pid, pid);
1759 }
1760}
1761
1762TEST(tombstoned, stress) {
1763 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1764 static constexpr int kDumpCount = 100;
1765
1766 std::atomic<bool> start(false);
1767 std::vector<std::thread> threads;
1768 threads.emplace_back([&start]() {
1769 while (!start) {
1770 continue;
1771 }
1772
1773 // Use a way out of range pid, to avoid stomping on an actual process.
1774 pid_t pid_base = 1'000'000;
1775
1776 for (int dump = 0; dump < kDumpCount; ++dump) {
1777 pid_t pid = pid_base + dump;
1778
1779 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001780 InterceptResponse response = {};
1781 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1782 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1783 << "Error messeage: " << response.error_message;
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;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001814 InterceptResponse response = {};
1815 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1816 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1817 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001818
1819 {
1820 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001821 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001822 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1823 tombstoned_notify_completion(tombstoned_socket.get());
1824 }
1825
1826 // TODO: Fix the race that requires this sleep.
1827 std::this_thread::sleep_for(50ms);
1828
1829 pid_t read_pid;
1830 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1831 ASSERT_EQ(read_pid, pid);
1832 }
1833 });
1834
1835 start = true;
1836
1837 for (std::thread& thread : threads) {
1838 thread.join();
1839 }
1840}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001841
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001842TEST(tombstoned, intercept_java_trace_smoke) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01001843 // Using a "real" PID is a little dangerous here - if the test fails
1844 // or crashes, we might end up getting a bogus / unreliable stack
1845 // trace.
1846 const pid_t self = getpid();
1847
1848 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001849 InterceptResponse response = {};
1850 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
1851 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1852 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001853
Josh Gao76e1e302021-01-26 15:53:11 -08001854 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001855 // should result in a "regular" FD and not the installed intercept.
1856 const char native[] = "native";
1857 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001858 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001859 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1860 tombstoned_notify_completion(tombstoned_socket.get());
1861
1862 // Then, connect to tombstoned asking for a java backtrace. This *should*
1863 // trigger the intercept.
1864 const char java[] = "java";
1865 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1866 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1867 tombstoned_notify_completion(tombstoned_socket.get());
1868
1869 char outbuf[sizeof(java)];
1870 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1871 ASSERT_STREQ("java", outbuf);
1872}
1873
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001874TEST(tombstoned, intercept_multiple_dump_types) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01001875 const pid_t fake_pid = 1'234'567;
1876 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001877 InterceptResponse response = {};
1878 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
1879 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1880 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001881
1882 unique_fd intercept_fd_2, output_fd_2;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001883 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
1884 kDebuggerdNativeBacktrace);
1885 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1886 << "Error message: " << response.error_message;
1887}
1888
1889TEST(tombstoned, intercept_bad_pid) {
1890 const pid_t fake_pid = -1;
1891 unique_fd intercept_fd, output_fd;
1892 InterceptResponse response = {};
1893 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
1894 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1895 << "Error message: " << response.error_message;
1896 ASSERT_MATCH(response.error_message, "bad pid");
1897}
1898
1899TEST(tombstoned, intercept_bad_dump_types) {
1900 const pid_t fake_pid = 1'234'567;
1901 unique_fd intercept_fd, output_fd;
1902 InterceptResponse response = {};
1903 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
1904 static_cast<DebuggerdDumpType>(20));
1905 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1906 << "Error message: " << response.error_message;
1907 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
1908
1909 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
1910 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1911 << "Error message: " << response.error_message;
1912 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
1913
1914 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
1915 ASSERT_EQ(InterceptStatus::kFailed, response.status)
1916 << "Error message: " << response.error_message;
1917 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
1918}
1919
1920TEST(tombstoned, intercept_already_registered) {
1921 const pid_t fake_pid = 1'234'567;
1922 unique_fd intercept_fd1, output_fd1;
1923 InterceptResponse response = {};
1924 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
1925 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1926 << "Error message: " << response.error_message;
1927
1928 unique_fd intercept_fd2, output_fd2;
1929 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
1930 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
1931 << "Error message: " << response.error_message;
1932 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
1933}
1934
1935TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
1936 const pid_t fake_pid = 1'234'567;
1937
1938 unique_fd intercept_fd, output_fd;
1939 InterceptResponse response = {};
1940 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1941 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1942 << "Error message: " << response.error_message;
1943
1944 const char data[] = "tombstone_proto";
1945 unique_fd tombstoned_socket, input_fd;
1946 ASSERT_TRUE(
1947 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
1948 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
1949 tombstoned_notify_completion(tombstoned_socket.get());
1950
1951 char outbuf[sizeof(data)];
1952 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1953 ASSERT_STREQ("tombstone_proto", outbuf);
Narayan Kamathca5e9082017-06-02 15:42:06 +01001954}
1955
1956TEST(tombstoned, intercept_any) {
1957 const pid_t fake_pid = 1'234'567;
1958
1959 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001960 InterceptResponse response = {};
1961 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
1962 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1963 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001964
1965 const char any[] = "any";
1966 unique_fd tombstoned_socket, input_fd;
1967 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1968 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1969 tombstoned_notify_completion(tombstoned_socket.get());
1970
1971 char outbuf[sizeof(any)];
1972 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1973 ASSERT_STREQ("any", outbuf);
1974}
Josh Gao2b22ae12018-09-12 14:51:03 -07001975
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001976TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
1977 const pid_t fake_pid = 1'234'567;
1978
1979 InterceptResponse response = {};
1980 unique_fd intercept_fd1, output_fd1;
1981 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
1982 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1983 << "Error message: " << response.error_message;
1984
1985 unique_fd intercept_fd2, output_fd2;
1986 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
1987 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1988 << "Error message: " << response.error_message;
1989
1990 unique_fd tombstoned_socket, input_fd;
1991 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1992}
1993
1994TEST(tombstoned, intercept_multiple_verify_intercept) {
1995 // Need to use our pid for java since that will verify the pid.
1996 const pid_t fake_pid = getpid();
1997
1998 InterceptResponse response = {};
1999 unique_fd intercept_fd1, output_fd1;
2000 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2001 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2002 << "Error message: " << response.error_message;
2003
2004 unique_fd intercept_fd2, output_fd2;
2005 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2006 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2007 << "Error message: " << response.error_message;
2008
2009 unique_fd intercept_fd3, output_fd3;
2010 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2011 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2012 << "Error message: " << response.error_message;
2013
2014 const char native_data[] = "native";
2015 unique_fd tombstoned_socket1, input_fd1;
2016 ASSERT_TRUE(
2017 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2018 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2019 tombstoned_notify_completion(tombstoned_socket1.get());
2020
2021 char native_outbuf[sizeof(native_data)];
2022 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2023 ASSERT_STREQ("native", native_outbuf);
2024
2025 const char java_data[] = "java";
2026 unique_fd tombstoned_socket2, input_fd2;
2027 ASSERT_TRUE(
2028 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2029 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2030 tombstoned_notify_completion(tombstoned_socket2.get());
2031
2032 char java_outbuf[sizeof(java_data)];
2033 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2034 ASSERT_STREQ("java", java_outbuf);
2035
2036 const char tomb_data[] = "tombstone";
2037 unique_fd tombstoned_socket3, input_fd3;
2038 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2039 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2040 tombstoned_notify_completion(tombstoned_socket3.get());
2041
2042 char tomb_outbuf[sizeof(tomb_data)];
2043 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2044 ASSERT_STREQ("tombstone", tomb_outbuf);
2045}
2046
Josh Gao2b22ae12018-09-12 14:51:03 -07002047TEST(tombstoned, interceptless_backtrace) {
2048 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2049 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2050 std::map<int, time_t> result;
2051 for (int i = 0; i < 99; ++i) {
2052 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2053 struct stat st;
2054 if (stat(path.c_str(), &st) == 0) {
2055 result[i] = st.st_mtim.tv_sec;
2056 }
2057 }
2058 return result;
2059 };
2060
2061 auto before = get_tombstone_timestamps();
2062 for (int i = 0; i < 50; ++i) {
2063 raise_debugger_signal(kDebuggerdNativeBacktrace);
2064 }
2065 auto after = get_tombstone_timestamps();
2066
2067 int diff = 0;
2068 for (int i = 0; i < 99; ++i) {
2069 if (after.count(i) == 0) {
2070 continue;
2071 }
2072 if (before.count(i) == 0) {
2073 ++diff;
2074 continue;
2075 }
2076 if (before[i] != after[i]) {
2077 ++diff;
2078 }
2079 }
2080
2081 // We can't be sure that nothing's crash looping in the background.
2082 // This should be good enough, though...
2083 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2084}
Christopher Ferris481e8372019-07-15 17:13:24 -07002085
2086static __attribute__((__noinline__)) void overflow_stack(void* p) {
2087 void* buf[1];
2088 buf[0] = p;
2089 static volatile void* global = buf;
2090 if (global) {
2091 global = buf;
2092 overflow_stack(&buf);
2093 }
2094}
2095
2096TEST_F(CrasherTest, stack_overflow) {
2097 int intercept_result;
2098 unique_fd output_fd;
2099 StartProcess([]() { overflow_stack(nullptr); });
2100
2101 StartIntercept(&output_fd);
2102 FinishCrasher();
2103 AssertDeath(SIGSEGV);
2104 FinishIntercept(&intercept_result);
2105
2106 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2107
2108 std::string result;
2109 ConsumeFd(std::move(output_fd), &result);
2110 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2111}
Josh Gao76e1e302021-01-26 15:53:11 -08002112
Christopher Ferris22035cc2023-01-31 17:50:22 -08002113static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002114 std::string test_lib(testing::internal::GetArgvs()[0]);
2115 auto const value = test_lib.find_last_of('/');
2116 if (value == std::string::npos) {
2117 test_lib = "./";
2118 } else {
2119 test_lib = test_lib.substr(0, value + 1) + "./";
2120 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08002121 return test_lib + "libcrash_test.so";
2122}
2123
2124static void CreateEmbeddedLibrary(int out_fd) {
2125 std::string test_lib(GetTestLibraryPath());
2126 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2127 ASSERT_NE(fd.get(), -1);
2128 off_t file_size = lseek(fd, 0, SEEK_END);
2129 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2130 std::vector<uint8_t> contents(file_size);
2131 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2132
2133 // Put the shared library data at a pagesize() offset.
2134 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2135 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2136}
2137
2138TEST_F(CrasherTest, non_zero_offset_in_library) {
2139 int intercept_result;
2140 unique_fd output_fd;
2141 TemporaryFile tf;
2142 CreateEmbeddedLibrary(tf.fd);
2143 StartProcess([&tf]() {
2144 android_dlextinfo extinfo{};
2145 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2146 extinfo.library_fd = tf.fd;
2147 extinfo.library_fd_offset = 4 * getpagesize();
2148 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2149 if (handle == nullptr) {
2150 _exit(1);
2151 }
2152 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2153 if (crash_func == nullptr) {
2154 _exit(1);
2155 }
2156 crash_func();
2157 });
2158
2159 StartIntercept(&output_fd);
2160 FinishCrasher();
2161 AssertDeath(SIGSEGV);
2162 FinishIntercept(&intercept_result);
2163
2164 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2165
2166 std::string result;
2167 ConsumeFd(std::move(output_fd), &result);
2168
2169 // Verify the crash includes an offset value in the backtrace.
2170 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2171 tf.path, 4 * getpagesize());
2172 ASSERT_MATCH(result, match_str);
2173}
2174
2175static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2176 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002177
2178 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2179 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2180
2181 // Copy the shared so to a tempory directory.
2182 return system(cp_cmd.c_str()) == 0;
2183}
2184
2185TEST_F(CrasherTest, unreadable_elf) {
2186 int intercept_result;
2187 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002188 std::string tmp_so_name;
2189 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002190 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002191 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2192 _exit(1);
2193 }
2194 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2195 if (handle == nullptr) {
2196 _exit(1);
2197 }
2198 // Delete the original shared library so that we get the warning
2199 // about unreadable elf files.
2200 if (unlink(tmp_so_name.c_str()) == -1) {
2201 _exit(1);
2202 }
2203 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2204 if (crash_func == nullptr) {
2205 _exit(1);
2206 }
2207 crash_func();
2208 });
2209
2210 StartIntercept(&output_fd);
2211 FinishCrasher();
2212 AssertDeath(SIGSEGV);
2213 FinishIntercept(&intercept_result);
2214
2215 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2216
2217 std::string result;
2218 ConsumeFd(std::move(output_fd), &result);
2219 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002220 std::string match_str = "NOTE: " + tmp_so_name;
2221 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002222}
2223
Josh Gao76e1e302021-01-26 15:53:11 -08002224TEST(tombstoned, proto) {
2225 const pid_t self = getpid();
2226 unique_fd tombstoned_socket, text_fd, proto_fd;
2227 ASSERT_TRUE(
2228 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2229
2230 tombstoned_notify_completion(tombstoned_socket.get());
2231
2232 ASSERT_NE(-1, text_fd.get());
2233 ASSERT_NE(-1, proto_fd.get());
2234
2235 struct stat text_st;
2236 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2237
2238 // Give tombstoned some time to link the files into place.
2239 std::this_thread::sleep_for(100ms);
2240
2241 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08002242 std::optional<std::string> tombstone_file;
2243 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2244 ASSERT_TRUE(dir_h != nullptr);
2245 std::regex tombstone_re("tombstone_\\d+");
2246 dirent* entry;
2247 while ((entry = readdir(dir_h.get())) != nullptr) {
2248 if (!std::regex_match(entry->d_name, tombstone_re)) {
2249 continue;
2250 }
2251 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002252
2253 struct stat st;
2254 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2255 continue;
2256 }
2257
2258 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002259 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002260 break;
2261 }
2262 }
2263
Christopher Ferris35da2882021-02-17 15:39:06 -08002264 ASSERT_TRUE(tombstone_file);
2265 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002266
2267 struct stat proto_fd_st;
2268 struct stat proto_file_st;
2269 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2270 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2271
2272 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2273 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2274}
2275
2276TEST(tombstoned, proto_intercept) {
2277 const pid_t self = getpid();
2278 unique_fd intercept_fd, output_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002279
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002280 InterceptResponse response = {};
2281 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2282 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2283 << "Error message: " << response.error_message;
Josh Gao76e1e302021-01-26 15:53:11 -08002284
2285 unique_fd tombstoned_socket, text_fd, proto_fd;
2286 ASSERT_TRUE(
2287 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2288 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2289 tombstoned_notify_completion(tombstoned_socket.get());
2290
2291 text_fd.reset();
2292
2293 std::string output;
2294 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2295 ASSERT_EQ("foo", output);
2296}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002297
2298// Verify that when an intercept is present for the main thread, and the signal
2299// is received on a different thread, the intercept still works.
2300TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2301 StartProcess([]() {
2302 std::thread thread([]() {
2303 // Raise the signal on the side thread.
2304 raise_debugger_signal(kDebuggerdNativeBacktrace);
2305 });
2306 thread.join();
2307 _exit(0);
2308 });
2309
2310 unique_fd output_fd;
2311 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2312 FinishCrasher();
2313 AssertDeath(0);
2314
2315 int intercept_result;
2316 FinishIntercept(&intercept_result);
2317 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2318
2319 std::string result;
2320 ConsumeFd(std::move(output_fd), &result);
2321 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2322}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002323
2324static std::string format_pointer(uintptr_t ptr) {
2325#if defined(__LP64__)
2326 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2327 static_cast<uint32_t>(ptr & 0xffffffff));
2328#else
2329 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2330#endif
2331}
2332
2333static std::string format_pointer(void* ptr) {
2334 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2335}
2336
2337static std::string format_full_pointer(uintptr_t ptr) {
2338#if defined(__LP64__)
2339 return android::base::StringPrintf("%016" PRIx64, ptr);
2340#else
2341 return android::base::StringPrintf("%08x", ptr);
2342#endif
2343}
2344
2345static std::string format_full_pointer(void* ptr) {
2346 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2347}
2348
2349__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2350 int* crash_ptr = reinterpret_cast<int*>(ptr);
2351 *crash_ptr = 1;
2352 return *crash_ptr;
2353}
2354
2355// Verify that a fault address before the first map is properly handled.
2356TEST_F(CrasherTest, fault_address_before_first_map) {
2357 StartProcess([]() {
2358 ASSERT_EQ(0, crash_call(0x1024));
2359 _exit(0);
2360 });
2361
2362 unique_fd output_fd;
2363 StartIntercept(&output_fd);
2364 FinishCrasher();
2365 AssertDeath(SIGSEGV);
2366
2367 int intercept_result;
2368 FinishIntercept(&intercept_result);
2369 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2370
2371 std::string result;
2372 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002373 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002374
2375 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2376
2377 std::string match_str = android::base::StringPrintf(
2378 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2379 format_pointer(0x1024).c_str());
2380 ASSERT_MATCH(result, match_str);
2381}
2382
2383// Verify that a fault address after the last map is properly handled.
2384TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002385 // This makes assumptions about the memory layout that are not true in HWASan
2386 // processes.
2387 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002388 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2389 StartProcess([crash_uptr]() {
2390 ASSERT_EQ(0, crash_call(crash_uptr));
2391 _exit(0);
2392 });
2393
2394 unique_fd output_fd;
2395 StartIntercept(&output_fd);
2396 FinishCrasher();
2397 AssertDeath(SIGSEGV);
2398
2399 int intercept_result;
2400 FinishIntercept(&intercept_result);
2401 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2402
2403 std::string result;
2404 ConsumeFd(std::move(output_fd), &result);
2405
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002406 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2407 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002408 ASSERT_MATCH(result, match_str);
2409
2410 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2411
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002412 // Verifies that the fault address error message is at the end of the
2413 // maps section. To do this, the check below looks for the start of the
2414 // open files section or the start of the log file section. It's possible
2415 // for either of these sections to be present after the maps section right
2416 // now.
2417 // If the sections move around, this check might need to be modified.
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002418 match_str = android::base::StringPrintf(
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002419 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002420 format_pointer(crash_uptr).c_str());
2421 ASSERT_MATCH(result, match_str);
2422}
2423
2424// Verify that a fault address between maps is properly handled.
2425TEST_F(CrasherTest, fault_address_between_maps) {
2426 // Create a map before the fork so it will be present in the child.
2427 void* start_ptr =
2428 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2429 ASSERT_NE(MAP_FAILED, start_ptr);
2430 // Unmap the page in the middle.
2431 void* middle_ptr =
2432 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2433 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2434
2435 StartProcess([middle_ptr]() {
2436 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2437 _exit(0);
2438 });
2439
2440 // Unmap the two maps.
2441 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2442 void* end_ptr =
2443 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2444 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2445
2446 unique_fd output_fd;
2447 StartIntercept(&output_fd);
2448 FinishCrasher();
2449 AssertDeath(SIGSEGV);
2450
2451 int intercept_result;
2452 FinishIntercept(&intercept_result);
2453 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2454
2455 std::string result;
2456 ConsumeFd(std::move(output_fd), &result);
2457
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002458 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2459 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002460 ASSERT_MATCH(result, match_str);
2461
2462 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2463
2464 match_str = android::base::StringPrintf(
2465 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2466 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2467 format_pointer(end_ptr).c_str());
2468 ASSERT_MATCH(result, match_str);
2469}
2470
2471// Verify that a fault address happens in the correct map.
2472TEST_F(CrasherTest, fault_address_in_map) {
2473 // Create a map before the fork so it will be present in the child.
2474 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2475 ASSERT_NE(MAP_FAILED, ptr);
2476
2477 StartProcess([ptr]() {
2478 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2479 _exit(0);
2480 });
2481
2482 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2483
2484 unique_fd output_fd;
2485 StartIntercept(&output_fd);
2486 FinishCrasher();
2487 AssertDeath(SIGSEGV);
2488
2489 int intercept_result;
2490 FinishIntercept(&intercept_result);
2491 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2492
2493 std::string result;
2494 ConsumeFd(std::move(output_fd), &result);
2495
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002496 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2497 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002498 ASSERT_MATCH(result, match_str);
2499
2500 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2501
2502 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2503 ASSERT_MATCH(result, match_str);
2504}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002505
2506static constexpr uint32_t kDexData[] = {
2507 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2508 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2509 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2510 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2511 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2512 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2513 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2514 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2515 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2516 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2517 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2518 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2519 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2520 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2521 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2522 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2523 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2524};
2525
2526TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2527 StartProcess([]() {
2528 TemporaryDir td;
2529 std::string tmp_so_name;
2530 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2531 _exit(1);
2532 }
2533
2534 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2535 // move the library to which has a basename of libart.so.
2536 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2537 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2538 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2539 if (handle == nullptr) {
2540 _exit(1);
2541 }
2542
2543 void* ptr =
2544 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2545 ASSERT_TRUE(ptr != MAP_FAILED);
2546 memcpy(ptr, kDexData, sizeof(kDexData));
2547 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2548
2549 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2550 .symfile_size = sizeof(kDexData)};
2551
2552 JITDescriptor* dex_debug =
2553 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2554 ASSERT_TRUE(dex_debug != nullptr);
2555 dex_debug->version = 1;
2556 dex_debug->action_flag = 0;
2557 dex_debug->relevant_entry = 0;
2558 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2559
2560 // This sets the magic dex pc value for register 0, using the value
2561 // of register 1 + 0x102.
2562 asm(".cfi_escape "
2563 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2564 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2565 "0x13 /* DW_OP_drop */,"
2566 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2567
2568 // For each different architecture, set register one to the dex ptr mmap
2569 // created above. Then do a nullptr dereference to force a crash.
2570#if defined(__arm__)
2571 asm volatile(
2572 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002573 "mov r2, #0\n"
2574 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002575 : [base] "+r"(ptr)
2576 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002577 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002578#elif defined(__aarch64__)
2579 asm volatile(
2580 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002581 "mov x2, #0\n"
2582 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002583 : [base] "+r"(ptr)
2584 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002585 : "x1", "x2", "memory");
2586#elif defined(__riscv)
2587 // TODO: x1 is ra (the link register) on riscv64, so this might have
2588 // unintended consequences, but we'll need to change the .cfi_escape if so.
2589 asm volatile(
2590 "mv x1, %[base]\n"
2591 "sw zero, 0(zero)\n"
2592 : [base] "+r"(ptr)
2593 :
2594 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002595#elif defined(__i386__)
2596 asm volatile(
2597 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002598 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002599 : [base] "+r"(ptr)
2600 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002601 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002602#elif defined(__x86_64__)
2603 asm volatile(
2604 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002605 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002606 : [base] "+r"(ptr)
2607 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002608 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002609#else
2610#error "Unsupported architecture"
2611#endif
2612 _exit(0);
2613 });
2614
2615 unique_fd output_fd;
2616 StartIntercept(&output_fd);
2617 FinishCrasher();
2618 AssertDeath(SIGSEGV);
2619
2620 int intercept_result;
2621 FinishIntercept(&intercept_result);
2622 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2623
2624 std::string result;
2625 ConsumeFd(std::move(output_fd), &result);
2626
2627 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002628 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002629
2630 // Now verify that the dex_pc frame includes a proper function name.
2631 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2632}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002633
2634static std::string format_map_pointer(uintptr_t ptr) {
2635#if defined(__LP64__)
2636 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2637 static_cast<uint32_t>(ptr & 0xffffffff));
2638#else
2639 return android::base::StringPrintf("%08x", ptr);
2640#endif
2641}
2642
2643// Verify that map data is properly formatted.
2644TEST_F(CrasherTest, verify_map_format) {
2645 // Create multiple maps to make sure that the map data is formatted properly.
2646 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2647 ASSERT_NE(MAP_FAILED, none_map);
2648 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2649 ASSERT_NE(MAP_FAILED, r_map);
2650 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2651 ASSERT_NE(MAP_FAILED, w_map);
2652 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2653 ASSERT_NE(MAP_FAILED, x_map);
2654
2655 TemporaryFile tf;
2656 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2657 char c = 'f';
2658 ASSERT_EQ(1, write(tf.fd, &c, 1));
2659 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2660 ASSERT_EQ(1, write(tf.fd, &c, 1));
2661 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2662 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2663 ASSERT_NE(MAP_FAILED, file_map);
2664
2665 StartProcess([]() { abort(); });
2666
2667 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2668 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2669 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2670 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2671 ASSERT_EQ(0, munmap(file_map, 0x3001));
2672
2673 unique_fd output_fd;
2674 StartIntercept(&output_fd);
2675 FinishCrasher();
2676 AssertDeath(SIGABRT);
2677 int intercept_result;
2678 FinishIntercept(&intercept_result);
2679
2680 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2681
2682 std::string result;
2683 ConsumeFd(std::move(output_fd), &result);
2684
2685 std::string match_str;
2686 // Verify none.
2687 match_str = android::base::StringPrintf(
2688 " %s-%s --- 0 1000\\n",
2689 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2690 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2691 ASSERT_MATCH(result, match_str);
2692
2693 // Verify read-only.
2694 match_str = android::base::StringPrintf(
2695 " %s-%s r-- 0 1000\\n",
2696 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2697 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2698 ASSERT_MATCH(result, match_str);
2699
2700 // Verify write-only.
2701 match_str = android::base::StringPrintf(
2702 " %s-%s -w- 0 1000\\n",
2703 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2704 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2705 ASSERT_MATCH(result, match_str);
2706
2707 // Verify exec-only.
2708 match_str = android::base::StringPrintf(
2709 " %s-%s --x 0 1000\\n",
2710 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2711 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2712 ASSERT_MATCH(result, match_str);
2713
2714 // Verify file map with non-zero offset and a name.
2715 match_str = android::base::StringPrintf(
2716 " %s-%s r-- 2000 4000 %s\\n",
2717 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2718 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2719 ASSERT_MATCH(result, match_str);
2720}
2721
2722// Verify that the tombstone map data is correct.
2723TEST_F(CrasherTest, verify_header) {
2724 StartProcess([]() { abort(); });
2725
2726 unique_fd output_fd;
2727 StartIntercept(&output_fd);
2728 FinishCrasher();
2729 AssertDeath(SIGABRT);
2730 int intercept_result;
2731 FinishIntercept(&intercept_result);
2732
2733 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2734
2735 std::string result;
2736 ConsumeFd(std::move(output_fd), &result);
2737
2738 std::string match_str = android::base::StringPrintf(
2739 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2740 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2741 android::base::GetProperty("ro.revision", "unknown").c_str());
2742 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2743 ASSERT_MATCH(result, match_str);
2744}
2745
2746// Verify that the thread header is formatted properly.
2747TEST_F(CrasherTest, verify_thread_header) {
2748 void* shared_map =
2749 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2750 ASSERT_NE(MAP_FAILED, shared_map);
2751 memset(shared_map, 0, sizeof(pid_t));
2752
2753 StartProcess([&shared_map]() {
2754 std::atomic_bool tid_written;
2755 std::thread thread([&tid_written, &shared_map]() {
2756 pid_t tid = gettid();
2757 memcpy(shared_map, &tid, sizeof(pid_t));
2758 tid_written = true;
2759 volatile bool done = false;
2760 while (!done)
2761 ;
2762 });
2763 thread.detach();
2764 while (!tid_written.load(std::memory_order_acquire))
2765 ;
2766 abort();
2767 });
2768
2769 pid_t primary_pid = crasher_pid;
2770
2771 unique_fd output_fd;
2772 StartIntercept(&output_fd);
2773 FinishCrasher();
2774 AssertDeath(SIGABRT);
2775 int intercept_result;
2776 FinishIntercept(&intercept_result);
2777 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2778
2779 // Read the tid data out.
2780 pid_t tid;
2781 memcpy(&tid, shared_map, sizeof(pid_t));
2782 ASSERT_NE(0, tid);
2783
2784 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2785
2786 std::string result;
2787 ConsumeFd(std::move(output_fd), &result);
2788
2789 // Verify that there are two headers, one where the tid is "primary_pid"
2790 // and the other where the tid is "tid".
2791 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2792 primary_pid, primary_pid);
2793 ASSERT_MATCH(result, match_str);
2794
2795 match_str =
2796 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2797 ASSERT_MATCH(result, match_str);
2798}
2799
2800// Verify that there is a BuildID present in the map section and set properly.
2801TEST_F(CrasherTest, verify_build_id) {
2802 StartProcess([]() { abort(); });
2803
2804 unique_fd output_fd;
2805 StartIntercept(&output_fd);
2806 FinishCrasher();
2807 AssertDeath(SIGABRT);
2808 int intercept_result;
2809 FinishIntercept(&intercept_result);
2810 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2811
2812 std::string result;
2813 ConsumeFd(std::move(output_fd), &result);
2814
2815 // Find every /system or /apex lib and verify the BuildID is displayed
2816 // properly.
2817 bool found_valid_elf = false;
2818 std::smatch match;
2819 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2820 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2821 result = match.suffix()) {
2822 if (prev_file == match[1]) {
2823 // Already checked this file.
2824 continue;
2825 }
2826
2827 prev_file = match[1];
Christopher Ferris15038902023-11-10 00:05:49 -08002828 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
2829 unwindstack::Elf elf(elf_memory);
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002830 if (!elf.Init() || !elf.valid()) {
2831 // Skipping invalid elf files.
2832 continue;
2833 }
2834 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2835
2836 found_valid_elf = true;
2837 }
2838 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2839}
Christopher Ferrisbda10642023-04-24 18:14:53 -07002840
2841const char kLogMessage[] = "Should not see this log message.";
2842
2843// Verify that the logd process does not read the log.
2844TEST_F(CrasherTest, logd_skips_reading_logs) {
2845 StartProcess([]() {
2846 pthread_setname_np(pthread_self(), "logd");
2847 LOG(INFO) << kLogMessage;
2848 abort();
2849 });
2850
2851 unique_fd output_fd;
2852 StartIntercept(&output_fd);
2853 FinishCrasher();
2854 AssertDeath(SIGABRT);
2855 int intercept_result;
2856 FinishIntercept(&intercept_result);
2857 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2858
2859 std::string result;
2860 ConsumeFd(std::move(output_fd), &result);
2861 // logd should not contain our log message.
2862 ASSERT_NOT_MATCH(result, kLogMessage);
2863}
2864
2865// Verify that the logd process does not read the log when the non-main
2866// thread crashes.
2867TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
2868 StartProcess([]() {
2869 pthread_setname_np(pthread_self(), "logd");
2870 LOG(INFO) << kLogMessage;
2871
2872 std::thread thread([]() {
2873 pthread_setname_np(pthread_self(), "not_logd_thread");
2874 // Raise the signal on the side thread.
2875 raise_debugger_signal(kDebuggerdTombstone);
2876 });
2877 thread.join();
2878 _exit(0);
2879 });
2880
2881 unique_fd output_fd;
2882 StartIntercept(&output_fd, kDebuggerdTombstone);
2883 FinishCrasher();
2884 AssertDeath(0);
2885
2886 int intercept_result;
2887 FinishIntercept(&intercept_result);
2888 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2889
2890 std::string result;
2891 ConsumeFd(std::move(output_fd), &result);
2892 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2893 ASSERT_NOT_MATCH(result, kLogMessage);
2894}
Christopher Ferris98d62422023-05-24 20:01:10 +00002895
2896// Disable this test since there is a high liklihood that this would
2897// be flaky since it requires 500 messages being in the log.
2898TEST_F(CrasherTest, DISABLED_max_log_messages) {
2899 StartProcess([]() {
2900 for (size_t i = 0; i < 600; i++) {
2901 LOG(INFO) << "Message number " << i;
2902 }
2903 abort();
2904 });
2905
2906 unique_fd output_fd;
2907 StartIntercept(&output_fd);
2908 FinishCrasher();
2909 AssertDeath(SIGABRT);
2910 int intercept_result;
2911 FinishIntercept(&intercept_result);
2912 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2913
2914 std::string result;
2915 ConsumeFd(std::move(output_fd), &result);
2916 ASSERT_NOT_MATCH(result, "Message number 99");
2917 ASSERT_MATCH(result, "Message number 100");
2918 ASSERT_MATCH(result, "Message number 599");
2919}
2920
2921TEST_F(CrasherTest, log_with_newline) {
2922 StartProcess([]() {
2923 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
2924 abort();
2925 });
2926
2927 unique_fd output_fd;
2928 StartIntercept(&output_fd);
2929 FinishCrasher();
2930 AssertDeath(SIGABRT);
2931 int intercept_result;
2932 FinishIntercept(&intercept_result);
2933 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2934
2935 std::string result;
2936 ConsumeFd(std::move(output_fd), &result);
2937 ASSERT_MATCH(result, ":\\s*This line has a newline.");
2938 ASSERT_MATCH(result, ":\\s*This is on the next line.");
2939}