blob: e1133081970c35b34ac245479bdb1d7fa9cff486 [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
Florian Mayerb4979292022-04-15 14:35:17 -0700386 // HWASan crashes with SIGABRT on tag mismatch.
387 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700388 int intercept_result;
389 unique_fd output_fd;
390 StartProcess([]() {
391 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
392 });
393
394 StartIntercept(&output_fd);
395 FinishCrasher();
396 AssertDeath(SIGSEGV);
397 FinishIntercept(&intercept_result);
398
399 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
400
401 std::string result;
402 ConsumeFd(std::move(output_fd), &result);
403
404 // The address can either be tagged (new kernels) or untagged (old kernels).
405 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800406 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700407}
408
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700409// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
410// compiler could still clobber the argument register before trapping, but that's unlikely.
411__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
412 __builtin_trap();
413}
414
415TEST_F(CrasherTest, heap_addr_in_register) {
416#if defined(__i386__)
417 GTEST_SKIP() << "architecture does not pass arguments in registers";
418#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700419 // The memory dump in HWASan crashes sadly shows the memory near the registers
420 // in the HWASan dump function, rather the faulting context. This is a known
421 // issue.
422 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700423 int intercept_result;
424 unique_fd output_fd;
425 StartProcess([]() {
426 // Crash with a heap pointer in the first argument register.
427 Trap(malloc(1));
428 });
429
430 StartIntercept(&output_fd);
431 FinishCrasher();
432 int status;
433 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
434 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
435 // Don't test the signal number because different architectures use different signals for
436 // __builtin_trap().
437 FinishIntercept(&intercept_result);
438
439 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
440
441 std::string result;
442 ConsumeFd(std::move(output_fd), &result);
443
444#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800445 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700446#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800447 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700448#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800449 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700450#else
451 ASSERT_TRUE(false) << "unsupported architecture";
452#endif
453}
454
Peter Collingbournecd278072020-12-21 14:08:38 -0800455#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700456static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800457 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700458 abort();
459 }
460}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800461
462static void SetTagCheckingLevelAsync() {
463 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
464 abort();
465 }
466}
Peter Collingbournef8622522020-04-07 14:07:32 -0700467#endif
468
Mitch Phillips7168a212021-03-09 16:53:23 -0800469// Number of iterations required to reliably guarantee a GWP-ASan crash.
470// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
471// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
472// the counter reaches zero, we provide a sampled allocation. Then, double that
473// figure to allow for left/right allocation alignment, as this is done randomly
474// without bias.
475#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
476
477struct GwpAsanTestParameters {
478 size_t alloc_size;
479 bool free_before_access;
480 int access_offset;
481 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
482};
483
484struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
485
486GwpAsanTestParameters gwp_asan_tests[] = {
487 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
488 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
489 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
490 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
491};
492
493INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
494
495TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
496 if (mte_supported()) {
497 // Skip this test on MTE hardware, as MTE will reliably catch these errors
498 // instead of GWP-ASan.
499 GTEST_SKIP() << "Skipped on MTE.";
500 }
Florian Mayerb4979292022-04-15 14:35:17 -0700501 // Skip this test on HWASan, which will reliably catch test errors as well.
502 SKIP_WITH_HWASAN;
Mitch Phillips7168a212021-03-09 16:53:23 -0800503
504 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700505 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800506
507 int intercept_result;
508 unique_fd output_fd;
509 StartProcess([&params]() {
510 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
511 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
512 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
513 p[params.access_offset] = 42;
514 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
515 }
516 });
517
518 StartIntercept(&output_fd);
519 FinishCrasher();
520 AssertDeath(SIGSEGV);
521 FinishIntercept(&intercept_result);
522
523 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
524
Mitch Phillips78f06702021-06-01 14:35:43 -0700525 std::vector<std::string> log_sources(2);
526 ConsumeFd(std::move(output_fd), &log_sources[0]);
527 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800528
Mitch Phillips78f06702021-06-01 14:35:43 -0700529 for (const auto& result : log_sources) {
530 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
531 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
532 if (params.free_before_access) {
533 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
534 }
535 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800536 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800537}
538
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800539struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
540
Peter Collingbourneaa544792021-05-13 13:53:37 -0700541INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800542
543TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800544#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700545 if (!mte_supported()) {
546 GTEST_SKIP() << "Requires MTE";
547 }
548
Peter Collingbourneaa544792021-05-13 13:53:37 -0700549 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
550 if (GetParam() == 0) {
551 return;
552 }
553
Mitch Phillips78f06702021-06-01 14:35:43 -0700554 LogcatCollector logcat_collector;
555
Peter Collingbournef8622522020-04-07 14:07:32 -0700556 int intercept_result;
557 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800558 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700559 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800560 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700561 free((void *)p);
562 p[0] = 42;
563 });
564
565 StartIntercept(&output_fd);
566 FinishCrasher();
567 AssertDeath(SIGSEGV);
568 FinishIntercept(&intercept_result);
569
570 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
571
Mitch Phillips78f06702021-06-01 14:35:43 -0700572 std::vector<std::string> log_sources(2);
573 ConsumeFd(std::move(output_fd), &log_sources[0]);
574 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700575 // Tag dump only available in the tombstone, not logcat.
576 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700577
Mitch Phillips78f06702021-06-01 14:35:43 -0700578 for (const auto& result : log_sources) {
579 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
580 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
581 std::to_string(GetParam()) + R"(-byte allocation)");
582 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
583 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
584 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700585#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800586 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700587#endif
588}
589
Peter Collingbournedc476342021-05-12 15:56:43 -0700590TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
591#if defined(__aarch64__)
592 if (!mte_supported()) {
593 GTEST_SKIP() << "Requires MTE";
594 }
595
596 int intercept_result;
597 unique_fd output_fd;
598 StartProcess([&]() {
599 SetTagCheckingLevelSync();
600 volatile int* p = (volatile int*)malloc(GetParam());
601 free((void *)p);
602 p[-1] = 42;
603 });
604
605 StartIntercept(&output_fd);
606 FinishCrasher();
607 AssertDeath(SIGSEGV);
608 FinishIntercept(&intercept_result);
609
610 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
611
612 std::string result;
613 ConsumeFd(std::move(output_fd), &result);
614
615 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
616 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
617#else
618 GTEST_SKIP() << "Requires aarch64";
619#endif
620}
621
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800622TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800623#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700624 if (!mte_supported()) {
625 GTEST_SKIP() << "Requires MTE";
626 }
627
Mitch Phillips78f06702021-06-01 14:35:43 -0700628 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700629 int intercept_result;
630 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800631 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700632 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800633 volatile char* p = (volatile char*)malloc(GetParam());
634 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700635 });
636
637 StartIntercept(&output_fd);
638 FinishCrasher();
639 AssertDeath(SIGSEGV);
640 FinishIntercept(&intercept_result);
641
642 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
643
Mitch Phillips78f06702021-06-01 14:35:43 -0700644 std::vector<std::string> log_sources(2);
645 ConsumeFd(std::move(output_fd), &log_sources[0]);
646 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700647
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700648 // Tag dump only in tombstone, not logcat, and tagging is not used for
649 // overflow protection in the scudo secondary (guard pages are used instead).
650 if (GetParam() < 0x10000) {
651 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
652 }
653
Mitch Phillips78f06702021-06-01 14:35:43 -0700654 for (const auto& result : log_sources) {
655 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
656 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
657 std::to_string(GetParam()) + R"(-byte allocation)");
658 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
659 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700660#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800661 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700662#endif
663}
664
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800665TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800666#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700667 if (!mte_supported()) {
668 GTEST_SKIP() << "Requires MTE";
669 }
670
671 int intercept_result;
672 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800673 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700674 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800675 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700676 p[-1] = 42;
677 });
678
679 StartIntercept(&output_fd);
680 FinishCrasher();
681 AssertDeath(SIGSEGV);
682 FinishIntercept(&intercept_result);
683
684 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
685
686 std::string result;
687 ConsumeFd(std::move(output_fd), &result);
688
689 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800690 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800691 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700692 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700693 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700694 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700695#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800696 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700697#endif
698}
699
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800700TEST_F(CrasherTest, mte_async) {
701#if defined(__aarch64__)
702 if (!mte_supported()) {
703 GTEST_SKIP() << "Requires MTE";
704 }
705
706 int intercept_result;
707 unique_fd output_fd;
708 StartProcess([&]() {
709 SetTagCheckingLevelAsync();
710 volatile int* p = (volatile int*)malloc(16);
711 p[-1] = 42;
712 });
713
714 StartIntercept(&output_fd);
715 FinishCrasher();
716 AssertDeath(SIGSEGV);
717 FinishIntercept(&intercept_result);
718
719 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
720
721 std::string result;
722 ConsumeFd(std::move(output_fd), &result);
723
724 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
725#else
726 GTEST_SKIP() << "Requires aarch64";
727#endif
728}
729
Peter Collingbournef8622522020-04-07 14:07:32 -0700730TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800731#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700732 if (!mte_supported()) {
733 GTEST_SKIP() << "Requires MTE";
734 }
735
Mitch Phillips78f06702021-06-01 14:35:43 -0700736 LogcatCollector logcat_collector;
737
Peter Collingbournef8622522020-04-07 14:07:32 -0700738 int intercept_result;
739 unique_fd output_fd;
740 StartProcess([]() {
741 SetTagCheckingLevelSync();
742
743 // Make two allocations with the same tag and close to one another. Check for both properties
744 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
745 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
746 // (some non-zero value << 56) apart.
747 //
748 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
749 // other.
750 std::set<uintptr_t> allocs;
751 for (int i = 0; i != 4096; ++i) {
752 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
753 auto it = allocs.insert(alloc).first;
754 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
755 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
756 }
757 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
758 *reinterpret_cast<int*>(alloc + 16) = 42;
759 }
760 }
761 });
762
763 StartIntercept(&output_fd);
764 FinishCrasher();
765 AssertDeath(SIGSEGV);
766 FinishIntercept(&intercept_result);
767
768 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
769
Mitch Phillips78f06702021-06-01 14:35:43 -0700770 std::vector<std::string> log_sources(2);
771 ConsumeFd(std::move(output_fd), &log_sources[0]);
772 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700773
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700774 // Tag dump only in the tombstone, not logcat.
775 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
776
Mitch Phillips78f06702021-06-01 14:35:43 -0700777 for (const auto& result : log_sources) {
778 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
779 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800780 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700781 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
782 // overflows), so we can't match explicitly for an underflow message.
783 ASSERT_MATCH(result,
784 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
785 // Ensure there's at least two allocation traces (one for each cause).
786 ASSERT_MATCH(
787 result,
788 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
789 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700790#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800791 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700792#endif
793}
794
Peter Collingbournecd278072020-12-21 14:08:38 -0800795#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700796static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700797 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
798 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
799 size_t page_size = getpagesize();
800 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
801 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
802 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700803 return 0;
804 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700805 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
806 PROT_READ | PROT_WRITE | PROT_MTE);
807 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
808 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
809 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
810 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
811 }
812 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700813}
814#endif
815
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700816TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800817#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700818 if (!mte_supported()) {
819 GTEST_SKIP() << "Requires MTE";
820 }
821
822 int intercept_result;
823 unique_fd output_fd;
824 StartProcess([&]() {
825 SetTagCheckingLevelSync();
826 Trap(reinterpret_cast<void *>(CreateTagMapping()));
827 });
828
829 StartIntercept(&output_fd);
830 FinishCrasher();
831 AssertDeath(SIGTRAP);
832 FinishIntercept(&intercept_result);
833
834 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
835
836 std::string result;
837 ConsumeFd(std::move(output_fd), &result);
838
839 ASSERT_MATCH(result, R"(memory near x0:
840.*
841.*
842 01.............0 0000000000000000 0000000000000000 ................
843 00.............0)");
844#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800845 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700846#endif
847}
848
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700849TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
850#if defined(__aarch64__)
851 if (!mte_supported()) {
852 GTEST_SKIP() << "Requires MTE";
853 }
854
855 int intercept_result;
856 unique_fd output_fd;
857 StartProcess([&]() {
858 SetTagCheckingLevelSync();
859 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
860 p[0] = 0; // Untagged pointer, tagged memory.
861 });
862
863 StartIntercept(&output_fd);
864 FinishCrasher();
865 AssertDeath(SIGSEGV);
866 FinishIntercept(&intercept_result);
867
868 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
869
870 std::string result;
871 ConsumeFd(std::move(output_fd), &result);
872
873 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
874\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
875#else
876 GTEST_SKIP() << "Requires aarch64";
877#endif
878}
879
880TEST_F(CrasherTest, mte_fault_tag_dump) {
881#if defined(__aarch64__)
882 if (!mte_supported()) {
883 GTEST_SKIP() << "Requires MTE";
884 }
885
886 int intercept_result;
887 unique_fd output_fd;
888 StartProcess([&]() {
889 SetTagCheckingLevelSync();
890 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
891 p[320] = 0; // Untagged pointer, tagged memory.
892 });
893
894 StartIntercept(&output_fd);
895 FinishCrasher();
896 AssertDeath(SIGSEGV);
897 FinishIntercept(&intercept_result);
898
899 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
900
901 std::string result;
902 ConsumeFd(std::move(output_fd), &result);
903
904 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
905\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
906\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
907\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
908)");
909#else
910 GTEST_SKIP() << "Requires aarch64";
911#endif
912}
913
914TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
915#if defined(__aarch64__)
916 if (!mte_supported()) {
917 GTEST_SKIP() << "Requires MTE";
918 }
919
920 int intercept_result;
921 unique_fd output_fd;
922 StartProcess([&]() {
923 SetTagCheckingLevelSync();
924 size_t page_size = getpagesize();
925 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
926 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
927 });
928
929 StartIntercept(&output_fd);
930 FinishCrasher();
931 AssertDeath(SIGSEGV);
932 FinishIntercept(&intercept_result);
933
934 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
935
936 std::string result;
937 ConsumeFd(std::move(output_fd), &result);
938
939 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
940 ASSERT_MATCH(result,
941 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
942\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
943
944)"); // Ensure truncation happened and there's a newline after the tag fault.
945#else
946 GTEST_SKIP() << "Requires aarch64";
947#endif
948}
949
Josh Gaocdea7502017-11-01 15:00:40 -0700950TEST_F(CrasherTest, LD_PRELOAD) {
951 int intercept_result;
952 unique_fd output_fd;
953 StartProcess([]() {
954 setenv("LD_PRELOAD", "nonexistent.so", 1);
955 *reinterpret_cast<volatile char*>(0xdead) = '1';
956 });
957
958 StartIntercept(&output_fd);
959 FinishCrasher();
960 AssertDeath(SIGSEGV);
961 FinishIntercept(&intercept_result);
962
963 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
964
965 std::string result;
966 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800967 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700968}
969
Josh Gaocbe70cb2016-10-18 18:17:52 -0700970TEST_F(CrasherTest, abort) {
971 int intercept_result;
972 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800973 StartProcess([]() {
974 abort();
975 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700976 StartIntercept(&output_fd);
977 FinishCrasher();
978 AssertDeath(SIGABRT);
979 FinishIntercept(&intercept_result);
980
981 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
982
983 std::string result;
984 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700985 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700986}
987
988TEST_F(CrasherTest, signal) {
989 int intercept_result;
990 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800991 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700992 while (true) {
993 sleep(1);
994 }
Josh Gao502cfd22017-02-17 01:39:15 -0800995 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700996 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700997 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700998 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
999
1000 AssertDeath(SIGSEGV);
1001 FinishIntercept(&intercept_result);
1002
1003 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1004
1005 std::string result;
1006 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -07001007 ASSERT_MATCH(
1008 result,
1009 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001010 ASSERT_MATCH(result, R"(backtrace:)");
1011}
1012
1013TEST_F(CrasherTest, abort_message) {
1014 int intercept_result;
1015 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001016 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001017 // Arrived at experimentally;
1018 // logd truncates at 4062.
1019 // strlen("Abort message: ''") is 17.
1020 // That's 4045, but we also want a NUL.
1021 char buf[4045 + 1];
1022 memset(buf, 'x', sizeof(buf));
1023 buf[sizeof(buf) - 1] = '\0';
1024 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001025 abort();
1026 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001027 StartIntercept(&output_fd);
1028 FinishCrasher();
1029 AssertDeath(SIGABRT);
1030 FinishIntercept(&intercept_result);
1031
1032 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1033
1034 std::string result;
1035 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001036 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001037}
1038
Christopher Ferrise8891452021-08-17 17:34:53 -07001039TEST_F(CrasherTest, abort_message_newline_trimmed) {
1040 int intercept_result;
1041 unique_fd output_fd;
1042 StartProcess([]() {
1043 android_set_abort_message("Message with a newline.\n");
1044 abort();
1045 });
1046 StartIntercept(&output_fd);
1047 FinishCrasher();
1048 AssertDeath(SIGABRT);
1049 FinishIntercept(&intercept_result);
1050
1051 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1052
1053 std::string result;
1054 ConsumeFd(std::move(output_fd), &result);
1055 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1056}
1057
1058TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1059 int intercept_result;
1060 unique_fd output_fd;
1061 StartProcess([]() {
1062 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1063 abort();
1064 });
1065 StartIntercept(&output_fd);
1066 FinishCrasher();
1067 AssertDeath(SIGABRT);
1068 FinishIntercept(&intercept_result);
1069
1070 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1071
1072 std::string result;
1073 ConsumeFd(std::move(output_fd), &result);
1074 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1075}
1076
Josh Gaoe06f2a42017-04-27 16:50:38 -07001077TEST_F(CrasherTest, abort_message_backtrace) {
1078 int intercept_result;
1079 unique_fd output_fd;
1080 StartProcess([]() {
1081 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001082 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001083 exit(0);
1084 });
1085 StartIntercept(&output_fd);
1086 FinishCrasher();
1087 AssertDeath(0);
1088 FinishIntercept(&intercept_result);
1089
1090 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1091
1092 std::string result;
1093 ConsumeFd(std::move(output_fd), &result);
1094 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1095}
1096
Josh Gaocbe70cb2016-10-18 18:17:52 -07001097TEST_F(CrasherTest, intercept_timeout) {
1098 int intercept_result;
1099 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001100 StartProcess([]() {
1101 abort();
1102 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001103 StartIntercept(&output_fd);
1104
1105 // Don't let crasher finish until we timeout.
1106 FinishIntercept(&intercept_result);
1107
1108 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1109 << intercept_result << ")";
1110
1111 FinishCrasher();
1112 AssertDeath(SIGABRT);
1113}
1114
Elliott Hughese4781d52021-03-17 09:15:15 -07001115TEST_F(CrasherTest, wait_for_debugger) {
1116 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1117 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001118 }
1119 sleep(1);
1120
Josh Gao502cfd22017-02-17 01:39:15 -08001121 StartProcess([]() {
1122 abort();
1123 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001124 FinishCrasher();
1125
1126 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001127 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001128 ASSERT_TRUE(WIFSTOPPED(status));
1129 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1130
1131 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1132
1133 AssertDeath(SIGABRT);
1134}
1135
Josh Gaocbe70cb2016-10-18 18:17:52 -07001136TEST_F(CrasherTest, backtrace) {
1137 std::string result;
1138 int intercept_result;
1139 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001140
1141 StartProcess([]() {
1142 abort();
1143 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001144 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001145
1146 std::this_thread::sleep_for(500ms);
1147
1148 sigval val;
1149 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001150 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001151 FinishIntercept(&intercept_result);
1152 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1153 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001154 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001155
1156 int status;
1157 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1158
1159 StartIntercept(&output_fd);
1160 FinishCrasher();
1161 AssertDeath(SIGABRT);
1162 FinishIntercept(&intercept_result);
1163 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1164 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001165 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001166}
Josh Gaofca7ca32017-01-23 12:05:35 -08001167
1168TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001169 int intercept_result;
1170 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001171 StartProcess([]() {
1172 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001173 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001174 });
Josh Gao502cfd22017-02-17 01:39:15 -08001175
1176 StartIntercept(&output_fd);
1177 FinishCrasher();
1178 AssertDeath(SIGABRT);
1179 FinishIntercept(&intercept_result);
1180
1181 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1182
1183 std::string result;
1184 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001185 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001186}
1187
Josh Gao502cfd22017-02-17 01:39:15 -08001188TEST_F(CrasherTest, capabilities) {
1189 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1190
Josh Gaofca7ca32017-01-23 12:05:35 -08001191 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001192 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1193 err(1, "failed to set PR_SET_KEEPCAPS");
1194 }
1195
1196 if (setresuid(1, 1, 1) != 0) {
1197 err(1, "setresuid failed");
1198 }
1199
1200 __user_cap_header_struct capheader;
1201 __user_cap_data_struct capdata[2];
1202 memset(&capheader, 0, sizeof(capheader));
1203 memset(&capdata, 0, sizeof(capdata));
1204
1205 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1206 capheader.pid = 0;
1207
1208 // Turn on every third capability.
1209 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1210 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1211 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1212 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1213 }
1214
1215 // Make sure CAP_SYS_PTRACE is off.
1216 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1217 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1218
1219 if (capset(&capheader, &capdata[0]) != 0) {
1220 err(1, "capset failed");
1221 }
1222
1223 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1224 err(1, "failed to drop ambient capabilities");
1225 }
1226
Josh Gaoa5199a92017-04-03 13:18:34 -07001227 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001228 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001229 });
Josh Gao502cfd22017-02-17 01:39:15 -08001230
1231 unique_fd output_fd;
1232 StartIntercept(&output_fd);
1233 FinishCrasher();
1234 AssertDeath(SIGSYS);
1235
1236 std::string result;
1237 int intercept_result;
1238 FinishIntercept(&intercept_result);
1239 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1240 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001241 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001242 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001243}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001244
Josh Gao2e7b8e22017-05-04 17:12:57 -07001245TEST_F(CrasherTest, fake_pid) {
1246 int intercept_result;
1247 unique_fd output_fd;
1248
1249 // Prime the getpid/gettid caches.
1250 UNUSED(getpid());
1251 UNUSED(gettid());
1252
1253 std::function<pid_t()> clone_fn = []() {
1254 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1255 };
1256 StartProcess(
1257 []() {
1258 ASSERT_NE(getpid(), syscall(__NR_getpid));
1259 ASSERT_NE(gettid(), syscall(__NR_gettid));
1260 raise(SIGSEGV);
1261 },
1262 clone_fn);
1263
1264 StartIntercept(&output_fd);
1265 FinishCrasher();
1266 AssertDeath(SIGSEGV);
1267 FinishIntercept(&intercept_result);
1268
1269 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1270
1271 std::string result;
1272 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001273 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001274}
1275
Josh Gaoe04ca272018-01-16 15:38:17 -08001276static const char* const kDebuggerdSeccompPolicy =
1277 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1278
Josh Gao70adac62018-02-22 11:38:33 -08001279static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001280 std::string policy;
1281 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1282 PLOG(FATAL) << "failed to read policy file";
1283 }
1284
1285 // Allow a bunch of syscalls used by the tests.
1286 policy += "\nclone: 1";
1287 policy += "\nsigaltstack: 1";
1288 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001289 policy += "\ngetrlimit: 1";
1290 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001291
1292 FILE* tmp_file = tmpfile();
1293 if (!tmp_file) {
1294 PLOG(FATAL) << "tmpfile failed";
1295 }
1296
Christopher Ferris172b0a02019-09-18 17:48:30 -07001297 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001298 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1299 PLOG(FATAL) << "failed to write policy to tmpfile";
1300 }
1301
1302 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1303 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001304 }
1305
1306 ScopedMinijail jail{minijail_new()};
1307 if (!jail) {
1308 LOG(FATAL) << "failed to create minijail";
1309 }
1310
1311 minijail_no_new_privs(jail.get());
1312 minijail_log_seccomp_filter_failures(jail.get());
1313 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001314 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001315
1316 pid_t result = fork();
1317 if (result == -1) {
1318 return result;
1319 } else if (result != 0) {
1320 return result;
1321 }
1322
1323 // Spawn and detach a thread that spins forever.
1324 std::atomic<bool> thread_ready(false);
1325 std::thread thread([&jail, &thread_ready]() {
1326 minijail_enter(jail.get());
1327 thread_ready = true;
1328 for (;;)
1329 ;
1330 });
1331 thread.detach();
1332
1333 while (!thread_ready) {
1334 continue;
1335 }
1336
Josh Gao70adac62018-02-22 11:38:33 -08001337 if (prejail) {
1338 prejail();
1339 }
1340
Josh Gaoe04ca272018-01-16 15:38:17 -08001341 minijail_enter(jail.get());
1342 return result;
1343}
1344
Josh Gao70adac62018-02-22 11:38:33 -08001345static pid_t seccomp_fork() {
1346 return seccomp_fork_impl(nullptr);
1347}
1348
Josh Gaoe04ca272018-01-16 15:38:17 -08001349TEST_F(CrasherTest, seccomp_crash) {
1350 int intercept_result;
1351 unique_fd output_fd;
1352
1353 StartProcess([]() { abort(); }, &seccomp_fork);
1354
1355 StartIntercept(&output_fd);
1356 FinishCrasher();
1357 AssertDeath(SIGABRT);
1358 FinishIntercept(&intercept_result);
1359 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1360
1361 std::string result;
1362 ConsumeFd(std::move(output_fd), &result);
1363 ASSERT_BACKTRACE_FRAME(result, "abort");
1364}
1365
Josh Gao70adac62018-02-22 11:38:33 -08001366static pid_t seccomp_fork_rlimit() {
1367 return seccomp_fork_impl([]() {
1368 struct rlimit rlim = {
1369 .rlim_cur = 512 * 1024 * 1024,
1370 .rlim_max = 512 * 1024 * 1024,
1371 };
1372
1373 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1374 raise(SIGINT);
1375 }
1376 });
1377}
1378
1379TEST_F(CrasherTest, seccomp_crash_oom) {
1380 int intercept_result;
1381 unique_fd output_fd;
1382
1383 StartProcess(
1384 []() {
1385 std::vector<void*> vec;
1386 for (int i = 0; i < 512; ++i) {
1387 char* buf = static_cast<char*>(malloc(1024 * 1024));
1388 if (!buf) {
1389 abort();
1390 }
1391 memset(buf, 0xff, 1024 * 1024);
1392 vec.push_back(buf);
1393 }
1394 },
1395 &seccomp_fork_rlimit);
1396
1397 StartIntercept(&output_fd);
1398 FinishCrasher();
1399 AssertDeath(SIGABRT);
1400 FinishIntercept(&intercept_result);
1401 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1402
1403 // We can't actually generate a backtrace, just make sure that the process terminates.
1404}
1405
Josh Gaoe04ca272018-01-16 15:38:17 -08001406__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1407 siginfo_t siginfo;
1408 siginfo.si_code = SI_QUEUE;
1409 siginfo.si_pid = getpid();
1410 siginfo.si_uid = getuid();
1411
1412 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1413 PLOG(FATAL) << "invalid dump type";
1414 }
1415
1416 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1417
Josh Gaoa48b41b2019-12-13 14:11:04 -08001418 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001419 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1420 return false;
1421 }
1422
1423 return true;
1424}
1425
Christopher Ferrisb999b822022-02-09 17:57:21 -08001426extern "C" void foo() {
1427 LOG(INFO) << "foo";
1428 std::this_thread::sleep_for(1s);
1429}
1430
1431extern "C" void bar() {
1432 LOG(INFO) << "bar";
1433 std::this_thread::sleep_for(1s);
1434}
1435
Josh Gaoe04ca272018-01-16 15:38:17 -08001436TEST_F(CrasherTest, seccomp_tombstone) {
1437 int intercept_result;
1438 unique_fd output_fd;
1439
1440 static const auto dump_type = kDebuggerdTombstone;
1441 StartProcess(
1442 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001443 std::thread a(foo);
1444 std::thread b(bar);
1445
1446 std::this_thread::sleep_for(100ms);
1447
Josh Gaoe04ca272018-01-16 15:38:17 -08001448 raise_debugger_signal(dump_type);
1449 _exit(0);
1450 },
1451 &seccomp_fork);
1452
1453 StartIntercept(&output_fd, dump_type);
1454 FinishCrasher();
1455 AssertDeath(0);
1456 FinishIntercept(&intercept_result);
1457 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1458
1459 std::string result;
1460 ConsumeFd(std::move(output_fd), &result);
1461 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001462 ASSERT_BACKTRACE_FRAME(result, "foo");
1463 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001464}
1465
Christopher Ferris303c6be2022-05-24 17:08:33 -07001466TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1467 int intercept_result;
1468 unique_fd output_fd;
1469
1470 static const auto dump_type = kDebuggerdTombstone;
1471 StartProcess(
1472 []() {
1473 std::thread abort_thread([] { abort(); });
1474 abort_thread.join();
1475 },
1476 &seccomp_fork);
1477
1478 StartIntercept(&output_fd, dump_type);
1479 FinishCrasher();
1480 AssertDeath(SIGABRT);
1481 FinishIntercept(&intercept_result);
1482 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1483
1484 std::string result;
1485 ConsumeFd(std::move(output_fd), &result);
1486 ASSERT_BACKTRACE_FRAME(result, "abort");
1487}
1488
Josh Gaoe04ca272018-01-16 15:38:17 -08001489TEST_F(CrasherTest, seccomp_backtrace) {
1490 int intercept_result;
1491 unique_fd output_fd;
1492
1493 static const auto dump_type = kDebuggerdNativeBacktrace;
1494 StartProcess(
1495 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001496 std::thread a(foo);
1497 std::thread b(bar);
1498
1499 std::this_thread::sleep_for(100ms);
1500
Josh Gaoe04ca272018-01-16 15:38:17 -08001501 raise_debugger_signal(dump_type);
1502 _exit(0);
1503 },
1504 &seccomp_fork);
1505
1506 StartIntercept(&output_fd, dump_type);
1507 FinishCrasher();
1508 AssertDeath(0);
1509 FinishIntercept(&intercept_result);
1510 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1511
1512 std::string result;
1513 ConsumeFd(std::move(output_fd), &result);
1514 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001515 ASSERT_BACKTRACE_FRAME(result, "foo");
1516 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001517}
1518
1519TEST_F(CrasherTest, seccomp_crash_logcat) {
1520 StartProcess([]() { abort(); }, &seccomp_fork);
1521 FinishCrasher();
1522
1523 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1524 AssertDeath(SIGABRT);
1525}
1526
Josh Gaofd13bf02017-08-18 15:37:26 -07001527TEST_F(CrasherTest, competing_tracer) {
1528 int intercept_result;
1529 unique_fd output_fd;
1530 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001531 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001532 });
1533
1534 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001535
1536 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001537 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001538
1539 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001540 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001541 ASSERT_TRUE(WIFSTOPPED(status));
1542 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1543
1544 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1545 FinishIntercept(&intercept_result);
1546 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1547
1548 std::string result;
1549 ConsumeFd(std::move(output_fd), &result);
1550 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1551 regex += std::to_string(gettid());
1552 regex += R"( \(.+debuggerd_test)";
1553 ASSERT_MATCH(result, regex.c_str());
1554
Christopher Ferris172b0a02019-09-18 17:48:30 -07001555 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001556 ASSERT_TRUE(WIFSTOPPED(status));
1557 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1558
Josh Gaofd13bf02017-08-18 15:37:26 -07001559 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1560 AssertDeath(SIGABRT);
1561}
1562
Josh Gaobf06a402018-08-27 16:34:01 -07001563TEST_F(CrasherTest, fdsan_warning_abort_message) {
1564 int intercept_result;
1565 unique_fd output_fd;
1566
1567 StartProcess([]() {
1568 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001569 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001570 if (fd == -1) {
1571 abort();
1572 }
1573 close(fd.get());
1574 _exit(0);
1575 });
1576
1577 StartIntercept(&output_fd);
1578 FinishCrasher();
1579 AssertDeath(0);
1580 FinishIntercept(&intercept_result);
1581 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1582
1583 std::string result;
1584 ConsumeFd(std::move(output_fd), &result);
1585 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1586}
1587
Josh Gaoc3c8c022017-02-13 16:36:18 -08001588TEST(crash_dump, zombie) {
1589 pid_t forkpid = fork();
1590
Josh Gaoc3c8c022017-02-13 16:36:18 -08001591 pid_t rc;
1592 int status;
1593
1594 if (forkpid == 0) {
1595 errno = 0;
1596 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1597 if (rc != -1 || errno != ECHILD) {
1598 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1599 }
1600
Josh Gaoa48b41b2019-12-13 14:11:04 -08001601 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001602
1603 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001604 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001605 if (rc != -1 || errno != ECHILD) {
1606 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1607 }
1608 _exit(0);
1609 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001610 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001611 ASSERT_EQ(forkpid, rc);
1612 ASSERT_TRUE(WIFEXITED(status));
1613 ASSERT_EQ(0, WEXITSTATUS(status));
1614 }
1615}
Josh Gao352a8452017-03-30 16:46:21 -07001616
1617TEST(tombstoned, no_notify) {
1618 // Do this a few times.
1619 for (int i = 0; i < 3; ++i) {
1620 pid_t pid = 123'456'789 + i;
1621
1622 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001623 InterceptStatus status;
1624 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1625 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001626
1627 {
1628 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001629 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001630 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1631 }
1632
1633 pid_t read_pid;
1634 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1635 ASSERT_EQ(read_pid, pid);
1636 }
1637}
1638
1639TEST(tombstoned, stress) {
1640 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1641 static constexpr int kDumpCount = 100;
1642
1643 std::atomic<bool> start(false);
1644 std::vector<std::thread> threads;
1645 threads.emplace_back([&start]() {
1646 while (!start) {
1647 continue;
1648 }
1649
1650 // Use a way out of range pid, to avoid stomping on an actual process.
1651 pid_t pid_base = 1'000'000;
1652
1653 for (int dump = 0; dump < kDumpCount; ++dump) {
1654 pid_t pid = pid_base + dump;
1655
1656 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001657 InterceptStatus status;
1658 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1659 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001660
1661 // Pretend to crash, and then immediately close the socket.
1662 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1663 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1664 if (sockfd == -1) {
1665 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1666 }
1667 TombstonedCrashPacket packet = {};
1668 packet.packet_type = CrashPacketType::kDumpRequest;
1669 packet.packet.dump_request.pid = pid;
1670 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1671 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1672 }
1673
1674 continue;
1675 }
1676 });
1677
1678 threads.emplace_back([&start]() {
1679 while (!start) {
1680 continue;
1681 }
1682
1683 // Use a way out of range pid, to avoid stomping on an actual process.
1684 pid_t pid_base = 2'000'000;
1685
1686 for (int dump = 0; dump < kDumpCount; ++dump) {
1687 pid_t pid = pid_base + dump;
1688
1689 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001690 InterceptStatus status;
1691 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1692 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001693
1694 {
1695 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001696 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001697 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1698 tombstoned_notify_completion(tombstoned_socket.get());
1699 }
1700
1701 // TODO: Fix the race that requires this sleep.
1702 std::this_thread::sleep_for(50ms);
1703
1704 pid_t read_pid;
1705 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1706 ASSERT_EQ(read_pid, pid);
1707 }
1708 });
1709
1710 start = true;
1711
1712 for (std::thread& thread : threads) {
1713 thread.join();
1714 }
1715}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001716
1717TEST(tombstoned, java_trace_intercept_smoke) {
1718 // Using a "real" PID is a little dangerous here - if the test fails
1719 // or crashes, we might end up getting a bogus / unreliable stack
1720 // trace.
1721 const pid_t self = getpid();
1722
1723 unique_fd intercept_fd, output_fd;
1724 InterceptStatus status;
1725 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1726 ASSERT_EQ(InterceptStatus::kRegistered, status);
1727
Josh Gao76e1e302021-01-26 15:53:11 -08001728 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001729 // should result in a "regular" FD and not the installed intercept.
1730 const char native[] = "native";
1731 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001732 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001733 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1734 tombstoned_notify_completion(tombstoned_socket.get());
1735
1736 // Then, connect to tombstoned asking for a java backtrace. This *should*
1737 // trigger the intercept.
1738 const char java[] = "java";
1739 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1740 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1741 tombstoned_notify_completion(tombstoned_socket.get());
1742
1743 char outbuf[sizeof(java)];
1744 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1745 ASSERT_STREQ("java", outbuf);
1746}
1747
1748TEST(tombstoned, multiple_intercepts) {
1749 const pid_t fake_pid = 1'234'567;
1750 unique_fd intercept_fd, output_fd;
1751 InterceptStatus status;
1752 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1753 ASSERT_EQ(InterceptStatus::kRegistered, status);
1754
1755 unique_fd intercept_fd_2, output_fd_2;
1756 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1757 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1758}
1759
1760TEST(tombstoned, intercept_any) {
1761 const pid_t fake_pid = 1'234'567;
1762
1763 unique_fd intercept_fd, output_fd;
1764 InterceptStatus status;
1765 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1766 ASSERT_EQ(InterceptStatus::kRegistered, status);
1767
1768 const char any[] = "any";
1769 unique_fd tombstoned_socket, input_fd;
1770 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1771 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1772 tombstoned_notify_completion(tombstoned_socket.get());
1773
1774 char outbuf[sizeof(any)];
1775 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1776 ASSERT_STREQ("any", outbuf);
1777}
Josh Gao2b22ae12018-09-12 14:51:03 -07001778
1779TEST(tombstoned, interceptless_backtrace) {
1780 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1781 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1782 std::map<int, time_t> result;
1783 for (int i = 0; i < 99; ++i) {
1784 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1785 struct stat st;
1786 if (stat(path.c_str(), &st) == 0) {
1787 result[i] = st.st_mtim.tv_sec;
1788 }
1789 }
1790 return result;
1791 };
1792
1793 auto before = get_tombstone_timestamps();
1794 for (int i = 0; i < 50; ++i) {
1795 raise_debugger_signal(kDebuggerdNativeBacktrace);
1796 }
1797 auto after = get_tombstone_timestamps();
1798
1799 int diff = 0;
1800 for (int i = 0; i < 99; ++i) {
1801 if (after.count(i) == 0) {
1802 continue;
1803 }
1804 if (before.count(i) == 0) {
1805 ++diff;
1806 continue;
1807 }
1808 if (before[i] != after[i]) {
1809 ++diff;
1810 }
1811 }
1812
1813 // We can't be sure that nothing's crash looping in the background.
1814 // This should be good enough, though...
1815 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1816}
Christopher Ferris481e8372019-07-15 17:13:24 -07001817
1818static __attribute__((__noinline__)) void overflow_stack(void* p) {
1819 void* buf[1];
1820 buf[0] = p;
1821 static volatile void* global = buf;
1822 if (global) {
1823 global = buf;
1824 overflow_stack(&buf);
1825 }
1826}
1827
1828TEST_F(CrasherTest, stack_overflow) {
1829 int intercept_result;
1830 unique_fd output_fd;
1831 StartProcess([]() { overflow_stack(nullptr); });
1832
1833 StartIntercept(&output_fd);
1834 FinishCrasher();
1835 AssertDeath(SIGSEGV);
1836 FinishIntercept(&intercept_result);
1837
1838 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1839
1840 std::string result;
1841 ConsumeFd(std::move(output_fd), &result);
1842 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1843}
Josh Gao76e1e302021-01-26 15:53:11 -08001844
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001845static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1846 std::string test_lib(testing::internal::GetArgvs()[0]);
1847 auto const value = test_lib.find_last_of('/');
1848 if (value == std::string::npos) {
1849 test_lib = "./";
1850 } else {
1851 test_lib = test_lib.substr(0, value + 1) + "./";
1852 }
1853 test_lib += "libcrash_test.so";
1854
1855 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1856 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1857
1858 // Copy the shared so to a tempory directory.
1859 return system(cp_cmd.c_str()) == 0;
1860}
1861
1862TEST_F(CrasherTest, unreadable_elf) {
1863 int intercept_result;
1864 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001865 std::string tmp_so_name;
1866 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001867 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001868 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1869 _exit(1);
1870 }
1871 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1872 if (handle == nullptr) {
1873 _exit(1);
1874 }
1875 // Delete the original shared library so that we get the warning
1876 // about unreadable elf files.
1877 if (unlink(tmp_so_name.c_str()) == -1) {
1878 _exit(1);
1879 }
1880 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1881 if (crash_func == nullptr) {
1882 _exit(1);
1883 }
1884 crash_func();
1885 });
1886
1887 StartIntercept(&output_fd);
1888 FinishCrasher();
1889 AssertDeath(SIGSEGV);
1890 FinishIntercept(&intercept_result);
1891
1892 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1893
1894 std::string result;
1895 ConsumeFd(std::move(output_fd), &result);
1896 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001897 std::string match_str = "NOTE: " + tmp_so_name;
1898 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001899}
1900
Josh Gao76e1e302021-01-26 15:53:11 -08001901TEST(tombstoned, proto) {
1902 const pid_t self = getpid();
1903 unique_fd tombstoned_socket, text_fd, proto_fd;
1904 ASSERT_TRUE(
1905 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1906
1907 tombstoned_notify_completion(tombstoned_socket.get());
1908
1909 ASSERT_NE(-1, text_fd.get());
1910 ASSERT_NE(-1, proto_fd.get());
1911
1912 struct stat text_st;
1913 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1914
1915 // Give tombstoned some time to link the files into place.
1916 std::this_thread::sleep_for(100ms);
1917
1918 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001919 std::optional<std::string> tombstone_file;
1920 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1921 ASSERT_TRUE(dir_h != nullptr);
1922 std::regex tombstone_re("tombstone_\\d+");
1923 dirent* entry;
1924 while ((entry = readdir(dir_h.get())) != nullptr) {
1925 if (!std::regex_match(entry->d_name, tombstone_re)) {
1926 continue;
1927 }
1928 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001929
1930 struct stat st;
1931 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1932 continue;
1933 }
1934
1935 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001936 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001937 break;
1938 }
1939 }
1940
Christopher Ferris35da2882021-02-17 15:39:06 -08001941 ASSERT_TRUE(tombstone_file);
1942 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001943
1944 struct stat proto_fd_st;
1945 struct stat proto_file_st;
1946 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1947 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1948
1949 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1950 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1951}
1952
1953TEST(tombstoned, proto_intercept) {
1954 const pid_t self = getpid();
1955 unique_fd intercept_fd, output_fd;
1956 InterceptStatus status;
1957
1958 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1959 ASSERT_EQ(InterceptStatus::kRegistered, status);
1960
1961 unique_fd tombstoned_socket, text_fd, proto_fd;
1962 ASSERT_TRUE(
1963 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1964 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1965 tombstoned_notify_completion(tombstoned_socket.get());
1966
1967 text_fd.reset();
1968
1969 std::string output;
1970 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1971 ASSERT_EQ("foo", output);
1972}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001973
1974// Verify that when an intercept is present for the main thread, and the signal
1975// is received on a different thread, the intercept still works.
1976TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1977 StartProcess([]() {
1978 std::thread thread([]() {
1979 // Raise the signal on the side thread.
1980 raise_debugger_signal(kDebuggerdNativeBacktrace);
1981 });
1982 thread.join();
1983 _exit(0);
1984 });
1985
1986 unique_fd output_fd;
1987 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1988 FinishCrasher();
1989 AssertDeath(0);
1990
1991 int intercept_result;
1992 FinishIntercept(&intercept_result);
1993 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1994
1995 std::string result;
1996 ConsumeFd(std::move(output_fd), &result);
1997 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1998}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001999
2000static std::string format_pointer(uintptr_t ptr) {
2001#if defined(__LP64__)
2002 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2003 static_cast<uint32_t>(ptr & 0xffffffff));
2004#else
2005 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2006#endif
2007}
2008
2009static std::string format_pointer(void* ptr) {
2010 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2011}
2012
2013static std::string format_full_pointer(uintptr_t ptr) {
2014#if defined(__LP64__)
2015 return android::base::StringPrintf("%016" PRIx64, ptr);
2016#else
2017 return android::base::StringPrintf("%08x", ptr);
2018#endif
2019}
2020
2021static std::string format_full_pointer(void* ptr) {
2022 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2023}
2024
2025__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2026 int* crash_ptr = reinterpret_cast<int*>(ptr);
2027 *crash_ptr = 1;
2028 return *crash_ptr;
2029}
2030
2031// Verify that a fault address before the first map is properly handled.
2032TEST_F(CrasherTest, fault_address_before_first_map) {
2033 StartProcess([]() {
2034 ASSERT_EQ(0, crash_call(0x1024));
2035 _exit(0);
2036 });
2037
2038 unique_fd output_fd;
2039 StartIntercept(&output_fd);
2040 FinishCrasher();
2041 AssertDeath(SIGSEGV);
2042
2043 int intercept_result;
2044 FinishIntercept(&intercept_result);
2045 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2046
2047 std::string result;
2048 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002049 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002050
2051 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2052
2053 std::string match_str = android::base::StringPrintf(
2054 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2055 format_pointer(0x1024).c_str());
2056 ASSERT_MATCH(result, match_str);
2057}
2058
2059// Verify that a fault address after the last map is properly handled.
2060TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002061 // This makes assumptions about the memory layout that are not true in HWASan
2062 // processes.
2063 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002064 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2065 StartProcess([crash_uptr]() {
2066 ASSERT_EQ(0, crash_call(crash_uptr));
2067 _exit(0);
2068 });
2069
2070 unique_fd output_fd;
2071 StartIntercept(&output_fd);
2072 FinishCrasher();
2073 AssertDeath(SIGSEGV);
2074
2075 int intercept_result;
2076 FinishIntercept(&intercept_result);
2077 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2078
2079 std::string result;
2080 ConsumeFd(std::move(output_fd), &result);
2081
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002082 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2083 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002084 ASSERT_MATCH(result, match_str);
2085
2086 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2087
2088 // Assumes that the open files section comes after the map section.
2089 // If that assumption changes, the regex below needs to change.
2090 match_str = android::base::StringPrintf(
2091 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2092 format_pointer(crash_uptr).c_str());
2093 ASSERT_MATCH(result, match_str);
2094}
2095
2096// Verify that a fault address between maps is properly handled.
2097TEST_F(CrasherTest, fault_address_between_maps) {
2098 // Create a map before the fork so it will be present in the child.
2099 void* start_ptr =
2100 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2101 ASSERT_NE(MAP_FAILED, start_ptr);
2102 // Unmap the page in the middle.
2103 void* middle_ptr =
2104 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2105 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2106
2107 StartProcess([middle_ptr]() {
2108 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2109 _exit(0);
2110 });
2111
2112 // Unmap the two maps.
2113 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2114 void* end_ptr =
2115 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2116 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2117
2118 unique_fd output_fd;
2119 StartIntercept(&output_fd);
2120 FinishCrasher();
2121 AssertDeath(SIGSEGV);
2122
2123 int intercept_result;
2124 FinishIntercept(&intercept_result);
2125 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2126
2127 std::string result;
2128 ConsumeFd(std::move(output_fd), &result);
2129
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002130 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2131 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002132 ASSERT_MATCH(result, match_str);
2133
2134 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2135
2136 match_str = android::base::StringPrintf(
2137 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2138 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2139 format_pointer(end_ptr).c_str());
2140 ASSERT_MATCH(result, match_str);
2141}
2142
2143// Verify that a fault address happens in the correct map.
2144TEST_F(CrasherTest, fault_address_in_map) {
2145 // Create a map before the fork so it will be present in the child.
2146 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2147 ASSERT_NE(MAP_FAILED, ptr);
2148
2149 StartProcess([ptr]() {
2150 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2151 _exit(0);
2152 });
2153
2154 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2155
2156 unique_fd output_fd;
2157 StartIntercept(&output_fd);
2158 FinishCrasher();
2159 AssertDeath(SIGSEGV);
2160
2161 int intercept_result;
2162 FinishIntercept(&intercept_result);
2163 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2164
2165 std::string result;
2166 ConsumeFd(std::move(output_fd), &result);
2167
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002168 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2169 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002170 ASSERT_MATCH(result, match_str);
2171
2172 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2173
2174 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2175 ASSERT_MATCH(result, match_str);
2176}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002177
2178static constexpr uint32_t kDexData[] = {
2179 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2180 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2181 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2182 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2183 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2184 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2185 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2186 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2187 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2188 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2189 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2190 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2191 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2192 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2193 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2194 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2195 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2196};
2197
2198TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2199 StartProcess([]() {
2200 TemporaryDir td;
2201 std::string tmp_so_name;
2202 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2203 _exit(1);
2204 }
2205
2206 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2207 // move the library to which has a basename of libart.so.
2208 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2209 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2210 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2211 if (handle == nullptr) {
2212 _exit(1);
2213 }
2214
2215 void* ptr =
2216 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2217 ASSERT_TRUE(ptr != MAP_FAILED);
2218 memcpy(ptr, kDexData, sizeof(kDexData));
2219 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2220
2221 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2222 .symfile_size = sizeof(kDexData)};
2223
2224 JITDescriptor* dex_debug =
2225 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2226 ASSERT_TRUE(dex_debug != nullptr);
2227 dex_debug->version = 1;
2228 dex_debug->action_flag = 0;
2229 dex_debug->relevant_entry = 0;
2230 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2231
2232 // This sets the magic dex pc value for register 0, using the value
2233 // of register 1 + 0x102.
2234 asm(".cfi_escape "
2235 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2236 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2237 "0x13 /* DW_OP_drop */,"
2238 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2239
2240 // For each different architecture, set register one to the dex ptr mmap
2241 // created above. Then do a nullptr dereference to force a crash.
2242#if defined(__arm__)
2243 asm volatile(
2244 "mov r1, %[base]\n"
2245 "mov r2, 0\n"
2246 "str r3, [r2]\n"
2247 : [base] "+r"(ptr)
2248 :
2249 : "r1", "r2", "r3", "memory");
2250#elif defined(__aarch64__)
2251 asm volatile(
2252 "mov x1, %[base]\n"
2253 "mov x2, 0\n"
2254 "str x3, [x2]\n"
2255 : [base] "+r"(ptr)
2256 :
2257 : "x1", "x2", "x3", "memory");
2258#elif defined(__i386__)
2259 asm volatile(
2260 "mov %[base], %%ecx\n"
2261 "movl $0, %%edi\n"
2262 "movl 0(%%edi), %%edx\n"
2263 : [base] "+r"(ptr)
2264 :
2265 : "edi", "ecx", "edx", "memory");
2266#elif defined(__x86_64__)
2267 asm volatile(
2268 "mov %[base], %%rdx\n"
2269 "movq 0, %%rdi\n"
2270 "movq 0(%%rdi), %%rcx\n"
2271 : [base] "+r"(ptr)
2272 :
2273 : "rcx", "rdx", "rdi", "memory");
2274#else
2275#error "Unsupported architecture"
2276#endif
2277 _exit(0);
2278 });
2279
2280 unique_fd output_fd;
2281 StartIntercept(&output_fd);
2282 FinishCrasher();
2283 AssertDeath(SIGSEGV);
2284
2285 int intercept_result;
2286 FinishIntercept(&intercept_result);
2287 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2288
2289 std::string result;
2290 ConsumeFd(std::move(output_fd), &result);
2291
2292 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002293 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002294
2295 // Now verify that the dex_pc frame includes a proper function name.
2296 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2297}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002298
2299static std::string format_map_pointer(uintptr_t ptr) {
2300#if defined(__LP64__)
2301 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2302 static_cast<uint32_t>(ptr & 0xffffffff));
2303#else
2304 return android::base::StringPrintf("%08x", ptr);
2305#endif
2306}
2307
2308// Verify that map data is properly formatted.
2309TEST_F(CrasherTest, verify_map_format) {
2310 // Create multiple maps to make sure that the map data is formatted properly.
2311 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2312 ASSERT_NE(MAP_FAILED, none_map);
2313 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2314 ASSERT_NE(MAP_FAILED, r_map);
2315 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2316 ASSERT_NE(MAP_FAILED, w_map);
2317 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2318 ASSERT_NE(MAP_FAILED, x_map);
2319
2320 TemporaryFile tf;
2321 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2322 char c = 'f';
2323 ASSERT_EQ(1, write(tf.fd, &c, 1));
2324 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2325 ASSERT_EQ(1, write(tf.fd, &c, 1));
2326 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2327 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2328 ASSERT_NE(MAP_FAILED, file_map);
2329
2330 StartProcess([]() { abort(); });
2331
2332 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2333 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2334 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2335 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2336 ASSERT_EQ(0, munmap(file_map, 0x3001));
2337
2338 unique_fd output_fd;
2339 StartIntercept(&output_fd);
2340 FinishCrasher();
2341 AssertDeath(SIGABRT);
2342 int intercept_result;
2343 FinishIntercept(&intercept_result);
2344
2345 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2346
2347 std::string result;
2348 ConsumeFd(std::move(output_fd), &result);
2349
2350 std::string match_str;
2351 // Verify none.
2352 match_str = android::base::StringPrintf(
2353 " %s-%s --- 0 1000\\n",
2354 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2355 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2356 ASSERT_MATCH(result, match_str);
2357
2358 // Verify read-only.
2359 match_str = android::base::StringPrintf(
2360 " %s-%s r-- 0 1000\\n",
2361 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2362 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2363 ASSERT_MATCH(result, match_str);
2364
2365 // Verify write-only.
2366 match_str = android::base::StringPrintf(
2367 " %s-%s -w- 0 1000\\n",
2368 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2369 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2370 ASSERT_MATCH(result, match_str);
2371
2372 // Verify exec-only.
2373 match_str = android::base::StringPrintf(
2374 " %s-%s --x 0 1000\\n",
2375 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2376 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2377 ASSERT_MATCH(result, match_str);
2378
2379 // Verify file map with non-zero offset and a name.
2380 match_str = android::base::StringPrintf(
2381 " %s-%s r-- 2000 4000 %s\\n",
2382 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2383 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2384 ASSERT_MATCH(result, match_str);
2385}
2386
2387// Verify that the tombstone map data is correct.
2388TEST_F(CrasherTest, verify_header) {
2389 StartProcess([]() { abort(); });
2390
2391 unique_fd output_fd;
2392 StartIntercept(&output_fd);
2393 FinishCrasher();
2394 AssertDeath(SIGABRT);
2395 int intercept_result;
2396 FinishIntercept(&intercept_result);
2397
2398 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2399
2400 std::string result;
2401 ConsumeFd(std::move(output_fd), &result);
2402
2403 std::string match_str = android::base::StringPrintf(
2404 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2405 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2406 android::base::GetProperty("ro.revision", "unknown").c_str());
2407 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2408 ASSERT_MATCH(result, match_str);
2409}
2410
2411// Verify that the thread header is formatted properly.
2412TEST_F(CrasherTest, verify_thread_header) {
2413 void* shared_map =
2414 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2415 ASSERT_NE(MAP_FAILED, shared_map);
2416 memset(shared_map, 0, sizeof(pid_t));
2417
2418 StartProcess([&shared_map]() {
2419 std::atomic_bool tid_written;
2420 std::thread thread([&tid_written, &shared_map]() {
2421 pid_t tid = gettid();
2422 memcpy(shared_map, &tid, sizeof(pid_t));
2423 tid_written = true;
2424 volatile bool done = false;
2425 while (!done)
2426 ;
2427 });
2428 thread.detach();
2429 while (!tid_written.load(std::memory_order_acquire))
2430 ;
2431 abort();
2432 });
2433
2434 pid_t primary_pid = crasher_pid;
2435
2436 unique_fd output_fd;
2437 StartIntercept(&output_fd);
2438 FinishCrasher();
2439 AssertDeath(SIGABRT);
2440 int intercept_result;
2441 FinishIntercept(&intercept_result);
2442 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2443
2444 // Read the tid data out.
2445 pid_t tid;
2446 memcpy(&tid, shared_map, sizeof(pid_t));
2447 ASSERT_NE(0, tid);
2448
2449 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2450
2451 std::string result;
2452 ConsumeFd(std::move(output_fd), &result);
2453
2454 // Verify that there are two headers, one where the tid is "primary_pid"
2455 // and the other where the tid is "tid".
2456 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2457 primary_pid, primary_pid);
2458 ASSERT_MATCH(result, match_str);
2459
2460 match_str =
2461 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2462 ASSERT_MATCH(result, match_str);
2463}
2464
2465// Verify that there is a BuildID present in the map section and set properly.
2466TEST_F(CrasherTest, verify_build_id) {
2467 StartProcess([]() { abort(); });
2468
2469 unique_fd output_fd;
2470 StartIntercept(&output_fd);
2471 FinishCrasher();
2472 AssertDeath(SIGABRT);
2473 int intercept_result;
2474 FinishIntercept(&intercept_result);
2475 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2476
2477 std::string result;
2478 ConsumeFd(std::move(output_fd), &result);
2479
2480 // Find every /system or /apex lib and verify the BuildID is displayed
2481 // properly.
2482 bool found_valid_elf = false;
2483 std::smatch match;
2484 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2485 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2486 result = match.suffix()) {
2487 if (prev_file == match[1]) {
2488 // Already checked this file.
2489 continue;
2490 }
2491
2492 prev_file = match[1];
2493 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2494 if (!elf.Init() || !elf.valid()) {
2495 // Skipping invalid elf files.
2496 continue;
2497 }
2498 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2499
2500 found_valid_elf = true;
2501 }
2502 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2503}