blob: a5e2413d59fa88717c27aeecd82c34a0e2c61835 [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 Phillips5ddcea22021-04-19 09:59:17 -070067#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010068#include "protocol.h"
69#include "tombstoned/tombstoned.h"
70#include "util.h"
71
Josh Gaocbe70cb2016-10-18 18:17:52 -070072using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080073
74using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070075using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070076using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070077
78#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070079#define ARCH_SUFFIX "64"
80#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070081#define ARCH_SUFFIX ""
82#endif
83
Elliott Hughese4781d52021-03-17 09:15:15 -070084constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070085
86#define TIMEOUT(seconds, expr) \
87 [&]() { \
88 struct sigaction old_sigaction; \
89 struct sigaction new_sigaction = {}; \
90 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080091 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070092 err(1, "sigaction failed"); \
93 } \
94 alarm(seconds); \
95 auto value = expr; \
96 int saved_errno = errno; \
97 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
98 err(1, "sigaction failed"); \
99 } \
100 alarm(0); \
101 errno = saved_errno; \
102 return value; \
103 }()
104
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700105// Backtrace frame dump could contain:
106// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
107// or
108// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800109#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700110 ASSERT_MATCH(result, \
111 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900112
Mitch Phillips7168a212021-03-09 16:53:23 -0800113// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
114// process sampling, so we need to ensure we force GWP-ASan on.
115__attribute__((constructor)) static void enable_gwp_asan() {
116 bool force = true;
117 android_mallopt(M_INITIALIZE_GWP_ASAN, &force, sizeof(force));
118}
119
Narayan Kamatha73df602017-05-24 15:07:25 +0100120static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100121 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700122 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
123 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
124 if (intercept_fd->get() == -1) {
125 FAIL() << "failed to contact tombstoned: " << strerror(errno);
126 }
127
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700128 InterceptRequest req = {
129 .dump_type = intercept_type,
130 .pid = target_pid,
131 };
Josh Gao460b3362017-03-30 16:40:47 -0700132
133 unique_fd output_pipe_write;
134 if (!Pipe(output_fd, &output_pipe_write)) {
135 FAIL() << "failed to create output pipe: " << strerror(errno);
136 }
137
138 std::string pipe_size_str;
139 int pipe_buffer_size;
140 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
141 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
142 }
143
144 pipe_size_str = android::base::Trim(pipe_size_str);
145
146 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
147 FAIL() << "failed to parse pipe max size";
148 }
149
150 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
151 FAIL() << "failed to set pipe size: " << strerror(errno);
152 }
153
Josh Gao5675f3c2017-06-01 12:19:53 -0700154 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
155
Josh Gao5f87bbd2019-01-09 17:01:49 -0800156 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
157 output_pipe_write.reset();
158 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700159 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
160 }
161
162 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800163 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700164 if (rc == -1) {
165 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
166 } else if (rc == 0) {
167 FAIL() << "failed to read response from tombstoned (EOF)";
168 } else if (rc != sizeof(response)) {
169 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
170 << ", received " << rc;
171 }
172
Narayan Kamathca5e9082017-06-02 15:42:06 +0100173 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700174}
175
Elliott Hughesd13ea522022-01-13 09:20:26 -0800176static bool pac_supported() {
177#if defined(__aarch64__)
178 return getauxval(AT_HWCAP) & HWCAP_PACA;
179#else
180 return false;
181#endif
182}
183
Josh Gaocbe70cb2016-10-18 18:17:52 -0700184class CrasherTest : public ::testing::Test {
185 public:
186 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700187 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700188 unique_fd crasher_pipe;
189 unique_fd intercept_fd;
190
191 CrasherTest();
192 ~CrasherTest();
193
Narayan Kamatha73df602017-05-24 15:07:25 +0100194 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700195
196 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
197 void FinishIntercept(int* result);
198
Josh Gao2e7b8e22017-05-04 17:12:57 -0700199 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700200 void StartCrasher(const std::string& crash_type);
201 void FinishCrasher();
202 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700203
204 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700205};
206
207CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700208 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
209 android::base::SetProperty(kWaitForDebuggerKey, "0");
210
211 // Clear the old property too, just in case someone's been using it
212 // on this device. (We only document the new name, but we still support
213 // the old name so we don't break anyone's existing setups.)
214 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700215}
216
217CrasherTest::~CrasherTest() {
218 if (crasher_pid != -1) {
219 kill(crasher_pid, SIGKILL);
220 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700221 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222 }
223
Elliott Hughese4781d52021-03-17 09:15:15 -0700224 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700225}
226
Narayan Kamatha73df602017-05-24 15:07:25 +0100227void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 if (crasher_pid == -1) {
229 FAIL() << "crasher hasn't been started";
230 }
231
Narayan Kamathca5e9082017-06-02 15:42:06 +0100232 InterceptStatus status;
233 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
234 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700235}
236
237void CrasherTest::FinishIntercept(int* result) {
238 InterceptResponse response;
239
Christopher Ferris11555f02019-09-20 14:18:55 -0700240 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700241 if (rc == -1) {
242 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
243 } else if (rc == 0) {
244 *result = -1;
245 } else if (rc != sizeof(response)) {
246 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
247 << ", received " << rc;
248 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700249 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700250 }
251}
252
Josh Gao2e7b8e22017-05-04 17:12:57 -0700253void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800254 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700255 unique_fd crasher_read_pipe;
256 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
257 FAIL() << "failed to create pipe: " << strerror(errno);
258 }
259
Josh Gao2e7b8e22017-05-04 17:12:57 -0700260 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 if (crasher_pid == -1) {
262 FAIL() << "fork failed: " << strerror(errno);
263 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800264 char dummy;
265 crasher_pipe.reset();
266 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800267 function();
268 _exit(0);
269 }
270}
271
Josh Gaocbe70cb2016-10-18 18:17:52 -0700272void CrasherTest::FinishCrasher() {
273 if (crasher_pipe == -1) {
274 FAIL() << "crasher pipe uninitialized";
275 }
276
Christopher Ferris172b0a02019-09-18 17:48:30 -0700277 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700278 if (rc == -1) {
279 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
280 } else if (rc == 0) {
281 FAIL() << "crasher pipe was closed";
282 }
283}
284
285void CrasherTest::AssertDeath(int signo) {
286 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700287 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700288 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700289 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
290 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700291 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700292 FAIL() << "failed to wait for crasher: " << strerror(errno);
293 }
294
Josh Gaoe06f2a42017-04-27 16:50:38 -0700295 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700296 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700297 ASSERT_EQ(0, WEXITSTATUS(signo));
298 } else {
299 ASSERT_FALSE(WIFEXITED(status));
300 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
301 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700302 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700303 crasher_pid = -1;
304}
305
306static void ConsumeFd(unique_fd fd, std::string* output) {
307 constexpr size_t read_length = PAGE_SIZE;
308 std::string result;
309
310 while (true) {
311 size_t offset = result.size();
312 result.resize(result.size() + PAGE_SIZE);
313 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
314 if (rc == -1) {
315 FAIL() << "read failed: " << strerror(errno);
316 } else if (rc == 0) {
317 result.resize(result.size() - PAGE_SIZE);
318 break;
319 }
320
321 result.resize(result.size() - PAGE_SIZE + rc);
322 }
323
324 *output = std::move(result);
325}
326
Mitch Phillips78f06702021-06-01 14:35:43 -0700327class LogcatCollector {
328 public:
329 LogcatCollector() { system("logcat -c"); }
330
331 void Collect(std::string* output) {
332 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
333 ASSERT_NE(cmd_stdout, nullptr);
334 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
335 ConsumeFd(std::move(tmp_fd), output);
336 pclose(cmd_stdout);
337 }
338};
339
Josh Gaocbe70cb2016-10-18 18:17:52 -0700340TEST_F(CrasherTest, smoke) {
341 int intercept_result;
342 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800343 StartProcess([]() {
344 *reinterpret_cast<volatile char*>(0xdead) = '1';
345 });
346
Josh Gaocbe70cb2016-10-18 18:17:52 -0700347 StartIntercept(&output_fd);
348 FinishCrasher();
349 AssertDeath(SIGSEGV);
350 FinishIntercept(&intercept_result);
351
352 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
353
354 std::string result;
355 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800356#ifdef __LP64__
357 ASSERT_MATCH(result,
358 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
359#else
360 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
361#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700362
363 if (mte_supported()) {
364 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700365 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
366 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700367 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800368
369 if (pac_supported()) {
370 // Test that the default PAC_ENABLED_KEYS value is set.
371 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
372 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
373 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700374}
375
Peter Collingbournef03af882020-03-20 18:09:00 -0700376TEST_F(CrasherTest, tagged_fault_addr) {
377#if !defined(__aarch64__)
378 GTEST_SKIP() << "Requires aarch64";
379#endif
380 int intercept_result;
381 unique_fd output_fd;
382 StartProcess([]() {
383 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
384 });
385
386 StartIntercept(&output_fd);
387 FinishCrasher();
388 AssertDeath(SIGSEGV);
389 FinishIntercept(&intercept_result);
390
391 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
392
393 std::string result;
394 ConsumeFd(std::move(output_fd), &result);
395
396 // The address can either be tagged (new kernels) or untagged (old kernels).
397 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800398 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700399}
400
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700401// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
402// compiler could still clobber the argument register before trapping, but that's unlikely.
403__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
404 __builtin_trap();
405}
406
407TEST_F(CrasherTest, heap_addr_in_register) {
408#if defined(__i386__)
409 GTEST_SKIP() << "architecture does not pass arguments in registers";
410#endif
411 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:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700436#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800437 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700438#else
439 ASSERT_TRUE(false) << "unsupported architecture";
440#endif
441}
442
Peter Collingbournecd278072020-12-21 14:08:38 -0800443#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700444static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800445 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700446 abort();
447 }
448}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800449
450static void SetTagCheckingLevelAsync() {
451 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
452 abort();
453 }
454}
Peter Collingbournef8622522020-04-07 14:07:32 -0700455#endif
456
Mitch Phillips7168a212021-03-09 16:53:23 -0800457// Number of iterations required to reliably guarantee a GWP-ASan crash.
458// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
459// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
460// the counter reaches zero, we provide a sampled allocation. Then, double that
461// figure to allow for left/right allocation alignment, as this is done randomly
462// without bias.
463#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
464
465struct GwpAsanTestParameters {
466 size_t alloc_size;
467 bool free_before_access;
468 int access_offset;
469 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
470};
471
472struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
473
474GwpAsanTestParameters gwp_asan_tests[] = {
475 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
476 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
477 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
478 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
479};
480
481INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
482
483TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
484 if (mte_supported()) {
485 // Skip this test on MTE hardware, as MTE will reliably catch these errors
486 // instead of GWP-ASan.
487 GTEST_SKIP() << "Skipped on MTE.";
488 }
489
490 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700491 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800492
493 int intercept_result;
494 unique_fd output_fd;
495 StartProcess([&params]() {
496 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
497 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
498 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
499 p[params.access_offset] = 42;
500 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
501 }
502 });
503
504 StartIntercept(&output_fd);
505 FinishCrasher();
506 AssertDeath(SIGSEGV);
507 FinishIntercept(&intercept_result);
508
509 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
510
Mitch Phillips78f06702021-06-01 14:35:43 -0700511 std::vector<std::string> log_sources(2);
512 ConsumeFd(std::move(output_fd), &log_sources[0]);
513 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800514
Mitch Phillips78f06702021-06-01 14:35:43 -0700515 for (const auto& result : log_sources) {
516 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
517 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
518 if (params.free_before_access) {
519 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
520 }
521 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800522 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800523}
524
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800525struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
526
Peter Collingbourneaa544792021-05-13 13:53:37 -0700527INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800528
529TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800530#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700531 if (!mte_supported()) {
532 GTEST_SKIP() << "Requires MTE";
533 }
534
Peter Collingbourneaa544792021-05-13 13:53:37 -0700535 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
536 if (GetParam() == 0) {
537 return;
538 }
539
Mitch Phillips78f06702021-06-01 14:35:43 -0700540 LogcatCollector logcat_collector;
541
Peter Collingbournef8622522020-04-07 14:07:32 -0700542 int intercept_result;
543 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800544 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700545 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800546 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700547 free((void *)p);
548 p[0] = 42;
549 });
550
551 StartIntercept(&output_fd);
552 FinishCrasher();
553 AssertDeath(SIGSEGV);
554 FinishIntercept(&intercept_result);
555
556 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
557
Mitch Phillips78f06702021-06-01 14:35:43 -0700558 std::vector<std::string> log_sources(2);
559 ConsumeFd(std::move(output_fd), &log_sources[0]);
560 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700561 // Tag dump only available in the tombstone, not logcat.
562 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700563
Mitch Phillips78f06702021-06-01 14:35:43 -0700564 for (const auto& result : log_sources) {
565 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
566 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
567 std::to_string(GetParam()) + R"(-byte allocation)");
568 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
569 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
570 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700571#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800572 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700573#endif
574}
575
Peter Collingbournedc476342021-05-12 15:56:43 -0700576TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
577#if defined(__aarch64__)
578 if (!mte_supported()) {
579 GTEST_SKIP() << "Requires MTE";
580 }
581
582 int intercept_result;
583 unique_fd output_fd;
584 StartProcess([&]() {
585 SetTagCheckingLevelSync();
586 volatile int* p = (volatile int*)malloc(GetParam());
587 free((void *)p);
588 p[-1] = 42;
589 });
590
591 StartIntercept(&output_fd);
592 FinishCrasher();
593 AssertDeath(SIGSEGV);
594 FinishIntercept(&intercept_result);
595
596 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
597
598 std::string result;
599 ConsumeFd(std::move(output_fd), &result);
600
601 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
602 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
603#else
604 GTEST_SKIP() << "Requires aarch64";
605#endif
606}
607
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800608TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800609#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700610 if (!mte_supported()) {
611 GTEST_SKIP() << "Requires MTE";
612 }
613
Mitch Phillips78f06702021-06-01 14:35:43 -0700614 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700615 int intercept_result;
616 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800617 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700618 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800619 volatile char* p = (volatile char*)malloc(GetParam());
620 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700621 });
622
623 StartIntercept(&output_fd);
624 FinishCrasher();
625 AssertDeath(SIGSEGV);
626 FinishIntercept(&intercept_result);
627
628 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
629
Mitch Phillips78f06702021-06-01 14:35:43 -0700630 std::vector<std::string> log_sources(2);
631 ConsumeFd(std::move(output_fd), &log_sources[0]);
632 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700633
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700634 // Tag dump only in tombstone, not logcat, and tagging is not used for
635 // overflow protection in the scudo secondary (guard pages are used instead).
636 if (GetParam() < 0x10000) {
637 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
638 }
639
Mitch Phillips78f06702021-06-01 14:35:43 -0700640 for (const auto& result : log_sources) {
641 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
642 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
643 std::to_string(GetParam()) + R"(-byte allocation)");
644 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
645 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700646#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800647 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700648#endif
649}
650
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800651TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800652#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700653 if (!mte_supported()) {
654 GTEST_SKIP() << "Requires MTE";
655 }
656
657 int intercept_result;
658 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800659 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700660 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800661 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700662 p[-1] = 42;
663 });
664
665 StartIntercept(&output_fd);
666 FinishCrasher();
667 AssertDeath(SIGSEGV);
668 FinishIntercept(&intercept_result);
669
670 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
671
672 std::string result;
673 ConsumeFd(std::move(output_fd), &result);
674
675 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800676 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800677 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700678 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700679 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700680 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700681#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800682 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700683#endif
684}
685
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800686TEST_F(CrasherTest, mte_async) {
687#if defined(__aarch64__)
688 if (!mte_supported()) {
689 GTEST_SKIP() << "Requires MTE";
690 }
691
692 int intercept_result;
693 unique_fd output_fd;
694 StartProcess([&]() {
695 SetTagCheckingLevelAsync();
696 volatile int* p = (volatile int*)malloc(16);
697 p[-1] = 42;
698 });
699
700 StartIntercept(&output_fd);
701 FinishCrasher();
702 AssertDeath(SIGSEGV);
703 FinishIntercept(&intercept_result);
704
705 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
706
707 std::string result;
708 ConsumeFd(std::move(output_fd), &result);
709
710 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
711#else
712 GTEST_SKIP() << "Requires aarch64";
713#endif
714}
715
Peter Collingbournef8622522020-04-07 14:07:32 -0700716TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800717#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700718 if (!mte_supported()) {
719 GTEST_SKIP() << "Requires MTE";
720 }
721
Mitch Phillips78f06702021-06-01 14:35:43 -0700722 LogcatCollector logcat_collector;
723
Peter Collingbournef8622522020-04-07 14:07:32 -0700724 int intercept_result;
725 unique_fd output_fd;
726 StartProcess([]() {
727 SetTagCheckingLevelSync();
728
729 // Make two allocations with the same tag and close to one another. Check for both properties
730 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
731 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
732 // (some non-zero value << 56) apart.
733 //
734 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
735 // other.
736 std::set<uintptr_t> allocs;
737 for (int i = 0; i != 4096; ++i) {
738 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
739 auto it = allocs.insert(alloc).first;
740 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
741 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
742 }
743 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
744 *reinterpret_cast<int*>(alloc + 16) = 42;
745 }
746 }
747 });
748
749 StartIntercept(&output_fd);
750 FinishCrasher();
751 AssertDeath(SIGSEGV);
752 FinishIntercept(&intercept_result);
753
754 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
755
Mitch Phillips78f06702021-06-01 14:35:43 -0700756 std::vector<std::string> log_sources(2);
757 ConsumeFd(std::move(output_fd), &log_sources[0]);
758 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700759
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700760 // Tag dump only in the tombstone, not logcat.
761 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
762
Mitch Phillips78f06702021-06-01 14:35:43 -0700763 for (const auto& result : log_sources) {
764 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
765 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800766 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700767 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
768 // overflows), so we can't match explicitly for an underflow message.
769 ASSERT_MATCH(result,
770 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
771 // Ensure there's at least two allocation traces (one for each cause).
772 ASSERT_MATCH(
773 result,
774 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
775 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700776#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800777 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700778#endif
779}
780
Peter Collingbournecd278072020-12-21 14:08:38 -0800781#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700782static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700783 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
784 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
785 size_t page_size = getpagesize();
786 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
787 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
788 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700789 return 0;
790 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700791 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
792 PROT_READ | PROT_WRITE | PROT_MTE);
793 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
794 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
795 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
796 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
797 }
798 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700799}
800#endif
801
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700802TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800803#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700804 if (!mte_supported()) {
805 GTEST_SKIP() << "Requires MTE";
806 }
807
808 int intercept_result;
809 unique_fd output_fd;
810 StartProcess([&]() {
811 SetTagCheckingLevelSync();
812 Trap(reinterpret_cast<void *>(CreateTagMapping()));
813 });
814
815 StartIntercept(&output_fd);
816 FinishCrasher();
817 AssertDeath(SIGTRAP);
818 FinishIntercept(&intercept_result);
819
820 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
821
822 std::string result;
823 ConsumeFd(std::move(output_fd), &result);
824
825 ASSERT_MATCH(result, R"(memory near x0:
826.*
827.*
828 01.............0 0000000000000000 0000000000000000 ................
829 00.............0)");
830#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800831 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700832#endif
833}
834
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700835TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
836#if defined(__aarch64__)
837 if (!mte_supported()) {
838 GTEST_SKIP() << "Requires MTE";
839 }
840
841 int intercept_result;
842 unique_fd output_fd;
843 StartProcess([&]() {
844 SetTagCheckingLevelSync();
845 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
846 p[0] = 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\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
861#else
862 GTEST_SKIP() << "Requires aarch64";
863#endif
864}
865
866TEST_F(CrasherTest, mte_fault_tag_dump) {
867#if defined(__aarch64__)
868 if (!mte_supported()) {
869 GTEST_SKIP() << "Requires MTE";
870 }
871
872 int intercept_result;
873 unique_fd output_fd;
874 StartProcess([&]() {
875 SetTagCheckingLevelSync();
876 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
877 p[320] = 0; // Untagged pointer, tagged memory.
878 });
879
880 StartIntercept(&output_fd);
881 FinishCrasher();
882 AssertDeath(SIGSEGV);
883 FinishIntercept(&intercept_result);
884
885 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
886
887 std::string result;
888 ConsumeFd(std::move(output_fd), &result);
889
890 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
891\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
892\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
893\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
894)");
895#else
896 GTEST_SKIP() << "Requires aarch64";
897#endif
898}
899
900TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
901#if defined(__aarch64__)
902 if (!mte_supported()) {
903 GTEST_SKIP() << "Requires MTE";
904 }
905
906 int intercept_result;
907 unique_fd output_fd;
908 StartProcess([&]() {
909 SetTagCheckingLevelSync();
910 size_t page_size = getpagesize();
911 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
912 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
913 });
914
915 StartIntercept(&output_fd);
916 FinishCrasher();
917 AssertDeath(SIGSEGV);
918 FinishIntercept(&intercept_result);
919
920 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
921
922 std::string result;
923 ConsumeFd(std::move(output_fd), &result);
924
925 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
926 ASSERT_MATCH(result,
927 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
928\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
929
930)"); // Ensure truncation happened and there's a newline after the tag fault.
931#else
932 GTEST_SKIP() << "Requires aarch64";
933#endif
934}
935
Josh Gaocdea7502017-11-01 15:00:40 -0700936TEST_F(CrasherTest, LD_PRELOAD) {
937 int intercept_result;
938 unique_fd output_fd;
939 StartProcess([]() {
940 setenv("LD_PRELOAD", "nonexistent.so", 1);
941 *reinterpret_cast<volatile char*>(0xdead) = '1';
942 });
943
944 StartIntercept(&output_fd);
945 FinishCrasher();
946 AssertDeath(SIGSEGV);
947 FinishIntercept(&intercept_result);
948
949 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
950
951 std::string result;
952 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800953 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700954}
955
Josh Gaocbe70cb2016-10-18 18:17:52 -0700956TEST_F(CrasherTest, abort) {
957 int intercept_result;
958 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800959 StartProcess([]() {
960 abort();
961 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700962 StartIntercept(&output_fd);
963 FinishCrasher();
964 AssertDeath(SIGABRT);
965 FinishIntercept(&intercept_result);
966
967 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
968
969 std::string result;
970 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700971 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700972}
973
974TEST_F(CrasherTest, signal) {
975 int intercept_result;
976 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800977 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700978 while (true) {
979 sleep(1);
980 }
Josh Gao502cfd22017-02-17 01:39:15 -0800981 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700982 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700983 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700984 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
985
986 AssertDeath(SIGSEGV);
987 FinishIntercept(&intercept_result);
988
989 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
990
991 std::string result;
992 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700993 ASSERT_MATCH(
994 result,
995 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700996 ASSERT_MATCH(result, R"(backtrace:)");
997}
998
999TEST_F(CrasherTest, abort_message) {
1000 int intercept_result;
1001 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001002 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001003 // Arrived at experimentally;
1004 // logd truncates at 4062.
1005 // strlen("Abort message: ''") is 17.
1006 // That's 4045, but we also want a NUL.
1007 char buf[4045 + 1];
1008 memset(buf, 'x', sizeof(buf));
1009 buf[sizeof(buf) - 1] = '\0';
1010 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001011 abort();
1012 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001013 StartIntercept(&output_fd);
1014 FinishCrasher();
1015 AssertDeath(SIGABRT);
1016 FinishIntercept(&intercept_result);
1017
1018 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1019
1020 std::string result;
1021 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001022 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001023}
1024
Christopher Ferrise8891452021-08-17 17:34:53 -07001025TEST_F(CrasherTest, abort_message_newline_trimmed) {
1026 int intercept_result;
1027 unique_fd output_fd;
1028 StartProcess([]() {
1029 android_set_abort_message("Message with a newline.\n");
1030 abort();
1031 });
1032 StartIntercept(&output_fd);
1033 FinishCrasher();
1034 AssertDeath(SIGABRT);
1035 FinishIntercept(&intercept_result);
1036
1037 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1038
1039 std::string result;
1040 ConsumeFd(std::move(output_fd), &result);
1041 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1042}
1043
1044TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1045 int intercept_result;
1046 unique_fd output_fd;
1047 StartProcess([]() {
1048 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1049 abort();
1050 });
1051 StartIntercept(&output_fd);
1052 FinishCrasher();
1053 AssertDeath(SIGABRT);
1054 FinishIntercept(&intercept_result);
1055
1056 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1057
1058 std::string result;
1059 ConsumeFd(std::move(output_fd), &result);
1060 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1061}
1062
Josh Gaoe06f2a42017-04-27 16:50:38 -07001063TEST_F(CrasherTest, abort_message_backtrace) {
1064 int intercept_result;
1065 unique_fd output_fd;
1066 StartProcess([]() {
1067 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001068 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001069 exit(0);
1070 });
1071 StartIntercept(&output_fd);
1072 FinishCrasher();
1073 AssertDeath(0);
1074 FinishIntercept(&intercept_result);
1075
1076 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1077
1078 std::string result;
1079 ConsumeFd(std::move(output_fd), &result);
1080 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1081}
1082
Josh Gaocbe70cb2016-10-18 18:17:52 -07001083TEST_F(CrasherTest, intercept_timeout) {
1084 int intercept_result;
1085 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001086 StartProcess([]() {
1087 abort();
1088 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001089 StartIntercept(&output_fd);
1090
1091 // Don't let crasher finish until we timeout.
1092 FinishIntercept(&intercept_result);
1093
1094 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1095 << intercept_result << ")";
1096
1097 FinishCrasher();
1098 AssertDeath(SIGABRT);
1099}
1100
Elliott Hughese4781d52021-03-17 09:15:15 -07001101TEST_F(CrasherTest, wait_for_debugger) {
1102 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1103 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001104 }
1105 sleep(1);
1106
Josh Gao502cfd22017-02-17 01:39:15 -08001107 StartProcess([]() {
1108 abort();
1109 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001110 FinishCrasher();
1111
1112 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001113 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001114 ASSERT_TRUE(WIFSTOPPED(status));
1115 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1116
1117 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1118
1119 AssertDeath(SIGABRT);
1120}
1121
Josh Gaocbe70cb2016-10-18 18:17:52 -07001122TEST_F(CrasherTest, backtrace) {
1123 std::string result;
1124 int intercept_result;
1125 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001126
1127 StartProcess([]() {
1128 abort();
1129 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001130 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001131
1132 std::this_thread::sleep_for(500ms);
1133
1134 sigval val;
1135 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001136 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001137 FinishIntercept(&intercept_result);
1138 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1139 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001140 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001141
1142 int status;
1143 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1144
1145 StartIntercept(&output_fd);
1146 FinishCrasher();
1147 AssertDeath(SIGABRT);
1148 FinishIntercept(&intercept_result);
1149 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1150 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001151 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001152}
Josh Gaofca7ca32017-01-23 12:05:35 -08001153
1154TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001155 int intercept_result;
1156 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001157 StartProcess([]() {
1158 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001159 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001160 });
Josh Gao502cfd22017-02-17 01:39:15 -08001161
1162 StartIntercept(&output_fd);
1163 FinishCrasher();
1164 AssertDeath(SIGABRT);
1165 FinishIntercept(&intercept_result);
1166
1167 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1168
1169 std::string result;
1170 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001171 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001172}
1173
Josh Gao502cfd22017-02-17 01:39:15 -08001174TEST_F(CrasherTest, capabilities) {
1175 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1176
Josh Gaofca7ca32017-01-23 12:05:35 -08001177 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001178 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1179 err(1, "failed to set PR_SET_KEEPCAPS");
1180 }
1181
1182 if (setresuid(1, 1, 1) != 0) {
1183 err(1, "setresuid failed");
1184 }
1185
1186 __user_cap_header_struct capheader;
1187 __user_cap_data_struct capdata[2];
1188 memset(&capheader, 0, sizeof(capheader));
1189 memset(&capdata, 0, sizeof(capdata));
1190
1191 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1192 capheader.pid = 0;
1193
1194 // Turn on every third capability.
1195 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1196 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1197 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1198 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1199 }
1200
1201 // Make sure CAP_SYS_PTRACE is off.
1202 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1203 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1204
1205 if (capset(&capheader, &capdata[0]) != 0) {
1206 err(1, "capset failed");
1207 }
1208
1209 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1210 err(1, "failed to drop ambient capabilities");
1211 }
1212
Josh Gaoa5199a92017-04-03 13:18:34 -07001213 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001214 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001215 });
Josh Gao502cfd22017-02-17 01:39:15 -08001216
1217 unique_fd output_fd;
1218 StartIntercept(&output_fd);
1219 FinishCrasher();
1220 AssertDeath(SIGSYS);
1221
1222 std::string result;
1223 int intercept_result;
1224 FinishIntercept(&intercept_result);
1225 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1226 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001227 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001228 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001229}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001230
Josh Gao2e7b8e22017-05-04 17:12:57 -07001231TEST_F(CrasherTest, fake_pid) {
1232 int intercept_result;
1233 unique_fd output_fd;
1234
1235 // Prime the getpid/gettid caches.
1236 UNUSED(getpid());
1237 UNUSED(gettid());
1238
1239 std::function<pid_t()> clone_fn = []() {
1240 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1241 };
1242 StartProcess(
1243 []() {
1244 ASSERT_NE(getpid(), syscall(__NR_getpid));
1245 ASSERT_NE(gettid(), syscall(__NR_gettid));
1246 raise(SIGSEGV);
1247 },
1248 clone_fn);
1249
1250 StartIntercept(&output_fd);
1251 FinishCrasher();
1252 AssertDeath(SIGSEGV);
1253 FinishIntercept(&intercept_result);
1254
1255 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1256
1257 std::string result;
1258 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001259 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001260}
1261
Josh Gaoe04ca272018-01-16 15:38:17 -08001262static const char* const kDebuggerdSeccompPolicy =
1263 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1264
Josh Gao70adac62018-02-22 11:38:33 -08001265static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001266 std::string policy;
1267 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1268 PLOG(FATAL) << "failed to read policy file";
1269 }
1270
1271 // Allow a bunch of syscalls used by the tests.
1272 policy += "\nclone: 1";
1273 policy += "\nsigaltstack: 1";
1274 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001275 policy += "\ngetrlimit: 1";
1276 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001277
1278 FILE* tmp_file = tmpfile();
1279 if (!tmp_file) {
1280 PLOG(FATAL) << "tmpfile failed";
1281 }
1282
Christopher Ferris172b0a02019-09-18 17:48:30 -07001283 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001284 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1285 PLOG(FATAL) << "failed to write policy to tmpfile";
1286 }
1287
1288 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1289 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001290 }
1291
1292 ScopedMinijail jail{minijail_new()};
1293 if (!jail) {
1294 LOG(FATAL) << "failed to create minijail";
1295 }
1296
1297 minijail_no_new_privs(jail.get());
1298 minijail_log_seccomp_filter_failures(jail.get());
1299 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001300 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001301
1302 pid_t result = fork();
1303 if (result == -1) {
1304 return result;
1305 } else if (result != 0) {
1306 return result;
1307 }
1308
1309 // Spawn and detach a thread that spins forever.
1310 std::atomic<bool> thread_ready(false);
1311 std::thread thread([&jail, &thread_ready]() {
1312 minijail_enter(jail.get());
1313 thread_ready = true;
1314 for (;;)
1315 ;
1316 });
1317 thread.detach();
1318
1319 while (!thread_ready) {
1320 continue;
1321 }
1322
Josh Gao70adac62018-02-22 11:38:33 -08001323 if (prejail) {
1324 prejail();
1325 }
1326
Josh Gaoe04ca272018-01-16 15:38:17 -08001327 minijail_enter(jail.get());
1328 return result;
1329}
1330
Josh Gao70adac62018-02-22 11:38:33 -08001331static pid_t seccomp_fork() {
1332 return seccomp_fork_impl(nullptr);
1333}
1334
Josh Gaoe04ca272018-01-16 15:38:17 -08001335TEST_F(CrasherTest, seccomp_crash) {
1336 int intercept_result;
1337 unique_fd output_fd;
1338
1339 StartProcess([]() { abort(); }, &seccomp_fork);
1340
1341 StartIntercept(&output_fd);
1342 FinishCrasher();
1343 AssertDeath(SIGABRT);
1344 FinishIntercept(&intercept_result);
1345 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1346
1347 std::string result;
1348 ConsumeFd(std::move(output_fd), &result);
1349 ASSERT_BACKTRACE_FRAME(result, "abort");
1350}
1351
Josh Gao70adac62018-02-22 11:38:33 -08001352static pid_t seccomp_fork_rlimit() {
1353 return seccomp_fork_impl([]() {
1354 struct rlimit rlim = {
1355 .rlim_cur = 512 * 1024 * 1024,
1356 .rlim_max = 512 * 1024 * 1024,
1357 };
1358
1359 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1360 raise(SIGINT);
1361 }
1362 });
1363}
1364
1365TEST_F(CrasherTest, seccomp_crash_oom) {
1366 int intercept_result;
1367 unique_fd output_fd;
1368
1369 StartProcess(
1370 []() {
1371 std::vector<void*> vec;
1372 for (int i = 0; i < 512; ++i) {
1373 char* buf = static_cast<char*>(malloc(1024 * 1024));
1374 if (!buf) {
1375 abort();
1376 }
1377 memset(buf, 0xff, 1024 * 1024);
1378 vec.push_back(buf);
1379 }
1380 },
1381 &seccomp_fork_rlimit);
1382
1383 StartIntercept(&output_fd);
1384 FinishCrasher();
1385 AssertDeath(SIGABRT);
1386 FinishIntercept(&intercept_result);
1387 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1388
1389 // We can't actually generate a backtrace, just make sure that the process terminates.
1390}
1391
Josh Gaoe04ca272018-01-16 15:38:17 -08001392__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1393 siginfo_t siginfo;
1394 siginfo.si_code = SI_QUEUE;
1395 siginfo.si_pid = getpid();
1396 siginfo.si_uid = getuid();
1397
1398 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1399 PLOG(FATAL) << "invalid dump type";
1400 }
1401
1402 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1403
Josh Gaoa48b41b2019-12-13 14:11:04 -08001404 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001405 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1406 return false;
1407 }
1408
1409 return true;
1410}
1411
Christopher Ferrisb999b822022-02-09 17:57:21 -08001412extern "C" void foo() {
1413 LOG(INFO) << "foo";
1414 std::this_thread::sleep_for(1s);
1415}
1416
1417extern "C" void bar() {
1418 LOG(INFO) << "bar";
1419 std::this_thread::sleep_for(1s);
1420}
1421
Josh Gaoe04ca272018-01-16 15:38:17 -08001422TEST_F(CrasherTest, seccomp_tombstone) {
1423 int intercept_result;
1424 unique_fd output_fd;
1425
1426 static const auto dump_type = kDebuggerdTombstone;
1427 StartProcess(
1428 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001429 std::thread a(foo);
1430 std::thread b(bar);
1431
1432 std::this_thread::sleep_for(100ms);
1433
Josh Gaoe04ca272018-01-16 15:38:17 -08001434 raise_debugger_signal(dump_type);
1435 _exit(0);
1436 },
1437 &seccomp_fork);
1438
1439 StartIntercept(&output_fd, dump_type);
1440 FinishCrasher();
1441 AssertDeath(0);
1442 FinishIntercept(&intercept_result);
1443 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1444
1445 std::string result;
1446 ConsumeFd(std::move(output_fd), &result);
1447 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001448 ASSERT_BACKTRACE_FRAME(result, "foo");
1449 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001450}
1451
Josh Gaoe04ca272018-01-16 15:38:17 -08001452TEST_F(CrasherTest, seccomp_backtrace) {
1453 int intercept_result;
1454 unique_fd output_fd;
1455
1456 static const auto dump_type = kDebuggerdNativeBacktrace;
1457 StartProcess(
1458 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001459 std::thread a(foo);
1460 std::thread b(bar);
1461
1462 std::this_thread::sleep_for(100ms);
1463
Josh Gaoe04ca272018-01-16 15:38:17 -08001464 raise_debugger_signal(dump_type);
1465 _exit(0);
1466 },
1467 &seccomp_fork);
1468
1469 StartIntercept(&output_fd, dump_type);
1470 FinishCrasher();
1471 AssertDeath(0);
1472 FinishIntercept(&intercept_result);
1473 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1474
1475 std::string result;
1476 ConsumeFd(std::move(output_fd), &result);
1477 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001478 ASSERT_BACKTRACE_FRAME(result, "foo");
1479 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001480}
1481
1482TEST_F(CrasherTest, seccomp_crash_logcat) {
1483 StartProcess([]() { abort(); }, &seccomp_fork);
1484 FinishCrasher();
1485
1486 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1487 AssertDeath(SIGABRT);
1488}
1489
Josh Gaofd13bf02017-08-18 15:37:26 -07001490TEST_F(CrasherTest, competing_tracer) {
1491 int intercept_result;
1492 unique_fd output_fd;
1493 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001494 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001495 });
1496
1497 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001498
1499 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001500 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001501
1502 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001503 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001504 ASSERT_TRUE(WIFSTOPPED(status));
1505 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1506
1507 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1508 FinishIntercept(&intercept_result);
1509 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1510
1511 std::string result;
1512 ConsumeFd(std::move(output_fd), &result);
1513 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1514 regex += std::to_string(gettid());
1515 regex += R"( \(.+debuggerd_test)";
1516 ASSERT_MATCH(result, regex.c_str());
1517
Christopher Ferris172b0a02019-09-18 17:48:30 -07001518 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001519 ASSERT_TRUE(WIFSTOPPED(status));
1520 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1521
Josh Gaofd13bf02017-08-18 15:37:26 -07001522 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1523 AssertDeath(SIGABRT);
1524}
1525
Josh Gaobf06a402018-08-27 16:34:01 -07001526TEST_F(CrasherTest, fdsan_warning_abort_message) {
1527 int intercept_result;
1528 unique_fd output_fd;
1529
1530 StartProcess([]() {
1531 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001532 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001533 if (fd == -1) {
1534 abort();
1535 }
1536 close(fd.get());
1537 _exit(0);
1538 });
1539
1540 StartIntercept(&output_fd);
1541 FinishCrasher();
1542 AssertDeath(0);
1543 FinishIntercept(&intercept_result);
1544 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1545
1546 std::string result;
1547 ConsumeFd(std::move(output_fd), &result);
1548 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1549}
1550
Josh Gaoc3c8c022017-02-13 16:36:18 -08001551TEST(crash_dump, zombie) {
1552 pid_t forkpid = fork();
1553
Josh Gaoc3c8c022017-02-13 16:36:18 -08001554 pid_t rc;
1555 int status;
1556
1557 if (forkpid == 0) {
1558 errno = 0;
1559 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1560 if (rc != -1 || errno != ECHILD) {
1561 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1562 }
1563
Josh Gaoa48b41b2019-12-13 14:11:04 -08001564 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001565
1566 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001567 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001568 if (rc != -1 || errno != ECHILD) {
1569 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1570 }
1571 _exit(0);
1572 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001573 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001574 ASSERT_EQ(forkpid, rc);
1575 ASSERT_TRUE(WIFEXITED(status));
1576 ASSERT_EQ(0, WEXITSTATUS(status));
1577 }
1578}
Josh Gao352a8452017-03-30 16:46:21 -07001579
1580TEST(tombstoned, no_notify) {
1581 // Do this a few times.
1582 for (int i = 0; i < 3; ++i) {
1583 pid_t pid = 123'456'789 + i;
1584
1585 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001586 InterceptStatus status;
1587 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1588 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001589
1590 {
1591 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001592 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001593 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1594 }
1595
1596 pid_t read_pid;
1597 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1598 ASSERT_EQ(read_pid, pid);
1599 }
1600}
1601
1602TEST(tombstoned, stress) {
1603 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1604 static constexpr int kDumpCount = 100;
1605
1606 std::atomic<bool> start(false);
1607 std::vector<std::thread> threads;
1608 threads.emplace_back([&start]() {
1609 while (!start) {
1610 continue;
1611 }
1612
1613 // Use a way out of range pid, to avoid stomping on an actual process.
1614 pid_t pid_base = 1'000'000;
1615
1616 for (int dump = 0; dump < kDumpCount; ++dump) {
1617 pid_t pid = pid_base + dump;
1618
1619 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001620 InterceptStatus status;
1621 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1622 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001623
1624 // Pretend to crash, and then immediately close the socket.
1625 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1626 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1627 if (sockfd == -1) {
1628 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1629 }
1630 TombstonedCrashPacket packet = {};
1631 packet.packet_type = CrashPacketType::kDumpRequest;
1632 packet.packet.dump_request.pid = pid;
1633 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1634 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1635 }
1636
1637 continue;
1638 }
1639 });
1640
1641 threads.emplace_back([&start]() {
1642 while (!start) {
1643 continue;
1644 }
1645
1646 // Use a way out of range pid, to avoid stomping on an actual process.
1647 pid_t pid_base = 2'000'000;
1648
1649 for (int dump = 0; dump < kDumpCount; ++dump) {
1650 pid_t pid = pid_base + dump;
1651
1652 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001653 InterceptStatus status;
1654 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1655 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001656
1657 {
1658 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001659 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001660 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1661 tombstoned_notify_completion(tombstoned_socket.get());
1662 }
1663
1664 // TODO: Fix the race that requires this sleep.
1665 std::this_thread::sleep_for(50ms);
1666
1667 pid_t read_pid;
1668 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1669 ASSERT_EQ(read_pid, pid);
1670 }
1671 });
1672
1673 start = true;
1674
1675 for (std::thread& thread : threads) {
1676 thread.join();
1677 }
1678}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001679
1680TEST(tombstoned, java_trace_intercept_smoke) {
1681 // Using a "real" PID is a little dangerous here - if the test fails
1682 // or crashes, we might end up getting a bogus / unreliable stack
1683 // trace.
1684 const pid_t self = getpid();
1685
1686 unique_fd intercept_fd, output_fd;
1687 InterceptStatus status;
1688 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1689 ASSERT_EQ(InterceptStatus::kRegistered, status);
1690
Josh Gao76e1e302021-01-26 15:53:11 -08001691 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001692 // should result in a "regular" FD and not the installed intercept.
1693 const char native[] = "native";
1694 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001695 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001696 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1697 tombstoned_notify_completion(tombstoned_socket.get());
1698
1699 // Then, connect to tombstoned asking for a java backtrace. This *should*
1700 // trigger the intercept.
1701 const char java[] = "java";
1702 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1703 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1704 tombstoned_notify_completion(tombstoned_socket.get());
1705
1706 char outbuf[sizeof(java)];
1707 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1708 ASSERT_STREQ("java", outbuf);
1709}
1710
1711TEST(tombstoned, multiple_intercepts) {
1712 const pid_t fake_pid = 1'234'567;
1713 unique_fd intercept_fd, output_fd;
1714 InterceptStatus status;
1715 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1716 ASSERT_EQ(InterceptStatus::kRegistered, status);
1717
1718 unique_fd intercept_fd_2, output_fd_2;
1719 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1720 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1721}
1722
1723TEST(tombstoned, intercept_any) {
1724 const pid_t fake_pid = 1'234'567;
1725
1726 unique_fd intercept_fd, output_fd;
1727 InterceptStatus status;
1728 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1729 ASSERT_EQ(InterceptStatus::kRegistered, status);
1730
1731 const char any[] = "any";
1732 unique_fd tombstoned_socket, input_fd;
1733 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1734 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1735 tombstoned_notify_completion(tombstoned_socket.get());
1736
1737 char outbuf[sizeof(any)];
1738 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1739 ASSERT_STREQ("any", outbuf);
1740}
Josh Gao2b22ae12018-09-12 14:51:03 -07001741
1742TEST(tombstoned, interceptless_backtrace) {
1743 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1744 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1745 std::map<int, time_t> result;
1746 for (int i = 0; i < 99; ++i) {
1747 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1748 struct stat st;
1749 if (stat(path.c_str(), &st) == 0) {
1750 result[i] = st.st_mtim.tv_sec;
1751 }
1752 }
1753 return result;
1754 };
1755
1756 auto before = get_tombstone_timestamps();
1757 for (int i = 0; i < 50; ++i) {
1758 raise_debugger_signal(kDebuggerdNativeBacktrace);
1759 }
1760 auto after = get_tombstone_timestamps();
1761
1762 int diff = 0;
1763 for (int i = 0; i < 99; ++i) {
1764 if (after.count(i) == 0) {
1765 continue;
1766 }
1767 if (before.count(i) == 0) {
1768 ++diff;
1769 continue;
1770 }
1771 if (before[i] != after[i]) {
1772 ++diff;
1773 }
1774 }
1775
1776 // We can't be sure that nothing's crash looping in the background.
1777 // This should be good enough, though...
1778 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1779}
Christopher Ferris481e8372019-07-15 17:13:24 -07001780
1781static __attribute__((__noinline__)) void overflow_stack(void* p) {
1782 void* buf[1];
1783 buf[0] = p;
1784 static volatile void* global = buf;
1785 if (global) {
1786 global = buf;
1787 overflow_stack(&buf);
1788 }
1789}
1790
1791TEST_F(CrasherTest, stack_overflow) {
1792 int intercept_result;
1793 unique_fd output_fd;
1794 StartProcess([]() { overflow_stack(nullptr); });
1795
1796 StartIntercept(&output_fd);
1797 FinishCrasher();
1798 AssertDeath(SIGSEGV);
1799 FinishIntercept(&intercept_result);
1800
1801 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1802
1803 std::string result;
1804 ConsumeFd(std::move(output_fd), &result);
1805 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1806}
Josh Gao76e1e302021-01-26 15:53:11 -08001807
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001808static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1809 std::string test_lib(testing::internal::GetArgvs()[0]);
1810 auto const value = test_lib.find_last_of('/');
1811 if (value == std::string::npos) {
1812 test_lib = "./";
1813 } else {
1814 test_lib = test_lib.substr(0, value + 1) + "./";
1815 }
1816 test_lib += "libcrash_test.so";
1817
1818 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1819 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1820
1821 // Copy the shared so to a tempory directory.
1822 return system(cp_cmd.c_str()) == 0;
1823}
1824
1825TEST_F(CrasherTest, unreadable_elf) {
1826 int intercept_result;
1827 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001828 std::string tmp_so_name;
1829 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001830 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001831 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1832 _exit(1);
1833 }
1834 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1835 if (handle == nullptr) {
1836 _exit(1);
1837 }
1838 // Delete the original shared library so that we get the warning
1839 // about unreadable elf files.
1840 if (unlink(tmp_so_name.c_str()) == -1) {
1841 _exit(1);
1842 }
1843 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1844 if (crash_func == nullptr) {
1845 _exit(1);
1846 }
1847 crash_func();
1848 });
1849
1850 StartIntercept(&output_fd);
1851 FinishCrasher();
1852 AssertDeath(SIGSEGV);
1853 FinishIntercept(&intercept_result);
1854
1855 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1856
1857 std::string result;
1858 ConsumeFd(std::move(output_fd), &result);
1859 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001860 std::string match_str = "NOTE: " + tmp_so_name;
1861 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001862}
1863
Josh Gao76e1e302021-01-26 15:53:11 -08001864TEST(tombstoned, proto) {
1865 const pid_t self = getpid();
1866 unique_fd tombstoned_socket, text_fd, proto_fd;
1867 ASSERT_TRUE(
1868 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1869
1870 tombstoned_notify_completion(tombstoned_socket.get());
1871
1872 ASSERT_NE(-1, text_fd.get());
1873 ASSERT_NE(-1, proto_fd.get());
1874
1875 struct stat text_st;
1876 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1877
1878 // Give tombstoned some time to link the files into place.
1879 std::this_thread::sleep_for(100ms);
1880
1881 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001882 std::optional<std::string> tombstone_file;
1883 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1884 ASSERT_TRUE(dir_h != nullptr);
1885 std::regex tombstone_re("tombstone_\\d+");
1886 dirent* entry;
1887 while ((entry = readdir(dir_h.get())) != nullptr) {
1888 if (!std::regex_match(entry->d_name, tombstone_re)) {
1889 continue;
1890 }
1891 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001892
1893 struct stat st;
1894 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1895 continue;
1896 }
1897
1898 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001899 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001900 break;
1901 }
1902 }
1903
Christopher Ferris35da2882021-02-17 15:39:06 -08001904 ASSERT_TRUE(tombstone_file);
1905 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001906
1907 struct stat proto_fd_st;
1908 struct stat proto_file_st;
1909 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1910 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1911
1912 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1913 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1914}
1915
1916TEST(tombstoned, proto_intercept) {
1917 const pid_t self = getpid();
1918 unique_fd intercept_fd, output_fd;
1919 InterceptStatus status;
1920
1921 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1922 ASSERT_EQ(InterceptStatus::kRegistered, status);
1923
1924 unique_fd tombstoned_socket, text_fd, proto_fd;
1925 ASSERT_TRUE(
1926 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1927 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1928 tombstoned_notify_completion(tombstoned_socket.get());
1929
1930 text_fd.reset();
1931
1932 std::string output;
1933 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1934 ASSERT_EQ("foo", output);
1935}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001936
1937// Verify that when an intercept is present for the main thread, and the signal
1938// is received on a different thread, the intercept still works.
1939TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1940 StartProcess([]() {
1941 std::thread thread([]() {
1942 // Raise the signal on the side thread.
1943 raise_debugger_signal(kDebuggerdNativeBacktrace);
1944 });
1945 thread.join();
1946 _exit(0);
1947 });
1948
1949 unique_fd output_fd;
1950 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1951 FinishCrasher();
1952 AssertDeath(0);
1953
1954 int intercept_result;
1955 FinishIntercept(&intercept_result);
1956 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1957
1958 std::string result;
1959 ConsumeFd(std::move(output_fd), &result);
1960 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1961}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001962
1963static std::string format_pointer(uintptr_t ptr) {
1964#if defined(__LP64__)
1965 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1966 static_cast<uint32_t>(ptr & 0xffffffff));
1967#else
1968 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1969#endif
1970}
1971
1972static std::string format_pointer(void* ptr) {
1973 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1974}
1975
1976static std::string format_full_pointer(uintptr_t ptr) {
1977#if defined(__LP64__)
1978 return android::base::StringPrintf("%016" PRIx64, ptr);
1979#else
1980 return android::base::StringPrintf("%08x", ptr);
1981#endif
1982}
1983
1984static std::string format_full_pointer(void* ptr) {
1985 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1986}
1987
1988__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1989 int* crash_ptr = reinterpret_cast<int*>(ptr);
1990 *crash_ptr = 1;
1991 return *crash_ptr;
1992}
1993
1994// Verify that a fault address before the first map is properly handled.
1995TEST_F(CrasherTest, fault_address_before_first_map) {
1996 StartProcess([]() {
1997 ASSERT_EQ(0, crash_call(0x1024));
1998 _exit(0);
1999 });
2000
2001 unique_fd output_fd;
2002 StartIntercept(&output_fd);
2003 FinishCrasher();
2004 AssertDeath(SIGSEGV);
2005
2006 int intercept_result;
2007 FinishIntercept(&intercept_result);
2008 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2009
2010 std::string result;
2011 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002012 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002013
2014 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2015
2016 std::string match_str = android::base::StringPrintf(
2017 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2018 format_pointer(0x1024).c_str());
2019 ASSERT_MATCH(result, match_str);
2020}
2021
2022// Verify that a fault address after the last map is properly handled.
2023TEST_F(CrasherTest, fault_address_after_last_map) {
2024 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2025 StartProcess([crash_uptr]() {
2026 ASSERT_EQ(0, crash_call(crash_uptr));
2027 _exit(0);
2028 });
2029
2030 unique_fd output_fd;
2031 StartIntercept(&output_fd);
2032 FinishCrasher();
2033 AssertDeath(SIGSEGV);
2034
2035 int intercept_result;
2036 FinishIntercept(&intercept_result);
2037 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2038
2039 std::string result;
2040 ConsumeFd(std::move(output_fd), &result);
2041
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002042 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2043 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002044 ASSERT_MATCH(result, match_str);
2045
2046 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2047
2048 // Assumes that the open files section comes after the map section.
2049 // If that assumption changes, the regex below needs to change.
2050 match_str = android::base::StringPrintf(
2051 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2052 format_pointer(crash_uptr).c_str());
2053 ASSERT_MATCH(result, match_str);
2054}
2055
2056// Verify that a fault address between maps is properly handled.
2057TEST_F(CrasherTest, fault_address_between_maps) {
2058 // Create a map before the fork so it will be present in the child.
2059 void* start_ptr =
2060 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2061 ASSERT_NE(MAP_FAILED, start_ptr);
2062 // Unmap the page in the middle.
2063 void* middle_ptr =
2064 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2065 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2066
2067 StartProcess([middle_ptr]() {
2068 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2069 _exit(0);
2070 });
2071
2072 // Unmap the two maps.
2073 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2074 void* end_ptr =
2075 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2076 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2077
2078 unique_fd output_fd;
2079 StartIntercept(&output_fd);
2080 FinishCrasher();
2081 AssertDeath(SIGSEGV);
2082
2083 int intercept_result;
2084 FinishIntercept(&intercept_result);
2085 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2086
2087 std::string result;
2088 ConsumeFd(std::move(output_fd), &result);
2089
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002090 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2091 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002092 ASSERT_MATCH(result, match_str);
2093
2094 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2095
2096 match_str = android::base::StringPrintf(
2097 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2098 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2099 format_pointer(end_ptr).c_str());
2100 ASSERT_MATCH(result, match_str);
2101}
2102
2103// Verify that a fault address happens in the correct map.
2104TEST_F(CrasherTest, fault_address_in_map) {
2105 // Create a map before the fork so it will be present in the child.
2106 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2107 ASSERT_NE(MAP_FAILED, ptr);
2108
2109 StartProcess([ptr]() {
2110 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2111 _exit(0);
2112 });
2113
2114 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2115
2116 unique_fd output_fd;
2117 StartIntercept(&output_fd);
2118 FinishCrasher();
2119 AssertDeath(SIGSEGV);
2120
2121 int intercept_result;
2122 FinishIntercept(&intercept_result);
2123 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2124
2125 std::string result;
2126 ConsumeFd(std::move(output_fd), &result);
2127
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002128 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2129 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002130 ASSERT_MATCH(result, match_str);
2131
2132 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2133
2134 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2135 ASSERT_MATCH(result, match_str);
2136}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002137
2138static constexpr uint32_t kDexData[] = {
2139 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2140 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2141 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2142 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2143 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2144 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2145 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2146 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2147 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2148 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2149 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2150 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2151 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2152 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2153 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2154 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2155 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2156};
2157
2158TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2159 StartProcess([]() {
2160 TemporaryDir td;
2161 std::string tmp_so_name;
2162 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2163 _exit(1);
2164 }
2165
2166 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2167 // move the library to which has a basename of libart.so.
2168 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2169 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2170 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2171 if (handle == nullptr) {
2172 _exit(1);
2173 }
2174
2175 void* ptr =
2176 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2177 ASSERT_TRUE(ptr != MAP_FAILED);
2178 memcpy(ptr, kDexData, sizeof(kDexData));
2179 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2180
2181 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2182 .symfile_size = sizeof(kDexData)};
2183
2184 JITDescriptor* dex_debug =
2185 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2186 ASSERT_TRUE(dex_debug != nullptr);
2187 dex_debug->version = 1;
2188 dex_debug->action_flag = 0;
2189 dex_debug->relevant_entry = 0;
2190 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2191
2192 // This sets the magic dex pc value for register 0, using the value
2193 // of register 1 + 0x102.
2194 asm(".cfi_escape "
2195 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2196 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2197 "0x13 /* DW_OP_drop */,"
2198 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2199
2200 // For each different architecture, set register one to the dex ptr mmap
2201 // created above. Then do a nullptr dereference to force a crash.
2202#if defined(__arm__)
2203 asm volatile(
2204 "mov r1, %[base]\n"
2205 "mov r2, 0\n"
2206 "str r3, [r2]\n"
2207 : [base] "+r"(ptr)
2208 :
2209 : "r1", "r2", "r3", "memory");
2210#elif defined(__aarch64__)
2211 asm volatile(
2212 "mov x1, %[base]\n"
2213 "mov x2, 0\n"
2214 "str x3, [x2]\n"
2215 : [base] "+r"(ptr)
2216 :
2217 : "x1", "x2", "x3", "memory");
2218#elif defined(__i386__)
2219 asm volatile(
2220 "mov %[base], %%ecx\n"
2221 "movl $0, %%edi\n"
2222 "movl 0(%%edi), %%edx\n"
2223 : [base] "+r"(ptr)
2224 :
2225 : "edi", "ecx", "edx", "memory");
2226#elif defined(__x86_64__)
2227 asm volatile(
2228 "mov %[base], %%rdx\n"
2229 "movq 0, %%rdi\n"
2230 "movq 0(%%rdi), %%rcx\n"
2231 : [base] "+r"(ptr)
2232 :
2233 : "rcx", "rdx", "rdi", "memory");
2234#else
2235#error "Unsupported architecture"
2236#endif
2237 _exit(0);
2238 });
2239
2240 unique_fd output_fd;
2241 StartIntercept(&output_fd);
2242 FinishCrasher();
2243 AssertDeath(SIGSEGV);
2244
2245 int intercept_result;
2246 FinishIntercept(&intercept_result);
2247 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2248
2249 std::string result;
2250 ConsumeFd(std::move(output_fd), &result);
2251
2252 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002253 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002254
2255 // Now verify that the dex_pc frame includes a proper function name.
2256 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2257}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002258
2259static std::string format_map_pointer(uintptr_t ptr) {
2260#if defined(__LP64__)
2261 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2262 static_cast<uint32_t>(ptr & 0xffffffff));
2263#else
2264 return android::base::StringPrintf("%08x", ptr);
2265#endif
2266}
2267
2268// Verify that map data is properly formatted.
2269TEST_F(CrasherTest, verify_map_format) {
2270 // Create multiple maps to make sure that the map data is formatted properly.
2271 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2272 ASSERT_NE(MAP_FAILED, none_map);
2273 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2274 ASSERT_NE(MAP_FAILED, r_map);
2275 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2276 ASSERT_NE(MAP_FAILED, w_map);
2277 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2278 ASSERT_NE(MAP_FAILED, x_map);
2279
2280 TemporaryFile tf;
2281 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2282 char c = 'f';
2283 ASSERT_EQ(1, write(tf.fd, &c, 1));
2284 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2285 ASSERT_EQ(1, write(tf.fd, &c, 1));
2286 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2287 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2288 ASSERT_NE(MAP_FAILED, file_map);
2289
2290 StartProcess([]() { abort(); });
2291
2292 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2293 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2294 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2295 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2296 ASSERT_EQ(0, munmap(file_map, 0x3001));
2297
2298 unique_fd output_fd;
2299 StartIntercept(&output_fd);
2300 FinishCrasher();
2301 AssertDeath(SIGABRT);
2302 int intercept_result;
2303 FinishIntercept(&intercept_result);
2304
2305 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2306
2307 std::string result;
2308 ConsumeFd(std::move(output_fd), &result);
2309
2310 std::string match_str;
2311 // Verify none.
2312 match_str = android::base::StringPrintf(
2313 " %s-%s --- 0 1000\\n",
2314 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2315 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2316 ASSERT_MATCH(result, match_str);
2317
2318 // Verify read-only.
2319 match_str = android::base::StringPrintf(
2320 " %s-%s r-- 0 1000\\n",
2321 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2322 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2323 ASSERT_MATCH(result, match_str);
2324
2325 // Verify write-only.
2326 match_str = android::base::StringPrintf(
2327 " %s-%s -w- 0 1000\\n",
2328 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2329 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2330 ASSERT_MATCH(result, match_str);
2331
2332 // Verify exec-only.
2333 match_str = android::base::StringPrintf(
2334 " %s-%s --x 0 1000\\n",
2335 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2336 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2337 ASSERT_MATCH(result, match_str);
2338
2339 // Verify file map with non-zero offset and a name.
2340 match_str = android::base::StringPrintf(
2341 " %s-%s r-- 2000 4000 %s\\n",
2342 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2343 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2344 ASSERT_MATCH(result, match_str);
2345}
2346
2347// Verify that the tombstone map data is correct.
2348TEST_F(CrasherTest, verify_header) {
2349 StartProcess([]() { abort(); });
2350
2351 unique_fd output_fd;
2352 StartIntercept(&output_fd);
2353 FinishCrasher();
2354 AssertDeath(SIGABRT);
2355 int intercept_result;
2356 FinishIntercept(&intercept_result);
2357
2358 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2359
2360 std::string result;
2361 ConsumeFd(std::move(output_fd), &result);
2362
2363 std::string match_str = android::base::StringPrintf(
2364 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2365 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2366 android::base::GetProperty("ro.revision", "unknown").c_str());
2367 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2368 ASSERT_MATCH(result, match_str);
2369}
2370
2371// Verify that the thread header is formatted properly.
2372TEST_F(CrasherTest, verify_thread_header) {
2373 void* shared_map =
2374 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2375 ASSERT_NE(MAP_FAILED, shared_map);
2376 memset(shared_map, 0, sizeof(pid_t));
2377
2378 StartProcess([&shared_map]() {
2379 std::atomic_bool tid_written;
2380 std::thread thread([&tid_written, &shared_map]() {
2381 pid_t tid = gettid();
2382 memcpy(shared_map, &tid, sizeof(pid_t));
2383 tid_written = true;
2384 volatile bool done = false;
2385 while (!done)
2386 ;
2387 });
2388 thread.detach();
2389 while (!tid_written.load(std::memory_order_acquire))
2390 ;
2391 abort();
2392 });
2393
2394 pid_t primary_pid = crasher_pid;
2395
2396 unique_fd output_fd;
2397 StartIntercept(&output_fd);
2398 FinishCrasher();
2399 AssertDeath(SIGABRT);
2400 int intercept_result;
2401 FinishIntercept(&intercept_result);
2402 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2403
2404 // Read the tid data out.
2405 pid_t tid;
2406 memcpy(&tid, shared_map, sizeof(pid_t));
2407 ASSERT_NE(0, tid);
2408
2409 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2410
2411 std::string result;
2412 ConsumeFd(std::move(output_fd), &result);
2413
2414 // Verify that there are two headers, one where the tid is "primary_pid"
2415 // and the other where the tid is "tid".
2416 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2417 primary_pid, primary_pid);
2418 ASSERT_MATCH(result, match_str);
2419
2420 match_str =
2421 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2422 ASSERT_MATCH(result, match_str);
2423}
2424
2425// Verify that there is a BuildID present in the map section and set properly.
2426TEST_F(CrasherTest, verify_build_id) {
2427 StartProcess([]() { abort(); });
2428
2429 unique_fd output_fd;
2430 StartIntercept(&output_fd);
2431 FinishCrasher();
2432 AssertDeath(SIGABRT);
2433 int intercept_result;
2434 FinishIntercept(&intercept_result);
2435 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2436
2437 std::string result;
2438 ConsumeFd(std::move(output_fd), &result);
2439
2440 // Find every /system or /apex lib and verify the BuildID is displayed
2441 // properly.
2442 bool found_valid_elf = false;
2443 std::smatch match;
2444 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2445 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2446 result = match.suffix()) {
2447 if (prev_file == match[1]) {
2448 // Already checked this file.
2449 continue;
2450 }
2451
2452 prev_file = match[1];
2453 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2454 if (!elf.Init() || !elf.valid()) {
2455 // Skipping invalid elf files.
2456 continue;
2457 }
2458 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2459
2460 found_valid_elf = true;
2461 }
2462 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2463}