blob: 194676aa4c13277cfa3ebb1dd1f226cae197af32 [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
Florian Mayer5fa66632024-02-07 16:42:23 -0800942static char g_crash_detail_value_changes[] = "crash_detail_value";
943static char g_crash_detail_value[] = "crash_detail_value";
944static char g_crash_detail_value2[] = "crash_detail_value2";
945
946inline crash_detail_t* _Nullable android_register_crash_detail_strs(const char* _Nonnull name,
947 const char* _Nonnull data) {
948 return android_register_crash_detail(name, strlen(name), data, strlen(data));
949}
950
951TEST_F(CrasherTest, crash_detail_single) {
952 int intercept_result;
953 unique_fd output_fd;
954 StartProcess([]() {
955 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
956 abort();
957 });
958 StartIntercept(&output_fd);
959 FinishCrasher();
960 AssertDeath(SIGABRT);
961 FinishIntercept(&intercept_result);
962
963 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
964
965 std::string result;
966 ConsumeFd(std::move(output_fd), &result);
967 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
968}
969
Florian Mayeraced3aa2024-02-13 13:44:50 -0800970TEST_F(CrasherTest, crash_detail_replace_data) {
971 int intercept_result;
972 unique_fd output_fd;
973 StartProcess([]() {
974 auto *cd = android_register_crash_detail_strs("CRASH_DETAIL_NAME", "original_data");
975 android_replace_crash_detail_data(cd, "new_data", strlen("new_data"));
976 abort();
977 });
978 StartIntercept(&output_fd);
979 FinishCrasher();
980 AssertDeath(SIGABRT);
981 FinishIntercept(&intercept_result);
982
983 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
984
985 std::string result;
986 ConsumeFd(std::move(output_fd), &result);
987 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'new_data')");
988 // Ensure the old one no longer shows up, i.e. that we actually replaced
989 // it, not added a new one.
990 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'original_data')");
991}
992
993TEST_F(CrasherTest, crash_detail_replace_name) {
994 int intercept_result;
995 unique_fd output_fd;
996 StartProcess([]() {
997 auto *cd = android_register_crash_detail_strs("old_name", g_crash_detail_value);
998 android_replace_crash_detail_name(cd, "new_name", strlen("new_name"));
999 abort();
1000 });
1001 StartIntercept(&output_fd);
1002 FinishCrasher();
1003 AssertDeath(SIGABRT);
1004 FinishIntercept(&intercept_result);
1005
1006 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1007
1008 std::string result;
1009 ConsumeFd(std::move(output_fd), &result);
1010 ASSERT_MATCH(result, R"(new_name: 'crash_detail_value')");
1011 // Ensure the old one no longer shows up, i.e. that we actually replaced
1012 // it, not added a new one.
1013 ASSERT_NOT_MATCH(result, R"(old_name: 'crash_detail_value')");
1014}
1015
Florian Mayer5fa66632024-02-07 16:42:23 -08001016TEST_F(CrasherTest, crash_detail_single_byte_name) {
1017 int intercept_result;
1018 unique_fd output_fd;
1019 StartProcess([]() {
1020 android_register_crash_detail_strs("CRASH_DETAIL_NAME\1", g_crash_detail_value);
1021 abort();
1022 });
1023 StartIntercept(&output_fd);
1024 FinishCrasher();
1025 AssertDeath(SIGABRT);
1026 FinishIntercept(&intercept_result);
1027
1028 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1029
1030 std::string result;
1031 ConsumeFd(std::move(output_fd), &result);
1032 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME\\1: 'crash_detail_value')");
1033}
1034
1035
1036TEST_F(CrasherTest, crash_detail_single_bytes) {
1037 int intercept_result;
1038 unique_fd output_fd;
1039 StartProcess([]() {
1040 android_register_crash_detail("CRASH_DETAIL_NAME", strlen("CRASH_DETAIL_NAME"), "\1",
1041 sizeof("\1"));
1042 abort();
1043 });
1044 StartIntercept(&output_fd);
1045 FinishCrasher();
1046 AssertDeath(SIGABRT);
1047 FinishIntercept(&intercept_result);
1048
1049 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1050
1051 std::string result;
1052 ConsumeFd(std::move(output_fd), &result);
1053 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: '\\1\\0')");
1054}
1055
1056TEST_F(CrasherTest, crash_detail_mixed) {
1057 int intercept_result;
1058 unique_fd output_fd;
1059 StartProcess([]() {
1060 const char data[] = "helloworld\1\255\3";
1061 android_register_crash_detail_strs("CRASH_DETAIL_NAME", data);
1062 abort();
1063 });
1064 StartIntercept(&output_fd);
1065 FinishCrasher();
1066 AssertDeath(SIGABRT);
1067 FinishIntercept(&intercept_result);
1068
1069 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1070
1071 std::string result;
1072 ConsumeFd(std::move(output_fd), &result);
1073 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'helloworld\\1\\255\\3')");
1074}
1075
1076TEST_F(CrasherTest, crash_detail_many) {
1077 int intercept_result;
1078 unique_fd output_fd;
1079 StartProcess([]() {
1080 for (int i = 0; i < 1000; ++i) {
1081 std::string name = "CRASH_DETAIL_NAME" + std::to_string(i);
1082 std::string value = "CRASH_DETAIL_VALUE" + std::to_string(i);
1083 auto* h = android_register_crash_detail_strs(name.data(), value.data());
1084 android_unregister_crash_detail(h);
1085 }
1086
1087 android_register_crash_detail_strs("FINAL_NAME", "FINAL_VALUE");
1088 android_register_crash_detail_strs("FINAL_NAME2", "FINAL_VALUE2");
1089 abort();
1090 });
1091 StartIntercept(&output_fd);
1092 FinishCrasher();
1093 AssertDeath(SIGABRT);
1094 FinishIntercept(&intercept_result);
1095
1096 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1097
1098 std::string result;
1099 ConsumeFd(std::move(output_fd), &result);
1100 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_NAME");
1101 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_VALUE");
1102 ASSERT_MATCH(result, R"(FINAL_NAME: 'FINAL_VALUE')");
1103 ASSERT_MATCH(result, R"(FINAL_NAME2: 'FINAL_VALUE2')");
1104}
1105
1106TEST_F(CrasherTest, crash_detail_single_changes) {
1107 int intercept_result;
1108 unique_fd output_fd;
1109 StartProcess([]() {
1110 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value_changes);
1111 g_crash_detail_value_changes[0] = 'C';
1112 abort();
1113 });
1114 StartIntercept(&output_fd);
1115 FinishCrasher();
1116 AssertDeath(SIGABRT);
1117 FinishIntercept(&intercept_result);
1118
1119 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1120
1121 std::string result;
1122 ConsumeFd(std::move(output_fd), &result);
1123 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'Crash_detail_value')");
1124}
1125
1126TEST_F(CrasherTest, crash_detail_multiple) {
1127 int intercept_result;
1128 unique_fd output_fd;
1129 StartProcess([]() {
1130 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1131 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1132 abort();
1133 });
1134 StartIntercept(&output_fd);
1135 FinishCrasher();
1136 AssertDeath(SIGABRT);
1137 FinishIntercept(&intercept_result);
1138
1139 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1140
1141 std::string result;
1142 ConsumeFd(std::move(output_fd), &result);
1143 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1144 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1145}
1146
1147TEST_F(CrasherTest, crash_detail_remove) {
1148 int intercept_result;
1149 unique_fd output_fd;
1150 StartProcess([]() {
1151 auto* detail1 = android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1152 android_unregister_crash_detail(detail1);
1153 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1154 abort();
1155 });
1156 StartIntercept(&output_fd);
1157 FinishCrasher();
1158 AssertDeath(SIGABRT);
1159 FinishIntercept(&intercept_result);
1160
1161 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1162
1163 std::string result;
1164 ConsumeFd(std::move(output_fd), &result);
1165 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1166 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1167}
1168
Christopher Ferrise8891452021-08-17 17:34:53 -07001169TEST_F(CrasherTest, abort_message_newline_trimmed) {
1170 int intercept_result;
1171 unique_fd output_fd;
1172 StartProcess([]() {
1173 android_set_abort_message("Message with a newline.\n");
1174 abort();
1175 });
1176 StartIntercept(&output_fd);
1177 FinishCrasher();
1178 AssertDeath(SIGABRT);
1179 FinishIntercept(&intercept_result);
1180
1181 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1182
1183 std::string result;
1184 ConsumeFd(std::move(output_fd), &result);
1185 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1186}
1187
1188TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1189 int intercept_result;
1190 unique_fd output_fd;
1191 StartProcess([]() {
1192 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1193 abort();
1194 });
1195 StartIntercept(&output_fd);
1196 FinishCrasher();
1197 AssertDeath(SIGABRT);
1198 FinishIntercept(&intercept_result);
1199
1200 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1201
1202 std::string result;
1203 ConsumeFd(std::move(output_fd), &result);
1204 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1205}
1206
Josh Gaoe06f2a42017-04-27 16:50:38 -07001207TEST_F(CrasherTest, abort_message_backtrace) {
1208 int intercept_result;
1209 unique_fd output_fd;
1210 StartProcess([]() {
1211 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001212 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001213 exit(0);
1214 });
1215 StartIntercept(&output_fd);
1216 FinishCrasher();
1217 AssertDeath(0);
1218 FinishIntercept(&intercept_result);
1219
1220 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1221
1222 std::string result;
1223 ConsumeFd(std::move(output_fd), &result);
1224 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1225}
1226
Josh Gaocbe70cb2016-10-18 18:17:52 -07001227TEST_F(CrasherTest, intercept_timeout) {
1228 int intercept_result;
1229 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001230 StartProcess([]() {
1231 abort();
1232 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001233 StartIntercept(&output_fd);
1234
1235 // Don't let crasher finish until we timeout.
1236 FinishIntercept(&intercept_result);
1237
1238 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1239 << intercept_result << ")";
1240
1241 FinishCrasher();
1242 AssertDeath(SIGABRT);
1243}
1244
Elliott Hughese4781d52021-03-17 09:15:15 -07001245TEST_F(CrasherTest, wait_for_debugger) {
1246 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1247 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001248 }
1249 sleep(1);
1250
Josh Gao502cfd22017-02-17 01:39:15 -08001251 StartProcess([]() {
1252 abort();
1253 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001254 FinishCrasher();
1255
1256 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001257 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001258 ASSERT_TRUE(WIFSTOPPED(status));
1259 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1260
1261 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1262
1263 AssertDeath(SIGABRT);
1264}
1265
Josh Gaocbe70cb2016-10-18 18:17:52 -07001266TEST_F(CrasherTest, backtrace) {
1267 std::string result;
1268 int intercept_result;
1269 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001270
1271 StartProcess([]() {
1272 abort();
1273 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001274 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001275
1276 std::this_thread::sleep_for(500ms);
1277
1278 sigval val;
1279 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001280 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001281 FinishIntercept(&intercept_result);
1282 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1283 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001284 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001285
1286 int status;
1287 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1288
1289 StartIntercept(&output_fd);
1290 FinishCrasher();
1291 AssertDeath(SIGABRT);
1292 FinishIntercept(&intercept_result);
1293 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1294 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001295 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001296}
Josh Gaofca7ca32017-01-23 12:05:35 -08001297
1298TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001299 int intercept_result;
1300 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001301 StartProcess([]() {
1302 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001303 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001304 });
Josh Gao502cfd22017-02-17 01:39:15 -08001305
1306 StartIntercept(&output_fd);
1307 FinishCrasher();
1308 AssertDeath(SIGABRT);
1309 FinishIntercept(&intercept_result);
1310
1311 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1312
1313 std::string result;
1314 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001315 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001316}
1317
Josh Gao502cfd22017-02-17 01:39:15 -08001318TEST_F(CrasherTest, capabilities) {
1319 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1320
Josh Gaofca7ca32017-01-23 12:05:35 -08001321 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001322 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1323 err(1, "failed to set PR_SET_KEEPCAPS");
1324 }
1325
1326 if (setresuid(1, 1, 1) != 0) {
1327 err(1, "setresuid failed");
1328 }
1329
1330 __user_cap_header_struct capheader;
1331 __user_cap_data_struct capdata[2];
1332 memset(&capheader, 0, sizeof(capheader));
1333 memset(&capdata, 0, sizeof(capdata));
1334
1335 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1336 capheader.pid = 0;
1337
1338 // Turn on every third capability.
1339 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1340 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1341 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1342 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1343 }
1344
1345 // Make sure CAP_SYS_PTRACE is off.
1346 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1347 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1348
1349 if (capset(&capheader, &capdata[0]) != 0) {
1350 err(1, "capset failed");
1351 }
1352
1353 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1354 err(1, "failed to drop ambient capabilities");
1355 }
1356
Josh Gaoa5199a92017-04-03 13:18:34 -07001357 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001358 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001359 });
Josh Gao502cfd22017-02-17 01:39:15 -08001360
1361 unique_fd output_fd;
1362 StartIntercept(&output_fd);
1363 FinishCrasher();
1364 AssertDeath(SIGSYS);
1365
1366 std::string result;
1367 int intercept_result;
1368 FinishIntercept(&intercept_result);
1369 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1370 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001371 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001372 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001373}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001374
Josh Gao2e7b8e22017-05-04 17:12:57 -07001375TEST_F(CrasherTest, fake_pid) {
1376 int intercept_result;
1377 unique_fd output_fd;
1378
1379 // Prime the getpid/gettid caches.
1380 UNUSED(getpid());
1381 UNUSED(gettid());
1382
1383 std::function<pid_t()> clone_fn = []() {
1384 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1385 };
1386 StartProcess(
1387 []() {
1388 ASSERT_NE(getpid(), syscall(__NR_getpid));
1389 ASSERT_NE(gettid(), syscall(__NR_gettid));
1390 raise(SIGSEGV);
1391 },
1392 clone_fn);
1393
1394 StartIntercept(&output_fd);
1395 FinishCrasher();
1396 AssertDeath(SIGSEGV);
1397 FinishIntercept(&intercept_result);
1398
1399 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1400
1401 std::string result;
1402 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001403 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001404}
1405
Josh Gaoe04ca272018-01-16 15:38:17 -08001406static const char* const kDebuggerdSeccompPolicy =
1407 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1408
Mitch Phillips18ce5422023-01-19 14:23:49 -08001409static void setup_jail(minijail* jail) {
1410 if (!jail) {
1411 LOG(FATAL) << "failed to create minijail";
1412 }
1413
Josh Gao6f9eeec2018-09-12 13:55:47 -07001414 std::string policy;
1415 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1416 PLOG(FATAL) << "failed to read policy file";
1417 }
1418
1419 // Allow a bunch of syscalls used by the tests.
1420 policy += "\nclone: 1";
1421 policy += "\nsigaltstack: 1";
1422 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001423 policy += "\ngetrlimit: 1";
1424 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001425
1426 FILE* tmp_file = tmpfile();
1427 if (!tmp_file) {
1428 PLOG(FATAL) << "tmpfile failed";
1429 }
1430
Christopher Ferris172b0a02019-09-18 17:48:30 -07001431 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001432 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1433 PLOG(FATAL) << "failed to write policy to tmpfile";
1434 }
1435
1436 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1437 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001438 }
1439
Mitch Phillips18ce5422023-01-19 14:23:49 -08001440 minijail_no_new_privs(jail);
1441 minijail_log_seccomp_filter_failures(jail);
1442 minijail_use_seccomp_filter(jail);
1443 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1444}
Josh Gaoe04ca272018-01-16 15:38:17 -08001445
Mitch Phillips18ce5422023-01-19 14:23:49 -08001446static pid_t seccomp_fork_impl(void (*prejail)()) {
1447 ScopedMinijail jail{minijail_new()};
1448 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001449
1450 pid_t result = fork();
1451 if (result == -1) {
1452 return result;
1453 } else if (result != 0) {
1454 return result;
1455 }
1456
1457 // Spawn and detach a thread that spins forever.
1458 std::atomic<bool> thread_ready(false);
1459 std::thread thread([&jail, &thread_ready]() {
1460 minijail_enter(jail.get());
1461 thread_ready = true;
1462 for (;;)
1463 ;
1464 });
1465 thread.detach();
1466
1467 while (!thread_ready) {
1468 continue;
1469 }
1470
Josh Gao70adac62018-02-22 11:38:33 -08001471 if (prejail) {
1472 prejail();
1473 }
1474
Josh Gaoe04ca272018-01-16 15:38:17 -08001475 minijail_enter(jail.get());
1476 return result;
1477}
1478
Josh Gao70adac62018-02-22 11:38:33 -08001479static pid_t seccomp_fork() {
1480 return seccomp_fork_impl(nullptr);
1481}
1482
Josh Gaoe04ca272018-01-16 15:38:17 -08001483TEST_F(CrasherTest, seccomp_crash) {
1484 int intercept_result;
1485 unique_fd output_fd;
1486
1487 StartProcess([]() { abort(); }, &seccomp_fork);
1488
1489 StartIntercept(&output_fd);
1490 FinishCrasher();
1491 AssertDeath(SIGABRT);
1492 FinishIntercept(&intercept_result);
1493 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1494
1495 std::string result;
1496 ConsumeFd(std::move(output_fd), &result);
1497 ASSERT_BACKTRACE_FRAME(result, "abort");
1498}
1499
Josh Gao70adac62018-02-22 11:38:33 -08001500static pid_t seccomp_fork_rlimit() {
1501 return seccomp_fork_impl([]() {
1502 struct rlimit rlim = {
1503 .rlim_cur = 512 * 1024 * 1024,
1504 .rlim_max = 512 * 1024 * 1024,
1505 };
1506
1507 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1508 raise(SIGINT);
1509 }
1510 });
1511}
1512
1513TEST_F(CrasherTest, seccomp_crash_oom) {
1514 int intercept_result;
1515 unique_fd output_fd;
1516
1517 StartProcess(
1518 []() {
1519 std::vector<void*> vec;
1520 for (int i = 0; i < 512; ++i) {
1521 char* buf = static_cast<char*>(malloc(1024 * 1024));
1522 if (!buf) {
1523 abort();
1524 }
1525 memset(buf, 0xff, 1024 * 1024);
1526 vec.push_back(buf);
1527 }
1528 },
1529 &seccomp_fork_rlimit);
1530
1531 StartIntercept(&output_fd);
1532 FinishCrasher();
1533 AssertDeath(SIGABRT);
1534 FinishIntercept(&intercept_result);
1535 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1536
1537 // We can't actually generate a backtrace, just make sure that the process terminates.
1538}
1539
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001540__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001541 siginfo_t siginfo;
1542 siginfo.si_code = SI_QUEUE;
1543 siginfo.si_pid = getpid();
1544 siginfo.si_uid = getuid();
1545
1546 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1547 PLOG(FATAL) << "invalid dump type";
1548 }
1549
1550 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1551
Josh Gaoa48b41b2019-12-13 14:11:04 -08001552 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001553 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1554 return false;
1555 }
1556
1557 return true;
1558}
1559
Christopher Ferrisb999b822022-02-09 17:57:21 -08001560extern "C" void foo() {
1561 LOG(INFO) << "foo";
1562 std::this_thread::sleep_for(1s);
1563}
1564
1565extern "C" void bar() {
1566 LOG(INFO) << "bar";
1567 std::this_thread::sleep_for(1s);
1568}
1569
Josh Gaoe04ca272018-01-16 15:38:17 -08001570TEST_F(CrasherTest, seccomp_tombstone) {
1571 int intercept_result;
1572 unique_fd output_fd;
1573
1574 static const auto dump_type = kDebuggerdTombstone;
1575 StartProcess(
1576 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001577 std::thread a(foo);
1578 std::thread b(bar);
1579
1580 std::this_thread::sleep_for(100ms);
1581
Josh Gaoe04ca272018-01-16 15:38:17 -08001582 raise_debugger_signal(dump_type);
1583 _exit(0);
1584 },
1585 &seccomp_fork);
1586
1587 StartIntercept(&output_fd, dump_type);
1588 FinishCrasher();
1589 AssertDeath(0);
1590 FinishIntercept(&intercept_result);
1591 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1592
1593 std::string result;
1594 ConsumeFd(std::move(output_fd), &result);
1595 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001596 ASSERT_BACKTRACE_FRAME(result, "foo");
1597 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001598}
1599
Christopher Ferris303c6be2022-05-24 17:08:33 -07001600TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1601 int intercept_result;
1602 unique_fd output_fd;
1603
1604 static const auto dump_type = kDebuggerdTombstone;
1605 StartProcess(
1606 []() {
1607 std::thread abort_thread([] { abort(); });
1608 abort_thread.join();
1609 },
1610 &seccomp_fork);
1611
1612 StartIntercept(&output_fd, dump_type);
1613 FinishCrasher();
1614 AssertDeath(SIGABRT);
1615 FinishIntercept(&intercept_result);
1616 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1617
1618 std::string result;
1619 ConsumeFd(std::move(output_fd), &result);
1620 ASSERT_BACKTRACE_FRAME(result, "abort");
1621}
1622
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001623TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1624 int intercept_result;
1625 unique_fd output_fd;
1626
1627 static const auto dump_type = kDebuggerdTombstone;
1628 StartProcess(
1629 []() {
1630 std::thread a(foo);
1631 std::thread b(bar);
1632
1633 std::this_thread::sleep_for(100ms);
1634
1635 std::thread abort_thread([] { abort(); });
1636 abort_thread.join();
1637 },
1638 &seccomp_fork);
1639
1640 StartIntercept(&output_fd, dump_type);
1641 FinishCrasher();
1642 AssertDeath(SIGABRT);
1643 FinishIntercept(&intercept_result);
1644 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1645
1646 std::string result;
1647 ConsumeFd(std::move(output_fd), &result);
1648 ASSERT_BACKTRACE_FRAME(result, "abort");
1649 ASSERT_BACKTRACE_FRAME(result, "foo");
1650 ASSERT_BACKTRACE_FRAME(result, "bar");
1651 ASSERT_BACKTRACE_FRAME(result, "main");
1652}
1653
Josh Gaoe04ca272018-01-16 15:38:17 -08001654TEST_F(CrasherTest, seccomp_backtrace) {
1655 int intercept_result;
1656 unique_fd output_fd;
1657
1658 static const auto dump_type = kDebuggerdNativeBacktrace;
1659 StartProcess(
1660 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001661 std::thread a(foo);
1662 std::thread b(bar);
1663
1664 std::this_thread::sleep_for(100ms);
1665
Josh Gaoe04ca272018-01-16 15:38:17 -08001666 raise_debugger_signal(dump_type);
1667 _exit(0);
1668 },
1669 &seccomp_fork);
1670
1671 StartIntercept(&output_fd, dump_type);
1672 FinishCrasher();
1673 AssertDeath(0);
1674 FinishIntercept(&intercept_result);
1675 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1676
1677 std::string result;
1678 ConsumeFd(std::move(output_fd), &result);
1679 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001680 ASSERT_BACKTRACE_FRAME(result, "foo");
1681 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001682}
1683
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001684TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1685 int intercept_result;
1686 unique_fd output_fd;
1687
1688 static const auto dump_type = kDebuggerdNativeBacktrace;
1689 StartProcess(
1690 []() {
1691 std::thread a(foo);
1692 std::thread b(bar);
1693
1694 std::this_thread::sleep_for(100ms);
1695
1696 std::thread raise_thread([] {
1697 raise_debugger_signal(dump_type);
1698 _exit(0);
1699 });
1700 raise_thread.join();
1701 },
1702 &seccomp_fork);
1703
1704 StartIntercept(&output_fd, dump_type);
1705 FinishCrasher();
1706 AssertDeath(0);
1707 FinishIntercept(&intercept_result);
1708 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1709
1710 std::string result;
1711 ConsumeFd(std::move(output_fd), &result);
1712 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1713 ASSERT_BACKTRACE_FRAME(result, "foo");
1714 ASSERT_BACKTRACE_FRAME(result, "bar");
1715 ASSERT_BACKTRACE_FRAME(result, "main");
1716}
1717
Josh Gaoe04ca272018-01-16 15:38:17 -08001718TEST_F(CrasherTest, seccomp_crash_logcat) {
1719 StartProcess([]() { abort(); }, &seccomp_fork);
1720 FinishCrasher();
1721
1722 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1723 AssertDeath(SIGABRT);
1724}
1725
Josh Gaofd13bf02017-08-18 15:37:26 -07001726TEST_F(CrasherTest, competing_tracer) {
1727 int intercept_result;
1728 unique_fd output_fd;
1729 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001730 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001731 });
1732
1733 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001734
1735 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001736 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001737
1738 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001739 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001740 ASSERT_TRUE(WIFSTOPPED(status));
1741 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1742
1743 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1744 FinishIntercept(&intercept_result);
1745 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1746
1747 std::string result;
1748 ConsumeFd(std::move(output_fd), &result);
1749 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1750 regex += std::to_string(gettid());
1751 regex += R"( \(.+debuggerd_test)";
1752 ASSERT_MATCH(result, regex.c_str());
1753
Christopher Ferris172b0a02019-09-18 17:48:30 -07001754 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001755 ASSERT_TRUE(WIFSTOPPED(status));
1756 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1757
Josh Gaofd13bf02017-08-18 15:37:26 -07001758 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1759 AssertDeath(SIGABRT);
1760}
1761
Mitch Phillips18ce5422023-01-19 14:23:49 -08001762struct GwpAsanTestParameters {
1763 size_t alloc_size;
1764 bool free_before_access;
1765 int access_offset;
1766 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1767};
1768
1769struct GwpAsanCrasherTest
1770 : CrasherTest,
1771 testing::WithParamInterface<
1772 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1773
1774GwpAsanTestParameters gwp_asan_tests[] = {
1775 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1776 "Use After Free, 0 bytes into a 7-byte allocation"},
1777 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1778 "Use After Free, 1 byte into a 15-byte allocation"},
1779 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1780 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1781 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1782 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1783};
1784
1785INSTANTIATE_TEST_SUITE_P(
1786 GwpAsanTests, GwpAsanCrasherTest,
1787 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1788 /* recoverable */ testing::Bool(),
1789 /* seccomp */ testing::Bool()),
1790 [](const testing::TestParamInfo<
1791 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1792 const GwpAsanTestParameters& params = std::get<0>(info.param);
1793 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1794 name += testing::PrintToString(params.alloc_size);
1795 name += "Alloc";
1796 if (params.access_offset < 0) {
1797 name += "Left";
1798 name += testing::PrintToString(params.access_offset * -1);
1799 } else {
1800 name += "Right";
1801 name += testing::PrintToString(params.access_offset);
1802 }
1803 name += "Bytes";
1804 if (std::get<1>(info.param)) name += "Recoverable";
1805 if (std::get<2>(info.param)) name += "Seccomp";
1806 return name;
1807 });
1808
1809TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1810 if (mte_supported()) {
1811 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1812 // instead of GWP-ASan.
1813 GTEST_SKIP() << "Skipped on MTE.";
1814 }
1815 // Skip this test on HWASan, which will reliably catch test errors as well.
1816 SKIP_WITH_HWASAN;
1817
1818 GwpAsanTestParameters params = std::get<0>(GetParam());
1819 bool recoverable = std::get<1>(GetParam());
1820 LogcatCollector logcat_collector;
1821
1822 int intercept_result;
1823 unique_fd output_fd;
1824 StartProcess([&recoverable]() {
1825 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1826 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1827 if (recoverable) {
1828 env[3] = "GWP_ASAN_RECOVERABLE=true";
1829 }
1830 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1831 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1832 "DISABLED_run_gwp_asan_test");
1833 std::string test_filter = "--gtest_filter=*";
1834 test_filter += test_name;
1835 std::string this_binary = android::base::GetExecutablePath();
1836 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1837 test_filter.c_str(), nullptr};
1838 // We check the crash report from a debuggerd handler and from logcat. The
1839 // echo from stdout/stderr of the subprocess trips up atest, because it
1840 // doesn't like that two tests started in a row without the first one
1841 // finishing (even though the second one is in a subprocess).
1842 close(STDOUT_FILENO);
1843 close(STDERR_FILENO);
1844 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1845 });
1846
1847 StartIntercept(&output_fd);
1848 FinishCrasher();
1849 if (recoverable) {
1850 AssertDeath(0);
1851 } else {
1852 AssertDeath(SIGSEGV);
1853 }
1854 FinishIntercept(&intercept_result);
1855
1856 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1857
1858 std::vector<std::string> log_sources(2);
1859 ConsumeFd(std::move(output_fd), &log_sources[0]);
1860 logcat_collector.Collect(&log_sources[1]);
1861
1862 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1863 // information. Make sure the recovery still works, but the report won't be
1864 // hugely useful, it looks like a regular SEGV.
1865 bool seccomp = std::get<2>(GetParam());
1866 if (!seccomp) {
1867 for (const auto& result : log_sources) {
1868 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1869 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1870 if (params.free_before_access) {
1871 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1872 }
1873 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1874 }
1875 }
1876}
1877
1878TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1879 GwpAsanTestParameters params = std::get<0>(GetParam());
1880 bool seccomp = std::get<2>(GetParam());
1881 if (seccomp) {
1882 ScopedMinijail jail{minijail_new()};
1883 setup_jail(jail.get());
1884 minijail_enter(jail.get());
1885 }
1886
1887 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1888 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1889 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1890 p[params.access_offset] = 42;
1891 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001892
1893 bool recoverable = std::get<1>(GetParam());
1894 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1895
1896 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1897 // we end with at least one in a different slot), make sure the process still
1898 // doesn't crash.
1899 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1900 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1901 free(static_cast<void*>(const_cast<char*>(p)));
1902 free(static_cast<void*>(const_cast<char*>(p2)));
1903 *p = 42;
1904 *p2 = 42;
1905
1906 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1907 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1908 // coverage does. Thus, skip the atexit handlers.
1909 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001910}
1911
Josh Gaobf06a402018-08-27 16:34:01 -07001912TEST_F(CrasherTest, fdsan_warning_abort_message) {
1913 int intercept_result;
1914 unique_fd output_fd;
1915
1916 StartProcess([]() {
1917 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001918 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001919 if (fd == -1) {
1920 abort();
1921 }
1922 close(fd.get());
1923 _exit(0);
1924 });
1925
1926 StartIntercept(&output_fd);
1927 FinishCrasher();
1928 AssertDeath(0);
1929 FinishIntercept(&intercept_result);
1930 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1931
1932 std::string result;
1933 ConsumeFd(std::move(output_fd), &result);
1934 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1935}
1936
Josh Gaoc3c8c022017-02-13 16:36:18 -08001937TEST(crash_dump, zombie) {
1938 pid_t forkpid = fork();
1939
Josh Gaoc3c8c022017-02-13 16:36:18 -08001940 pid_t rc;
1941 int status;
1942
1943 if (forkpid == 0) {
1944 errno = 0;
1945 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1946 if (rc != -1 || errno != ECHILD) {
1947 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1948 }
1949
Josh Gaoa48b41b2019-12-13 14:11:04 -08001950 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001951
1952 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001953 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001954 if (rc != -1 || errno != ECHILD) {
1955 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1956 }
1957 _exit(0);
1958 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001959 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001960 ASSERT_EQ(forkpid, rc);
1961 ASSERT_TRUE(WIFEXITED(status));
1962 ASSERT_EQ(0, WEXITSTATUS(status));
1963 }
1964}
Josh Gao352a8452017-03-30 16:46:21 -07001965
1966TEST(tombstoned, no_notify) {
1967 // Do this a few times.
1968 for (int i = 0; i < 3; ++i) {
1969 pid_t pid = 123'456'789 + i;
1970
1971 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001972 InterceptResponse response = {};
1973 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1974 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1975 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001976
1977 {
1978 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001979 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001980 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1981 }
1982
1983 pid_t read_pid;
1984 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1985 ASSERT_EQ(read_pid, pid);
1986 }
1987}
1988
1989TEST(tombstoned, stress) {
1990 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1991 static constexpr int kDumpCount = 100;
1992
1993 std::atomic<bool> start(false);
1994 std::vector<std::thread> threads;
1995 threads.emplace_back([&start]() {
1996 while (!start) {
1997 continue;
1998 }
1999
2000 // Use a way out of range pid, to avoid stomping on an actual process.
2001 pid_t pid_base = 1'000'000;
2002
2003 for (int dump = 0; dump < kDumpCount; ++dump) {
2004 pid_t pid = pid_base + dump;
2005
2006 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002007 InterceptResponse response = {};
2008 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2009 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2010 << "Error messeage: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002011
2012 // Pretend to crash, and then immediately close the socket.
2013 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
2014 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
2015 if (sockfd == -1) {
2016 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
2017 }
2018 TombstonedCrashPacket packet = {};
2019 packet.packet_type = CrashPacketType::kDumpRequest;
2020 packet.packet.dump_request.pid = pid;
2021 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
2022 FAIL() << "failed to write to tombstoned: " << strerror(errno);
2023 }
2024
2025 continue;
2026 }
2027 });
2028
2029 threads.emplace_back([&start]() {
2030 while (!start) {
2031 continue;
2032 }
2033
2034 // Use a way out of range pid, to avoid stomping on an actual process.
2035 pid_t pid_base = 2'000'000;
2036
2037 for (int dump = 0; dump < kDumpCount; ++dump) {
2038 pid_t pid = pid_base + dump;
2039
2040 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002041 InterceptResponse response = {};
2042 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2043 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2044 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002045
2046 {
2047 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01002048 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07002049 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2050 tombstoned_notify_completion(tombstoned_socket.get());
2051 }
2052
2053 // TODO: Fix the race that requires this sleep.
2054 std::this_thread::sleep_for(50ms);
2055
2056 pid_t read_pid;
2057 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2058 ASSERT_EQ(read_pid, pid);
2059 }
2060 });
2061
2062 start = true;
2063
2064 for (std::thread& thread : threads) {
2065 thread.join();
2066 }
2067}
Narayan Kamathca5e9082017-06-02 15:42:06 +01002068
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002069TEST(tombstoned, intercept_java_trace_smoke) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002070 // Using a "real" PID is a little dangerous here - if the test fails
2071 // or crashes, we might end up getting a bogus / unreliable stack
2072 // trace.
2073 const pid_t self = getpid();
2074
2075 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002076 InterceptResponse response = {};
2077 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2078 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2079 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002080
Josh Gao76e1e302021-01-26 15:53:11 -08002081 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01002082 // should result in a "regular" FD and not the installed intercept.
2083 const char native[] = "native";
2084 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002085 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01002086 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
2087 tombstoned_notify_completion(tombstoned_socket.get());
2088
2089 // Then, connect to tombstoned asking for a java backtrace. This *should*
2090 // trigger the intercept.
2091 const char java[] = "java";
2092 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
2093 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
2094 tombstoned_notify_completion(tombstoned_socket.get());
2095
2096 char outbuf[sizeof(java)];
2097 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2098 ASSERT_STREQ("java", outbuf);
2099}
2100
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002101TEST(tombstoned, intercept_multiple_dump_types) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002102 const pid_t fake_pid = 1'234'567;
2103 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002104 InterceptResponse response = {};
2105 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2106 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2107 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002108
2109 unique_fd intercept_fd_2, output_fd_2;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002110 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
2111 kDebuggerdNativeBacktrace);
2112 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2113 << "Error message: " << response.error_message;
2114}
2115
2116TEST(tombstoned, intercept_bad_pid) {
2117 const pid_t fake_pid = -1;
2118 unique_fd intercept_fd, output_fd;
2119 InterceptResponse response = {};
2120 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2121 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2122 << "Error message: " << response.error_message;
2123 ASSERT_MATCH(response.error_message, "bad pid");
2124}
2125
2126TEST(tombstoned, intercept_bad_dump_types) {
2127 const pid_t fake_pid = 1'234'567;
2128 unique_fd intercept_fd, output_fd;
2129 InterceptResponse response = {};
2130 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
2131 static_cast<DebuggerdDumpType>(20));
2132 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2133 << "Error message: " << response.error_message;
2134 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
2135
2136 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
2137 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2138 << "Error message: " << response.error_message;
2139 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
2140
2141 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
2142 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2143 << "Error message: " << response.error_message;
2144 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
2145}
2146
2147TEST(tombstoned, intercept_already_registered) {
2148 const pid_t fake_pid = 1'234'567;
2149 unique_fd intercept_fd1, output_fd1;
2150 InterceptResponse response = {};
2151 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
2152 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2153 << "Error message: " << response.error_message;
2154
2155 unique_fd intercept_fd2, output_fd2;
2156 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
2157 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
2158 << "Error message: " << response.error_message;
2159 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
2160}
2161
2162TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
2163 const pid_t fake_pid = 1'234'567;
2164
2165 unique_fd intercept_fd, output_fd;
2166 InterceptResponse response = {};
2167 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2168 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2169 << "Error message: " << response.error_message;
2170
2171 const char data[] = "tombstone_proto";
2172 unique_fd tombstoned_socket, input_fd;
2173 ASSERT_TRUE(
2174 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
2175 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
2176 tombstoned_notify_completion(tombstoned_socket.get());
2177
2178 char outbuf[sizeof(data)];
2179 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2180 ASSERT_STREQ("tombstone_proto", outbuf);
Narayan Kamathca5e9082017-06-02 15:42:06 +01002181}
2182
2183TEST(tombstoned, intercept_any) {
2184 const pid_t fake_pid = 1'234'567;
2185
2186 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002187 InterceptResponse response = {};
2188 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2189 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2190 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002191
2192 const char any[] = "any";
2193 unique_fd tombstoned_socket, input_fd;
2194 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2195 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
2196 tombstoned_notify_completion(tombstoned_socket.get());
2197
2198 char outbuf[sizeof(any)];
2199 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2200 ASSERT_STREQ("any", outbuf);
2201}
Josh Gao2b22ae12018-09-12 14:51:03 -07002202
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002203TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
2204 const pid_t fake_pid = 1'234'567;
2205
2206 InterceptResponse response = {};
2207 unique_fd intercept_fd1, output_fd1;
2208 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2209 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2210 << "Error message: " << response.error_message;
2211
2212 unique_fd intercept_fd2, output_fd2;
2213 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2214 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2215 << "Error message: " << response.error_message;
2216
2217 unique_fd tombstoned_socket, input_fd;
2218 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2219}
2220
2221TEST(tombstoned, intercept_multiple_verify_intercept) {
2222 // Need to use our pid for java since that will verify the pid.
2223 const pid_t fake_pid = getpid();
2224
2225 InterceptResponse response = {};
2226 unique_fd intercept_fd1, output_fd1;
2227 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2228 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2229 << "Error message: " << response.error_message;
2230
2231 unique_fd intercept_fd2, output_fd2;
2232 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2233 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2234 << "Error message: " << response.error_message;
2235
2236 unique_fd intercept_fd3, output_fd3;
2237 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2238 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2239 << "Error message: " << response.error_message;
2240
2241 const char native_data[] = "native";
2242 unique_fd tombstoned_socket1, input_fd1;
2243 ASSERT_TRUE(
2244 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2245 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2246 tombstoned_notify_completion(tombstoned_socket1.get());
2247
2248 char native_outbuf[sizeof(native_data)];
2249 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2250 ASSERT_STREQ("native", native_outbuf);
2251
2252 const char java_data[] = "java";
2253 unique_fd tombstoned_socket2, input_fd2;
2254 ASSERT_TRUE(
2255 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2256 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2257 tombstoned_notify_completion(tombstoned_socket2.get());
2258
2259 char java_outbuf[sizeof(java_data)];
2260 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2261 ASSERT_STREQ("java", java_outbuf);
2262
2263 const char tomb_data[] = "tombstone";
2264 unique_fd tombstoned_socket3, input_fd3;
2265 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2266 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2267 tombstoned_notify_completion(tombstoned_socket3.get());
2268
2269 char tomb_outbuf[sizeof(tomb_data)];
2270 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2271 ASSERT_STREQ("tombstone", tomb_outbuf);
2272}
2273
Josh Gao2b22ae12018-09-12 14:51:03 -07002274TEST(tombstoned, interceptless_backtrace) {
2275 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2276 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2277 std::map<int, time_t> result;
2278 for (int i = 0; i < 99; ++i) {
2279 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2280 struct stat st;
2281 if (stat(path.c_str(), &st) == 0) {
2282 result[i] = st.st_mtim.tv_sec;
2283 }
2284 }
2285 return result;
2286 };
2287
2288 auto before = get_tombstone_timestamps();
2289 for (int i = 0; i < 50; ++i) {
2290 raise_debugger_signal(kDebuggerdNativeBacktrace);
2291 }
2292 auto after = get_tombstone_timestamps();
2293
2294 int diff = 0;
2295 for (int i = 0; i < 99; ++i) {
2296 if (after.count(i) == 0) {
2297 continue;
2298 }
2299 if (before.count(i) == 0) {
2300 ++diff;
2301 continue;
2302 }
2303 if (before[i] != after[i]) {
2304 ++diff;
2305 }
2306 }
2307
2308 // We can't be sure that nothing's crash looping in the background.
2309 // This should be good enough, though...
2310 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2311}
Christopher Ferris481e8372019-07-15 17:13:24 -07002312
2313static __attribute__((__noinline__)) void overflow_stack(void* p) {
2314 void* buf[1];
2315 buf[0] = p;
2316 static volatile void* global = buf;
2317 if (global) {
2318 global = buf;
2319 overflow_stack(&buf);
2320 }
2321}
2322
2323TEST_F(CrasherTest, stack_overflow) {
2324 int intercept_result;
2325 unique_fd output_fd;
2326 StartProcess([]() { overflow_stack(nullptr); });
2327
2328 StartIntercept(&output_fd);
2329 FinishCrasher();
2330 AssertDeath(SIGSEGV);
2331 FinishIntercept(&intercept_result);
2332
2333 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2334
2335 std::string result;
2336 ConsumeFd(std::move(output_fd), &result);
2337 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2338}
Josh Gao76e1e302021-01-26 15:53:11 -08002339
Christopher Ferris22035cc2023-01-31 17:50:22 -08002340static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002341 std::string test_lib(testing::internal::GetArgvs()[0]);
2342 auto const value = test_lib.find_last_of('/');
2343 if (value == std::string::npos) {
2344 test_lib = "./";
2345 } else {
2346 test_lib = test_lib.substr(0, value + 1) + "./";
2347 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08002348 return test_lib + "libcrash_test.so";
2349}
2350
2351static void CreateEmbeddedLibrary(int out_fd) {
2352 std::string test_lib(GetTestLibraryPath());
2353 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2354 ASSERT_NE(fd.get(), -1);
2355 off_t file_size = lseek(fd, 0, SEEK_END);
2356 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2357 std::vector<uint8_t> contents(file_size);
2358 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2359
2360 // Put the shared library data at a pagesize() offset.
2361 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2362 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2363}
2364
2365TEST_F(CrasherTest, non_zero_offset_in_library) {
2366 int intercept_result;
2367 unique_fd output_fd;
2368 TemporaryFile tf;
2369 CreateEmbeddedLibrary(tf.fd);
2370 StartProcess([&tf]() {
2371 android_dlextinfo extinfo{};
2372 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2373 extinfo.library_fd = tf.fd;
2374 extinfo.library_fd_offset = 4 * getpagesize();
2375 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2376 if (handle == nullptr) {
2377 _exit(1);
2378 }
2379 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2380 if (crash_func == nullptr) {
2381 _exit(1);
2382 }
2383 crash_func();
2384 });
2385
2386 StartIntercept(&output_fd);
2387 FinishCrasher();
2388 AssertDeath(SIGSEGV);
2389 FinishIntercept(&intercept_result);
2390
2391 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2392
2393 std::string result;
2394 ConsumeFd(std::move(output_fd), &result);
2395
2396 // Verify the crash includes an offset value in the backtrace.
2397 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2398 tf.path, 4 * getpagesize());
2399 ASSERT_MATCH(result, match_str);
2400}
2401
2402static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2403 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002404
2405 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2406 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2407
2408 // Copy the shared so to a tempory directory.
2409 return system(cp_cmd.c_str()) == 0;
2410}
2411
2412TEST_F(CrasherTest, unreadable_elf) {
2413 int intercept_result;
2414 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002415 std::string tmp_so_name;
2416 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002417 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002418 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2419 _exit(1);
2420 }
2421 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2422 if (handle == nullptr) {
2423 _exit(1);
2424 }
2425 // Delete the original shared library so that we get the warning
2426 // about unreadable elf files.
2427 if (unlink(tmp_so_name.c_str()) == -1) {
2428 _exit(1);
2429 }
2430 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2431 if (crash_func == nullptr) {
2432 _exit(1);
2433 }
2434 crash_func();
2435 });
2436
2437 StartIntercept(&output_fd);
2438 FinishCrasher();
2439 AssertDeath(SIGSEGV);
2440 FinishIntercept(&intercept_result);
2441
2442 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2443
2444 std::string result;
2445 ConsumeFd(std::move(output_fd), &result);
2446 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002447 std::string match_str = "NOTE: " + tmp_so_name;
2448 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002449}
2450
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002451void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
2452 static std::regex tombstone_re("tombstone_\\d+");
Christopher Ferris35da2882021-02-17 15:39:06 -08002453 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2454 ASSERT_TRUE(dir_h != nullptr);
Christopher Ferris35da2882021-02-17 15:39:06 -08002455 dirent* entry;
2456 while ((entry = readdir(dir_h.get())) != nullptr) {
2457 if (!std::regex_match(entry->d_name, tombstone_re)) {
2458 continue;
2459 }
2460 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002461
2462 struct stat st;
2463 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2464 continue;
2465 }
2466
2467 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002468 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002469 break;
2470 }
2471 }
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002472}
Josh Gao76e1e302021-01-26 15:53:11 -08002473
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002474TEST(tombstoned, proto) {
2475 const pid_t self = getpid();
2476 unique_fd tombstoned_socket, text_fd, proto_fd;
2477 ASSERT_TRUE(
2478 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2479
2480 tombstoned_notify_completion(tombstoned_socket.get());
2481
2482 ASSERT_NE(-1, text_fd.get());
2483 ASSERT_NE(-1, proto_fd.get());
2484
2485 struct stat text_st;
2486 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2487
2488 std::optional<std::string> tombstone_file;
2489 // Allow up to 5 seconds for the tombstone to be written to the system.
2490 const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
2491 const auto start = std::chrono::high_resolution_clock::now();
2492 while (true) {
2493 std::this_thread::sleep_for(100ms);
2494 CheckForTombstone(text_st, tombstone_file);
2495 if (tombstone_file) {
2496 break;
2497 }
2498 if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
2499 break;
2500 }
2501 }
2502
2503 ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
Christopher Ferris35da2882021-02-17 15:39:06 -08002504 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002505
2506 struct stat proto_fd_st;
2507 struct stat proto_file_st;
2508 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2509 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2510
2511 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2512 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2513}
2514
2515TEST(tombstoned, proto_intercept) {
2516 const pid_t self = getpid();
2517 unique_fd intercept_fd, output_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002518
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002519 InterceptResponse response = {};
2520 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2521 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2522 << "Error message: " << response.error_message;
Josh Gao76e1e302021-01-26 15:53:11 -08002523
2524 unique_fd tombstoned_socket, text_fd, proto_fd;
2525 ASSERT_TRUE(
2526 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2527 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2528 tombstoned_notify_completion(tombstoned_socket.get());
2529
2530 text_fd.reset();
2531
2532 std::string output;
2533 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2534 ASSERT_EQ("foo", output);
2535}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002536
2537// Verify that when an intercept is present for the main thread, and the signal
2538// is received on a different thread, the intercept still works.
2539TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2540 StartProcess([]() {
2541 std::thread thread([]() {
2542 // Raise the signal on the side thread.
2543 raise_debugger_signal(kDebuggerdNativeBacktrace);
2544 });
2545 thread.join();
2546 _exit(0);
2547 });
2548
2549 unique_fd output_fd;
2550 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2551 FinishCrasher();
2552 AssertDeath(0);
2553
2554 int intercept_result;
2555 FinishIntercept(&intercept_result);
2556 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2557
2558 std::string result;
2559 ConsumeFd(std::move(output_fd), &result);
2560 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2561}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002562
2563static std::string format_pointer(uintptr_t ptr) {
2564#if defined(__LP64__)
2565 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2566 static_cast<uint32_t>(ptr & 0xffffffff));
2567#else
2568 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2569#endif
2570}
2571
2572static std::string format_pointer(void* ptr) {
2573 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2574}
2575
2576static std::string format_full_pointer(uintptr_t ptr) {
2577#if defined(__LP64__)
2578 return android::base::StringPrintf("%016" PRIx64, ptr);
2579#else
2580 return android::base::StringPrintf("%08x", ptr);
2581#endif
2582}
2583
2584static std::string format_full_pointer(void* ptr) {
2585 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2586}
2587
2588__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2589 int* crash_ptr = reinterpret_cast<int*>(ptr);
2590 *crash_ptr = 1;
2591 return *crash_ptr;
2592}
2593
2594// Verify that a fault address before the first map is properly handled.
2595TEST_F(CrasherTest, fault_address_before_first_map) {
2596 StartProcess([]() {
2597 ASSERT_EQ(0, crash_call(0x1024));
2598 _exit(0);
2599 });
2600
2601 unique_fd output_fd;
2602 StartIntercept(&output_fd);
2603 FinishCrasher();
2604 AssertDeath(SIGSEGV);
2605
2606 int intercept_result;
2607 FinishIntercept(&intercept_result);
2608 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2609
2610 std::string result;
2611 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002612 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002613
2614 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2615
2616 std::string match_str = android::base::StringPrintf(
2617 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2618 format_pointer(0x1024).c_str());
2619 ASSERT_MATCH(result, match_str);
2620}
2621
2622// Verify that a fault address after the last map is properly handled.
2623TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002624 // This makes assumptions about the memory layout that are not true in HWASan
2625 // processes.
2626 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002627 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2628 StartProcess([crash_uptr]() {
2629 ASSERT_EQ(0, crash_call(crash_uptr));
2630 _exit(0);
2631 });
2632
2633 unique_fd output_fd;
2634 StartIntercept(&output_fd);
2635 FinishCrasher();
2636 AssertDeath(SIGSEGV);
2637
2638 int intercept_result;
2639 FinishIntercept(&intercept_result);
2640 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2641
2642 std::string result;
2643 ConsumeFd(std::move(output_fd), &result);
2644
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002645 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2646 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002647 ASSERT_MATCH(result, match_str);
2648
2649 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2650
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002651 // Verifies that the fault address error message is at the end of the
2652 // maps section. To do this, the check below looks for the start of the
2653 // open files section or the start of the log file section. It's possible
2654 // for either of these sections to be present after the maps section right
2655 // now.
2656 // If the sections move around, this check might need to be modified.
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002657 match_str = android::base::StringPrintf(
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002658 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002659 format_pointer(crash_uptr).c_str());
2660 ASSERT_MATCH(result, match_str);
2661}
2662
2663// Verify that a fault address between maps is properly handled.
2664TEST_F(CrasherTest, fault_address_between_maps) {
2665 // Create a map before the fork so it will be present in the child.
2666 void* start_ptr =
2667 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2668 ASSERT_NE(MAP_FAILED, start_ptr);
2669 // Unmap the page in the middle.
2670 void* middle_ptr =
2671 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2672 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2673
2674 StartProcess([middle_ptr]() {
2675 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2676 _exit(0);
2677 });
2678
2679 // Unmap the two maps.
2680 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2681 void* end_ptr =
2682 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2683 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2684
2685 unique_fd output_fd;
2686 StartIntercept(&output_fd);
2687 FinishCrasher();
2688 AssertDeath(SIGSEGV);
2689
2690 int intercept_result;
2691 FinishIntercept(&intercept_result);
2692 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2693
2694 std::string result;
2695 ConsumeFd(std::move(output_fd), &result);
2696
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002697 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2698 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002699 ASSERT_MATCH(result, match_str);
2700
2701 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2702
2703 match_str = android::base::StringPrintf(
2704 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2705 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2706 format_pointer(end_ptr).c_str());
2707 ASSERT_MATCH(result, match_str);
2708}
2709
2710// Verify that a fault address happens in the correct map.
2711TEST_F(CrasherTest, fault_address_in_map) {
2712 // Create a map before the fork so it will be present in the child.
2713 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2714 ASSERT_NE(MAP_FAILED, ptr);
2715
2716 StartProcess([ptr]() {
2717 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2718 _exit(0);
2719 });
2720
2721 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2722
2723 unique_fd output_fd;
2724 StartIntercept(&output_fd);
2725 FinishCrasher();
2726 AssertDeath(SIGSEGV);
2727
2728 int intercept_result;
2729 FinishIntercept(&intercept_result);
2730 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2731
2732 std::string result;
2733 ConsumeFd(std::move(output_fd), &result);
2734
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002735 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2736 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002737 ASSERT_MATCH(result, match_str);
2738
2739 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2740
2741 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2742 ASSERT_MATCH(result, match_str);
2743}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002744
2745static constexpr uint32_t kDexData[] = {
2746 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2747 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2748 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2749 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2750 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2751 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2752 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2753 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2754 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2755 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2756 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2757 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2758 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2759 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2760 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2761 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2762 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2763};
2764
2765TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2766 StartProcess([]() {
2767 TemporaryDir td;
2768 std::string tmp_so_name;
2769 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2770 _exit(1);
2771 }
2772
2773 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2774 // move the library to which has a basename of libart.so.
2775 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2776 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2777 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2778 if (handle == nullptr) {
2779 _exit(1);
2780 }
2781
2782 void* ptr =
2783 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2784 ASSERT_TRUE(ptr != MAP_FAILED);
2785 memcpy(ptr, kDexData, sizeof(kDexData));
2786 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2787
2788 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2789 .symfile_size = sizeof(kDexData)};
2790
2791 JITDescriptor* dex_debug =
2792 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2793 ASSERT_TRUE(dex_debug != nullptr);
2794 dex_debug->version = 1;
2795 dex_debug->action_flag = 0;
2796 dex_debug->relevant_entry = 0;
2797 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2798
2799 // This sets the magic dex pc value for register 0, using the value
2800 // of register 1 + 0x102.
2801 asm(".cfi_escape "
2802 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2803 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2804 "0x13 /* DW_OP_drop */,"
2805 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2806
2807 // For each different architecture, set register one to the dex ptr mmap
2808 // created above. Then do a nullptr dereference to force a crash.
2809#if defined(__arm__)
2810 asm volatile(
2811 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002812 "mov r2, #0\n"
2813 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002814 : [base] "+r"(ptr)
2815 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002816 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002817#elif defined(__aarch64__)
2818 asm volatile(
2819 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002820 "mov x2, #0\n"
2821 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002822 : [base] "+r"(ptr)
2823 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002824 : "x1", "x2", "memory");
2825#elif defined(__riscv)
2826 // TODO: x1 is ra (the link register) on riscv64, so this might have
2827 // unintended consequences, but we'll need to change the .cfi_escape if so.
2828 asm volatile(
2829 "mv x1, %[base]\n"
2830 "sw zero, 0(zero)\n"
2831 : [base] "+r"(ptr)
2832 :
2833 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002834#elif defined(__i386__)
2835 asm volatile(
2836 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002837 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002838 : [base] "+r"(ptr)
2839 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002840 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002841#elif defined(__x86_64__)
2842 asm volatile(
2843 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002844 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002845 : [base] "+r"(ptr)
2846 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002847 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002848#else
2849#error "Unsupported architecture"
2850#endif
2851 _exit(0);
2852 });
2853
2854 unique_fd output_fd;
2855 StartIntercept(&output_fd);
2856 FinishCrasher();
2857 AssertDeath(SIGSEGV);
2858
2859 int intercept_result;
2860 FinishIntercept(&intercept_result);
2861 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2862
2863 std::string result;
2864 ConsumeFd(std::move(output_fd), &result);
2865
2866 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002867 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002868
2869 // Now verify that the dex_pc frame includes a proper function name.
2870 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2871}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002872
2873static std::string format_map_pointer(uintptr_t ptr) {
2874#if defined(__LP64__)
2875 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2876 static_cast<uint32_t>(ptr & 0xffffffff));
2877#else
2878 return android::base::StringPrintf("%08x", ptr);
2879#endif
2880}
2881
2882// Verify that map data is properly formatted.
2883TEST_F(CrasherTest, verify_map_format) {
2884 // Create multiple maps to make sure that the map data is formatted properly.
2885 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2886 ASSERT_NE(MAP_FAILED, none_map);
2887 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2888 ASSERT_NE(MAP_FAILED, r_map);
2889 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2890 ASSERT_NE(MAP_FAILED, w_map);
2891 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2892 ASSERT_NE(MAP_FAILED, x_map);
2893
2894 TemporaryFile tf;
2895 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2896 char c = 'f';
2897 ASSERT_EQ(1, write(tf.fd, &c, 1));
2898 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2899 ASSERT_EQ(1, write(tf.fd, &c, 1));
2900 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2901 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2902 ASSERT_NE(MAP_FAILED, file_map);
2903
2904 StartProcess([]() { abort(); });
2905
2906 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2907 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2908 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2909 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2910 ASSERT_EQ(0, munmap(file_map, 0x3001));
2911
2912 unique_fd output_fd;
2913 StartIntercept(&output_fd);
2914 FinishCrasher();
2915 AssertDeath(SIGABRT);
2916 int intercept_result;
2917 FinishIntercept(&intercept_result);
2918
2919 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2920
2921 std::string result;
2922 ConsumeFd(std::move(output_fd), &result);
2923
2924 std::string match_str;
2925 // Verify none.
2926 match_str = android::base::StringPrintf(
2927 " %s-%s --- 0 1000\\n",
2928 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2929 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2930 ASSERT_MATCH(result, match_str);
2931
2932 // Verify read-only.
2933 match_str = android::base::StringPrintf(
2934 " %s-%s r-- 0 1000\\n",
2935 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2936 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2937 ASSERT_MATCH(result, match_str);
2938
2939 // Verify write-only.
2940 match_str = android::base::StringPrintf(
2941 " %s-%s -w- 0 1000\\n",
2942 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2943 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2944 ASSERT_MATCH(result, match_str);
2945
2946 // Verify exec-only.
2947 match_str = android::base::StringPrintf(
2948 " %s-%s --x 0 1000\\n",
2949 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2950 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2951 ASSERT_MATCH(result, match_str);
2952
2953 // Verify file map with non-zero offset and a name.
2954 match_str = android::base::StringPrintf(
2955 " %s-%s r-- 2000 4000 %s\\n",
2956 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2957 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2958 ASSERT_MATCH(result, match_str);
2959}
2960
2961// Verify that the tombstone map data is correct.
2962TEST_F(CrasherTest, verify_header) {
2963 StartProcess([]() { abort(); });
2964
2965 unique_fd output_fd;
2966 StartIntercept(&output_fd);
2967 FinishCrasher();
2968 AssertDeath(SIGABRT);
2969 int intercept_result;
2970 FinishIntercept(&intercept_result);
2971
2972 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2973
2974 std::string result;
2975 ConsumeFd(std::move(output_fd), &result);
2976
2977 std::string match_str = android::base::StringPrintf(
2978 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2979 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2980 android::base::GetProperty("ro.revision", "unknown").c_str());
2981 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2982 ASSERT_MATCH(result, match_str);
2983}
2984
2985// Verify that the thread header is formatted properly.
2986TEST_F(CrasherTest, verify_thread_header) {
2987 void* shared_map =
2988 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2989 ASSERT_NE(MAP_FAILED, shared_map);
2990 memset(shared_map, 0, sizeof(pid_t));
2991
2992 StartProcess([&shared_map]() {
2993 std::atomic_bool tid_written;
2994 std::thread thread([&tid_written, &shared_map]() {
2995 pid_t tid = gettid();
2996 memcpy(shared_map, &tid, sizeof(pid_t));
2997 tid_written = true;
2998 volatile bool done = false;
2999 while (!done)
3000 ;
3001 });
3002 thread.detach();
3003 while (!tid_written.load(std::memory_order_acquire))
3004 ;
3005 abort();
3006 });
3007
3008 pid_t primary_pid = crasher_pid;
3009
3010 unique_fd output_fd;
3011 StartIntercept(&output_fd);
3012 FinishCrasher();
3013 AssertDeath(SIGABRT);
3014 int intercept_result;
3015 FinishIntercept(&intercept_result);
3016 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3017
3018 // Read the tid data out.
3019 pid_t tid;
3020 memcpy(&tid, shared_map, sizeof(pid_t));
3021 ASSERT_NE(0, tid);
3022
3023 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
3024
3025 std::string result;
3026 ConsumeFd(std::move(output_fd), &result);
3027
3028 // Verify that there are two headers, one where the tid is "primary_pid"
3029 // and the other where the tid is "tid".
3030 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
3031 primary_pid, primary_pid);
3032 ASSERT_MATCH(result, match_str);
3033
3034 match_str =
3035 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
3036 ASSERT_MATCH(result, match_str);
3037}
3038
3039// Verify that there is a BuildID present in the map section and set properly.
3040TEST_F(CrasherTest, verify_build_id) {
3041 StartProcess([]() { abort(); });
3042
3043 unique_fd output_fd;
3044 StartIntercept(&output_fd);
3045 FinishCrasher();
3046 AssertDeath(SIGABRT);
3047 int intercept_result;
3048 FinishIntercept(&intercept_result);
3049 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3050
3051 std::string result;
3052 ConsumeFd(std::move(output_fd), &result);
3053
3054 // Find every /system or /apex lib and verify the BuildID is displayed
3055 // properly.
3056 bool found_valid_elf = false;
3057 std::smatch match;
3058 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
3059 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
3060 result = match.suffix()) {
3061 if (prev_file == match[1]) {
3062 // Already checked this file.
3063 continue;
3064 }
3065
3066 prev_file = match[1];
Christopher Ferris15038902023-11-10 00:05:49 -08003067 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
3068 unwindstack::Elf elf(elf_memory);
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003069 if (!elf.Init() || !elf.valid()) {
3070 // Skipping invalid elf files.
3071 continue;
3072 }
3073 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
3074
3075 found_valid_elf = true;
3076 }
3077 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
3078}
Christopher Ferrisbda10642023-04-24 18:14:53 -07003079
3080const char kLogMessage[] = "Should not see this log message.";
3081
3082// Verify that the logd process does not read the log.
3083TEST_F(CrasherTest, logd_skips_reading_logs) {
3084 StartProcess([]() {
3085 pthread_setname_np(pthread_self(), "logd");
3086 LOG(INFO) << kLogMessage;
3087 abort();
3088 });
3089
3090 unique_fd output_fd;
3091 StartIntercept(&output_fd);
3092 FinishCrasher();
3093 AssertDeath(SIGABRT);
3094 int intercept_result;
3095 FinishIntercept(&intercept_result);
3096 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3097
3098 std::string result;
3099 ConsumeFd(std::move(output_fd), &result);
3100 // logd should not contain our log message.
3101 ASSERT_NOT_MATCH(result, kLogMessage);
3102}
3103
3104// Verify that the logd process does not read the log when the non-main
3105// thread crashes.
3106TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
3107 StartProcess([]() {
3108 pthread_setname_np(pthread_self(), "logd");
3109 LOG(INFO) << kLogMessage;
3110
3111 std::thread thread([]() {
3112 pthread_setname_np(pthread_self(), "not_logd_thread");
3113 // Raise the signal on the side thread.
3114 raise_debugger_signal(kDebuggerdTombstone);
3115 });
3116 thread.join();
3117 _exit(0);
3118 });
3119
3120 unique_fd output_fd;
3121 StartIntercept(&output_fd, kDebuggerdTombstone);
3122 FinishCrasher();
3123 AssertDeath(0);
3124
3125 int intercept_result;
3126 FinishIntercept(&intercept_result);
3127 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3128
3129 std::string result;
3130 ConsumeFd(std::move(output_fd), &result);
3131 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
3132 ASSERT_NOT_MATCH(result, kLogMessage);
3133}
Christopher Ferris98d62422023-05-24 20:01:10 +00003134
3135// Disable this test since there is a high liklihood that this would
3136// be flaky since it requires 500 messages being in the log.
3137TEST_F(CrasherTest, DISABLED_max_log_messages) {
3138 StartProcess([]() {
3139 for (size_t i = 0; i < 600; i++) {
3140 LOG(INFO) << "Message number " << i;
3141 }
3142 abort();
3143 });
3144
3145 unique_fd output_fd;
3146 StartIntercept(&output_fd);
3147 FinishCrasher();
3148 AssertDeath(SIGABRT);
3149 int intercept_result;
3150 FinishIntercept(&intercept_result);
3151 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3152
3153 std::string result;
3154 ConsumeFd(std::move(output_fd), &result);
3155 ASSERT_NOT_MATCH(result, "Message number 99");
3156 ASSERT_MATCH(result, "Message number 100");
3157 ASSERT_MATCH(result, "Message number 599");
3158}
3159
3160TEST_F(CrasherTest, log_with_newline) {
3161 StartProcess([]() {
3162 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
3163 abort();
3164 });
3165
3166 unique_fd output_fd;
3167 StartIntercept(&output_fd);
3168 FinishCrasher();
3169 AssertDeath(SIGABRT);
3170 int intercept_result;
3171 FinishIntercept(&intercept_result);
3172 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3173
3174 std::string result;
3175 ConsumeFd(std::move(output_fd), &result);
3176 ASSERT_MATCH(result, ":\\s*This line has a newline.");
3177 ASSERT_MATCH(result, ":\\s*This is on the next line.");
3178}