blob: a52bf2159c8f2cfc3a591e7c33f8e3996cf64d4c [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() {
Mitch Phillips1e096992022-03-22 15:59:31 -0700116 android_mallopt_gwp_asan_options_t opts;
117 // No, we're not an app, but let's turn ourselves on without sampling.
118 // Technically, if someone's using the *.default_app sysprops, they'll adjust
119 // our settings, but I don't think this will be common on a device that's
120 // running debuggerd_tests.
121 opts.desire = android_mallopt_gwp_asan_options_t::Action::TURN_ON_FOR_APP;
122 opts.program_name = "";
123 android_mallopt(M_INITIALIZE_GWP_ASAN, &opts, sizeof(android_mallopt_gwp_asan_options_t));
Mitch Phillips7168a212021-03-09 16:53:23 -0800124}
125
Narayan Kamatha73df602017-05-24 15:07:25 +0100126static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100127 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700128 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
129 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
130 if (intercept_fd->get() == -1) {
131 FAIL() << "failed to contact tombstoned: " << strerror(errno);
132 }
133
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700134 InterceptRequest req = {
135 .dump_type = intercept_type,
136 .pid = target_pid,
137 };
Josh Gao460b3362017-03-30 16:40:47 -0700138
139 unique_fd output_pipe_write;
140 if (!Pipe(output_fd, &output_pipe_write)) {
141 FAIL() << "failed to create output pipe: " << strerror(errno);
142 }
143
144 std::string pipe_size_str;
145 int pipe_buffer_size;
146 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
147 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
148 }
149
150 pipe_size_str = android::base::Trim(pipe_size_str);
151
152 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
153 FAIL() << "failed to parse pipe max size";
154 }
155
156 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
157 FAIL() << "failed to set pipe size: " << strerror(errno);
158 }
159
Josh Gao5675f3c2017-06-01 12:19:53 -0700160 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
161
Josh Gao5f87bbd2019-01-09 17:01:49 -0800162 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
163 output_pipe_write.reset();
164 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700165 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
166 }
167
168 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800169 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700170 if (rc == -1) {
171 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
172 } else if (rc == 0) {
173 FAIL() << "failed to read response from tombstoned (EOF)";
174 } else if (rc != sizeof(response)) {
175 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
176 << ", received " << rc;
177 }
178
Narayan Kamathca5e9082017-06-02 15:42:06 +0100179 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700180}
181
Elliott Hughesd13ea522022-01-13 09:20:26 -0800182static bool pac_supported() {
183#if defined(__aarch64__)
184 return getauxval(AT_HWCAP) & HWCAP_PACA;
185#else
186 return false;
187#endif
188}
189
Josh Gaocbe70cb2016-10-18 18:17:52 -0700190class CrasherTest : public ::testing::Test {
191 public:
192 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700193 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700194 unique_fd crasher_pipe;
195 unique_fd intercept_fd;
196
197 CrasherTest();
198 ~CrasherTest();
199
Narayan Kamatha73df602017-05-24 15:07:25 +0100200 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700201
202 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
203 void FinishIntercept(int* result);
204
Josh Gao2e7b8e22017-05-04 17:12:57 -0700205 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700206 void StartCrasher(const std::string& crash_type);
207 void FinishCrasher();
208 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700209
210 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700211};
212
213CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700214 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
215 android::base::SetProperty(kWaitForDebuggerKey, "0");
216
217 // Clear the old property too, just in case someone's been using it
218 // on this device. (We only document the new name, but we still support
219 // the old name so we don't break anyone's existing setups.)
220 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221}
222
223CrasherTest::~CrasherTest() {
224 if (crasher_pid != -1) {
225 kill(crasher_pid, SIGKILL);
226 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700227 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 }
229
Elliott Hughese4781d52021-03-17 09:15:15 -0700230 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700231}
232
Narayan Kamatha73df602017-05-24 15:07:25 +0100233void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700234 if (crasher_pid == -1) {
235 FAIL() << "crasher hasn't been started";
236 }
237
Narayan Kamathca5e9082017-06-02 15:42:06 +0100238 InterceptStatus status;
239 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
240 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700241}
242
243void CrasherTest::FinishIntercept(int* result) {
244 InterceptResponse response;
245
Christopher Ferris11555f02019-09-20 14:18:55 -0700246 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700247 if (rc == -1) {
248 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
249 } else if (rc == 0) {
250 *result = -1;
251 } else if (rc != sizeof(response)) {
252 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
253 << ", received " << rc;
254 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700255 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700256 }
257}
258
Josh Gao2e7b8e22017-05-04 17:12:57 -0700259void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800260 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 unique_fd crasher_read_pipe;
262 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
263 FAIL() << "failed to create pipe: " << strerror(errno);
264 }
265
Josh Gao2e7b8e22017-05-04 17:12:57 -0700266 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700267 if (crasher_pid == -1) {
268 FAIL() << "fork failed: " << strerror(errno);
269 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800270 char dummy;
271 crasher_pipe.reset();
272 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800273 function();
274 _exit(0);
275 }
276}
277
Josh Gaocbe70cb2016-10-18 18:17:52 -0700278void CrasherTest::FinishCrasher() {
279 if (crasher_pipe == -1) {
280 FAIL() << "crasher pipe uninitialized";
281 }
282
Christopher Ferris172b0a02019-09-18 17:48:30 -0700283 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700284 if (rc == -1) {
285 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
286 } else if (rc == 0) {
287 FAIL() << "crasher pipe was closed";
288 }
289}
290
291void CrasherTest::AssertDeath(int signo) {
292 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700293 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700294 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700295 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
296 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700297 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 FAIL() << "failed to wait for crasher: " << strerror(errno);
299 }
300
Josh Gaoe06f2a42017-04-27 16:50:38 -0700301 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700302 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700303 ASSERT_EQ(0, WEXITSTATUS(signo));
304 } else {
305 ASSERT_FALSE(WIFEXITED(status));
306 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
307 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700308 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700309 crasher_pid = -1;
310}
311
312static void ConsumeFd(unique_fd fd, std::string* output) {
313 constexpr size_t read_length = PAGE_SIZE;
314 std::string result;
315
316 while (true) {
317 size_t offset = result.size();
318 result.resize(result.size() + PAGE_SIZE);
319 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
320 if (rc == -1) {
321 FAIL() << "read failed: " << strerror(errno);
322 } else if (rc == 0) {
323 result.resize(result.size() - PAGE_SIZE);
324 break;
325 }
326
327 result.resize(result.size() - PAGE_SIZE + rc);
328 }
329
330 *output = std::move(result);
331}
332
Mitch Phillips78f06702021-06-01 14:35:43 -0700333class LogcatCollector {
334 public:
335 LogcatCollector() { system("logcat -c"); }
336
337 void Collect(std::string* output) {
338 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
339 ASSERT_NE(cmd_stdout, nullptr);
340 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
341 ConsumeFd(std::move(tmp_fd), output);
342 pclose(cmd_stdout);
343 }
344};
345
Josh Gaocbe70cb2016-10-18 18:17:52 -0700346TEST_F(CrasherTest, smoke) {
347 int intercept_result;
348 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800349 StartProcess([]() {
350 *reinterpret_cast<volatile char*>(0xdead) = '1';
351 });
352
Josh Gaocbe70cb2016-10-18 18:17:52 -0700353 StartIntercept(&output_fd);
354 FinishCrasher();
355 AssertDeath(SIGSEGV);
356 FinishIntercept(&intercept_result);
357
358 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
359
360 std::string result;
361 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800362#ifdef __LP64__
363 ASSERT_MATCH(result,
364 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
365#else
366 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
367#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700368
369 if (mte_supported()) {
370 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700371 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
372 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700373 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800374
375 if (pac_supported()) {
376 // Test that the default PAC_ENABLED_KEYS value is set.
377 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
378 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
379 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700380}
381
Peter Collingbournef03af882020-03-20 18:09:00 -0700382TEST_F(CrasherTest, tagged_fault_addr) {
383#if !defined(__aarch64__)
384 GTEST_SKIP() << "Requires aarch64";
385#endif
386 int intercept_result;
387 unique_fd output_fd;
388 StartProcess([]() {
389 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
390 });
391
392 StartIntercept(&output_fd);
393 FinishCrasher();
394 AssertDeath(SIGSEGV);
395 FinishIntercept(&intercept_result);
396
397 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
398
399 std::string result;
400 ConsumeFd(std::move(output_fd), &result);
401
402 // The address can either be tagged (new kernels) or untagged (old kernels).
403 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800404 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700405}
406
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700407// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
408// compiler could still clobber the argument register before trapping, but that's unlikely.
409__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
410 __builtin_trap();
411}
412
413TEST_F(CrasherTest, heap_addr_in_register) {
414#if defined(__i386__)
415 GTEST_SKIP() << "architecture does not pass arguments in registers";
416#endif
417 int intercept_result;
418 unique_fd output_fd;
419 StartProcess([]() {
420 // Crash with a heap pointer in the first argument register.
421 Trap(malloc(1));
422 });
423
424 StartIntercept(&output_fd);
425 FinishCrasher();
426 int status;
427 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
428 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
429 // Don't test the signal number because different architectures use different signals for
430 // __builtin_trap().
431 FinishIntercept(&intercept_result);
432
433 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
434
435 std::string result;
436 ConsumeFd(std::move(output_fd), &result);
437
438#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800439 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700440#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800441 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700442#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800443 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700444#else
445 ASSERT_TRUE(false) << "unsupported architecture";
446#endif
447}
448
Peter Collingbournecd278072020-12-21 14:08:38 -0800449#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700450static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800451 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700452 abort();
453 }
454}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800455
456static void SetTagCheckingLevelAsync() {
457 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
458 abort();
459 }
460}
Peter Collingbournef8622522020-04-07 14:07:32 -0700461#endif
462
Mitch Phillips7168a212021-03-09 16:53:23 -0800463// Number of iterations required to reliably guarantee a GWP-ASan crash.
464// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
465// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
466// the counter reaches zero, we provide a sampled allocation. Then, double that
467// figure to allow for left/right allocation alignment, as this is done randomly
468// without bias.
469#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
470
471struct GwpAsanTestParameters {
472 size_t alloc_size;
473 bool free_before_access;
474 int access_offset;
475 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
476};
477
478struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
479
480GwpAsanTestParameters gwp_asan_tests[] = {
481 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
482 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
483 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
484 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
485};
486
487INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
488
489TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
490 if (mte_supported()) {
491 // Skip this test on MTE hardware, as MTE will reliably catch these errors
492 // instead of GWP-ASan.
493 GTEST_SKIP() << "Skipped on MTE.";
494 }
495
496 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700497 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800498
499 int intercept_result;
500 unique_fd output_fd;
501 StartProcess([&params]() {
502 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
503 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
504 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
505 p[params.access_offset] = 42;
506 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
507 }
508 });
509
510 StartIntercept(&output_fd);
511 FinishCrasher();
512 AssertDeath(SIGSEGV);
513 FinishIntercept(&intercept_result);
514
515 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
516
Mitch Phillips78f06702021-06-01 14:35:43 -0700517 std::vector<std::string> log_sources(2);
518 ConsumeFd(std::move(output_fd), &log_sources[0]);
519 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800520
Mitch Phillips78f06702021-06-01 14:35:43 -0700521 for (const auto& result : log_sources) {
522 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
523 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
524 if (params.free_before_access) {
525 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
526 }
527 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800528 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800529}
530
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800531struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
532
Peter Collingbourneaa544792021-05-13 13:53:37 -0700533INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800534
535TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800536#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700537 if (!mte_supported()) {
538 GTEST_SKIP() << "Requires MTE";
539 }
540
Peter Collingbourneaa544792021-05-13 13:53:37 -0700541 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
542 if (GetParam() == 0) {
543 return;
544 }
545
Mitch Phillips78f06702021-06-01 14:35:43 -0700546 LogcatCollector logcat_collector;
547
Peter Collingbournef8622522020-04-07 14:07:32 -0700548 int intercept_result;
549 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800550 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700551 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800552 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700553 free((void *)p);
554 p[0] = 42;
555 });
556
557 StartIntercept(&output_fd);
558 FinishCrasher();
559 AssertDeath(SIGSEGV);
560 FinishIntercept(&intercept_result);
561
562 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
563
Mitch Phillips78f06702021-06-01 14:35:43 -0700564 std::vector<std::string> log_sources(2);
565 ConsumeFd(std::move(output_fd), &log_sources[0]);
566 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700567 // Tag dump only available in the tombstone, not logcat.
568 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700569
Mitch Phillips78f06702021-06-01 14:35:43 -0700570 for (const auto& result : log_sources) {
571 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
572 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
573 std::to_string(GetParam()) + R"(-byte allocation)");
574 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
575 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
576 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700577#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800578 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700579#endif
580}
581
Peter Collingbournedc476342021-05-12 15:56:43 -0700582TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
583#if defined(__aarch64__)
584 if (!mte_supported()) {
585 GTEST_SKIP() << "Requires MTE";
586 }
587
588 int intercept_result;
589 unique_fd output_fd;
590 StartProcess([&]() {
591 SetTagCheckingLevelSync();
592 volatile int* p = (volatile int*)malloc(GetParam());
593 free((void *)p);
594 p[-1] = 42;
595 });
596
597 StartIntercept(&output_fd);
598 FinishCrasher();
599 AssertDeath(SIGSEGV);
600 FinishIntercept(&intercept_result);
601
602 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
603
604 std::string result;
605 ConsumeFd(std::move(output_fd), &result);
606
607 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
608 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
609#else
610 GTEST_SKIP() << "Requires aarch64";
611#endif
612}
613
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800614TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800615#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700616 if (!mte_supported()) {
617 GTEST_SKIP() << "Requires MTE";
618 }
619
Mitch Phillips78f06702021-06-01 14:35:43 -0700620 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700621 int intercept_result;
622 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800623 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700624 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800625 volatile char* p = (volatile char*)malloc(GetParam());
626 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700627 });
628
629 StartIntercept(&output_fd);
630 FinishCrasher();
631 AssertDeath(SIGSEGV);
632 FinishIntercept(&intercept_result);
633
634 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
635
Mitch Phillips78f06702021-06-01 14:35:43 -0700636 std::vector<std::string> log_sources(2);
637 ConsumeFd(std::move(output_fd), &log_sources[0]);
638 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700639
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700640 // Tag dump only in tombstone, not logcat, and tagging is not used for
641 // overflow protection in the scudo secondary (guard pages are used instead).
642 if (GetParam() < 0x10000) {
643 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
644 }
645
Mitch Phillips78f06702021-06-01 14:35:43 -0700646 for (const auto& result : log_sources) {
647 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
648 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
649 std::to_string(GetParam()) + R"(-byte allocation)");
650 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
651 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700652#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800653 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700654#endif
655}
656
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800657TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800658#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700659 if (!mte_supported()) {
660 GTEST_SKIP() << "Requires MTE";
661 }
662
663 int intercept_result;
664 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800665 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700666 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800667 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700668 p[-1] = 42;
669 });
670
671 StartIntercept(&output_fd);
672 FinishCrasher();
673 AssertDeath(SIGSEGV);
674 FinishIntercept(&intercept_result);
675
676 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
677
678 std::string result;
679 ConsumeFd(std::move(output_fd), &result);
680
681 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800682 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800683 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700684 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700685 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700686 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700687#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800688 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700689#endif
690}
691
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800692TEST_F(CrasherTest, mte_async) {
693#if defined(__aarch64__)
694 if (!mte_supported()) {
695 GTEST_SKIP() << "Requires MTE";
696 }
697
698 int intercept_result;
699 unique_fd output_fd;
700 StartProcess([&]() {
701 SetTagCheckingLevelAsync();
702 volatile int* p = (volatile int*)malloc(16);
703 p[-1] = 42;
704 });
705
706 StartIntercept(&output_fd);
707 FinishCrasher();
708 AssertDeath(SIGSEGV);
709 FinishIntercept(&intercept_result);
710
711 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
712
713 std::string result;
714 ConsumeFd(std::move(output_fd), &result);
715
716 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
717#else
718 GTEST_SKIP() << "Requires aarch64";
719#endif
720}
721
Peter Collingbournef8622522020-04-07 14:07:32 -0700722TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800723#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700724 if (!mte_supported()) {
725 GTEST_SKIP() << "Requires MTE";
726 }
727
Mitch Phillips78f06702021-06-01 14:35:43 -0700728 LogcatCollector logcat_collector;
729
Peter Collingbournef8622522020-04-07 14:07:32 -0700730 int intercept_result;
731 unique_fd output_fd;
732 StartProcess([]() {
733 SetTagCheckingLevelSync();
734
735 // Make two allocations with the same tag and close to one another. Check for both properties
736 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
737 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
738 // (some non-zero value << 56) apart.
739 //
740 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
741 // other.
742 std::set<uintptr_t> allocs;
743 for (int i = 0; i != 4096; ++i) {
744 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
745 auto it = allocs.insert(alloc).first;
746 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
747 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
748 }
749 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
750 *reinterpret_cast<int*>(alloc + 16) = 42;
751 }
752 }
753 });
754
755 StartIntercept(&output_fd);
756 FinishCrasher();
757 AssertDeath(SIGSEGV);
758 FinishIntercept(&intercept_result);
759
760 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
761
Mitch Phillips78f06702021-06-01 14:35:43 -0700762 std::vector<std::string> log_sources(2);
763 ConsumeFd(std::move(output_fd), &log_sources[0]);
764 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700765
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700766 // Tag dump only in the tombstone, not logcat.
767 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
768
Mitch Phillips78f06702021-06-01 14:35:43 -0700769 for (const auto& result : log_sources) {
770 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
771 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800772 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700773 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
774 // overflows), so we can't match explicitly for an underflow message.
775 ASSERT_MATCH(result,
776 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
777 // Ensure there's at least two allocation traces (one for each cause).
778 ASSERT_MATCH(
779 result,
780 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
781 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700782#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800783 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700784#endif
785}
786
Peter Collingbournecd278072020-12-21 14:08:38 -0800787#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700788static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700789 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
790 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
791 size_t page_size = getpagesize();
792 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
793 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
794 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700795 return 0;
796 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700797 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
798 PROT_READ | PROT_WRITE | PROT_MTE);
799 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
800 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
801 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
802 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
803 }
804 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700805}
806#endif
807
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700808TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800809#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700810 if (!mte_supported()) {
811 GTEST_SKIP() << "Requires MTE";
812 }
813
814 int intercept_result;
815 unique_fd output_fd;
816 StartProcess([&]() {
817 SetTagCheckingLevelSync();
818 Trap(reinterpret_cast<void *>(CreateTagMapping()));
819 });
820
821 StartIntercept(&output_fd);
822 FinishCrasher();
823 AssertDeath(SIGTRAP);
824 FinishIntercept(&intercept_result);
825
826 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
827
828 std::string result;
829 ConsumeFd(std::move(output_fd), &result);
830
831 ASSERT_MATCH(result, R"(memory near x0:
832.*
833.*
834 01.............0 0000000000000000 0000000000000000 ................
835 00.............0)");
836#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800837 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700838#endif
839}
840
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700841TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
842#if defined(__aarch64__)
843 if (!mte_supported()) {
844 GTEST_SKIP() << "Requires MTE";
845 }
846
847 int intercept_result;
848 unique_fd output_fd;
849 StartProcess([&]() {
850 SetTagCheckingLevelSync();
851 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
852 p[0] = 0; // Untagged pointer, tagged memory.
853 });
854
855 StartIntercept(&output_fd);
856 FinishCrasher();
857 AssertDeath(SIGSEGV);
858 FinishIntercept(&intercept_result);
859
860 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
861
862 std::string result;
863 ConsumeFd(std::move(output_fd), &result);
864
865 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
866\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
867#else
868 GTEST_SKIP() << "Requires aarch64";
869#endif
870}
871
872TEST_F(CrasherTest, mte_fault_tag_dump) {
873#if defined(__aarch64__)
874 if (!mte_supported()) {
875 GTEST_SKIP() << "Requires MTE";
876 }
877
878 int intercept_result;
879 unique_fd output_fd;
880 StartProcess([&]() {
881 SetTagCheckingLevelSync();
882 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
883 p[320] = 0; // Untagged pointer, tagged memory.
884 });
885
886 StartIntercept(&output_fd);
887 FinishCrasher();
888 AssertDeath(SIGSEGV);
889 FinishIntercept(&intercept_result);
890
891 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
892
893 std::string result;
894 ConsumeFd(std::move(output_fd), &result);
895
896 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
897\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
898\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
899\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
900)");
901#else
902 GTEST_SKIP() << "Requires aarch64";
903#endif
904}
905
906TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
907#if defined(__aarch64__)
908 if (!mte_supported()) {
909 GTEST_SKIP() << "Requires MTE";
910 }
911
912 int intercept_result;
913 unique_fd output_fd;
914 StartProcess([&]() {
915 SetTagCheckingLevelSync();
916 size_t page_size = getpagesize();
917 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
918 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
919 });
920
921 StartIntercept(&output_fd);
922 FinishCrasher();
923 AssertDeath(SIGSEGV);
924 FinishIntercept(&intercept_result);
925
926 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
927
928 std::string result;
929 ConsumeFd(std::move(output_fd), &result);
930
931 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
932 ASSERT_MATCH(result,
933 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
934\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
935
936)"); // Ensure truncation happened and there's a newline after the tag fault.
937#else
938 GTEST_SKIP() << "Requires aarch64";
939#endif
940}
941
Josh Gaocdea7502017-11-01 15:00:40 -0700942TEST_F(CrasherTest, LD_PRELOAD) {
943 int intercept_result;
944 unique_fd output_fd;
945 StartProcess([]() {
946 setenv("LD_PRELOAD", "nonexistent.so", 1);
947 *reinterpret_cast<volatile char*>(0xdead) = '1';
948 });
949
950 StartIntercept(&output_fd);
951 FinishCrasher();
952 AssertDeath(SIGSEGV);
953 FinishIntercept(&intercept_result);
954
955 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
956
957 std::string result;
958 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800959 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700960}
961
Josh Gaocbe70cb2016-10-18 18:17:52 -0700962TEST_F(CrasherTest, abort) {
963 int intercept_result;
964 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800965 StartProcess([]() {
966 abort();
967 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700968 StartIntercept(&output_fd);
969 FinishCrasher();
970 AssertDeath(SIGABRT);
971 FinishIntercept(&intercept_result);
972
973 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
974
975 std::string result;
976 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700977 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700978}
979
980TEST_F(CrasherTest, signal) {
981 int intercept_result;
982 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800983 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700984 while (true) {
985 sleep(1);
986 }
Josh Gao502cfd22017-02-17 01:39:15 -0800987 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700988 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700989 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700990 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
991
992 AssertDeath(SIGSEGV);
993 FinishIntercept(&intercept_result);
994
995 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
996
997 std::string result;
998 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700999 ASSERT_MATCH(
1000 result,
1001 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001002 ASSERT_MATCH(result, R"(backtrace:)");
1003}
1004
1005TEST_F(CrasherTest, abort_message) {
1006 int intercept_result;
1007 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001008 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001009 // Arrived at experimentally;
1010 // logd truncates at 4062.
1011 // strlen("Abort message: ''") is 17.
1012 // That's 4045, but we also want a NUL.
1013 char buf[4045 + 1];
1014 memset(buf, 'x', sizeof(buf));
1015 buf[sizeof(buf) - 1] = '\0';
1016 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001017 abort();
1018 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001019 StartIntercept(&output_fd);
1020 FinishCrasher();
1021 AssertDeath(SIGABRT);
1022 FinishIntercept(&intercept_result);
1023
1024 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1025
1026 std::string result;
1027 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001028 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001029}
1030
Christopher Ferrise8891452021-08-17 17:34:53 -07001031TEST_F(CrasherTest, abort_message_newline_trimmed) {
1032 int intercept_result;
1033 unique_fd output_fd;
1034 StartProcess([]() {
1035 android_set_abort_message("Message with a newline.\n");
1036 abort();
1037 });
1038 StartIntercept(&output_fd);
1039 FinishCrasher();
1040 AssertDeath(SIGABRT);
1041 FinishIntercept(&intercept_result);
1042
1043 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1044
1045 std::string result;
1046 ConsumeFd(std::move(output_fd), &result);
1047 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1048}
1049
1050TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1051 int intercept_result;
1052 unique_fd output_fd;
1053 StartProcess([]() {
1054 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1055 abort();
1056 });
1057 StartIntercept(&output_fd);
1058 FinishCrasher();
1059 AssertDeath(SIGABRT);
1060 FinishIntercept(&intercept_result);
1061
1062 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1063
1064 std::string result;
1065 ConsumeFd(std::move(output_fd), &result);
1066 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1067}
1068
Josh Gaoe06f2a42017-04-27 16:50:38 -07001069TEST_F(CrasherTest, abort_message_backtrace) {
1070 int intercept_result;
1071 unique_fd output_fd;
1072 StartProcess([]() {
1073 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001074 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001075 exit(0);
1076 });
1077 StartIntercept(&output_fd);
1078 FinishCrasher();
1079 AssertDeath(0);
1080 FinishIntercept(&intercept_result);
1081
1082 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1083
1084 std::string result;
1085 ConsumeFd(std::move(output_fd), &result);
1086 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1087}
1088
Josh Gaocbe70cb2016-10-18 18:17:52 -07001089TEST_F(CrasherTest, intercept_timeout) {
1090 int intercept_result;
1091 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001092 StartProcess([]() {
1093 abort();
1094 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001095 StartIntercept(&output_fd);
1096
1097 // Don't let crasher finish until we timeout.
1098 FinishIntercept(&intercept_result);
1099
1100 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1101 << intercept_result << ")";
1102
1103 FinishCrasher();
1104 AssertDeath(SIGABRT);
1105}
1106
Elliott Hughese4781d52021-03-17 09:15:15 -07001107TEST_F(CrasherTest, wait_for_debugger) {
1108 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1109 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001110 }
1111 sleep(1);
1112
Josh Gao502cfd22017-02-17 01:39:15 -08001113 StartProcess([]() {
1114 abort();
1115 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001116 FinishCrasher();
1117
1118 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001119 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001120 ASSERT_TRUE(WIFSTOPPED(status));
1121 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1122
1123 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1124
1125 AssertDeath(SIGABRT);
1126}
1127
Josh Gaocbe70cb2016-10-18 18:17:52 -07001128TEST_F(CrasherTest, backtrace) {
1129 std::string result;
1130 int intercept_result;
1131 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001132
1133 StartProcess([]() {
1134 abort();
1135 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001136 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001137
1138 std::this_thread::sleep_for(500ms);
1139
1140 sigval val;
1141 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001142 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001143 FinishIntercept(&intercept_result);
1144 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1145 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001146 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001147
1148 int status;
1149 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1150
1151 StartIntercept(&output_fd);
1152 FinishCrasher();
1153 AssertDeath(SIGABRT);
1154 FinishIntercept(&intercept_result);
1155 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1156 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001157 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001158}
Josh Gaofca7ca32017-01-23 12:05:35 -08001159
1160TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001161 int intercept_result;
1162 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001163 StartProcess([]() {
1164 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001165 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001166 });
Josh Gao502cfd22017-02-17 01:39:15 -08001167
1168 StartIntercept(&output_fd);
1169 FinishCrasher();
1170 AssertDeath(SIGABRT);
1171 FinishIntercept(&intercept_result);
1172
1173 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1174
1175 std::string result;
1176 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001177 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001178}
1179
Josh Gao502cfd22017-02-17 01:39:15 -08001180TEST_F(CrasherTest, capabilities) {
1181 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1182
Josh Gaofca7ca32017-01-23 12:05:35 -08001183 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001184 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1185 err(1, "failed to set PR_SET_KEEPCAPS");
1186 }
1187
1188 if (setresuid(1, 1, 1) != 0) {
1189 err(1, "setresuid failed");
1190 }
1191
1192 __user_cap_header_struct capheader;
1193 __user_cap_data_struct capdata[2];
1194 memset(&capheader, 0, sizeof(capheader));
1195 memset(&capdata, 0, sizeof(capdata));
1196
1197 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1198 capheader.pid = 0;
1199
1200 // Turn on every third capability.
1201 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1202 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1203 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1204 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1205 }
1206
1207 // Make sure CAP_SYS_PTRACE is off.
1208 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1209 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1210
1211 if (capset(&capheader, &capdata[0]) != 0) {
1212 err(1, "capset failed");
1213 }
1214
1215 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1216 err(1, "failed to drop ambient capabilities");
1217 }
1218
Josh Gaoa5199a92017-04-03 13:18:34 -07001219 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001220 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001221 });
Josh Gao502cfd22017-02-17 01:39:15 -08001222
1223 unique_fd output_fd;
1224 StartIntercept(&output_fd);
1225 FinishCrasher();
1226 AssertDeath(SIGSYS);
1227
1228 std::string result;
1229 int intercept_result;
1230 FinishIntercept(&intercept_result);
1231 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1232 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001233 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001234 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001235}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001236
Josh Gao2e7b8e22017-05-04 17:12:57 -07001237TEST_F(CrasherTest, fake_pid) {
1238 int intercept_result;
1239 unique_fd output_fd;
1240
1241 // Prime the getpid/gettid caches.
1242 UNUSED(getpid());
1243 UNUSED(gettid());
1244
1245 std::function<pid_t()> clone_fn = []() {
1246 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1247 };
1248 StartProcess(
1249 []() {
1250 ASSERT_NE(getpid(), syscall(__NR_getpid));
1251 ASSERT_NE(gettid(), syscall(__NR_gettid));
1252 raise(SIGSEGV);
1253 },
1254 clone_fn);
1255
1256 StartIntercept(&output_fd);
1257 FinishCrasher();
1258 AssertDeath(SIGSEGV);
1259 FinishIntercept(&intercept_result);
1260
1261 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1262
1263 std::string result;
1264 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001265 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001266}
1267
Josh Gaoe04ca272018-01-16 15:38:17 -08001268static const char* const kDebuggerdSeccompPolicy =
1269 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1270
Josh Gao70adac62018-02-22 11:38:33 -08001271static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001272 std::string policy;
1273 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1274 PLOG(FATAL) << "failed to read policy file";
1275 }
1276
1277 // Allow a bunch of syscalls used by the tests.
1278 policy += "\nclone: 1";
1279 policy += "\nsigaltstack: 1";
1280 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001281 policy += "\ngetrlimit: 1";
1282 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001283
1284 FILE* tmp_file = tmpfile();
1285 if (!tmp_file) {
1286 PLOG(FATAL) << "tmpfile failed";
1287 }
1288
Christopher Ferris172b0a02019-09-18 17:48:30 -07001289 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001290 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1291 PLOG(FATAL) << "failed to write policy to tmpfile";
1292 }
1293
1294 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1295 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001296 }
1297
1298 ScopedMinijail jail{minijail_new()};
1299 if (!jail) {
1300 LOG(FATAL) << "failed to create minijail";
1301 }
1302
1303 minijail_no_new_privs(jail.get());
1304 minijail_log_seccomp_filter_failures(jail.get());
1305 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001306 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001307
1308 pid_t result = fork();
1309 if (result == -1) {
1310 return result;
1311 } else if (result != 0) {
1312 return result;
1313 }
1314
1315 // Spawn and detach a thread that spins forever.
1316 std::atomic<bool> thread_ready(false);
1317 std::thread thread([&jail, &thread_ready]() {
1318 minijail_enter(jail.get());
1319 thread_ready = true;
1320 for (;;)
1321 ;
1322 });
1323 thread.detach();
1324
1325 while (!thread_ready) {
1326 continue;
1327 }
1328
Josh Gao70adac62018-02-22 11:38:33 -08001329 if (prejail) {
1330 prejail();
1331 }
1332
Josh Gaoe04ca272018-01-16 15:38:17 -08001333 minijail_enter(jail.get());
1334 return result;
1335}
1336
Josh Gao70adac62018-02-22 11:38:33 -08001337static pid_t seccomp_fork() {
1338 return seccomp_fork_impl(nullptr);
1339}
1340
Josh Gaoe04ca272018-01-16 15:38:17 -08001341TEST_F(CrasherTest, seccomp_crash) {
1342 int intercept_result;
1343 unique_fd output_fd;
1344
1345 StartProcess([]() { abort(); }, &seccomp_fork);
1346
1347 StartIntercept(&output_fd);
1348 FinishCrasher();
1349 AssertDeath(SIGABRT);
1350 FinishIntercept(&intercept_result);
1351 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1352
1353 std::string result;
1354 ConsumeFd(std::move(output_fd), &result);
1355 ASSERT_BACKTRACE_FRAME(result, "abort");
1356}
1357
Josh Gao70adac62018-02-22 11:38:33 -08001358static pid_t seccomp_fork_rlimit() {
1359 return seccomp_fork_impl([]() {
1360 struct rlimit rlim = {
1361 .rlim_cur = 512 * 1024 * 1024,
1362 .rlim_max = 512 * 1024 * 1024,
1363 };
1364
1365 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1366 raise(SIGINT);
1367 }
1368 });
1369}
1370
1371TEST_F(CrasherTest, seccomp_crash_oom) {
1372 int intercept_result;
1373 unique_fd output_fd;
1374
1375 StartProcess(
1376 []() {
1377 std::vector<void*> vec;
1378 for (int i = 0; i < 512; ++i) {
1379 char* buf = static_cast<char*>(malloc(1024 * 1024));
1380 if (!buf) {
1381 abort();
1382 }
1383 memset(buf, 0xff, 1024 * 1024);
1384 vec.push_back(buf);
1385 }
1386 },
1387 &seccomp_fork_rlimit);
1388
1389 StartIntercept(&output_fd);
1390 FinishCrasher();
1391 AssertDeath(SIGABRT);
1392 FinishIntercept(&intercept_result);
1393 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1394
1395 // We can't actually generate a backtrace, just make sure that the process terminates.
1396}
1397
Josh Gaoe04ca272018-01-16 15:38:17 -08001398__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1399 siginfo_t siginfo;
1400 siginfo.si_code = SI_QUEUE;
1401 siginfo.si_pid = getpid();
1402 siginfo.si_uid = getuid();
1403
1404 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1405 PLOG(FATAL) << "invalid dump type";
1406 }
1407
1408 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1409
Josh Gaoa48b41b2019-12-13 14:11:04 -08001410 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001411 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1412 return false;
1413 }
1414
1415 return true;
1416}
1417
Christopher Ferrisb999b822022-02-09 17:57:21 -08001418extern "C" void foo() {
1419 LOG(INFO) << "foo";
1420 std::this_thread::sleep_for(1s);
1421}
1422
1423extern "C" void bar() {
1424 LOG(INFO) << "bar";
1425 std::this_thread::sleep_for(1s);
1426}
1427
Josh Gaoe04ca272018-01-16 15:38:17 -08001428TEST_F(CrasherTest, seccomp_tombstone) {
1429 int intercept_result;
1430 unique_fd output_fd;
1431
1432 static const auto dump_type = kDebuggerdTombstone;
1433 StartProcess(
1434 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001435 std::thread a(foo);
1436 std::thread b(bar);
1437
1438 std::this_thread::sleep_for(100ms);
1439
Josh Gaoe04ca272018-01-16 15:38:17 -08001440 raise_debugger_signal(dump_type);
1441 _exit(0);
1442 },
1443 &seccomp_fork);
1444
1445 StartIntercept(&output_fd, dump_type);
1446 FinishCrasher();
1447 AssertDeath(0);
1448 FinishIntercept(&intercept_result);
1449 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1450
1451 std::string result;
1452 ConsumeFd(std::move(output_fd), &result);
1453 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001454 ASSERT_BACKTRACE_FRAME(result, "foo");
1455 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001456}
1457
Josh Gaoe04ca272018-01-16 15:38:17 -08001458TEST_F(CrasherTest, seccomp_backtrace) {
1459 int intercept_result;
1460 unique_fd output_fd;
1461
1462 static const auto dump_type = kDebuggerdNativeBacktrace;
1463 StartProcess(
1464 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001465 std::thread a(foo);
1466 std::thread b(bar);
1467
1468 std::this_thread::sleep_for(100ms);
1469
Josh Gaoe04ca272018-01-16 15:38:17 -08001470 raise_debugger_signal(dump_type);
1471 _exit(0);
1472 },
1473 &seccomp_fork);
1474
1475 StartIntercept(&output_fd, dump_type);
1476 FinishCrasher();
1477 AssertDeath(0);
1478 FinishIntercept(&intercept_result);
1479 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1480
1481 std::string result;
1482 ConsumeFd(std::move(output_fd), &result);
1483 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001484 ASSERT_BACKTRACE_FRAME(result, "foo");
1485 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001486}
1487
1488TEST_F(CrasherTest, seccomp_crash_logcat) {
1489 StartProcess([]() { abort(); }, &seccomp_fork);
1490 FinishCrasher();
1491
1492 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1493 AssertDeath(SIGABRT);
1494}
1495
Josh Gaofd13bf02017-08-18 15:37:26 -07001496TEST_F(CrasherTest, competing_tracer) {
1497 int intercept_result;
1498 unique_fd output_fd;
1499 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001500 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001501 });
1502
1503 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001504
1505 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001506 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001507
1508 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001509 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001510 ASSERT_TRUE(WIFSTOPPED(status));
1511 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1512
1513 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1514 FinishIntercept(&intercept_result);
1515 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1516
1517 std::string result;
1518 ConsumeFd(std::move(output_fd), &result);
1519 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1520 regex += std::to_string(gettid());
1521 regex += R"( \(.+debuggerd_test)";
1522 ASSERT_MATCH(result, regex.c_str());
1523
Christopher Ferris172b0a02019-09-18 17:48:30 -07001524 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001525 ASSERT_TRUE(WIFSTOPPED(status));
1526 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1527
Josh Gaofd13bf02017-08-18 15:37:26 -07001528 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1529 AssertDeath(SIGABRT);
1530}
1531
Josh Gaobf06a402018-08-27 16:34:01 -07001532TEST_F(CrasherTest, fdsan_warning_abort_message) {
1533 int intercept_result;
1534 unique_fd output_fd;
1535
1536 StartProcess([]() {
1537 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001538 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001539 if (fd == -1) {
1540 abort();
1541 }
1542 close(fd.get());
1543 _exit(0);
1544 });
1545
1546 StartIntercept(&output_fd);
1547 FinishCrasher();
1548 AssertDeath(0);
1549 FinishIntercept(&intercept_result);
1550 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1551
1552 std::string result;
1553 ConsumeFd(std::move(output_fd), &result);
1554 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1555}
1556
Josh Gaoc3c8c022017-02-13 16:36:18 -08001557TEST(crash_dump, zombie) {
1558 pid_t forkpid = fork();
1559
Josh Gaoc3c8c022017-02-13 16:36:18 -08001560 pid_t rc;
1561 int status;
1562
1563 if (forkpid == 0) {
1564 errno = 0;
1565 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1566 if (rc != -1 || errno != ECHILD) {
1567 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1568 }
1569
Josh Gaoa48b41b2019-12-13 14:11:04 -08001570 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001571
1572 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001573 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001574 if (rc != -1 || errno != ECHILD) {
1575 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1576 }
1577 _exit(0);
1578 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001579 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001580 ASSERT_EQ(forkpid, rc);
1581 ASSERT_TRUE(WIFEXITED(status));
1582 ASSERT_EQ(0, WEXITSTATUS(status));
1583 }
1584}
Josh Gao352a8452017-03-30 16:46:21 -07001585
1586TEST(tombstoned, no_notify) {
1587 // Do this a few times.
1588 for (int i = 0; i < 3; ++i) {
1589 pid_t pid = 123'456'789 + i;
1590
1591 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001592 InterceptStatus status;
1593 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1594 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001595
1596 {
1597 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001598 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001599 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1600 }
1601
1602 pid_t read_pid;
1603 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1604 ASSERT_EQ(read_pid, pid);
1605 }
1606}
1607
1608TEST(tombstoned, stress) {
1609 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1610 static constexpr int kDumpCount = 100;
1611
1612 std::atomic<bool> start(false);
1613 std::vector<std::thread> threads;
1614 threads.emplace_back([&start]() {
1615 while (!start) {
1616 continue;
1617 }
1618
1619 // Use a way out of range pid, to avoid stomping on an actual process.
1620 pid_t pid_base = 1'000'000;
1621
1622 for (int dump = 0; dump < kDumpCount; ++dump) {
1623 pid_t pid = pid_base + dump;
1624
1625 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001626 InterceptStatus status;
1627 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1628 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001629
1630 // Pretend to crash, and then immediately close the socket.
1631 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1632 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1633 if (sockfd == -1) {
1634 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1635 }
1636 TombstonedCrashPacket packet = {};
1637 packet.packet_type = CrashPacketType::kDumpRequest;
1638 packet.packet.dump_request.pid = pid;
1639 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1640 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1641 }
1642
1643 continue;
1644 }
1645 });
1646
1647 threads.emplace_back([&start]() {
1648 while (!start) {
1649 continue;
1650 }
1651
1652 // Use a way out of range pid, to avoid stomping on an actual process.
1653 pid_t pid_base = 2'000'000;
1654
1655 for (int dump = 0; dump < kDumpCount; ++dump) {
1656 pid_t pid = pid_base + dump;
1657
1658 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001659 InterceptStatus status;
1660 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1661 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001662
1663 {
1664 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001665 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001666 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1667 tombstoned_notify_completion(tombstoned_socket.get());
1668 }
1669
1670 // TODO: Fix the race that requires this sleep.
1671 std::this_thread::sleep_for(50ms);
1672
1673 pid_t read_pid;
1674 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1675 ASSERT_EQ(read_pid, pid);
1676 }
1677 });
1678
1679 start = true;
1680
1681 for (std::thread& thread : threads) {
1682 thread.join();
1683 }
1684}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001685
1686TEST(tombstoned, java_trace_intercept_smoke) {
1687 // Using a "real" PID is a little dangerous here - if the test fails
1688 // or crashes, we might end up getting a bogus / unreliable stack
1689 // trace.
1690 const pid_t self = getpid();
1691
1692 unique_fd intercept_fd, output_fd;
1693 InterceptStatus status;
1694 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1695 ASSERT_EQ(InterceptStatus::kRegistered, status);
1696
Josh Gao76e1e302021-01-26 15:53:11 -08001697 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001698 // should result in a "regular" FD and not the installed intercept.
1699 const char native[] = "native";
1700 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001701 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001702 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1703 tombstoned_notify_completion(tombstoned_socket.get());
1704
1705 // Then, connect to tombstoned asking for a java backtrace. This *should*
1706 // trigger the intercept.
1707 const char java[] = "java";
1708 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1709 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1710 tombstoned_notify_completion(tombstoned_socket.get());
1711
1712 char outbuf[sizeof(java)];
1713 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1714 ASSERT_STREQ("java", outbuf);
1715}
1716
1717TEST(tombstoned, multiple_intercepts) {
1718 const pid_t fake_pid = 1'234'567;
1719 unique_fd intercept_fd, output_fd;
1720 InterceptStatus status;
1721 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1722 ASSERT_EQ(InterceptStatus::kRegistered, status);
1723
1724 unique_fd intercept_fd_2, output_fd_2;
1725 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1726 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1727}
1728
1729TEST(tombstoned, intercept_any) {
1730 const pid_t fake_pid = 1'234'567;
1731
1732 unique_fd intercept_fd, output_fd;
1733 InterceptStatus status;
1734 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1735 ASSERT_EQ(InterceptStatus::kRegistered, status);
1736
1737 const char any[] = "any";
1738 unique_fd tombstoned_socket, input_fd;
1739 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1740 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1741 tombstoned_notify_completion(tombstoned_socket.get());
1742
1743 char outbuf[sizeof(any)];
1744 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1745 ASSERT_STREQ("any", outbuf);
1746}
Josh Gao2b22ae12018-09-12 14:51:03 -07001747
1748TEST(tombstoned, interceptless_backtrace) {
1749 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1750 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1751 std::map<int, time_t> result;
1752 for (int i = 0; i < 99; ++i) {
1753 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1754 struct stat st;
1755 if (stat(path.c_str(), &st) == 0) {
1756 result[i] = st.st_mtim.tv_sec;
1757 }
1758 }
1759 return result;
1760 };
1761
1762 auto before = get_tombstone_timestamps();
1763 for (int i = 0; i < 50; ++i) {
1764 raise_debugger_signal(kDebuggerdNativeBacktrace);
1765 }
1766 auto after = get_tombstone_timestamps();
1767
1768 int diff = 0;
1769 for (int i = 0; i < 99; ++i) {
1770 if (after.count(i) == 0) {
1771 continue;
1772 }
1773 if (before.count(i) == 0) {
1774 ++diff;
1775 continue;
1776 }
1777 if (before[i] != after[i]) {
1778 ++diff;
1779 }
1780 }
1781
1782 // We can't be sure that nothing's crash looping in the background.
1783 // This should be good enough, though...
1784 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1785}
Christopher Ferris481e8372019-07-15 17:13:24 -07001786
1787static __attribute__((__noinline__)) void overflow_stack(void* p) {
1788 void* buf[1];
1789 buf[0] = p;
1790 static volatile void* global = buf;
1791 if (global) {
1792 global = buf;
1793 overflow_stack(&buf);
1794 }
1795}
1796
1797TEST_F(CrasherTest, stack_overflow) {
1798 int intercept_result;
1799 unique_fd output_fd;
1800 StartProcess([]() { overflow_stack(nullptr); });
1801
1802 StartIntercept(&output_fd);
1803 FinishCrasher();
1804 AssertDeath(SIGSEGV);
1805 FinishIntercept(&intercept_result);
1806
1807 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1808
1809 std::string result;
1810 ConsumeFd(std::move(output_fd), &result);
1811 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1812}
Josh Gao76e1e302021-01-26 15:53:11 -08001813
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001814static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1815 std::string test_lib(testing::internal::GetArgvs()[0]);
1816 auto const value = test_lib.find_last_of('/');
1817 if (value == std::string::npos) {
1818 test_lib = "./";
1819 } else {
1820 test_lib = test_lib.substr(0, value + 1) + "./";
1821 }
1822 test_lib += "libcrash_test.so";
1823
1824 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1825 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1826
1827 // Copy the shared so to a tempory directory.
1828 return system(cp_cmd.c_str()) == 0;
1829}
1830
1831TEST_F(CrasherTest, unreadable_elf) {
1832 int intercept_result;
1833 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001834 std::string tmp_so_name;
1835 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001836 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001837 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1838 _exit(1);
1839 }
1840 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1841 if (handle == nullptr) {
1842 _exit(1);
1843 }
1844 // Delete the original shared library so that we get the warning
1845 // about unreadable elf files.
1846 if (unlink(tmp_so_name.c_str()) == -1) {
1847 _exit(1);
1848 }
1849 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1850 if (crash_func == nullptr) {
1851 _exit(1);
1852 }
1853 crash_func();
1854 });
1855
1856 StartIntercept(&output_fd);
1857 FinishCrasher();
1858 AssertDeath(SIGSEGV);
1859 FinishIntercept(&intercept_result);
1860
1861 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1862
1863 std::string result;
1864 ConsumeFd(std::move(output_fd), &result);
1865 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001866 std::string match_str = "NOTE: " + tmp_so_name;
1867 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001868}
1869
Josh Gao76e1e302021-01-26 15:53:11 -08001870TEST(tombstoned, proto) {
1871 const pid_t self = getpid();
1872 unique_fd tombstoned_socket, text_fd, proto_fd;
1873 ASSERT_TRUE(
1874 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1875
1876 tombstoned_notify_completion(tombstoned_socket.get());
1877
1878 ASSERT_NE(-1, text_fd.get());
1879 ASSERT_NE(-1, proto_fd.get());
1880
1881 struct stat text_st;
1882 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1883
1884 // Give tombstoned some time to link the files into place.
1885 std::this_thread::sleep_for(100ms);
1886
1887 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001888 std::optional<std::string> tombstone_file;
1889 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1890 ASSERT_TRUE(dir_h != nullptr);
1891 std::regex tombstone_re("tombstone_\\d+");
1892 dirent* entry;
1893 while ((entry = readdir(dir_h.get())) != nullptr) {
1894 if (!std::regex_match(entry->d_name, tombstone_re)) {
1895 continue;
1896 }
1897 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001898
1899 struct stat st;
1900 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1901 continue;
1902 }
1903
1904 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001905 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001906 break;
1907 }
1908 }
1909
Christopher Ferris35da2882021-02-17 15:39:06 -08001910 ASSERT_TRUE(tombstone_file);
1911 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001912
1913 struct stat proto_fd_st;
1914 struct stat proto_file_st;
1915 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1916 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1917
1918 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1919 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1920}
1921
1922TEST(tombstoned, proto_intercept) {
1923 const pid_t self = getpid();
1924 unique_fd intercept_fd, output_fd;
1925 InterceptStatus status;
1926
1927 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1928 ASSERT_EQ(InterceptStatus::kRegistered, status);
1929
1930 unique_fd tombstoned_socket, text_fd, proto_fd;
1931 ASSERT_TRUE(
1932 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1933 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1934 tombstoned_notify_completion(tombstoned_socket.get());
1935
1936 text_fd.reset();
1937
1938 std::string output;
1939 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1940 ASSERT_EQ("foo", output);
1941}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001942
1943// Verify that when an intercept is present for the main thread, and the signal
1944// is received on a different thread, the intercept still works.
1945TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1946 StartProcess([]() {
1947 std::thread thread([]() {
1948 // Raise the signal on the side thread.
1949 raise_debugger_signal(kDebuggerdNativeBacktrace);
1950 });
1951 thread.join();
1952 _exit(0);
1953 });
1954
1955 unique_fd output_fd;
1956 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1957 FinishCrasher();
1958 AssertDeath(0);
1959
1960 int intercept_result;
1961 FinishIntercept(&intercept_result);
1962 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1963
1964 std::string result;
1965 ConsumeFd(std::move(output_fd), &result);
1966 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1967}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001968
1969static std::string format_pointer(uintptr_t ptr) {
1970#if defined(__LP64__)
1971 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1972 static_cast<uint32_t>(ptr & 0xffffffff));
1973#else
1974 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1975#endif
1976}
1977
1978static std::string format_pointer(void* ptr) {
1979 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1980}
1981
1982static std::string format_full_pointer(uintptr_t ptr) {
1983#if defined(__LP64__)
1984 return android::base::StringPrintf("%016" PRIx64, ptr);
1985#else
1986 return android::base::StringPrintf("%08x", ptr);
1987#endif
1988}
1989
1990static std::string format_full_pointer(void* ptr) {
1991 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1992}
1993
1994__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1995 int* crash_ptr = reinterpret_cast<int*>(ptr);
1996 *crash_ptr = 1;
1997 return *crash_ptr;
1998}
1999
2000// Verify that a fault address before the first map is properly handled.
2001TEST_F(CrasherTest, fault_address_before_first_map) {
2002 StartProcess([]() {
2003 ASSERT_EQ(0, crash_call(0x1024));
2004 _exit(0);
2005 });
2006
2007 unique_fd output_fd;
2008 StartIntercept(&output_fd);
2009 FinishCrasher();
2010 AssertDeath(SIGSEGV);
2011
2012 int intercept_result;
2013 FinishIntercept(&intercept_result);
2014 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2015
2016 std::string result;
2017 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002018 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002019
2020 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2021
2022 std::string match_str = android::base::StringPrintf(
2023 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2024 format_pointer(0x1024).c_str());
2025 ASSERT_MATCH(result, match_str);
2026}
2027
2028// Verify that a fault address after the last map is properly handled.
2029TEST_F(CrasherTest, fault_address_after_last_map) {
2030 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2031 StartProcess([crash_uptr]() {
2032 ASSERT_EQ(0, crash_call(crash_uptr));
2033 _exit(0);
2034 });
2035
2036 unique_fd output_fd;
2037 StartIntercept(&output_fd);
2038 FinishCrasher();
2039 AssertDeath(SIGSEGV);
2040
2041 int intercept_result;
2042 FinishIntercept(&intercept_result);
2043 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2044
2045 std::string result;
2046 ConsumeFd(std::move(output_fd), &result);
2047
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002048 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2049 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002050 ASSERT_MATCH(result, match_str);
2051
2052 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2053
2054 // Assumes that the open files section comes after the map section.
2055 // If that assumption changes, the regex below needs to change.
2056 match_str = android::base::StringPrintf(
2057 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2058 format_pointer(crash_uptr).c_str());
2059 ASSERT_MATCH(result, match_str);
2060}
2061
2062// Verify that a fault address between maps is properly handled.
2063TEST_F(CrasherTest, fault_address_between_maps) {
2064 // Create a map before the fork so it will be present in the child.
2065 void* start_ptr =
2066 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2067 ASSERT_NE(MAP_FAILED, start_ptr);
2068 // Unmap the page in the middle.
2069 void* middle_ptr =
2070 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2071 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2072
2073 StartProcess([middle_ptr]() {
2074 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2075 _exit(0);
2076 });
2077
2078 // Unmap the two maps.
2079 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2080 void* end_ptr =
2081 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2082 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2083
2084 unique_fd output_fd;
2085 StartIntercept(&output_fd);
2086 FinishCrasher();
2087 AssertDeath(SIGSEGV);
2088
2089 int intercept_result;
2090 FinishIntercept(&intercept_result);
2091 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2092
2093 std::string result;
2094 ConsumeFd(std::move(output_fd), &result);
2095
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002096 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2097 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002098 ASSERT_MATCH(result, match_str);
2099
2100 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2101
2102 match_str = android::base::StringPrintf(
2103 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2104 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2105 format_pointer(end_ptr).c_str());
2106 ASSERT_MATCH(result, match_str);
2107}
2108
2109// Verify that a fault address happens in the correct map.
2110TEST_F(CrasherTest, fault_address_in_map) {
2111 // Create a map before the fork so it will be present in the child.
2112 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2113 ASSERT_NE(MAP_FAILED, ptr);
2114
2115 StartProcess([ptr]() {
2116 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2117 _exit(0);
2118 });
2119
2120 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2121
2122 unique_fd output_fd;
2123 StartIntercept(&output_fd);
2124 FinishCrasher();
2125 AssertDeath(SIGSEGV);
2126
2127 int intercept_result;
2128 FinishIntercept(&intercept_result);
2129 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2130
2131 std::string result;
2132 ConsumeFd(std::move(output_fd), &result);
2133
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002134 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2135 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002136 ASSERT_MATCH(result, match_str);
2137
2138 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2139
2140 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2141 ASSERT_MATCH(result, match_str);
2142}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002143
2144static constexpr uint32_t kDexData[] = {
2145 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2146 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2147 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2148 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2149 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2150 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2151 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2152 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2153 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2154 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2155 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2156 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2157 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2158 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2159 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2160 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2161 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2162};
2163
2164TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2165 StartProcess([]() {
2166 TemporaryDir td;
2167 std::string tmp_so_name;
2168 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2169 _exit(1);
2170 }
2171
2172 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2173 // move the library to which has a basename of libart.so.
2174 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2175 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2176 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2177 if (handle == nullptr) {
2178 _exit(1);
2179 }
2180
2181 void* ptr =
2182 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2183 ASSERT_TRUE(ptr != MAP_FAILED);
2184 memcpy(ptr, kDexData, sizeof(kDexData));
2185 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2186
2187 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2188 .symfile_size = sizeof(kDexData)};
2189
2190 JITDescriptor* dex_debug =
2191 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2192 ASSERT_TRUE(dex_debug != nullptr);
2193 dex_debug->version = 1;
2194 dex_debug->action_flag = 0;
2195 dex_debug->relevant_entry = 0;
2196 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2197
2198 // This sets the magic dex pc value for register 0, using the value
2199 // of register 1 + 0x102.
2200 asm(".cfi_escape "
2201 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2202 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2203 "0x13 /* DW_OP_drop */,"
2204 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2205
2206 // For each different architecture, set register one to the dex ptr mmap
2207 // created above. Then do a nullptr dereference to force a crash.
2208#if defined(__arm__)
2209 asm volatile(
2210 "mov r1, %[base]\n"
2211 "mov r2, 0\n"
2212 "str r3, [r2]\n"
2213 : [base] "+r"(ptr)
2214 :
2215 : "r1", "r2", "r3", "memory");
2216#elif defined(__aarch64__)
2217 asm volatile(
2218 "mov x1, %[base]\n"
2219 "mov x2, 0\n"
2220 "str x3, [x2]\n"
2221 : [base] "+r"(ptr)
2222 :
2223 : "x1", "x2", "x3", "memory");
2224#elif defined(__i386__)
2225 asm volatile(
2226 "mov %[base], %%ecx\n"
2227 "movl $0, %%edi\n"
2228 "movl 0(%%edi), %%edx\n"
2229 : [base] "+r"(ptr)
2230 :
2231 : "edi", "ecx", "edx", "memory");
2232#elif defined(__x86_64__)
2233 asm volatile(
2234 "mov %[base], %%rdx\n"
2235 "movq 0, %%rdi\n"
2236 "movq 0(%%rdi), %%rcx\n"
2237 : [base] "+r"(ptr)
2238 :
2239 : "rcx", "rdx", "rdi", "memory");
2240#else
2241#error "Unsupported architecture"
2242#endif
2243 _exit(0);
2244 });
2245
2246 unique_fd output_fd;
2247 StartIntercept(&output_fd);
2248 FinishCrasher();
2249 AssertDeath(SIGSEGV);
2250
2251 int intercept_result;
2252 FinishIntercept(&intercept_result);
2253 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2254
2255 std::string result;
2256 ConsumeFd(std::move(output_fd), &result);
2257
2258 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002259 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002260
2261 // Now verify that the dex_pc frame includes a proper function name.
2262 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2263}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002264
2265static std::string format_map_pointer(uintptr_t ptr) {
2266#if defined(__LP64__)
2267 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2268 static_cast<uint32_t>(ptr & 0xffffffff));
2269#else
2270 return android::base::StringPrintf("%08x", ptr);
2271#endif
2272}
2273
2274// Verify that map data is properly formatted.
2275TEST_F(CrasherTest, verify_map_format) {
2276 // Create multiple maps to make sure that the map data is formatted properly.
2277 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2278 ASSERT_NE(MAP_FAILED, none_map);
2279 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2280 ASSERT_NE(MAP_FAILED, r_map);
2281 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2282 ASSERT_NE(MAP_FAILED, w_map);
2283 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2284 ASSERT_NE(MAP_FAILED, x_map);
2285
2286 TemporaryFile tf;
2287 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2288 char c = 'f';
2289 ASSERT_EQ(1, write(tf.fd, &c, 1));
2290 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2291 ASSERT_EQ(1, write(tf.fd, &c, 1));
2292 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2293 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2294 ASSERT_NE(MAP_FAILED, file_map);
2295
2296 StartProcess([]() { abort(); });
2297
2298 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2299 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2300 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2301 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2302 ASSERT_EQ(0, munmap(file_map, 0x3001));
2303
2304 unique_fd output_fd;
2305 StartIntercept(&output_fd);
2306 FinishCrasher();
2307 AssertDeath(SIGABRT);
2308 int intercept_result;
2309 FinishIntercept(&intercept_result);
2310
2311 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2312
2313 std::string result;
2314 ConsumeFd(std::move(output_fd), &result);
2315
2316 std::string match_str;
2317 // Verify none.
2318 match_str = android::base::StringPrintf(
2319 " %s-%s --- 0 1000\\n",
2320 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2321 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2322 ASSERT_MATCH(result, match_str);
2323
2324 // Verify read-only.
2325 match_str = android::base::StringPrintf(
2326 " %s-%s r-- 0 1000\\n",
2327 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2328 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2329 ASSERT_MATCH(result, match_str);
2330
2331 // Verify write-only.
2332 match_str = android::base::StringPrintf(
2333 " %s-%s -w- 0 1000\\n",
2334 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2335 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2336 ASSERT_MATCH(result, match_str);
2337
2338 // Verify exec-only.
2339 match_str = android::base::StringPrintf(
2340 " %s-%s --x 0 1000\\n",
2341 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2342 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2343 ASSERT_MATCH(result, match_str);
2344
2345 // Verify file map with non-zero offset and a name.
2346 match_str = android::base::StringPrintf(
2347 " %s-%s r-- 2000 4000 %s\\n",
2348 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2349 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2350 ASSERT_MATCH(result, match_str);
2351}
2352
2353// Verify that the tombstone map data is correct.
2354TEST_F(CrasherTest, verify_header) {
2355 StartProcess([]() { abort(); });
2356
2357 unique_fd output_fd;
2358 StartIntercept(&output_fd);
2359 FinishCrasher();
2360 AssertDeath(SIGABRT);
2361 int intercept_result;
2362 FinishIntercept(&intercept_result);
2363
2364 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2365
2366 std::string result;
2367 ConsumeFd(std::move(output_fd), &result);
2368
2369 std::string match_str = android::base::StringPrintf(
2370 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2371 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2372 android::base::GetProperty("ro.revision", "unknown").c_str());
2373 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2374 ASSERT_MATCH(result, match_str);
2375}
2376
2377// Verify that the thread header is formatted properly.
2378TEST_F(CrasherTest, verify_thread_header) {
2379 void* shared_map =
2380 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2381 ASSERT_NE(MAP_FAILED, shared_map);
2382 memset(shared_map, 0, sizeof(pid_t));
2383
2384 StartProcess([&shared_map]() {
2385 std::atomic_bool tid_written;
2386 std::thread thread([&tid_written, &shared_map]() {
2387 pid_t tid = gettid();
2388 memcpy(shared_map, &tid, sizeof(pid_t));
2389 tid_written = true;
2390 volatile bool done = false;
2391 while (!done)
2392 ;
2393 });
2394 thread.detach();
2395 while (!tid_written.load(std::memory_order_acquire))
2396 ;
2397 abort();
2398 });
2399
2400 pid_t primary_pid = crasher_pid;
2401
2402 unique_fd output_fd;
2403 StartIntercept(&output_fd);
2404 FinishCrasher();
2405 AssertDeath(SIGABRT);
2406 int intercept_result;
2407 FinishIntercept(&intercept_result);
2408 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2409
2410 // Read the tid data out.
2411 pid_t tid;
2412 memcpy(&tid, shared_map, sizeof(pid_t));
2413 ASSERT_NE(0, tid);
2414
2415 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2416
2417 std::string result;
2418 ConsumeFd(std::move(output_fd), &result);
2419
2420 // Verify that there are two headers, one where the tid is "primary_pid"
2421 // and the other where the tid is "tid".
2422 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2423 primary_pid, primary_pid);
2424 ASSERT_MATCH(result, match_str);
2425
2426 match_str =
2427 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2428 ASSERT_MATCH(result, match_str);
2429}
2430
2431// Verify that there is a BuildID present in the map section and set properly.
2432TEST_F(CrasherTest, verify_build_id) {
2433 StartProcess([]() { abort(); });
2434
2435 unique_fd output_fd;
2436 StartIntercept(&output_fd);
2437 FinishCrasher();
2438 AssertDeath(SIGABRT);
2439 int intercept_result;
2440 FinishIntercept(&intercept_result);
2441 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2442
2443 std::string result;
2444 ConsumeFd(std::move(output_fd), &result);
2445
2446 // Find every /system or /apex lib and verify the BuildID is displayed
2447 // properly.
2448 bool found_valid_elf = false;
2449 std::smatch match;
2450 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2451 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2452 result = match.suffix()) {
2453 if (prev_file == match[1]) {
2454 // Already checked this file.
2455 continue;
2456 }
2457
2458 prev_file = match[1];
2459 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2460 if (!elf.Init() || !elf.valid()) {
2461 // Skipping invalid elf files.
2462 continue;
2463 }
2464 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2465
2466 found_valid_elf = true;
2467 }
2468 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2469}