blob: f904d487a5165c2dde6f9fc7ce46d5af9fb1227c [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>
Josh Gaocdea7502017-11-01 15:00:40 -070023#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080024#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070025#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080026#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070027#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080028#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070029#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070030#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070031#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070032
33#include <chrono>
34#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000035#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070036#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070037#include <thread>
38
Josh Gaobf06a402018-08-27 16:34:01 -070039#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080040#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080041#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070042#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080043#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080044
Josh Gao5f87bbd2019-01-09 17:01:49 -080045#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070046#include <android-base/file.h>
47#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070048#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070049#include <android-base/parseint.h>
50#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070051#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070053#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/unique_fd.h>
55#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070056#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070057#include <gtest/gtest.h>
58
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000059#include <unwindstack/Elf.h>
60#include <unwindstack/Memory.h>
61
Josh Gaoe04ca272018-01-16 15:38:17 -080062#include <libminijail.h>
63#include <scoped_minijail.h>
64
Christopher Ferris2038cc72021-09-15 03:57:10 +000065#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010066#include "debuggerd/handler.h"
Mitch Phillips18ce5422023-01-19 14:23:49 -080067#include "gtest/gtest.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070068#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010069#include "protocol.h"
70#include "tombstoned/tombstoned.h"
71#include "util.h"
72
Josh Gaocbe70cb2016-10-18 18:17:52 -070073using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080074
75using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070076using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070077using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070078
79#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070080#define ARCH_SUFFIX "64"
81#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070082#define ARCH_SUFFIX ""
83#endif
84
Elliott Hughese4781d52021-03-17 09:15:15 -070085constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070086
87#define TIMEOUT(seconds, expr) \
88 [&]() { \
89 struct sigaction old_sigaction; \
90 struct sigaction new_sigaction = {}; \
91 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080092 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070093 err(1, "sigaction failed"); \
94 } \
95 alarm(seconds); \
96 auto value = expr; \
97 int saved_errno = errno; \
98 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
99 err(1, "sigaction failed"); \
100 } \
101 alarm(0); \
102 errno = saved_errno; \
103 return value; \
104 }()
105
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700106// Backtrace frame dump could contain:
107// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
108// or
109// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800110#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700111 ASSERT_MATCH(result, \
112 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900113
Narayan Kamatha73df602017-05-24 15:07:25 +0100114static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100115 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700116 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
117 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
118 if (intercept_fd->get() == -1) {
119 FAIL() << "failed to contact tombstoned: " << strerror(errno);
120 }
121
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700122 InterceptRequest req = {
123 .dump_type = intercept_type,
124 .pid = target_pid,
125 };
Josh Gao460b3362017-03-30 16:40:47 -0700126
127 unique_fd output_pipe_write;
128 if (!Pipe(output_fd, &output_pipe_write)) {
129 FAIL() << "failed to create output pipe: " << strerror(errno);
130 }
131
132 std::string pipe_size_str;
133 int pipe_buffer_size;
134 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
135 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
136 }
137
138 pipe_size_str = android::base::Trim(pipe_size_str);
139
140 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
141 FAIL() << "failed to parse pipe max size";
142 }
143
144 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
145 FAIL() << "failed to set pipe size: " << strerror(errno);
146 }
147
Josh Gao5675f3c2017-06-01 12:19:53 -0700148 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
149
Josh Gao5f87bbd2019-01-09 17:01:49 -0800150 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
151 output_pipe_write.reset();
152 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700153 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
154 }
155
156 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800157 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700158 if (rc == -1) {
159 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
160 } else if (rc == 0) {
161 FAIL() << "failed to read response from tombstoned (EOF)";
162 } else if (rc != sizeof(response)) {
163 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
164 << ", received " << rc;
165 }
166
Narayan Kamathca5e9082017-06-02 15:42:06 +0100167 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700168}
169
Elliott Hughesd13ea522022-01-13 09:20:26 -0800170static bool pac_supported() {
171#if defined(__aarch64__)
172 return getauxval(AT_HWCAP) & HWCAP_PACA;
173#else
174 return false;
175#endif
176}
177
Josh Gaocbe70cb2016-10-18 18:17:52 -0700178class CrasherTest : public ::testing::Test {
179 public:
180 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700181 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700182 unique_fd crasher_pipe;
183 unique_fd intercept_fd;
184
185 CrasherTest();
186 ~CrasherTest();
187
Narayan Kamatha73df602017-05-24 15:07:25 +0100188 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700189
190 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
191 void FinishIntercept(int* result);
192
Josh Gao2e7b8e22017-05-04 17:12:57 -0700193 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700194 void StartCrasher(const std::string& crash_type);
195 void FinishCrasher();
196 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700197
198 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700199};
200
201CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700202 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
203 android::base::SetProperty(kWaitForDebuggerKey, "0");
204
205 // Clear the old property too, just in case someone's been using it
206 // on this device. (We only document the new name, but we still support
207 // the old name so we don't break anyone's existing setups.)
208 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700209}
210
211CrasherTest::~CrasherTest() {
212 if (crasher_pid != -1) {
213 kill(crasher_pid, SIGKILL);
214 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700215 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700216 }
217
Elliott Hughese4781d52021-03-17 09:15:15 -0700218 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700219}
220
Narayan Kamatha73df602017-05-24 15:07:25 +0100221void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222 if (crasher_pid == -1) {
223 FAIL() << "crasher hasn't been started";
224 }
225
Narayan Kamathca5e9082017-06-02 15:42:06 +0100226 InterceptStatus status;
227 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
228 ASSERT_EQ(InterceptStatus::kRegistered, status);
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) {
301 constexpr size_t read_length = PAGE_SIZE;
302 std::string result;
303
304 while (true) {
305 size_t offset = result.size();
306 result.resize(result.size() + PAGE_SIZE);
307 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
308 if (rc == -1) {
309 FAIL() << "read failed: " << strerror(errno);
310 } else if (rc == 0) {
311 result.resize(result.size() - PAGE_SIZE);
312 break;
313 }
314
315 result.resize(result.size() - PAGE_SIZE + rc);
316 }
317
318 *output = std::move(result);
319}
320
Mitch Phillips78f06702021-06-01 14:35:43 -0700321class LogcatCollector {
322 public:
323 LogcatCollector() { system("logcat -c"); }
324
325 void Collect(std::string* output) {
326 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
327 ASSERT_NE(cmd_stdout, nullptr);
328 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
329 ConsumeFd(std::move(tmp_fd), output);
330 pclose(cmd_stdout);
331 }
332};
333
Josh Gaocbe70cb2016-10-18 18:17:52 -0700334TEST_F(CrasherTest, smoke) {
335 int intercept_result;
336 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800337 StartProcess([]() {
338 *reinterpret_cast<volatile char*>(0xdead) = '1';
339 });
340
Josh Gaocbe70cb2016-10-18 18:17:52 -0700341 StartIntercept(&output_fd);
342 FinishCrasher();
343 AssertDeath(SIGSEGV);
344 FinishIntercept(&intercept_result);
345
346 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
347
348 std::string result;
349 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800350#ifdef __LP64__
351 ASSERT_MATCH(result,
352 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
353#else
354 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
355#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700356
357 if (mte_supported()) {
358 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700359 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
360 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700361 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800362
363 if (pac_supported()) {
364 // Test that the default PAC_ENABLED_KEYS value is set.
365 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
366 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
367 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700368}
369
Peter Collingbournef03af882020-03-20 18:09:00 -0700370TEST_F(CrasherTest, tagged_fault_addr) {
371#if !defined(__aarch64__)
372 GTEST_SKIP() << "Requires aarch64";
373#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700374 // HWASan crashes with SIGABRT on tag mismatch.
375 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700376 int intercept_result;
377 unique_fd output_fd;
378 StartProcess([]() {
379 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
380 });
381
382 StartIntercept(&output_fd);
383 FinishCrasher();
384 AssertDeath(SIGSEGV);
385 FinishIntercept(&intercept_result);
386
387 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
388
389 std::string result;
390 ConsumeFd(std::move(output_fd), &result);
391
392 // The address can either be tagged (new kernels) or untagged (old kernels).
393 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800394 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700395}
396
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700397void CrasherTest::Trap(void* ptr) {
398 void (*volatile f)(void*) = nullptr;
399 __asm__ __volatile__("" : : "r"(f) : "memory");
400 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700401}
402
403TEST_F(CrasherTest, heap_addr_in_register) {
404#if defined(__i386__)
405 GTEST_SKIP() << "architecture does not pass arguments in registers";
406#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700407 // The memory dump in HWASan crashes sadly shows the memory near the registers
408 // in the HWASan dump function, rather the faulting context. This is a known
409 // issue.
410 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700411 int intercept_result;
412 unique_fd output_fd;
413 StartProcess([]() {
414 // Crash with a heap pointer in the first argument register.
415 Trap(malloc(1));
416 });
417
418 StartIntercept(&output_fd);
419 FinishCrasher();
420 int status;
421 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
422 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
423 // Don't test the signal number because different architectures use different signals for
424 // __builtin_trap().
425 FinishIntercept(&intercept_result);
426
427 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
428
429 std::string result;
430 ConsumeFd(std::move(output_fd), &result);
431
432#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800433 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700434#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800435 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800436#elif defined(__riscv)
437 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700438#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800439 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700440#else
441 ASSERT_TRUE(false) << "unsupported architecture";
442#endif
443}
444
Peter Collingbournecd278072020-12-21 14:08:38 -0800445#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700446static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800447 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700448 abort();
449 }
450}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800451
452static void SetTagCheckingLevelAsync() {
453 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
454 abort();
455 }
456}
Peter Collingbournef8622522020-04-07 14:07:32 -0700457#endif
458
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800459struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
460
Peter Collingbourneaa544792021-05-13 13:53:37 -0700461INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800462
463TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800464#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700465 if (!mte_supported()) {
466 GTEST_SKIP() << "Requires MTE";
467 }
468
Peter Collingbourneaa544792021-05-13 13:53:37 -0700469 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
470 if (GetParam() == 0) {
471 return;
472 }
473
Mitch Phillips78f06702021-06-01 14:35:43 -0700474 LogcatCollector logcat_collector;
475
Peter Collingbournef8622522020-04-07 14:07:32 -0700476 int intercept_result;
477 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800478 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700479 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800480 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700481 free((void *)p);
482 p[0] = 42;
483 });
484
485 StartIntercept(&output_fd);
486 FinishCrasher();
487 AssertDeath(SIGSEGV);
488 FinishIntercept(&intercept_result);
489
490 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
491
Mitch Phillips78f06702021-06-01 14:35:43 -0700492 std::vector<std::string> log_sources(2);
493 ConsumeFd(std::move(output_fd), &log_sources[0]);
494 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700495 // Tag dump only available in the tombstone, not logcat.
496 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700497
Mitch Phillips78f06702021-06-01 14:35:43 -0700498 for (const auto& result : log_sources) {
499 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
500 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
501 std::to_string(GetParam()) + R"(-byte allocation)");
502 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
503 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
504 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700505#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800506 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700507#endif
508}
509
Peter Collingbournedc476342021-05-12 15:56:43 -0700510TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
511#if defined(__aarch64__)
512 if (!mte_supported()) {
513 GTEST_SKIP() << "Requires MTE";
514 }
515
516 int intercept_result;
517 unique_fd output_fd;
518 StartProcess([&]() {
519 SetTagCheckingLevelSync();
520 volatile int* p = (volatile int*)malloc(GetParam());
521 free((void *)p);
522 p[-1] = 42;
523 });
524
525 StartIntercept(&output_fd);
526 FinishCrasher();
527 AssertDeath(SIGSEGV);
528 FinishIntercept(&intercept_result);
529
530 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
531
532 std::string result;
533 ConsumeFd(std::move(output_fd), &result);
534
535 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
536 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
537#else
538 GTEST_SKIP() << "Requires aarch64";
539#endif
540}
541
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800542TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800543#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700544 if (!mte_supported()) {
545 GTEST_SKIP() << "Requires MTE";
546 }
547
Mitch Phillips78f06702021-06-01 14:35:43 -0700548 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700549 int intercept_result;
550 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800551 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700552 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800553 volatile char* p = (volatile char*)malloc(GetParam());
554 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700555 });
556
557 StartIntercept(&output_fd);
558 FinishCrasher();
559 AssertDeath(SIGSEGV);
560 FinishIntercept(&intercept_result);
561
562 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
563
Mitch Phillips78f06702021-06-01 14:35:43 -0700564 std::vector<std::string> log_sources(2);
565 ConsumeFd(std::move(output_fd), &log_sources[0]);
566 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700567
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700568 // Tag dump only in tombstone, not logcat, and tagging is not used for
569 // overflow protection in the scudo secondary (guard pages are used instead).
570 if (GetParam() < 0x10000) {
571 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
572 }
573
Mitch Phillips78f06702021-06-01 14:35:43 -0700574 for (const auto& result : log_sources) {
575 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
576 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
577 std::to_string(GetParam()) + R"(-byte allocation)");
578 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
579 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700580#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800581 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700582#endif
583}
584
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800585TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800586#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700587 if (!mte_supported()) {
588 GTEST_SKIP() << "Requires MTE";
589 }
590
591 int intercept_result;
592 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800593 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700594 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800595 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700596 p[-1] = 42;
597 });
598
599 StartIntercept(&output_fd);
600 FinishCrasher();
601 AssertDeath(SIGSEGV);
602 FinishIntercept(&intercept_result);
603
604 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
605
606 std::string result;
607 ConsumeFd(std::move(output_fd), &result);
608
609 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800610 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800611 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700612 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700613 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700614 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700615#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800616 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700617#endif
618}
619
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800620TEST_F(CrasherTest, mte_async) {
621#if defined(__aarch64__)
622 if (!mte_supported()) {
623 GTEST_SKIP() << "Requires MTE";
624 }
625
626 int intercept_result;
627 unique_fd output_fd;
628 StartProcess([&]() {
629 SetTagCheckingLevelAsync();
630 volatile int* p = (volatile int*)malloc(16);
631 p[-1] = 42;
632 });
633
634 StartIntercept(&output_fd);
635 FinishCrasher();
636 AssertDeath(SIGSEGV);
637 FinishIntercept(&intercept_result);
638
639 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
640
641 std::string result;
642 ConsumeFd(std::move(output_fd), &result);
643
644 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
645#else
646 GTEST_SKIP() << "Requires aarch64";
647#endif
648}
649
Peter Collingbournef8622522020-04-07 14:07:32 -0700650TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800651#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700652 if (!mte_supported()) {
653 GTEST_SKIP() << "Requires MTE";
654 }
655
Mitch Phillips78f06702021-06-01 14:35:43 -0700656 LogcatCollector logcat_collector;
657
Peter Collingbournef8622522020-04-07 14:07:32 -0700658 int intercept_result;
659 unique_fd output_fd;
660 StartProcess([]() {
661 SetTagCheckingLevelSync();
662
663 // Make two allocations with the same tag and close to one another. Check for both properties
664 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
665 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
666 // (some non-zero value << 56) apart.
667 //
668 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
669 // other.
670 std::set<uintptr_t> allocs;
671 for (int i = 0; i != 4096; ++i) {
672 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
673 auto it = allocs.insert(alloc).first;
674 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
675 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
676 }
677 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
678 *reinterpret_cast<int*>(alloc + 16) = 42;
679 }
680 }
681 });
682
683 StartIntercept(&output_fd);
684 FinishCrasher();
685 AssertDeath(SIGSEGV);
686 FinishIntercept(&intercept_result);
687
688 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
689
Mitch Phillips78f06702021-06-01 14:35:43 -0700690 std::vector<std::string> log_sources(2);
691 ConsumeFd(std::move(output_fd), &log_sources[0]);
692 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700693
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700694 // Tag dump only in the tombstone, not logcat.
695 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
696
Mitch Phillips78f06702021-06-01 14:35:43 -0700697 for (const auto& result : log_sources) {
698 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
699 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800700 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700701 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
702 // overflows), so we can't match explicitly for an underflow message.
703 ASSERT_MATCH(result,
704 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
705 // Ensure there's at least two allocation traces (one for each cause).
706 ASSERT_MATCH(
707 result,
708 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
709 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700710#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800711 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700712#endif
713}
714
Peter Collingbournecd278072020-12-21 14:08:38 -0800715#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700716static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700717 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
718 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
719 size_t page_size = getpagesize();
720 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
721 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
722 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700723 return 0;
724 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700725 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
726 PROT_READ | PROT_WRITE | PROT_MTE);
727 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
728 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
729 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
730 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
731 }
732 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700733}
734#endif
735
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700736TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800737#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700738 if (!mte_supported()) {
739 GTEST_SKIP() << "Requires MTE";
740 }
741
742 int intercept_result;
743 unique_fd output_fd;
744 StartProcess([&]() {
745 SetTagCheckingLevelSync();
746 Trap(reinterpret_cast<void *>(CreateTagMapping()));
747 });
748
749 StartIntercept(&output_fd);
750 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700751 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700752 FinishIntercept(&intercept_result);
753
754 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
755
756 std::string result;
757 ConsumeFd(std::move(output_fd), &result);
758
759 ASSERT_MATCH(result, R"(memory near x0:
760.*
761.*
762 01.............0 0000000000000000 0000000000000000 ................
763 00.............0)");
764#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800765 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700766#endif
767}
768
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700769TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
770#if defined(__aarch64__)
771 if (!mte_supported()) {
772 GTEST_SKIP() << "Requires MTE";
773 }
774
775 int intercept_result;
776 unique_fd output_fd;
777 StartProcess([&]() {
778 SetTagCheckingLevelSync();
779 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
780 p[0] = 0; // Untagged pointer, tagged memory.
781 });
782
783 StartIntercept(&output_fd);
784 FinishCrasher();
785 AssertDeath(SIGSEGV);
786 FinishIntercept(&intercept_result);
787
788 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
789
790 std::string result;
791 ConsumeFd(std::move(output_fd), &result);
792
793 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
794\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
795#else
796 GTEST_SKIP() << "Requires aarch64";
797#endif
798}
799
800TEST_F(CrasherTest, mte_fault_tag_dump) {
801#if defined(__aarch64__)
802 if (!mte_supported()) {
803 GTEST_SKIP() << "Requires MTE";
804 }
805
806 int intercept_result;
807 unique_fd output_fd;
808 StartProcess([&]() {
809 SetTagCheckingLevelSync();
810 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
811 p[320] = 0; // Untagged pointer, tagged memory.
812 });
813
814 StartIntercept(&output_fd);
815 FinishCrasher();
816 AssertDeath(SIGSEGV);
817 FinishIntercept(&intercept_result);
818
819 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
820
821 std::string result;
822 ConsumeFd(std::move(output_fd), &result);
823
824 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
825\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
826\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
827\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
828)");
829#else
830 GTEST_SKIP() << "Requires aarch64";
831#endif
832}
833
834TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
835#if defined(__aarch64__)
836 if (!mte_supported()) {
837 GTEST_SKIP() << "Requires MTE";
838 }
839
840 int intercept_result;
841 unique_fd output_fd;
842 StartProcess([&]() {
843 SetTagCheckingLevelSync();
844 size_t page_size = getpagesize();
845 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
846 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
847 });
848
849 StartIntercept(&output_fd);
850 FinishCrasher();
851 AssertDeath(SIGSEGV);
852 FinishIntercept(&intercept_result);
853
854 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
855
856 std::string result;
857 ConsumeFd(std::move(output_fd), &result);
858
859 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
860 ASSERT_MATCH(result,
861 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
862\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
863
864)"); // Ensure truncation happened and there's a newline after the tag fault.
865#else
866 GTEST_SKIP() << "Requires aarch64";
867#endif
868}
869
Josh Gaocdea7502017-11-01 15:00:40 -0700870TEST_F(CrasherTest, LD_PRELOAD) {
871 int intercept_result;
872 unique_fd output_fd;
873 StartProcess([]() {
874 setenv("LD_PRELOAD", "nonexistent.so", 1);
875 *reinterpret_cast<volatile char*>(0xdead) = '1';
876 });
877
878 StartIntercept(&output_fd);
879 FinishCrasher();
880 AssertDeath(SIGSEGV);
881 FinishIntercept(&intercept_result);
882
883 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
884
885 std::string result;
886 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800887 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700888}
889
Josh Gaocbe70cb2016-10-18 18:17:52 -0700890TEST_F(CrasherTest, abort) {
891 int intercept_result;
892 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800893 StartProcess([]() {
894 abort();
895 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700896 StartIntercept(&output_fd);
897 FinishCrasher();
898 AssertDeath(SIGABRT);
899 FinishIntercept(&intercept_result);
900
901 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
902
903 std::string result;
904 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700905 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700906}
907
908TEST_F(CrasherTest, signal) {
909 int intercept_result;
910 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800911 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700912 while (true) {
913 sleep(1);
914 }
Josh Gao502cfd22017-02-17 01:39:15 -0800915 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700916 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700917 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700918 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
919
920 AssertDeath(SIGSEGV);
921 FinishIntercept(&intercept_result);
922
923 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
924
925 std::string result;
926 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700927 ASSERT_MATCH(
928 result,
929 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700930 ASSERT_MATCH(result, R"(backtrace:)");
931}
932
933TEST_F(CrasherTest, abort_message) {
934 int intercept_result;
935 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800936 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800937 // Arrived at experimentally;
938 // logd truncates at 4062.
939 // strlen("Abort message: ''") is 17.
940 // That's 4045, but we also want a NUL.
941 char buf[4045 + 1];
942 memset(buf, 'x', sizeof(buf));
943 buf[sizeof(buf) - 1] = '\0';
944 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800945 abort();
946 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700947 StartIntercept(&output_fd);
948 FinishCrasher();
949 AssertDeath(SIGABRT);
950 FinishIntercept(&intercept_result);
951
952 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
953
954 std::string result;
955 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800956 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700957}
958
Christopher Ferrise8891452021-08-17 17:34:53 -0700959TEST_F(CrasherTest, abort_message_newline_trimmed) {
960 int intercept_result;
961 unique_fd output_fd;
962 StartProcess([]() {
963 android_set_abort_message("Message with a newline.\n");
964 abort();
965 });
966 StartIntercept(&output_fd);
967 FinishCrasher();
968 AssertDeath(SIGABRT);
969 FinishIntercept(&intercept_result);
970
971 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
972
973 std::string result;
974 ConsumeFd(std::move(output_fd), &result);
975 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
976}
977
978TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
979 int intercept_result;
980 unique_fd output_fd;
981 StartProcess([]() {
982 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
983 abort();
984 });
985 StartIntercept(&output_fd);
986 FinishCrasher();
987 AssertDeath(SIGABRT);
988 FinishIntercept(&intercept_result);
989
990 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
991
992 std::string result;
993 ConsumeFd(std::move(output_fd), &result);
994 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
995}
996
Josh Gaoe06f2a42017-04-27 16:50:38 -0700997TEST_F(CrasherTest, abort_message_backtrace) {
998 int intercept_result;
999 unique_fd output_fd;
1000 StartProcess([]() {
1001 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001002 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001003 exit(0);
1004 });
1005 StartIntercept(&output_fd);
1006 FinishCrasher();
1007 AssertDeath(0);
1008 FinishIntercept(&intercept_result);
1009
1010 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1011
1012 std::string result;
1013 ConsumeFd(std::move(output_fd), &result);
1014 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1015}
1016
Josh Gaocbe70cb2016-10-18 18:17:52 -07001017TEST_F(CrasherTest, intercept_timeout) {
1018 int intercept_result;
1019 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001020 StartProcess([]() {
1021 abort();
1022 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001023 StartIntercept(&output_fd);
1024
1025 // Don't let crasher finish until we timeout.
1026 FinishIntercept(&intercept_result);
1027
1028 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1029 << intercept_result << ")";
1030
1031 FinishCrasher();
1032 AssertDeath(SIGABRT);
1033}
1034
Elliott Hughese4781d52021-03-17 09:15:15 -07001035TEST_F(CrasherTest, wait_for_debugger) {
1036 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1037 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001038 }
1039 sleep(1);
1040
Josh Gao502cfd22017-02-17 01:39:15 -08001041 StartProcess([]() {
1042 abort();
1043 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001044 FinishCrasher();
1045
1046 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001047 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001048 ASSERT_TRUE(WIFSTOPPED(status));
1049 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1050
1051 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1052
1053 AssertDeath(SIGABRT);
1054}
1055
Josh Gaocbe70cb2016-10-18 18:17:52 -07001056TEST_F(CrasherTest, backtrace) {
1057 std::string result;
1058 int intercept_result;
1059 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001060
1061 StartProcess([]() {
1062 abort();
1063 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001064 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001065
1066 std::this_thread::sleep_for(500ms);
1067
1068 sigval val;
1069 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001070 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001071 FinishIntercept(&intercept_result);
1072 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1073 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001074 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001075
1076 int status;
1077 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1078
1079 StartIntercept(&output_fd);
1080 FinishCrasher();
1081 AssertDeath(SIGABRT);
1082 FinishIntercept(&intercept_result);
1083 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1084 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001085 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001086}
Josh Gaofca7ca32017-01-23 12:05:35 -08001087
1088TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001089 int intercept_result;
1090 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001091 StartProcess([]() {
1092 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001093 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001094 });
Josh Gao502cfd22017-02-17 01:39:15 -08001095
1096 StartIntercept(&output_fd);
1097 FinishCrasher();
1098 AssertDeath(SIGABRT);
1099 FinishIntercept(&intercept_result);
1100
1101 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1102
1103 std::string result;
1104 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001105 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001106}
1107
Josh Gao502cfd22017-02-17 01:39:15 -08001108TEST_F(CrasherTest, capabilities) {
1109 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1110
Josh Gaofca7ca32017-01-23 12:05:35 -08001111 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001112 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1113 err(1, "failed to set PR_SET_KEEPCAPS");
1114 }
1115
1116 if (setresuid(1, 1, 1) != 0) {
1117 err(1, "setresuid failed");
1118 }
1119
1120 __user_cap_header_struct capheader;
1121 __user_cap_data_struct capdata[2];
1122 memset(&capheader, 0, sizeof(capheader));
1123 memset(&capdata, 0, sizeof(capdata));
1124
1125 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1126 capheader.pid = 0;
1127
1128 // Turn on every third capability.
1129 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1130 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1131 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1132 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1133 }
1134
1135 // Make sure CAP_SYS_PTRACE is off.
1136 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1137 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1138
1139 if (capset(&capheader, &capdata[0]) != 0) {
1140 err(1, "capset failed");
1141 }
1142
1143 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1144 err(1, "failed to drop ambient capabilities");
1145 }
1146
Josh Gaoa5199a92017-04-03 13:18:34 -07001147 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001148 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001149 });
Josh Gao502cfd22017-02-17 01:39:15 -08001150
1151 unique_fd output_fd;
1152 StartIntercept(&output_fd);
1153 FinishCrasher();
1154 AssertDeath(SIGSYS);
1155
1156 std::string result;
1157 int intercept_result;
1158 FinishIntercept(&intercept_result);
1159 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1160 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001161 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001162 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001163}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001164
Josh Gao2e7b8e22017-05-04 17:12:57 -07001165TEST_F(CrasherTest, fake_pid) {
1166 int intercept_result;
1167 unique_fd output_fd;
1168
1169 // Prime the getpid/gettid caches.
1170 UNUSED(getpid());
1171 UNUSED(gettid());
1172
1173 std::function<pid_t()> clone_fn = []() {
1174 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1175 };
1176 StartProcess(
1177 []() {
1178 ASSERT_NE(getpid(), syscall(__NR_getpid));
1179 ASSERT_NE(gettid(), syscall(__NR_gettid));
1180 raise(SIGSEGV);
1181 },
1182 clone_fn);
1183
1184 StartIntercept(&output_fd);
1185 FinishCrasher();
1186 AssertDeath(SIGSEGV);
1187 FinishIntercept(&intercept_result);
1188
1189 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1190
1191 std::string result;
1192 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001193 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001194}
1195
Josh Gaoe04ca272018-01-16 15:38:17 -08001196static const char* const kDebuggerdSeccompPolicy =
1197 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1198
Mitch Phillips18ce5422023-01-19 14:23:49 -08001199static void setup_jail(minijail* jail) {
1200 if (!jail) {
1201 LOG(FATAL) << "failed to create minijail";
1202 }
1203
Josh Gao6f9eeec2018-09-12 13:55:47 -07001204 std::string policy;
1205 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1206 PLOG(FATAL) << "failed to read policy file";
1207 }
1208
1209 // Allow a bunch of syscalls used by the tests.
1210 policy += "\nclone: 1";
1211 policy += "\nsigaltstack: 1";
1212 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001213 policy += "\ngetrlimit: 1";
1214 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001215
1216 FILE* tmp_file = tmpfile();
1217 if (!tmp_file) {
1218 PLOG(FATAL) << "tmpfile failed";
1219 }
1220
Christopher Ferris172b0a02019-09-18 17:48:30 -07001221 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001222 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1223 PLOG(FATAL) << "failed to write policy to tmpfile";
1224 }
1225
1226 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1227 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001228 }
1229
Mitch Phillips18ce5422023-01-19 14:23:49 -08001230 minijail_no_new_privs(jail);
1231 minijail_log_seccomp_filter_failures(jail);
1232 minijail_use_seccomp_filter(jail);
1233 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1234}
Josh Gaoe04ca272018-01-16 15:38:17 -08001235
Mitch Phillips18ce5422023-01-19 14:23:49 -08001236static pid_t seccomp_fork_impl(void (*prejail)()) {
1237 ScopedMinijail jail{minijail_new()};
1238 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001239
1240 pid_t result = fork();
1241 if (result == -1) {
1242 return result;
1243 } else if (result != 0) {
1244 return result;
1245 }
1246
1247 // Spawn and detach a thread that spins forever.
1248 std::atomic<bool> thread_ready(false);
1249 std::thread thread([&jail, &thread_ready]() {
1250 minijail_enter(jail.get());
1251 thread_ready = true;
1252 for (;;)
1253 ;
1254 });
1255 thread.detach();
1256
1257 while (!thread_ready) {
1258 continue;
1259 }
1260
Josh Gao70adac62018-02-22 11:38:33 -08001261 if (prejail) {
1262 prejail();
1263 }
1264
Josh Gaoe04ca272018-01-16 15:38:17 -08001265 minijail_enter(jail.get());
1266 return result;
1267}
1268
Josh Gao70adac62018-02-22 11:38:33 -08001269static pid_t seccomp_fork() {
1270 return seccomp_fork_impl(nullptr);
1271}
1272
Josh Gaoe04ca272018-01-16 15:38:17 -08001273TEST_F(CrasherTest, seccomp_crash) {
1274 int intercept_result;
1275 unique_fd output_fd;
1276
1277 StartProcess([]() { abort(); }, &seccomp_fork);
1278
1279 StartIntercept(&output_fd);
1280 FinishCrasher();
1281 AssertDeath(SIGABRT);
1282 FinishIntercept(&intercept_result);
1283 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1284
1285 std::string result;
1286 ConsumeFd(std::move(output_fd), &result);
1287 ASSERT_BACKTRACE_FRAME(result, "abort");
1288}
1289
Josh Gao70adac62018-02-22 11:38:33 -08001290static pid_t seccomp_fork_rlimit() {
1291 return seccomp_fork_impl([]() {
1292 struct rlimit rlim = {
1293 .rlim_cur = 512 * 1024 * 1024,
1294 .rlim_max = 512 * 1024 * 1024,
1295 };
1296
1297 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1298 raise(SIGINT);
1299 }
1300 });
1301}
1302
1303TEST_F(CrasherTest, seccomp_crash_oom) {
1304 int intercept_result;
1305 unique_fd output_fd;
1306
1307 StartProcess(
1308 []() {
1309 std::vector<void*> vec;
1310 for (int i = 0; i < 512; ++i) {
1311 char* buf = static_cast<char*>(malloc(1024 * 1024));
1312 if (!buf) {
1313 abort();
1314 }
1315 memset(buf, 0xff, 1024 * 1024);
1316 vec.push_back(buf);
1317 }
1318 },
1319 &seccomp_fork_rlimit);
1320
1321 StartIntercept(&output_fd);
1322 FinishCrasher();
1323 AssertDeath(SIGABRT);
1324 FinishIntercept(&intercept_result);
1325 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1326
1327 // We can't actually generate a backtrace, just make sure that the process terminates.
1328}
1329
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001330__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001331 siginfo_t siginfo;
1332 siginfo.si_code = SI_QUEUE;
1333 siginfo.si_pid = getpid();
1334 siginfo.si_uid = getuid();
1335
1336 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1337 PLOG(FATAL) << "invalid dump type";
1338 }
1339
1340 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1341
Josh Gaoa48b41b2019-12-13 14:11:04 -08001342 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001343 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1344 return false;
1345 }
1346
1347 return true;
1348}
1349
Christopher Ferrisb999b822022-02-09 17:57:21 -08001350extern "C" void foo() {
1351 LOG(INFO) << "foo";
1352 std::this_thread::sleep_for(1s);
1353}
1354
1355extern "C" void bar() {
1356 LOG(INFO) << "bar";
1357 std::this_thread::sleep_for(1s);
1358}
1359
Josh Gaoe04ca272018-01-16 15:38:17 -08001360TEST_F(CrasherTest, seccomp_tombstone) {
1361 int intercept_result;
1362 unique_fd output_fd;
1363
1364 static const auto dump_type = kDebuggerdTombstone;
1365 StartProcess(
1366 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001367 std::thread a(foo);
1368 std::thread b(bar);
1369
1370 std::this_thread::sleep_for(100ms);
1371
Josh Gaoe04ca272018-01-16 15:38:17 -08001372 raise_debugger_signal(dump_type);
1373 _exit(0);
1374 },
1375 &seccomp_fork);
1376
1377 StartIntercept(&output_fd, dump_type);
1378 FinishCrasher();
1379 AssertDeath(0);
1380 FinishIntercept(&intercept_result);
1381 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1382
1383 std::string result;
1384 ConsumeFd(std::move(output_fd), &result);
1385 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001386 ASSERT_BACKTRACE_FRAME(result, "foo");
1387 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001388}
1389
Christopher Ferris303c6be2022-05-24 17:08:33 -07001390TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1391 int intercept_result;
1392 unique_fd output_fd;
1393
1394 static const auto dump_type = kDebuggerdTombstone;
1395 StartProcess(
1396 []() {
1397 std::thread abort_thread([] { abort(); });
1398 abort_thread.join();
1399 },
1400 &seccomp_fork);
1401
1402 StartIntercept(&output_fd, dump_type);
1403 FinishCrasher();
1404 AssertDeath(SIGABRT);
1405 FinishIntercept(&intercept_result);
1406 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1407
1408 std::string result;
1409 ConsumeFd(std::move(output_fd), &result);
1410 ASSERT_BACKTRACE_FRAME(result, "abort");
1411}
1412
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001413TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1414 int intercept_result;
1415 unique_fd output_fd;
1416
1417 static const auto dump_type = kDebuggerdTombstone;
1418 StartProcess(
1419 []() {
1420 std::thread a(foo);
1421 std::thread b(bar);
1422
1423 std::this_thread::sleep_for(100ms);
1424
1425 std::thread abort_thread([] { abort(); });
1426 abort_thread.join();
1427 },
1428 &seccomp_fork);
1429
1430 StartIntercept(&output_fd, dump_type);
1431 FinishCrasher();
1432 AssertDeath(SIGABRT);
1433 FinishIntercept(&intercept_result);
1434 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1435
1436 std::string result;
1437 ConsumeFd(std::move(output_fd), &result);
1438 ASSERT_BACKTRACE_FRAME(result, "abort");
1439 ASSERT_BACKTRACE_FRAME(result, "foo");
1440 ASSERT_BACKTRACE_FRAME(result, "bar");
1441 ASSERT_BACKTRACE_FRAME(result, "main");
1442}
1443
Josh Gaoe04ca272018-01-16 15:38:17 -08001444TEST_F(CrasherTest, seccomp_backtrace) {
1445 int intercept_result;
1446 unique_fd output_fd;
1447
1448 static const auto dump_type = kDebuggerdNativeBacktrace;
1449 StartProcess(
1450 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001451 std::thread a(foo);
1452 std::thread b(bar);
1453
1454 std::this_thread::sleep_for(100ms);
1455
Josh Gaoe04ca272018-01-16 15:38:17 -08001456 raise_debugger_signal(dump_type);
1457 _exit(0);
1458 },
1459 &seccomp_fork);
1460
1461 StartIntercept(&output_fd, dump_type);
1462 FinishCrasher();
1463 AssertDeath(0);
1464 FinishIntercept(&intercept_result);
1465 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1466
1467 std::string result;
1468 ConsumeFd(std::move(output_fd), &result);
1469 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001470 ASSERT_BACKTRACE_FRAME(result, "foo");
1471 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001472}
1473
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001474TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1475 int intercept_result;
1476 unique_fd output_fd;
1477
1478 static const auto dump_type = kDebuggerdNativeBacktrace;
1479 StartProcess(
1480 []() {
1481 std::thread a(foo);
1482 std::thread b(bar);
1483
1484 std::this_thread::sleep_for(100ms);
1485
1486 std::thread raise_thread([] {
1487 raise_debugger_signal(dump_type);
1488 _exit(0);
1489 });
1490 raise_thread.join();
1491 },
1492 &seccomp_fork);
1493
1494 StartIntercept(&output_fd, dump_type);
1495 FinishCrasher();
1496 AssertDeath(0);
1497 FinishIntercept(&intercept_result);
1498 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1499
1500 std::string result;
1501 ConsumeFd(std::move(output_fd), &result);
1502 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1503 ASSERT_BACKTRACE_FRAME(result, "foo");
1504 ASSERT_BACKTRACE_FRAME(result, "bar");
1505 ASSERT_BACKTRACE_FRAME(result, "main");
1506}
1507
Josh Gaoe04ca272018-01-16 15:38:17 -08001508TEST_F(CrasherTest, seccomp_crash_logcat) {
1509 StartProcess([]() { abort(); }, &seccomp_fork);
1510 FinishCrasher();
1511
1512 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1513 AssertDeath(SIGABRT);
1514}
1515
Josh Gaofd13bf02017-08-18 15:37:26 -07001516TEST_F(CrasherTest, competing_tracer) {
1517 int intercept_result;
1518 unique_fd output_fd;
1519 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001520 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001521 });
1522
1523 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001524
1525 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001526 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001527
1528 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001529 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001530 ASSERT_TRUE(WIFSTOPPED(status));
1531 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1532
1533 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1534 FinishIntercept(&intercept_result);
1535 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1536
1537 std::string result;
1538 ConsumeFd(std::move(output_fd), &result);
1539 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1540 regex += std::to_string(gettid());
1541 regex += R"( \(.+debuggerd_test)";
1542 ASSERT_MATCH(result, regex.c_str());
1543
Christopher Ferris172b0a02019-09-18 17:48:30 -07001544 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001545 ASSERT_TRUE(WIFSTOPPED(status));
1546 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1547
Josh Gaofd13bf02017-08-18 15:37:26 -07001548 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1549 AssertDeath(SIGABRT);
1550}
1551
Mitch Phillips18ce5422023-01-19 14:23:49 -08001552struct GwpAsanTestParameters {
1553 size_t alloc_size;
1554 bool free_before_access;
1555 int access_offset;
1556 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1557};
1558
1559struct GwpAsanCrasherTest
1560 : CrasherTest,
1561 testing::WithParamInterface<
1562 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1563
1564GwpAsanTestParameters gwp_asan_tests[] = {
1565 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1566 "Use After Free, 0 bytes into a 7-byte allocation"},
1567 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1568 "Use After Free, 1 byte into a 15-byte allocation"},
1569 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1570 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1571 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1572 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1573};
1574
1575INSTANTIATE_TEST_SUITE_P(
1576 GwpAsanTests, GwpAsanCrasherTest,
1577 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1578 /* recoverable */ testing::Bool(),
1579 /* seccomp */ testing::Bool()),
1580 [](const testing::TestParamInfo<
1581 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1582 const GwpAsanTestParameters& params = std::get<0>(info.param);
1583 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1584 name += testing::PrintToString(params.alloc_size);
1585 name += "Alloc";
1586 if (params.access_offset < 0) {
1587 name += "Left";
1588 name += testing::PrintToString(params.access_offset * -1);
1589 } else {
1590 name += "Right";
1591 name += testing::PrintToString(params.access_offset);
1592 }
1593 name += "Bytes";
1594 if (std::get<1>(info.param)) name += "Recoverable";
1595 if (std::get<2>(info.param)) name += "Seccomp";
1596 return name;
1597 });
1598
1599TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1600 if (mte_supported()) {
1601 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1602 // instead of GWP-ASan.
1603 GTEST_SKIP() << "Skipped on MTE.";
1604 }
1605 // Skip this test on HWASan, which will reliably catch test errors as well.
1606 SKIP_WITH_HWASAN;
1607
1608 GwpAsanTestParameters params = std::get<0>(GetParam());
1609 bool recoverable = std::get<1>(GetParam());
1610 LogcatCollector logcat_collector;
1611
1612 int intercept_result;
1613 unique_fd output_fd;
1614 StartProcess([&recoverable]() {
1615 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1616 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1617 if (recoverable) {
1618 env[3] = "GWP_ASAN_RECOVERABLE=true";
1619 }
1620 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1621 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1622 "DISABLED_run_gwp_asan_test");
1623 std::string test_filter = "--gtest_filter=*";
1624 test_filter += test_name;
1625 std::string this_binary = android::base::GetExecutablePath();
1626 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1627 test_filter.c_str(), nullptr};
1628 // We check the crash report from a debuggerd handler and from logcat. The
1629 // echo from stdout/stderr of the subprocess trips up atest, because it
1630 // doesn't like that two tests started in a row without the first one
1631 // finishing (even though the second one is in a subprocess).
1632 close(STDOUT_FILENO);
1633 close(STDERR_FILENO);
1634 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1635 });
1636
1637 StartIntercept(&output_fd);
1638 FinishCrasher();
1639 if (recoverable) {
1640 AssertDeath(0);
1641 } else {
1642 AssertDeath(SIGSEGV);
1643 }
1644 FinishIntercept(&intercept_result);
1645
1646 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1647
1648 std::vector<std::string> log_sources(2);
1649 ConsumeFd(std::move(output_fd), &log_sources[0]);
1650 logcat_collector.Collect(&log_sources[1]);
1651
1652 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1653 // information. Make sure the recovery still works, but the report won't be
1654 // hugely useful, it looks like a regular SEGV.
1655 bool seccomp = std::get<2>(GetParam());
1656 if (!seccomp) {
1657 for (const auto& result : log_sources) {
1658 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1659 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1660 if (params.free_before_access) {
1661 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1662 }
1663 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1664 }
1665 }
1666}
1667
1668TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1669 GwpAsanTestParameters params = std::get<0>(GetParam());
1670 bool seccomp = std::get<2>(GetParam());
1671 if (seccomp) {
1672 ScopedMinijail jail{minijail_new()};
1673 setup_jail(jail.get());
1674 minijail_enter(jail.get());
1675 }
1676
1677 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1678 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1679 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1680 p[params.access_offset] = 42;
1681 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1682}
1683
Josh Gaobf06a402018-08-27 16:34:01 -07001684TEST_F(CrasherTest, fdsan_warning_abort_message) {
1685 int intercept_result;
1686 unique_fd output_fd;
1687
1688 StartProcess([]() {
1689 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001690 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001691 if (fd == -1) {
1692 abort();
1693 }
1694 close(fd.get());
1695 _exit(0);
1696 });
1697
1698 StartIntercept(&output_fd);
1699 FinishCrasher();
1700 AssertDeath(0);
1701 FinishIntercept(&intercept_result);
1702 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1703
1704 std::string result;
1705 ConsumeFd(std::move(output_fd), &result);
1706 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1707}
1708
Josh Gaoc3c8c022017-02-13 16:36:18 -08001709TEST(crash_dump, zombie) {
1710 pid_t forkpid = fork();
1711
Josh Gaoc3c8c022017-02-13 16:36:18 -08001712 pid_t rc;
1713 int status;
1714
1715 if (forkpid == 0) {
1716 errno = 0;
1717 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1718 if (rc != -1 || errno != ECHILD) {
1719 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1720 }
1721
Josh Gaoa48b41b2019-12-13 14:11:04 -08001722 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001723
1724 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001725 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001726 if (rc != -1 || errno != ECHILD) {
1727 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1728 }
1729 _exit(0);
1730 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001731 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001732 ASSERT_EQ(forkpid, rc);
1733 ASSERT_TRUE(WIFEXITED(status));
1734 ASSERT_EQ(0, WEXITSTATUS(status));
1735 }
1736}
Josh Gao352a8452017-03-30 16:46:21 -07001737
1738TEST(tombstoned, no_notify) {
1739 // Do this a few times.
1740 for (int i = 0; i < 3; ++i) {
1741 pid_t pid = 123'456'789 + i;
1742
1743 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001744 InterceptStatus status;
1745 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1746 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001747
1748 {
1749 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001750 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001751 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1752 }
1753
1754 pid_t read_pid;
1755 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1756 ASSERT_EQ(read_pid, pid);
1757 }
1758}
1759
1760TEST(tombstoned, stress) {
1761 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1762 static constexpr int kDumpCount = 100;
1763
1764 std::atomic<bool> start(false);
1765 std::vector<std::thread> threads;
1766 threads.emplace_back([&start]() {
1767 while (!start) {
1768 continue;
1769 }
1770
1771 // Use a way out of range pid, to avoid stomping on an actual process.
1772 pid_t pid_base = 1'000'000;
1773
1774 for (int dump = 0; dump < kDumpCount; ++dump) {
1775 pid_t pid = pid_base + dump;
1776
1777 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001778 InterceptStatus status;
1779 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1780 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001781
1782 // Pretend to crash, and then immediately close the socket.
1783 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1784 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1785 if (sockfd == -1) {
1786 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1787 }
1788 TombstonedCrashPacket packet = {};
1789 packet.packet_type = CrashPacketType::kDumpRequest;
1790 packet.packet.dump_request.pid = pid;
1791 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1792 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1793 }
1794
1795 continue;
1796 }
1797 });
1798
1799 threads.emplace_back([&start]() {
1800 while (!start) {
1801 continue;
1802 }
1803
1804 // Use a way out of range pid, to avoid stomping on an actual process.
1805 pid_t pid_base = 2'000'000;
1806
1807 for (int dump = 0; dump < kDumpCount; ++dump) {
1808 pid_t pid = pid_base + dump;
1809
1810 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001811 InterceptStatus status;
1812 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1813 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001814
1815 {
1816 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001817 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001818 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1819 tombstoned_notify_completion(tombstoned_socket.get());
1820 }
1821
1822 // TODO: Fix the race that requires this sleep.
1823 std::this_thread::sleep_for(50ms);
1824
1825 pid_t read_pid;
1826 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1827 ASSERT_EQ(read_pid, pid);
1828 }
1829 });
1830
1831 start = true;
1832
1833 for (std::thread& thread : threads) {
1834 thread.join();
1835 }
1836}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001837
1838TEST(tombstoned, java_trace_intercept_smoke) {
1839 // Using a "real" PID is a little dangerous here - if the test fails
1840 // or crashes, we might end up getting a bogus / unreliable stack
1841 // trace.
1842 const pid_t self = getpid();
1843
1844 unique_fd intercept_fd, output_fd;
1845 InterceptStatus status;
1846 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1847 ASSERT_EQ(InterceptStatus::kRegistered, status);
1848
Josh Gao76e1e302021-01-26 15:53:11 -08001849 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001850 // should result in a "regular" FD and not the installed intercept.
1851 const char native[] = "native";
1852 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001853 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001854 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1855 tombstoned_notify_completion(tombstoned_socket.get());
1856
1857 // Then, connect to tombstoned asking for a java backtrace. This *should*
1858 // trigger the intercept.
1859 const char java[] = "java";
1860 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1861 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1862 tombstoned_notify_completion(tombstoned_socket.get());
1863
1864 char outbuf[sizeof(java)];
1865 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1866 ASSERT_STREQ("java", outbuf);
1867}
1868
1869TEST(tombstoned, multiple_intercepts) {
1870 const pid_t fake_pid = 1'234'567;
1871 unique_fd intercept_fd, output_fd;
1872 InterceptStatus status;
1873 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1874 ASSERT_EQ(InterceptStatus::kRegistered, status);
1875
1876 unique_fd intercept_fd_2, output_fd_2;
1877 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1878 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1879}
1880
1881TEST(tombstoned, intercept_any) {
1882 const pid_t fake_pid = 1'234'567;
1883
1884 unique_fd intercept_fd, output_fd;
1885 InterceptStatus status;
1886 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1887 ASSERT_EQ(InterceptStatus::kRegistered, status);
1888
1889 const char any[] = "any";
1890 unique_fd tombstoned_socket, input_fd;
1891 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1892 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1893 tombstoned_notify_completion(tombstoned_socket.get());
1894
1895 char outbuf[sizeof(any)];
1896 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1897 ASSERT_STREQ("any", outbuf);
1898}
Josh Gao2b22ae12018-09-12 14:51:03 -07001899
1900TEST(tombstoned, interceptless_backtrace) {
1901 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1902 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1903 std::map<int, time_t> result;
1904 for (int i = 0; i < 99; ++i) {
1905 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1906 struct stat st;
1907 if (stat(path.c_str(), &st) == 0) {
1908 result[i] = st.st_mtim.tv_sec;
1909 }
1910 }
1911 return result;
1912 };
1913
1914 auto before = get_tombstone_timestamps();
1915 for (int i = 0; i < 50; ++i) {
1916 raise_debugger_signal(kDebuggerdNativeBacktrace);
1917 }
1918 auto after = get_tombstone_timestamps();
1919
1920 int diff = 0;
1921 for (int i = 0; i < 99; ++i) {
1922 if (after.count(i) == 0) {
1923 continue;
1924 }
1925 if (before.count(i) == 0) {
1926 ++diff;
1927 continue;
1928 }
1929 if (before[i] != after[i]) {
1930 ++diff;
1931 }
1932 }
1933
1934 // We can't be sure that nothing's crash looping in the background.
1935 // This should be good enough, though...
1936 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1937}
Christopher Ferris481e8372019-07-15 17:13:24 -07001938
1939static __attribute__((__noinline__)) void overflow_stack(void* p) {
1940 void* buf[1];
1941 buf[0] = p;
1942 static volatile void* global = buf;
1943 if (global) {
1944 global = buf;
1945 overflow_stack(&buf);
1946 }
1947}
1948
1949TEST_F(CrasherTest, stack_overflow) {
1950 int intercept_result;
1951 unique_fd output_fd;
1952 StartProcess([]() { overflow_stack(nullptr); });
1953
1954 StartIntercept(&output_fd);
1955 FinishCrasher();
1956 AssertDeath(SIGSEGV);
1957 FinishIntercept(&intercept_result);
1958
1959 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1960
1961 std::string result;
1962 ConsumeFd(std::move(output_fd), &result);
1963 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1964}
Josh Gao76e1e302021-01-26 15:53:11 -08001965
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001966static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1967 std::string test_lib(testing::internal::GetArgvs()[0]);
1968 auto const value = test_lib.find_last_of('/');
1969 if (value == std::string::npos) {
1970 test_lib = "./";
1971 } else {
1972 test_lib = test_lib.substr(0, value + 1) + "./";
1973 }
1974 test_lib += "libcrash_test.so";
1975
1976 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1977 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1978
1979 // Copy the shared so to a tempory directory.
1980 return system(cp_cmd.c_str()) == 0;
1981}
1982
1983TEST_F(CrasherTest, unreadable_elf) {
1984 int intercept_result;
1985 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001986 std::string tmp_so_name;
1987 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001988 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001989 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1990 _exit(1);
1991 }
1992 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1993 if (handle == nullptr) {
1994 _exit(1);
1995 }
1996 // Delete the original shared library so that we get the warning
1997 // about unreadable elf files.
1998 if (unlink(tmp_so_name.c_str()) == -1) {
1999 _exit(1);
2000 }
2001 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2002 if (crash_func == nullptr) {
2003 _exit(1);
2004 }
2005 crash_func();
2006 });
2007
2008 StartIntercept(&output_fd);
2009 FinishCrasher();
2010 AssertDeath(SIGSEGV);
2011 FinishIntercept(&intercept_result);
2012
2013 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2014
2015 std::string result;
2016 ConsumeFd(std::move(output_fd), &result);
2017 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002018 std::string match_str = "NOTE: " + tmp_so_name;
2019 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002020}
2021
Josh Gao76e1e302021-01-26 15:53:11 -08002022TEST(tombstoned, proto) {
2023 const pid_t self = getpid();
2024 unique_fd tombstoned_socket, text_fd, proto_fd;
2025 ASSERT_TRUE(
2026 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2027
2028 tombstoned_notify_completion(tombstoned_socket.get());
2029
2030 ASSERT_NE(-1, text_fd.get());
2031 ASSERT_NE(-1, proto_fd.get());
2032
2033 struct stat text_st;
2034 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2035
2036 // Give tombstoned some time to link the files into place.
2037 std::this_thread::sleep_for(100ms);
2038
2039 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08002040 std::optional<std::string> tombstone_file;
2041 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2042 ASSERT_TRUE(dir_h != nullptr);
2043 std::regex tombstone_re("tombstone_\\d+");
2044 dirent* entry;
2045 while ((entry = readdir(dir_h.get())) != nullptr) {
2046 if (!std::regex_match(entry->d_name, tombstone_re)) {
2047 continue;
2048 }
2049 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002050
2051 struct stat st;
2052 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2053 continue;
2054 }
2055
2056 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002057 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002058 break;
2059 }
2060 }
2061
Christopher Ferris35da2882021-02-17 15:39:06 -08002062 ASSERT_TRUE(tombstone_file);
2063 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002064
2065 struct stat proto_fd_st;
2066 struct stat proto_file_st;
2067 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2068 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2069
2070 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2071 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2072}
2073
2074TEST(tombstoned, proto_intercept) {
2075 const pid_t self = getpid();
2076 unique_fd intercept_fd, output_fd;
2077 InterceptStatus status;
2078
2079 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2080 ASSERT_EQ(InterceptStatus::kRegistered, status);
2081
2082 unique_fd tombstoned_socket, text_fd, proto_fd;
2083 ASSERT_TRUE(
2084 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2085 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2086 tombstoned_notify_completion(tombstoned_socket.get());
2087
2088 text_fd.reset();
2089
2090 std::string output;
2091 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2092 ASSERT_EQ("foo", output);
2093}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002094
2095// Verify that when an intercept is present for the main thread, and the signal
2096// is received on a different thread, the intercept still works.
2097TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2098 StartProcess([]() {
2099 std::thread thread([]() {
2100 // Raise the signal on the side thread.
2101 raise_debugger_signal(kDebuggerdNativeBacktrace);
2102 });
2103 thread.join();
2104 _exit(0);
2105 });
2106
2107 unique_fd output_fd;
2108 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2109 FinishCrasher();
2110 AssertDeath(0);
2111
2112 int intercept_result;
2113 FinishIntercept(&intercept_result);
2114 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2115
2116 std::string result;
2117 ConsumeFd(std::move(output_fd), &result);
2118 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2119}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002120
2121static std::string format_pointer(uintptr_t ptr) {
2122#if defined(__LP64__)
2123 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2124 static_cast<uint32_t>(ptr & 0xffffffff));
2125#else
2126 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2127#endif
2128}
2129
2130static std::string format_pointer(void* ptr) {
2131 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2132}
2133
2134static std::string format_full_pointer(uintptr_t ptr) {
2135#if defined(__LP64__)
2136 return android::base::StringPrintf("%016" PRIx64, ptr);
2137#else
2138 return android::base::StringPrintf("%08x", ptr);
2139#endif
2140}
2141
2142static std::string format_full_pointer(void* ptr) {
2143 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2144}
2145
2146__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2147 int* crash_ptr = reinterpret_cast<int*>(ptr);
2148 *crash_ptr = 1;
2149 return *crash_ptr;
2150}
2151
2152// Verify that a fault address before the first map is properly handled.
2153TEST_F(CrasherTest, fault_address_before_first_map) {
2154 StartProcess([]() {
2155 ASSERT_EQ(0, crash_call(0x1024));
2156 _exit(0);
2157 });
2158
2159 unique_fd output_fd;
2160 StartIntercept(&output_fd);
2161 FinishCrasher();
2162 AssertDeath(SIGSEGV);
2163
2164 int intercept_result;
2165 FinishIntercept(&intercept_result);
2166 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2167
2168 std::string result;
2169 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002170 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002171
2172 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2173
2174 std::string match_str = android::base::StringPrintf(
2175 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2176 format_pointer(0x1024).c_str());
2177 ASSERT_MATCH(result, match_str);
2178}
2179
2180// Verify that a fault address after the last map is properly handled.
2181TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002182 // This makes assumptions about the memory layout that are not true in HWASan
2183 // processes.
2184 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002185 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2186 StartProcess([crash_uptr]() {
2187 ASSERT_EQ(0, crash_call(crash_uptr));
2188 _exit(0);
2189 });
2190
2191 unique_fd output_fd;
2192 StartIntercept(&output_fd);
2193 FinishCrasher();
2194 AssertDeath(SIGSEGV);
2195
2196 int intercept_result;
2197 FinishIntercept(&intercept_result);
2198 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2199
2200 std::string result;
2201 ConsumeFd(std::move(output_fd), &result);
2202
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002203 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2204 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002205 ASSERT_MATCH(result, match_str);
2206
2207 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2208
2209 // Assumes that the open files section comes after the map section.
2210 // If that assumption changes, the regex below needs to change.
2211 match_str = android::base::StringPrintf(
2212 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2213 format_pointer(crash_uptr).c_str());
2214 ASSERT_MATCH(result, match_str);
2215}
2216
2217// Verify that a fault address between maps is properly handled.
2218TEST_F(CrasherTest, fault_address_between_maps) {
2219 // Create a map before the fork so it will be present in the child.
2220 void* start_ptr =
2221 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2222 ASSERT_NE(MAP_FAILED, start_ptr);
2223 // Unmap the page in the middle.
2224 void* middle_ptr =
2225 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2226 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2227
2228 StartProcess([middle_ptr]() {
2229 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2230 _exit(0);
2231 });
2232
2233 // Unmap the two maps.
2234 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2235 void* end_ptr =
2236 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2237 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2238
2239 unique_fd output_fd;
2240 StartIntercept(&output_fd);
2241 FinishCrasher();
2242 AssertDeath(SIGSEGV);
2243
2244 int intercept_result;
2245 FinishIntercept(&intercept_result);
2246 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2247
2248 std::string result;
2249 ConsumeFd(std::move(output_fd), &result);
2250
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002251 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2252 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002253 ASSERT_MATCH(result, match_str);
2254
2255 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2256
2257 match_str = android::base::StringPrintf(
2258 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2259 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2260 format_pointer(end_ptr).c_str());
2261 ASSERT_MATCH(result, match_str);
2262}
2263
2264// Verify that a fault address happens in the correct map.
2265TEST_F(CrasherTest, fault_address_in_map) {
2266 // Create a map before the fork so it will be present in the child.
2267 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2268 ASSERT_NE(MAP_FAILED, ptr);
2269
2270 StartProcess([ptr]() {
2271 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2272 _exit(0);
2273 });
2274
2275 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2276
2277 unique_fd output_fd;
2278 StartIntercept(&output_fd);
2279 FinishCrasher();
2280 AssertDeath(SIGSEGV);
2281
2282 int intercept_result;
2283 FinishIntercept(&intercept_result);
2284 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2285
2286 std::string result;
2287 ConsumeFd(std::move(output_fd), &result);
2288
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002289 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2290 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002291 ASSERT_MATCH(result, match_str);
2292
2293 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2294
2295 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2296 ASSERT_MATCH(result, match_str);
2297}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002298
2299static constexpr uint32_t kDexData[] = {
2300 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2301 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2302 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2303 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2304 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2305 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2306 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2307 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2308 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2309 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2310 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2311 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2312 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2313 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2314 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2315 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2316 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2317};
2318
2319TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2320 StartProcess([]() {
2321 TemporaryDir td;
2322 std::string tmp_so_name;
2323 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2324 _exit(1);
2325 }
2326
2327 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2328 // move the library to which has a basename of libart.so.
2329 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2330 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2331 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2332 if (handle == nullptr) {
2333 _exit(1);
2334 }
2335
2336 void* ptr =
2337 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2338 ASSERT_TRUE(ptr != MAP_FAILED);
2339 memcpy(ptr, kDexData, sizeof(kDexData));
2340 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2341
2342 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2343 .symfile_size = sizeof(kDexData)};
2344
2345 JITDescriptor* dex_debug =
2346 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2347 ASSERT_TRUE(dex_debug != nullptr);
2348 dex_debug->version = 1;
2349 dex_debug->action_flag = 0;
2350 dex_debug->relevant_entry = 0;
2351 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2352
2353 // This sets the magic dex pc value for register 0, using the value
2354 // of register 1 + 0x102.
2355 asm(".cfi_escape "
2356 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2357 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2358 "0x13 /* DW_OP_drop */,"
2359 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2360
2361 // For each different architecture, set register one to the dex ptr mmap
2362 // created above. Then do a nullptr dereference to force a crash.
2363#if defined(__arm__)
2364 asm volatile(
2365 "mov r1, %[base]\n"
2366 "mov r2, 0\n"
2367 "str r3, [r2]\n"
2368 : [base] "+r"(ptr)
2369 :
2370 : "r1", "r2", "r3", "memory");
2371#elif defined(__aarch64__)
2372 asm volatile(
2373 "mov x1, %[base]\n"
2374 "mov x2, 0\n"
2375 "str x3, [x2]\n"
2376 : [base] "+r"(ptr)
2377 :
2378 : "x1", "x2", "x3", "memory");
2379#elif defined(__i386__)
2380 asm volatile(
2381 "mov %[base], %%ecx\n"
2382 "movl $0, %%edi\n"
2383 "movl 0(%%edi), %%edx\n"
2384 : [base] "+r"(ptr)
2385 :
2386 : "edi", "ecx", "edx", "memory");
2387#elif defined(__x86_64__)
2388 asm volatile(
2389 "mov %[base], %%rdx\n"
2390 "movq 0, %%rdi\n"
2391 "movq 0(%%rdi), %%rcx\n"
2392 : [base] "+r"(ptr)
2393 :
2394 : "rcx", "rdx", "rdi", "memory");
2395#else
2396#error "Unsupported architecture"
2397#endif
2398 _exit(0);
2399 });
2400
2401 unique_fd output_fd;
2402 StartIntercept(&output_fd);
2403 FinishCrasher();
2404 AssertDeath(SIGSEGV);
2405
2406 int intercept_result;
2407 FinishIntercept(&intercept_result);
2408 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2409
2410 std::string result;
2411 ConsumeFd(std::move(output_fd), &result);
2412
2413 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002414 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002415
2416 // Now verify that the dex_pc frame includes a proper function name.
2417 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2418}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002419
2420static std::string format_map_pointer(uintptr_t ptr) {
2421#if defined(__LP64__)
2422 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2423 static_cast<uint32_t>(ptr & 0xffffffff));
2424#else
2425 return android::base::StringPrintf("%08x", ptr);
2426#endif
2427}
2428
2429// Verify that map data is properly formatted.
2430TEST_F(CrasherTest, verify_map_format) {
2431 // Create multiple maps to make sure that the map data is formatted properly.
2432 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2433 ASSERT_NE(MAP_FAILED, none_map);
2434 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2435 ASSERT_NE(MAP_FAILED, r_map);
2436 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2437 ASSERT_NE(MAP_FAILED, w_map);
2438 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2439 ASSERT_NE(MAP_FAILED, x_map);
2440
2441 TemporaryFile tf;
2442 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2443 char c = 'f';
2444 ASSERT_EQ(1, write(tf.fd, &c, 1));
2445 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2446 ASSERT_EQ(1, write(tf.fd, &c, 1));
2447 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2448 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2449 ASSERT_NE(MAP_FAILED, file_map);
2450
2451 StartProcess([]() { abort(); });
2452
2453 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2454 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2455 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2456 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2457 ASSERT_EQ(0, munmap(file_map, 0x3001));
2458
2459 unique_fd output_fd;
2460 StartIntercept(&output_fd);
2461 FinishCrasher();
2462 AssertDeath(SIGABRT);
2463 int intercept_result;
2464 FinishIntercept(&intercept_result);
2465
2466 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2467
2468 std::string result;
2469 ConsumeFd(std::move(output_fd), &result);
2470
2471 std::string match_str;
2472 // Verify none.
2473 match_str = android::base::StringPrintf(
2474 " %s-%s --- 0 1000\\n",
2475 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2476 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2477 ASSERT_MATCH(result, match_str);
2478
2479 // Verify read-only.
2480 match_str = android::base::StringPrintf(
2481 " %s-%s r-- 0 1000\\n",
2482 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2483 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2484 ASSERT_MATCH(result, match_str);
2485
2486 // Verify write-only.
2487 match_str = android::base::StringPrintf(
2488 " %s-%s -w- 0 1000\\n",
2489 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2490 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2491 ASSERT_MATCH(result, match_str);
2492
2493 // Verify exec-only.
2494 match_str = android::base::StringPrintf(
2495 " %s-%s --x 0 1000\\n",
2496 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2497 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2498 ASSERT_MATCH(result, match_str);
2499
2500 // Verify file map with non-zero offset and a name.
2501 match_str = android::base::StringPrintf(
2502 " %s-%s r-- 2000 4000 %s\\n",
2503 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2504 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2505 ASSERT_MATCH(result, match_str);
2506}
2507
2508// Verify that the tombstone map data is correct.
2509TEST_F(CrasherTest, verify_header) {
2510 StartProcess([]() { abort(); });
2511
2512 unique_fd output_fd;
2513 StartIntercept(&output_fd);
2514 FinishCrasher();
2515 AssertDeath(SIGABRT);
2516 int intercept_result;
2517 FinishIntercept(&intercept_result);
2518
2519 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2520
2521 std::string result;
2522 ConsumeFd(std::move(output_fd), &result);
2523
2524 std::string match_str = android::base::StringPrintf(
2525 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2526 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2527 android::base::GetProperty("ro.revision", "unknown").c_str());
2528 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2529 ASSERT_MATCH(result, match_str);
2530}
2531
2532// Verify that the thread header is formatted properly.
2533TEST_F(CrasherTest, verify_thread_header) {
2534 void* shared_map =
2535 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2536 ASSERT_NE(MAP_FAILED, shared_map);
2537 memset(shared_map, 0, sizeof(pid_t));
2538
2539 StartProcess([&shared_map]() {
2540 std::atomic_bool tid_written;
2541 std::thread thread([&tid_written, &shared_map]() {
2542 pid_t tid = gettid();
2543 memcpy(shared_map, &tid, sizeof(pid_t));
2544 tid_written = true;
2545 volatile bool done = false;
2546 while (!done)
2547 ;
2548 });
2549 thread.detach();
2550 while (!tid_written.load(std::memory_order_acquire))
2551 ;
2552 abort();
2553 });
2554
2555 pid_t primary_pid = crasher_pid;
2556
2557 unique_fd output_fd;
2558 StartIntercept(&output_fd);
2559 FinishCrasher();
2560 AssertDeath(SIGABRT);
2561 int intercept_result;
2562 FinishIntercept(&intercept_result);
2563 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2564
2565 // Read the tid data out.
2566 pid_t tid;
2567 memcpy(&tid, shared_map, sizeof(pid_t));
2568 ASSERT_NE(0, tid);
2569
2570 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2571
2572 std::string result;
2573 ConsumeFd(std::move(output_fd), &result);
2574
2575 // Verify that there are two headers, one where the tid is "primary_pid"
2576 // and the other where the tid is "tid".
2577 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2578 primary_pid, primary_pid);
2579 ASSERT_MATCH(result, match_str);
2580
2581 match_str =
2582 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2583 ASSERT_MATCH(result, match_str);
2584}
2585
2586// Verify that there is a BuildID present in the map section and set properly.
2587TEST_F(CrasherTest, verify_build_id) {
2588 StartProcess([]() { abort(); });
2589
2590 unique_fd output_fd;
2591 StartIntercept(&output_fd);
2592 FinishCrasher();
2593 AssertDeath(SIGABRT);
2594 int intercept_result;
2595 FinishIntercept(&intercept_result);
2596 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2597
2598 std::string result;
2599 ConsumeFd(std::move(output_fd), &result);
2600
2601 // Find every /system or /apex lib and verify the BuildID is displayed
2602 // properly.
2603 bool found_valid_elf = false;
2604 std::smatch match;
2605 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2606 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2607 result = match.suffix()) {
2608 if (prev_file == match[1]) {
2609 // Already checked this file.
2610 continue;
2611 }
2612
2613 prev_file = match[1];
2614 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2615 if (!elf.Init() || !elf.valid()) {
2616 // Skipping invalid elf files.
2617 continue;
2618 }
2619 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2620
2621 found_valid_elf = true;
2622 }
2623 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2624}