blob: 5a9d4f2a645ab344aa333c1c9052b5bb5c0f51a6 [file] [log] [blame]
Josh Gaocbe70cb2016-10-18 18:17:52 -07001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Christopher Ferris35da2882021-02-17 15:39:06 -080017#include <dirent.h>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070018#include <dlfcn.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070019#include <err.h>
20#include <fcntl.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000021#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080022#include <malloc.h>
Josh Gaocdea7502017-11-01 15:00:40 -070023#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080024#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070025#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080026#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070027#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080028#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070029#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070030#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070031#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070032
33#include <chrono>
34#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000035#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070036#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070037#include <thread>
38
Josh Gaobf06a402018-08-27 16:34:01 -070039#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080040#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080041#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070042#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080043#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080044
Josh Gao5f87bbd2019-01-09 17:01:49 -080045#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070046#include <android-base/file.h>
47#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070048#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070049#include <android-base/parseint.h>
50#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070051#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070053#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/unique_fd.h>
55#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070056#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070057#include <gtest/gtest.h>
58
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000059#include <unwindstack/Elf.h>
60#include <unwindstack/Memory.h>
61
Josh Gaoe04ca272018-01-16 15:38:17 -080062#include <libminijail.h>
63#include <scoped_minijail.h>
64
Christopher Ferris2038cc72021-09-15 03:57:10 +000065#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010066#include "debuggerd/handler.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070067#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010068#include "protocol.h"
69#include "tombstoned/tombstoned.h"
70#include "util.h"
71
Josh Gaocbe70cb2016-10-18 18:17:52 -070072using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080073
74using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070075using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070076using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070077
78#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070079#define ARCH_SUFFIX "64"
80#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070081#define ARCH_SUFFIX ""
82#endif
83
Elliott Hughese4781d52021-03-17 09:15:15 -070084constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070085
86#define TIMEOUT(seconds, expr) \
87 [&]() { \
88 struct sigaction old_sigaction; \
89 struct sigaction new_sigaction = {}; \
90 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080091 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070092 err(1, "sigaction failed"); \
93 } \
94 alarm(seconds); \
95 auto value = expr; \
96 int saved_errno = errno; \
97 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
98 err(1, "sigaction failed"); \
99 } \
100 alarm(0); \
101 errno = saved_errno; \
102 return value; \
103 }()
104
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700105// Backtrace frame dump could contain:
106// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
107// or
108// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800109#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700110 ASSERT_MATCH(result, \
111 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900112
Mitch Phillips7168a212021-03-09 16:53:23 -0800113// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
114// process sampling, so we need to ensure we force GWP-ASan on.
115__attribute__((constructor)) static void enable_gwp_asan() {
116 bool force = true;
117 android_mallopt(M_INITIALIZE_GWP_ASAN, &force, sizeof(force));
118}
119
Narayan Kamatha73df602017-05-24 15:07:25 +0100120static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100121 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700122 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
123 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
124 if (intercept_fd->get() == -1) {
125 FAIL() << "failed to contact tombstoned: " << strerror(errno);
126 }
127
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700128 InterceptRequest req = {
129 .dump_type = intercept_type,
130 .pid = target_pid,
131 };
Josh Gao460b3362017-03-30 16:40:47 -0700132
133 unique_fd output_pipe_write;
134 if (!Pipe(output_fd, &output_pipe_write)) {
135 FAIL() << "failed to create output pipe: " << strerror(errno);
136 }
137
138 std::string pipe_size_str;
139 int pipe_buffer_size;
140 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
141 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
142 }
143
144 pipe_size_str = android::base::Trim(pipe_size_str);
145
146 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
147 FAIL() << "failed to parse pipe max size";
148 }
149
150 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
151 FAIL() << "failed to set pipe size: " << strerror(errno);
152 }
153
Josh Gao5675f3c2017-06-01 12:19:53 -0700154 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
155
Josh Gao5f87bbd2019-01-09 17:01:49 -0800156 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
157 output_pipe_write.reset();
158 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700159 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
160 }
161
162 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800163 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700164 if (rc == -1) {
165 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
166 } else if (rc == 0) {
167 FAIL() << "failed to read response from tombstoned (EOF)";
168 } else if (rc != sizeof(response)) {
169 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
170 << ", received " << rc;
171 }
172
Narayan Kamathca5e9082017-06-02 15:42:06 +0100173 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700174}
175
Elliott Hughesd13ea522022-01-13 09:20:26 -0800176static bool pac_supported() {
177#if defined(__aarch64__)
178 return getauxval(AT_HWCAP) & HWCAP_PACA;
179#else
180 return false;
181#endif
182}
183
Josh Gaocbe70cb2016-10-18 18:17:52 -0700184class CrasherTest : public ::testing::Test {
185 public:
186 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700187 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700188 unique_fd crasher_pipe;
189 unique_fd intercept_fd;
190
191 CrasherTest();
192 ~CrasherTest();
193
Narayan Kamatha73df602017-05-24 15:07:25 +0100194 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700195
196 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
197 void FinishIntercept(int* result);
198
Josh Gao2e7b8e22017-05-04 17:12:57 -0700199 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700200 void StartCrasher(const std::string& crash_type);
201 void FinishCrasher();
202 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700203
204 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700205};
206
207CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700208 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
209 android::base::SetProperty(kWaitForDebuggerKey, "0");
210
211 // Clear the old property too, just in case someone's been using it
212 // on this device. (We only document the new name, but we still support
213 // the old name so we don't break anyone's existing setups.)
214 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700215}
216
217CrasherTest::~CrasherTest() {
218 if (crasher_pid != -1) {
219 kill(crasher_pid, SIGKILL);
220 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700221 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222 }
223
Elliott Hughese4781d52021-03-17 09:15:15 -0700224 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700225}
226
Narayan Kamatha73df602017-05-24 15:07:25 +0100227void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 if (crasher_pid == -1) {
229 FAIL() << "crasher hasn't been started";
230 }
231
Narayan Kamathca5e9082017-06-02 15:42:06 +0100232 InterceptStatus status;
233 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
234 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700235}
236
237void CrasherTest::FinishIntercept(int* result) {
238 InterceptResponse response;
239
Christopher Ferris11555f02019-09-20 14:18:55 -0700240 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700241 if (rc == -1) {
242 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
243 } else if (rc == 0) {
244 *result = -1;
245 } else if (rc != sizeof(response)) {
246 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
247 << ", received " << rc;
248 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700249 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700250 }
251}
252
Josh Gao2e7b8e22017-05-04 17:12:57 -0700253void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800254 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700255 unique_fd crasher_read_pipe;
256 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
257 FAIL() << "failed to create pipe: " << strerror(errno);
258 }
259
Josh Gao2e7b8e22017-05-04 17:12:57 -0700260 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 if (crasher_pid == -1) {
262 FAIL() << "fork failed: " << strerror(errno);
263 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800264 char dummy;
265 crasher_pipe.reset();
266 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800267 function();
268 _exit(0);
269 }
270}
271
Josh Gaocbe70cb2016-10-18 18:17:52 -0700272void CrasherTest::FinishCrasher() {
273 if (crasher_pipe == -1) {
274 FAIL() << "crasher pipe uninitialized";
275 }
276
Christopher Ferris172b0a02019-09-18 17:48:30 -0700277 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700278 if (rc == -1) {
279 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
280 } else if (rc == 0) {
281 FAIL() << "crasher pipe was closed";
282 }
283}
284
285void CrasherTest::AssertDeath(int signo) {
286 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700287 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700288 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700289 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
290 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700291 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700292 FAIL() << "failed to wait for crasher: " << strerror(errno);
293 }
294
Josh Gaoe06f2a42017-04-27 16:50:38 -0700295 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700296 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700297 ASSERT_EQ(0, WEXITSTATUS(signo));
298 } else {
299 ASSERT_FALSE(WIFEXITED(status));
300 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
301 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700302 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700303 crasher_pid = -1;
304}
305
306static void ConsumeFd(unique_fd fd, std::string* output) {
307 constexpr size_t read_length = PAGE_SIZE;
308 std::string result;
309
310 while (true) {
311 size_t offset = result.size();
312 result.resize(result.size() + PAGE_SIZE);
313 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
314 if (rc == -1) {
315 FAIL() << "read failed: " << strerror(errno);
316 } else if (rc == 0) {
317 result.resize(result.size() - PAGE_SIZE);
318 break;
319 }
320
321 result.resize(result.size() - PAGE_SIZE + rc);
322 }
323
324 *output = std::move(result);
325}
326
Mitch Phillips78f06702021-06-01 14:35:43 -0700327class LogcatCollector {
328 public:
329 LogcatCollector() { system("logcat -c"); }
330
331 void Collect(std::string* output) {
332 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
333 ASSERT_NE(cmd_stdout, nullptr);
334 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
335 ConsumeFd(std::move(tmp_fd), output);
336 pclose(cmd_stdout);
337 }
338};
339
Josh Gaocbe70cb2016-10-18 18:17:52 -0700340TEST_F(CrasherTest, smoke) {
341 int intercept_result;
342 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800343 StartProcess([]() {
344 *reinterpret_cast<volatile char*>(0xdead) = '1';
345 });
346
Josh Gaocbe70cb2016-10-18 18:17:52 -0700347 StartIntercept(&output_fd);
348 FinishCrasher();
349 AssertDeath(SIGSEGV);
350 FinishIntercept(&intercept_result);
351
352 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
353
354 std::string result;
355 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800356#ifdef __LP64__
357 ASSERT_MATCH(result,
358 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
359#else
360 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
361#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700362
363 if (mte_supported()) {
364 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700365 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
366 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700367 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800368
369 if (pac_supported()) {
370 // Test that the default PAC_ENABLED_KEYS value is set.
371 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
372 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
373 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700374}
375
Peter Collingbournef03af882020-03-20 18:09:00 -0700376TEST_F(CrasherTest, tagged_fault_addr) {
377#if !defined(__aarch64__)
378 GTEST_SKIP() << "Requires aarch64";
379#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700380 // HWASan crashes with SIGABRT on tag mismatch.
381 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700382 int intercept_result;
383 unique_fd output_fd;
384 StartProcess([]() {
385 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
386 });
387
388 StartIntercept(&output_fd);
389 FinishCrasher();
390 AssertDeath(SIGSEGV);
391 FinishIntercept(&intercept_result);
392
393 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
394
395 std::string result;
396 ConsumeFd(std::move(output_fd), &result);
397
398 // The address can either be tagged (new kernels) or untagged (old kernels).
399 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800400 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700401}
402
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700403// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
404// compiler could still clobber the argument register before trapping, but that's unlikely.
405__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
406 __builtin_trap();
407}
408
409TEST_F(CrasherTest, heap_addr_in_register) {
410#if defined(__i386__)
411 GTEST_SKIP() << "architecture does not pass arguments in registers";
412#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700413 // The memory dump in HWASan crashes sadly shows the memory near the registers
414 // in the HWASan dump function, rather the faulting context. This is a known
415 // issue.
416 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700417 int intercept_result;
418 unique_fd output_fd;
419 StartProcess([]() {
420 // Crash with a heap pointer in the first argument register.
421 Trap(malloc(1));
422 });
423
424 StartIntercept(&output_fd);
425 FinishCrasher();
426 int status;
427 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
428 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
429 // Don't test the signal number because different architectures use different signals for
430 // __builtin_trap().
431 FinishIntercept(&intercept_result);
432
433 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
434
435 std::string result;
436 ConsumeFd(std::move(output_fd), &result);
437
438#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800439 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700440#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800441 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700442#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800443 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700444#else
445 ASSERT_TRUE(false) << "unsupported architecture";
446#endif
447}
448
Peter Collingbournecd278072020-12-21 14:08:38 -0800449#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700450static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800451 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700452 abort();
453 }
454}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800455
456static void SetTagCheckingLevelAsync() {
457 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
458 abort();
459 }
460}
Peter Collingbournef8622522020-04-07 14:07:32 -0700461#endif
462
Mitch Phillips7168a212021-03-09 16:53:23 -0800463// Number of iterations required to reliably guarantee a GWP-ASan crash.
464// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
465// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
466// the counter reaches zero, we provide a sampled allocation. Then, double that
467// figure to allow for left/right allocation alignment, as this is done randomly
468// without bias.
469#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
470
471struct GwpAsanTestParameters {
472 size_t alloc_size;
473 bool free_before_access;
474 int access_offset;
475 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
476};
477
478struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
479
480GwpAsanTestParameters gwp_asan_tests[] = {
481 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
482 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
483 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
484 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
485};
486
487INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
488
489TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
490 if (mte_supported()) {
491 // Skip this test on MTE hardware, as MTE will reliably catch these errors
492 // instead of GWP-ASan.
493 GTEST_SKIP() << "Skipped on MTE.";
494 }
Florian Mayerb4979292022-04-15 14:35:17 -0700495 // Skip this test on HWASan, which will reliably catch test errors as well.
496 SKIP_WITH_HWASAN;
Mitch Phillips7168a212021-03-09 16:53:23 -0800497
498 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700499 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800500
501 int intercept_result;
502 unique_fd output_fd;
503 StartProcess([&params]() {
504 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
505 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
506 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
507 p[params.access_offset] = 42;
508 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
509 }
510 });
511
512 StartIntercept(&output_fd);
513 FinishCrasher();
514 AssertDeath(SIGSEGV);
515 FinishIntercept(&intercept_result);
516
517 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
518
Mitch Phillips78f06702021-06-01 14:35:43 -0700519 std::vector<std::string> log_sources(2);
520 ConsumeFd(std::move(output_fd), &log_sources[0]);
521 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800522
Mitch Phillips78f06702021-06-01 14:35:43 -0700523 for (const auto& result : log_sources) {
524 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
525 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
526 if (params.free_before_access) {
527 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
528 }
529 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800530 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800531}
532
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800533struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
534
Peter Collingbourneaa544792021-05-13 13:53:37 -0700535INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800536
537TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800538#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700539 if (!mte_supported()) {
540 GTEST_SKIP() << "Requires MTE";
541 }
542
Peter Collingbourneaa544792021-05-13 13:53:37 -0700543 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
544 if (GetParam() == 0) {
545 return;
546 }
547
Mitch Phillips78f06702021-06-01 14:35:43 -0700548 LogcatCollector logcat_collector;
549
Peter Collingbournef8622522020-04-07 14:07:32 -0700550 int intercept_result;
551 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800552 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700553 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800554 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700555 free((void *)p);
556 p[0] = 42;
557 });
558
559 StartIntercept(&output_fd);
560 FinishCrasher();
561 AssertDeath(SIGSEGV);
562 FinishIntercept(&intercept_result);
563
564 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
565
Mitch Phillips78f06702021-06-01 14:35:43 -0700566 std::vector<std::string> log_sources(2);
567 ConsumeFd(std::move(output_fd), &log_sources[0]);
568 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700569 // Tag dump only available in the tombstone, not logcat.
570 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700571
Mitch Phillips78f06702021-06-01 14:35:43 -0700572 for (const auto& result : log_sources) {
573 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
574 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
575 std::to_string(GetParam()) + R"(-byte allocation)");
576 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
577 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
578 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700579#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800580 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700581#endif
582}
583
Peter Collingbournedc476342021-05-12 15:56:43 -0700584TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
585#if defined(__aarch64__)
586 if (!mte_supported()) {
587 GTEST_SKIP() << "Requires MTE";
588 }
589
590 int intercept_result;
591 unique_fd output_fd;
592 StartProcess([&]() {
593 SetTagCheckingLevelSync();
594 volatile int* p = (volatile int*)malloc(GetParam());
595 free((void *)p);
596 p[-1] = 42;
597 });
598
599 StartIntercept(&output_fd);
600 FinishCrasher();
601 AssertDeath(SIGSEGV);
602 FinishIntercept(&intercept_result);
603
604 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
605
606 std::string result;
607 ConsumeFd(std::move(output_fd), &result);
608
609 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
610 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
611#else
612 GTEST_SKIP() << "Requires aarch64";
613#endif
614}
615
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800616TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800617#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700618 if (!mte_supported()) {
619 GTEST_SKIP() << "Requires MTE";
620 }
621
Mitch Phillips78f06702021-06-01 14:35:43 -0700622 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700623 int intercept_result;
624 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800625 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700626 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800627 volatile char* p = (volatile char*)malloc(GetParam());
628 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700629 });
630
631 StartIntercept(&output_fd);
632 FinishCrasher();
633 AssertDeath(SIGSEGV);
634 FinishIntercept(&intercept_result);
635
636 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
637
Mitch Phillips78f06702021-06-01 14:35:43 -0700638 std::vector<std::string> log_sources(2);
639 ConsumeFd(std::move(output_fd), &log_sources[0]);
640 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700641
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700642 // Tag dump only in tombstone, not logcat, and tagging is not used for
643 // overflow protection in the scudo secondary (guard pages are used instead).
644 if (GetParam() < 0x10000) {
645 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
646 }
647
Mitch Phillips78f06702021-06-01 14:35:43 -0700648 for (const auto& result : log_sources) {
649 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
650 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
651 std::to_string(GetParam()) + R"(-byte allocation)");
652 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
653 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700654#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800655 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700656#endif
657}
658
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800659TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800660#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700661 if (!mte_supported()) {
662 GTEST_SKIP() << "Requires MTE";
663 }
664
665 int intercept_result;
666 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800667 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700668 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800669 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700670 p[-1] = 42;
671 });
672
673 StartIntercept(&output_fd);
674 FinishCrasher();
675 AssertDeath(SIGSEGV);
676 FinishIntercept(&intercept_result);
677
678 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
679
680 std::string result;
681 ConsumeFd(std::move(output_fd), &result);
682
683 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800684 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800685 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700686 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700687 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700688 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700689#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800690 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700691#endif
692}
693
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800694TEST_F(CrasherTest, mte_async) {
695#if defined(__aarch64__)
696 if (!mte_supported()) {
697 GTEST_SKIP() << "Requires MTE";
698 }
699
700 int intercept_result;
701 unique_fd output_fd;
702 StartProcess([&]() {
703 SetTagCheckingLevelAsync();
704 volatile int* p = (volatile int*)malloc(16);
705 p[-1] = 42;
706 });
707
708 StartIntercept(&output_fd);
709 FinishCrasher();
710 AssertDeath(SIGSEGV);
711 FinishIntercept(&intercept_result);
712
713 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
714
715 std::string result;
716 ConsumeFd(std::move(output_fd), &result);
717
718 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
719#else
720 GTEST_SKIP() << "Requires aarch64";
721#endif
722}
723
Peter Collingbournef8622522020-04-07 14:07:32 -0700724TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800725#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700726 if (!mte_supported()) {
727 GTEST_SKIP() << "Requires MTE";
728 }
729
Mitch Phillips78f06702021-06-01 14:35:43 -0700730 LogcatCollector logcat_collector;
731
Peter Collingbournef8622522020-04-07 14:07:32 -0700732 int intercept_result;
733 unique_fd output_fd;
734 StartProcess([]() {
735 SetTagCheckingLevelSync();
736
737 // Make two allocations with the same tag and close to one another. Check for both properties
738 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
739 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
740 // (some non-zero value << 56) apart.
741 //
742 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
743 // other.
744 std::set<uintptr_t> allocs;
745 for (int i = 0; i != 4096; ++i) {
746 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
747 auto it = allocs.insert(alloc).first;
748 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
749 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
750 }
751 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
752 *reinterpret_cast<int*>(alloc + 16) = 42;
753 }
754 }
755 });
756
757 StartIntercept(&output_fd);
758 FinishCrasher();
759 AssertDeath(SIGSEGV);
760 FinishIntercept(&intercept_result);
761
762 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
763
Mitch Phillips78f06702021-06-01 14:35:43 -0700764 std::vector<std::string> log_sources(2);
765 ConsumeFd(std::move(output_fd), &log_sources[0]);
766 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700767
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700768 // Tag dump only in the tombstone, not logcat.
769 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
770
Mitch Phillips78f06702021-06-01 14:35:43 -0700771 for (const auto& result : log_sources) {
772 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
773 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800774 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700775 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
776 // overflows), so we can't match explicitly for an underflow message.
777 ASSERT_MATCH(result,
778 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
779 // Ensure there's at least two allocation traces (one for each cause).
780 ASSERT_MATCH(
781 result,
782 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
783 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700784#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800785 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700786#endif
787}
788
Peter Collingbournecd278072020-12-21 14:08:38 -0800789#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700790static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700791 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
792 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
793 size_t page_size = getpagesize();
794 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
795 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
796 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700797 return 0;
798 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700799 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
800 PROT_READ | PROT_WRITE | PROT_MTE);
801 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
802 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
803 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
804 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
805 }
806 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700807}
808#endif
809
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700810TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800811#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700812 if (!mte_supported()) {
813 GTEST_SKIP() << "Requires MTE";
814 }
815
816 int intercept_result;
817 unique_fd output_fd;
818 StartProcess([&]() {
819 SetTagCheckingLevelSync();
820 Trap(reinterpret_cast<void *>(CreateTagMapping()));
821 });
822
823 StartIntercept(&output_fd);
824 FinishCrasher();
825 AssertDeath(SIGTRAP);
826 FinishIntercept(&intercept_result);
827
828 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
829
830 std::string result;
831 ConsumeFd(std::move(output_fd), &result);
832
833 ASSERT_MATCH(result, R"(memory near x0:
834.*
835.*
836 01.............0 0000000000000000 0000000000000000 ................
837 00.............0)");
838#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800839 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700840#endif
841}
842
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700843TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
844#if defined(__aarch64__)
845 if (!mte_supported()) {
846 GTEST_SKIP() << "Requires MTE";
847 }
848
849 int intercept_result;
850 unique_fd output_fd;
851 StartProcess([&]() {
852 SetTagCheckingLevelSync();
853 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
854 p[0] = 0; // Untagged pointer, tagged memory.
855 });
856
857 StartIntercept(&output_fd);
858 FinishCrasher();
859 AssertDeath(SIGSEGV);
860 FinishIntercept(&intercept_result);
861
862 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
863
864 std::string result;
865 ConsumeFd(std::move(output_fd), &result);
866
867 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
868\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
869#else
870 GTEST_SKIP() << "Requires aarch64";
871#endif
872}
873
874TEST_F(CrasherTest, mte_fault_tag_dump) {
875#if defined(__aarch64__)
876 if (!mte_supported()) {
877 GTEST_SKIP() << "Requires MTE";
878 }
879
880 int intercept_result;
881 unique_fd output_fd;
882 StartProcess([&]() {
883 SetTagCheckingLevelSync();
884 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
885 p[320] = 0; // Untagged pointer, tagged memory.
886 });
887
888 StartIntercept(&output_fd);
889 FinishCrasher();
890 AssertDeath(SIGSEGV);
891 FinishIntercept(&intercept_result);
892
893 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
894
895 std::string result;
896 ConsumeFd(std::move(output_fd), &result);
897
898 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
899\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
900\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
901\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
902)");
903#else
904 GTEST_SKIP() << "Requires aarch64";
905#endif
906}
907
908TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
909#if defined(__aarch64__)
910 if (!mte_supported()) {
911 GTEST_SKIP() << "Requires MTE";
912 }
913
914 int intercept_result;
915 unique_fd output_fd;
916 StartProcess([&]() {
917 SetTagCheckingLevelSync();
918 size_t page_size = getpagesize();
919 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
920 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
921 });
922
923 StartIntercept(&output_fd);
924 FinishCrasher();
925 AssertDeath(SIGSEGV);
926 FinishIntercept(&intercept_result);
927
928 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
929
930 std::string result;
931 ConsumeFd(std::move(output_fd), &result);
932
933 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
934 ASSERT_MATCH(result,
935 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
936\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
937
938)"); // Ensure truncation happened and there's a newline after the tag fault.
939#else
940 GTEST_SKIP() << "Requires aarch64";
941#endif
942}
943
Josh Gaocdea7502017-11-01 15:00:40 -0700944TEST_F(CrasherTest, LD_PRELOAD) {
945 int intercept_result;
946 unique_fd output_fd;
947 StartProcess([]() {
948 setenv("LD_PRELOAD", "nonexistent.so", 1);
949 *reinterpret_cast<volatile char*>(0xdead) = '1';
950 });
951
952 StartIntercept(&output_fd);
953 FinishCrasher();
954 AssertDeath(SIGSEGV);
955 FinishIntercept(&intercept_result);
956
957 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
958
959 std::string result;
960 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800961 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700962}
963
Josh Gaocbe70cb2016-10-18 18:17:52 -0700964TEST_F(CrasherTest, abort) {
965 int intercept_result;
966 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800967 StartProcess([]() {
968 abort();
969 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700970 StartIntercept(&output_fd);
971 FinishCrasher();
972 AssertDeath(SIGABRT);
973 FinishIntercept(&intercept_result);
974
975 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
976
977 std::string result;
978 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700979 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700980}
981
982TEST_F(CrasherTest, signal) {
983 int intercept_result;
984 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800985 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700986 while (true) {
987 sleep(1);
988 }
Josh Gao502cfd22017-02-17 01:39:15 -0800989 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700990 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700991 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700992 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
993
994 AssertDeath(SIGSEGV);
995 FinishIntercept(&intercept_result);
996
997 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
998
999 std::string result;
1000 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -07001001 ASSERT_MATCH(
1002 result,
1003 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001004 ASSERT_MATCH(result, R"(backtrace:)");
1005}
1006
1007TEST_F(CrasherTest, abort_message) {
1008 int intercept_result;
1009 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001010 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001011 // Arrived at experimentally;
1012 // logd truncates at 4062.
1013 // strlen("Abort message: ''") is 17.
1014 // That's 4045, but we also want a NUL.
1015 char buf[4045 + 1];
1016 memset(buf, 'x', sizeof(buf));
1017 buf[sizeof(buf) - 1] = '\0';
1018 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001019 abort();
1020 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001021 StartIntercept(&output_fd);
1022 FinishCrasher();
1023 AssertDeath(SIGABRT);
1024 FinishIntercept(&intercept_result);
1025
1026 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1027
1028 std::string result;
1029 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001030 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001031}
1032
Christopher Ferrise8891452021-08-17 17:34:53 -07001033TEST_F(CrasherTest, abort_message_newline_trimmed) {
1034 int intercept_result;
1035 unique_fd output_fd;
1036 StartProcess([]() {
1037 android_set_abort_message("Message with a newline.\n");
1038 abort();
1039 });
1040 StartIntercept(&output_fd);
1041 FinishCrasher();
1042 AssertDeath(SIGABRT);
1043 FinishIntercept(&intercept_result);
1044
1045 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1046
1047 std::string result;
1048 ConsumeFd(std::move(output_fd), &result);
1049 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1050}
1051
1052TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1053 int intercept_result;
1054 unique_fd output_fd;
1055 StartProcess([]() {
1056 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1057 abort();
1058 });
1059 StartIntercept(&output_fd);
1060 FinishCrasher();
1061 AssertDeath(SIGABRT);
1062 FinishIntercept(&intercept_result);
1063
1064 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1065
1066 std::string result;
1067 ConsumeFd(std::move(output_fd), &result);
1068 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1069}
1070
Josh Gaoe06f2a42017-04-27 16:50:38 -07001071TEST_F(CrasherTest, abort_message_backtrace) {
1072 int intercept_result;
1073 unique_fd output_fd;
1074 StartProcess([]() {
1075 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001076 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001077 exit(0);
1078 });
1079 StartIntercept(&output_fd);
1080 FinishCrasher();
1081 AssertDeath(0);
1082 FinishIntercept(&intercept_result);
1083
1084 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1085
1086 std::string result;
1087 ConsumeFd(std::move(output_fd), &result);
1088 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1089}
1090
Josh Gaocbe70cb2016-10-18 18:17:52 -07001091TEST_F(CrasherTest, intercept_timeout) {
1092 int intercept_result;
1093 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001094 StartProcess([]() {
1095 abort();
1096 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001097 StartIntercept(&output_fd);
1098
1099 // Don't let crasher finish until we timeout.
1100 FinishIntercept(&intercept_result);
1101
1102 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1103 << intercept_result << ")";
1104
1105 FinishCrasher();
1106 AssertDeath(SIGABRT);
1107}
1108
Elliott Hughese4781d52021-03-17 09:15:15 -07001109TEST_F(CrasherTest, wait_for_debugger) {
1110 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1111 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001112 }
1113 sleep(1);
1114
Josh Gao502cfd22017-02-17 01:39:15 -08001115 StartProcess([]() {
1116 abort();
1117 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001118 FinishCrasher();
1119
1120 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001121 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001122 ASSERT_TRUE(WIFSTOPPED(status));
1123 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1124
1125 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1126
1127 AssertDeath(SIGABRT);
1128}
1129
Josh Gaocbe70cb2016-10-18 18:17:52 -07001130TEST_F(CrasherTest, backtrace) {
1131 std::string result;
1132 int intercept_result;
1133 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001134
1135 StartProcess([]() {
1136 abort();
1137 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001138 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001139
1140 std::this_thread::sleep_for(500ms);
1141
1142 sigval val;
1143 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001144 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001145 FinishIntercept(&intercept_result);
1146 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1147 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001148 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001149
1150 int status;
1151 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1152
1153 StartIntercept(&output_fd);
1154 FinishCrasher();
1155 AssertDeath(SIGABRT);
1156 FinishIntercept(&intercept_result);
1157 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1158 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001159 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001160}
Josh Gaofca7ca32017-01-23 12:05:35 -08001161
1162TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001163 int intercept_result;
1164 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001165 StartProcess([]() {
1166 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001167 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001168 });
Josh Gao502cfd22017-02-17 01:39:15 -08001169
1170 StartIntercept(&output_fd);
1171 FinishCrasher();
1172 AssertDeath(SIGABRT);
1173 FinishIntercept(&intercept_result);
1174
1175 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1176
1177 std::string result;
1178 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001179 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001180}
1181
Josh Gao502cfd22017-02-17 01:39:15 -08001182TEST_F(CrasherTest, capabilities) {
1183 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1184
Josh Gaofca7ca32017-01-23 12:05:35 -08001185 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001186 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1187 err(1, "failed to set PR_SET_KEEPCAPS");
1188 }
1189
1190 if (setresuid(1, 1, 1) != 0) {
1191 err(1, "setresuid failed");
1192 }
1193
1194 __user_cap_header_struct capheader;
1195 __user_cap_data_struct capdata[2];
1196 memset(&capheader, 0, sizeof(capheader));
1197 memset(&capdata, 0, sizeof(capdata));
1198
1199 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1200 capheader.pid = 0;
1201
1202 // Turn on every third capability.
1203 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1204 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1205 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1206 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1207 }
1208
1209 // Make sure CAP_SYS_PTRACE is off.
1210 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1211 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1212
1213 if (capset(&capheader, &capdata[0]) != 0) {
1214 err(1, "capset failed");
1215 }
1216
1217 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1218 err(1, "failed to drop ambient capabilities");
1219 }
1220
Josh Gaoa5199a92017-04-03 13:18:34 -07001221 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001222 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001223 });
Josh Gao502cfd22017-02-17 01:39:15 -08001224
1225 unique_fd output_fd;
1226 StartIntercept(&output_fd);
1227 FinishCrasher();
1228 AssertDeath(SIGSYS);
1229
1230 std::string result;
1231 int intercept_result;
1232 FinishIntercept(&intercept_result);
1233 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1234 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001235 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001236 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001237}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001238
Josh Gao2e7b8e22017-05-04 17:12:57 -07001239TEST_F(CrasherTest, fake_pid) {
1240 int intercept_result;
1241 unique_fd output_fd;
1242
1243 // Prime the getpid/gettid caches.
1244 UNUSED(getpid());
1245 UNUSED(gettid());
1246
1247 std::function<pid_t()> clone_fn = []() {
1248 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1249 };
1250 StartProcess(
1251 []() {
1252 ASSERT_NE(getpid(), syscall(__NR_getpid));
1253 ASSERT_NE(gettid(), syscall(__NR_gettid));
1254 raise(SIGSEGV);
1255 },
1256 clone_fn);
1257
1258 StartIntercept(&output_fd);
1259 FinishCrasher();
1260 AssertDeath(SIGSEGV);
1261 FinishIntercept(&intercept_result);
1262
1263 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1264
1265 std::string result;
1266 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001267 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001268}
1269
Josh Gaoe04ca272018-01-16 15:38:17 -08001270static const char* const kDebuggerdSeccompPolicy =
1271 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1272
Josh Gao70adac62018-02-22 11:38:33 -08001273static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001274 std::string policy;
1275 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1276 PLOG(FATAL) << "failed to read policy file";
1277 }
1278
1279 // Allow a bunch of syscalls used by the tests.
1280 policy += "\nclone: 1";
1281 policy += "\nsigaltstack: 1";
1282 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001283 policy += "\ngetrlimit: 1";
1284 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001285
1286 FILE* tmp_file = tmpfile();
1287 if (!tmp_file) {
1288 PLOG(FATAL) << "tmpfile failed";
1289 }
1290
Christopher Ferris172b0a02019-09-18 17:48:30 -07001291 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001292 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1293 PLOG(FATAL) << "failed to write policy to tmpfile";
1294 }
1295
1296 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1297 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001298 }
1299
1300 ScopedMinijail jail{minijail_new()};
1301 if (!jail) {
1302 LOG(FATAL) << "failed to create minijail";
1303 }
1304
1305 minijail_no_new_privs(jail.get());
1306 minijail_log_seccomp_filter_failures(jail.get());
1307 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001308 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001309
1310 pid_t result = fork();
1311 if (result == -1) {
1312 return result;
1313 } else if (result != 0) {
1314 return result;
1315 }
1316
1317 // Spawn and detach a thread that spins forever.
1318 std::atomic<bool> thread_ready(false);
1319 std::thread thread([&jail, &thread_ready]() {
1320 minijail_enter(jail.get());
1321 thread_ready = true;
1322 for (;;)
1323 ;
1324 });
1325 thread.detach();
1326
1327 while (!thread_ready) {
1328 continue;
1329 }
1330
Josh Gao70adac62018-02-22 11:38:33 -08001331 if (prejail) {
1332 prejail();
1333 }
1334
Josh Gaoe04ca272018-01-16 15:38:17 -08001335 minijail_enter(jail.get());
1336 return result;
1337}
1338
Josh Gao70adac62018-02-22 11:38:33 -08001339static pid_t seccomp_fork() {
1340 return seccomp_fork_impl(nullptr);
1341}
1342
Josh Gaoe04ca272018-01-16 15:38:17 -08001343TEST_F(CrasherTest, seccomp_crash) {
1344 int intercept_result;
1345 unique_fd output_fd;
1346
1347 StartProcess([]() { abort(); }, &seccomp_fork);
1348
1349 StartIntercept(&output_fd);
1350 FinishCrasher();
1351 AssertDeath(SIGABRT);
1352 FinishIntercept(&intercept_result);
1353 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1354
1355 std::string result;
1356 ConsumeFd(std::move(output_fd), &result);
1357 ASSERT_BACKTRACE_FRAME(result, "abort");
1358}
1359
Josh Gao70adac62018-02-22 11:38:33 -08001360static pid_t seccomp_fork_rlimit() {
1361 return seccomp_fork_impl([]() {
1362 struct rlimit rlim = {
1363 .rlim_cur = 512 * 1024 * 1024,
1364 .rlim_max = 512 * 1024 * 1024,
1365 };
1366
1367 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1368 raise(SIGINT);
1369 }
1370 });
1371}
1372
1373TEST_F(CrasherTest, seccomp_crash_oom) {
1374 int intercept_result;
1375 unique_fd output_fd;
1376
1377 StartProcess(
1378 []() {
1379 std::vector<void*> vec;
1380 for (int i = 0; i < 512; ++i) {
1381 char* buf = static_cast<char*>(malloc(1024 * 1024));
1382 if (!buf) {
1383 abort();
1384 }
1385 memset(buf, 0xff, 1024 * 1024);
1386 vec.push_back(buf);
1387 }
1388 },
1389 &seccomp_fork_rlimit);
1390
1391 StartIntercept(&output_fd);
1392 FinishCrasher();
1393 AssertDeath(SIGABRT);
1394 FinishIntercept(&intercept_result);
1395 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1396
1397 // We can't actually generate a backtrace, just make sure that the process terminates.
1398}
1399
Josh Gaoe04ca272018-01-16 15:38:17 -08001400__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1401 siginfo_t siginfo;
1402 siginfo.si_code = SI_QUEUE;
1403 siginfo.si_pid = getpid();
1404 siginfo.si_uid = getuid();
1405
1406 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1407 PLOG(FATAL) << "invalid dump type";
1408 }
1409
1410 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1411
Josh Gaoa48b41b2019-12-13 14:11:04 -08001412 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001413 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1414 return false;
1415 }
1416
1417 return true;
1418}
1419
Christopher Ferrisb999b822022-02-09 17:57:21 -08001420extern "C" void foo() {
1421 LOG(INFO) << "foo";
1422 std::this_thread::sleep_for(1s);
1423}
1424
1425extern "C" void bar() {
1426 LOG(INFO) << "bar";
1427 std::this_thread::sleep_for(1s);
1428}
1429
Josh Gaoe04ca272018-01-16 15:38:17 -08001430TEST_F(CrasherTest, seccomp_tombstone) {
1431 int intercept_result;
1432 unique_fd output_fd;
1433
1434 static const auto dump_type = kDebuggerdTombstone;
1435 StartProcess(
1436 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001437 std::thread a(foo);
1438 std::thread b(bar);
1439
1440 std::this_thread::sleep_for(100ms);
1441
Josh Gaoe04ca272018-01-16 15:38:17 -08001442 raise_debugger_signal(dump_type);
1443 _exit(0);
1444 },
1445 &seccomp_fork);
1446
1447 StartIntercept(&output_fd, dump_type);
1448 FinishCrasher();
1449 AssertDeath(0);
1450 FinishIntercept(&intercept_result);
1451 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1452
1453 std::string result;
1454 ConsumeFd(std::move(output_fd), &result);
1455 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001456 ASSERT_BACKTRACE_FRAME(result, "foo");
1457 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001458}
1459
Josh Gaoe04ca272018-01-16 15:38:17 -08001460TEST_F(CrasherTest, seccomp_backtrace) {
1461 int intercept_result;
1462 unique_fd output_fd;
1463
1464 static const auto dump_type = kDebuggerdNativeBacktrace;
1465 StartProcess(
1466 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001467 std::thread a(foo);
1468 std::thread b(bar);
1469
1470 std::this_thread::sleep_for(100ms);
1471
Josh Gaoe04ca272018-01-16 15:38:17 -08001472 raise_debugger_signal(dump_type);
1473 _exit(0);
1474 },
1475 &seccomp_fork);
1476
1477 StartIntercept(&output_fd, dump_type);
1478 FinishCrasher();
1479 AssertDeath(0);
1480 FinishIntercept(&intercept_result);
1481 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1482
1483 std::string result;
1484 ConsumeFd(std::move(output_fd), &result);
1485 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001486 ASSERT_BACKTRACE_FRAME(result, "foo");
1487 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001488}
1489
1490TEST_F(CrasherTest, seccomp_crash_logcat) {
1491 StartProcess([]() { abort(); }, &seccomp_fork);
1492 FinishCrasher();
1493
1494 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1495 AssertDeath(SIGABRT);
1496}
1497
Josh Gaofd13bf02017-08-18 15:37:26 -07001498TEST_F(CrasherTest, competing_tracer) {
1499 int intercept_result;
1500 unique_fd output_fd;
1501 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001502 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001503 });
1504
1505 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001506
1507 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001508 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001509
1510 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001511 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001512 ASSERT_TRUE(WIFSTOPPED(status));
1513 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1514
1515 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1516 FinishIntercept(&intercept_result);
1517 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1518
1519 std::string result;
1520 ConsumeFd(std::move(output_fd), &result);
1521 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1522 regex += std::to_string(gettid());
1523 regex += R"( \(.+debuggerd_test)";
1524 ASSERT_MATCH(result, regex.c_str());
1525
Christopher Ferris172b0a02019-09-18 17:48:30 -07001526 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001527 ASSERT_TRUE(WIFSTOPPED(status));
1528 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1529
Josh Gaofd13bf02017-08-18 15:37:26 -07001530 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1531 AssertDeath(SIGABRT);
1532}
1533
Josh Gaobf06a402018-08-27 16:34:01 -07001534TEST_F(CrasherTest, fdsan_warning_abort_message) {
1535 int intercept_result;
1536 unique_fd output_fd;
1537
1538 StartProcess([]() {
1539 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001540 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001541 if (fd == -1) {
1542 abort();
1543 }
1544 close(fd.get());
1545 _exit(0);
1546 });
1547
1548 StartIntercept(&output_fd);
1549 FinishCrasher();
1550 AssertDeath(0);
1551 FinishIntercept(&intercept_result);
1552 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1553
1554 std::string result;
1555 ConsumeFd(std::move(output_fd), &result);
1556 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1557}
1558
Josh Gaoc3c8c022017-02-13 16:36:18 -08001559TEST(crash_dump, zombie) {
1560 pid_t forkpid = fork();
1561
Josh Gaoc3c8c022017-02-13 16:36:18 -08001562 pid_t rc;
1563 int status;
1564
1565 if (forkpid == 0) {
1566 errno = 0;
1567 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1568 if (rc != -1 || errno != ECHILD) {
1569 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1570 }
1571
Josh Gaoa48b41b2019-12-13 14:11:04 -08001572 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001573
1574 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001575 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001576 if (rc != -1 || errno != ECHILD) {
1577 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1578 }
1579 _exit(0);
1580 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001581 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001582 ASSERT_EQ(forkpid, rc);
1583 ASSERT_TRUE(WIFEXITED(status));
1584 ASSERT_EQ(0, WEXITSTATUS(status));
1585 }
1586}
Josh Gao352a8452017-03-30 16:46:21 -07001587
1588TEST(tombstoned, no_notify) {
1589 // Do this a few times.
1590 for (int i = 0; i < 3; ++i) {
1591 pid_t pid = 123'456'789 + i;
1592
1593 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001594 InterceptStatus status;
1595 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1596 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001597
1598 {
1599 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001600 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001601 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1602 }
1603
1604 pid_t read_pid;
1605 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1606 ASSERT_EQ(read_pid, pid);
1607 }
1608}
1609
1610TEST(tombstoned, stress) {
1611 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1612 static constexpr int kDumpCount = 100;
1613
1614 std::atomic<bool> start(false);
1615 std::vector<std::thread> threads;
1616 threads.emplace_back([&start]() {
1617 while (!start) {
1618 continue;
1619 }
1620
1621 // Use a way out of range pid, to avoid stomping on an actual process.
1622 pid_t pid_base = 1'000'000;
1623
1624 for (int dump = 0; dump < kDumpCount; ++dump) {
1625 pid_t pid = pid_base + dump;
1626
1627 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001628 InterceptStatus status;
1629 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1630 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001631
1632 // Pretend to crash, and then immediately close the socket.
1633 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1634 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1635 if (sockfd == -1) {
1636 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1637 }
1638 TombstonedCrashPacket packet = {};
1639 packet.packet_type = CrashPacketType::kDumpRequest;
1640 packet.packet.dump_request.pid = pid;
1641 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1642 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1643 }
1644
1645 continue;
1646 }
1647 });
1648
1649 threads.emplace_back([&start]() {
1650 while (!start) {
1651 continue;
1652 }
1653
1654 // Use a way out of range pid, to avoid stomping on an actual process.
1655 pid_t pid_base = 2'000'000;
1656
1657 for (int dump = 0; dump < kDumpCount; ++dump) {
1658 pid_t pid = pid_base + dump;
1659
1660 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001661 InterceptStatus status;
1662 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1663 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001664
1665 {
1666 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001667 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001668 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1669 tombstoned_notify_completion(tombstoned_socket.get());
1670 }
1671
1672 // TODO: Fix the race that requires this sleep.
1673 std::this_thread::sleep_for(50ms);
1674
1675 pid_t read_pid;
1676 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1677 ASSERT_EQ(read_pid, pid);
1678 }
1679 });
1680
1681 start = true;
1682
1683 for (std::thread& thread : threads) {
1684 thread.join();
1685 }
1686}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001687
1688TEST(tombstoned, java_trace_intercept_smoke) {
1689 // Using a "real" PID is a little dangerous here - if the test fails
1690 // or crashes, we might end up getting a bogus / unreliable stack
1691 // trace.
1692 const pid_t self = getpid();
1693
1694 unique_fd intercept_fd, output_fd;
1695 InterceptStatus status;
1696 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1697 ASSERT_EQ(InterceptStatus::kRegistered, status);
1698
Josh Gao76e1e302021-01-26 15:53:11 -08001699 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001700 // should result in a "regular" FD and not the installed intercept.
1701 const char native[] = "native";
1702 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001703 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001704 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1705 tombstoned_notify_completion(tombstoned_socket.get());
1706
1707 // Then, connect to tombstoned asking for a java backtrace. This *should*
1708 // trigger the intercept.
1709 const char java[] = "java";
1710 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1711 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1712 tombstoned_notify_completion(tombstoned_socket.get());
1713
1714 char outbuf[sizeof(java)];
1715 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1716 ASSERT_STREQ("java", outbuf);
1717}
1718
1719TEST(tombstoned, multiple_intercepts) {
1720 const pid_t fake_pid = 1'234'567;
1721 unique_fd intercept_fd, output_fd;
1722 InterceptStatus status;
1723 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1724 ASSERT_EQ(InterceptStatus::kRegistered, status);
1725
1726 unique_fd intercept_fd_2, output_fd_2;
1727 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1728 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1729}
1730
1731TEST(tombstoned, intercept_any) {
1732 const pid_t fake_pid = 1'234'567;
1733
1734 unique_fd intercept_fd, output_fd;
1735 InterceptStatus status;
1736 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1737 ASSERT_EQ(InterceptStatus::kRegistered, status);
1738
1739 const char any[] = "any";
1740 unique_fd tombstoned_socket, input_fd;
1741 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1742 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1743 tombstoned_notify_completion(tombstoned_socket.get());
1744
1745 char outbuf[sizeof(any)];
1746 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1747 ASSERT_STREQ("any", outbuf);
1748}
Josh Gao2b22ae12018-09-12 14:51:03 -07001749
1750TEST(tombstoned, interceptless_backtrace) {
1751 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1752 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1753 std::map<int, time_t> result;
1754 for (int i = 0; i < 99; ++i) {
1755 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1756 struct stat st;
1757 if (stat(path.c_str(), &st) == 0) {
1758 result[i] = st.st_mtim.tv_sec;
1759 }
1760 }
1761 return result;
1762 };
1763
1764 auto before = get_tombstone_timestamps();
1765 for (int i = 0; i < 50; ++i) {
1766 raise_debugger_signal(kDebuggerdNativeBacktrace);
1767 }
1768 auto after = get_tombstone_timestamps();
1769
1770 int diff = 0;
1771 for (int i = 0; i < 99; ++i) {
1772 if (after.count(i) == 0) {
1773 continue;
1774 }
1775 if (before.count(i) == 0) {
1776 ++diff;
1777 continue;
1778 }
1779 if (before[i] != after[i]) {
1780 ++diff;
1781 }
1782 }
1783
1784 // We can't be sure that nothing's crash looping in the background.
1785 // This should be good enough, though...
1786 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1787}
Christopher Ferris481e8372019-07-15 17:13:24 -07001788
1789static __attribute__((__noinline__)) void overflow_stack(void* p) {
1790 void* buf[1];
1791 buf[0] = p;
1792 static volatile void* global = buf;
1793 if (global) {
1794 global = buf;
1795 overflow_stack(&buf);
1796 }
1797}
1798
1799TEST_F(CrasherTest, stack_overflow) {
1800 int intercept_result;
1801 unique_fd output_fd;
1802 StartProcess([]() { overflow_stack(nullptr); });
1803
1804 StartIntercept(&output_fd);
1805 FinishCrasher();
1806 AssertDeath(SIGSEGV);
1807 FinishIntercept(&intercept_result);
1808
1809 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1810
1811 std::string result;
1812 ConsumeFd(std::move(output_fd), &result);
1813 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1814}
Josh Gao76e1e302021-01-26 15:53:11 -08001815
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001816static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1817 std::string test_lib(testing::internal::GetArgvs()[0]);
1818 auto const value = test_lib.find_last_of('/');
1819 if (value == std::string::npos) {
1820 test_lib = "./";
1821 } else {
1822 test_lib = test_lib.substr(0, value + 1) + "./";
1823 }
1824 test_lib += "libcrash_test.so";
1825
1826 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1827 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1828
1829 // Copy the shared so to a tempory directory.
1830 return system(cp_cmd.c_str()) == 0;
1831}
1832
1833TEST_F(CrasherTest, unreadable_elf) {
1834 int intercept_result;
1835 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001836 std::string tmp_so_name;
1837 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001838 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001839 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1840 _exit(1);
1841 }
1842 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1843 if (handle == nullptr) {
1844 _exit(1);
1845 }
1846 // Delete the original shared library so that we get the warning
1847 // about unreadable elf files.
1848 if (unlink(tmp_so_name.c_str()) == -1) {
1849 _exit(1);
1850 }
1851 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1852 if (crash_func == nullptr) {
1853 _exit(1);
1854 }
1855 crash_func();
1856 });
1857
1858 StartIntercept(&output_fd);
1859 FinishCrasher();
1860 AssertDeath(SIGSEGV);
1861 FinishIntercept(&intercept_result);
1862
1863 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1864
1865 std::string result;
1866 ConsumeFd(std::move(output_fd), &result);
1867 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001868 std::string match_str = "NOTE: " + tmp_so_name;
1869 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001870}
1871
Josh Gao76e1e302021-01-26 15:53:11 -08001872TEST(tombstoned, proto) {
1873 const pid_t self = getpid();
1874 unique_fd tombstoned_socket, text_fd, proto_fd;
1875 ASSERT_TRUE(
1876 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1877
1878 tombstoned_notify_completion(tombstoned_socket.get());
1879
1880 ASSERT_NE(-1, text_fd.get());
1881 ASSERT_NE(-1, proto_fd.get());
1882
1883 struct stat text_st;
1884 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1885
1886 // Give tombstoned some time to link the files into place.
1887 std::this_thread::sleep_for(100ms);
1888
1889 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001890 std::optional<std::string> tombstone_file;
1891 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1892 ASSERT_TRUE(dir_h != nullptr);
1893 std::regex tombstone_re("tombstone_\\d+");
1894 dirent* entry;
1895 while ((entry = readdir(dir_h.get())) != nullptr) {
1896 if (!std::regex_match(entry->d_name, tombstone_re)) {
1897 continue;
1898 }
1899 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001900
1901 struct stat st;
1902 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1903 continue;
1904 }
1905
1906 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001907 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001908 break;
1909 }
1910 }
1911
Christopher Ferris35da2882021-02-17 15:39:06 -08001912 ASSERT_TRUE(tombstone_file);
1913 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001914
1915 struct stat proto_fd_st;
1916 struct stat proto_file_st;
1917 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1918 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1919
1920 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1921 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1922}
1923
1924TEST(tombstoned, proto_intercept) {
1925 const pid_t self = getpid();
1926 unique_fd intercept_fd, output_fd;
1927 InterceptStatus status;
1928
1929 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1930 ASSERT_EQ(InterceptStatus::kRegistered, status);
1931
1932 unique_fd tombstoned_socket, text_fd, proto_fd;
1933 ASSERT_TRUE(
1934 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1935 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1936 tombstoned_notify_completion(tombstoned_socket.get());
1937
1938 text_fd.reset();
1939
1940 std::string output;
1941 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1942 ASSERT_EQ("foo", output);
1943}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001944
1945// Verify that when an intercept is present for the main thread, and the signal
1946// is received on a different thread, the intercept still works.
1947TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1948 StartProcess([]() {
1949 std::thread thread([]() {
1950 // Raise the signal on the side thread.
1951 raise_debugger_signal(kDebuggerdNativeBacktrace);
1952 });
1953 thread.join();
1954 _exit(0);
1955 });
1956
1957 unique_fd output_fd;
1958 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1959 FinishCrasher();
1960 AssertDeath(0);
1961
1962 int intercept_result;
1963 FinishIntercept(&intercept_result);
1964 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1965
1966 std::string result;
1967 ConsumeFd(std::move(output_fd), &result);
1968 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1969}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001970
1971static std::string format_pointer(uintptr_t ptr) {
1972#if defined(__LP64__)
1973 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1974 static_cast<uint32_t>(ptr & 0xffffffff));
1975#else
1976 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1977#endif
1978}
1979
1980static std::string format_pointer(void* ptr) {
1981 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1982}
1983
1984static std::string format_full_pointer(uintptr_t ptr) {
1985#if defined(__LP64__)
1986 return android::base::StringPrintf("%016" PRIx64, ptr);
1987#else
1988 return android::base::StringPrintf("%08x", ptr);
1989#endif
1990}
1991
1992static std::string format_full_pointer(void* ptr) {
1993 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1994}
1995
1996__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1997 int* crash_ptr = reinterpret_cast<int*>(ptr);
1998 *crash_ptr = 1;
1999 return *crash_ptr;
2000}
2001
2002// Verify that a fault address before the first map is properly handled.
2003TEST_F(CrasherTest, fault_address_before_first_map) {
2004 StartProcess([]() {
2005 ASSERT_EQ(0, crash_call(0x1024));
2006 _exit(0);
2007 });
2008
2009 unique_fd output_fd;
2010 StartIntercept(&output_fd);
2011 FinishCrasher();
2012 AssertDeath(SIGSEGV);
2013
2014 int intercept_result;
2015 FinishIntercept(&intercept_result);
2016 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2017
2018 std::string result;
2019 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002020 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002021
2022 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2023
2024 std::string match_str = android::base::StringPrintf(
2025 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2026 format_pointer(0x1024).c_str());
2027 ASSERT_MATCH(result, match_str);
2028}
2029
2030// Verify that a fault address after the last map is properly handled.
2031TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002032 // This makes assumptions about the memory layout that are not true in HWASan
2033 // processes.
2034 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002035 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2036 StartProcess([crash_uptr]() {
2037 ASSERT_EQ(0, crash_call(crash_uptr));
2038 _exit(0);
2039 });
2040
2041 unique_fd output_fd;
2042 StartIntercept(&output_fd);
2043 FinishCrasher();
2044 AssertDeath(SIGSEGV);
2045
2046 int intercept_result;
2047 FinishIntercept(&intercept_result);
2048 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2049
2050 std::string result;
2051 ConsumeFd(std::move(output_fd), &result);
2052
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002053 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2054 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002055 ASSERT_MATCH(result, match_str);
2056
2057 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2058
2059 // Assumes that the open files section comes after the map section.
2060 // If that assumption changes, the regex below needs to change.
2061 match_str = android::base::StringPrintf(
2062 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2063 format_pointer(crash_uptr).c_str());
2064 ASSERT_MATCH(result, match_str);
2065}
2066
2067// Verify that a fault address between maps is properly handled.
2068TEST_F(CrasherTest, fault_address_between_maps) {
2069 // Create a map before the fork so it will be present in the child.
2070 void* start_ptr =
2071 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2072 ASSERT_NE(MAP_FAILED, start_ptr);
2073 // Unmap the page in the middle.
2074 void* middle_ptr =
2075 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2076 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2077
2078 StartProcess([middle_ptr]() {
2079 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2080 _exit(0);
2081 });
2082
2083 // Unmap the two maps.
2084 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2085 void* end_ptr =
2086 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2087 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2088
2089 unique_fd output_fd;
2090 StartIntercept(&output_fd);
2091 FinishCrasher();
2092 AssertDeath(SIGSEGV);
2093
2094 int intercept_result;
2095 FinishIntercept(&intercept_result);
2096 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2097
2098 std::string result;
2099 ConsumeFd(std::move(output_fd), &result);
2100
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002101 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2102 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002103 ASSERT_MATCH(result, match_str);
2104
2105 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2106
2107 match_str = android::base::StringPrintf(
2108 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2109 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2110 format_pointer(end_ptr).c_str());
2111 ASSERT_MATCH(result, match_str);
2112}
2113
2114// Verify that a fault address happens in the correct map.
2115TEST_F(CrasherTest, fault_address_in_map) {
2116 // Create a map before the fork so it will be present in the child.
2117 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2118 ASSERT_NE(MAP_FAILED, ptr);
2119
2120 StartProcess([ptr]() {
2121 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2122 _exit(0);
2123 });
2124
2125 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2126
2127 unique_fd output_fd;
2128 StartIntercept(&output_fd);
2129 FinishCrasher();
2130 AssertDeath(SIGSEGV);
2131
2132 int intercept_result;
2133 FinishIntercept(&intercept_result);
2134 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2135
2136 std::string result;
2137 ConsumeFd(std::move(output_fd), &result);
2138
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002139 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2140 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002141 ASSERT_MATCH(result, match_str);
2142
2143 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2144
2145 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2146 ASSERT_MATCH(result, match_str);
2147}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002148
2149static constexpr uint32_t kDexData[] = {
2150 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2151 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2152 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2153 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2154 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2155 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2156 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2157 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2158 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2159 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2160 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2161 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2162 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2163 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2164 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2165 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2166 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2167};
2168
2169TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2170 StartProcess([]() {
2171 TemporaryDir td;
2172 std::string tmp_so_name;
2173 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2174 _exit(1);
2175 }
2176
2177 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2178 // move the library to which has a basename of libart.so.
2179 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2180 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2181 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2182 if (handle == nullptr) {
2183 _exit(1);
2184 }
2185
2186 void* ptr =
2187 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2188 ASSERT_TRUE(ptr != MAP_FAILED);
2189 memcpy(ptr, kDexData, sizeof(kDexData));
2190 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2191
2192 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2193 .symfile_size = sizeof(kDexData)};
2194
2195 JITDescriptor* dex_debug =
2196 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2197 ASSERT_TRUE(dex_debug != nullptr);
2198 dex_debug->version = 1;
2199 dex_debug->action_flag = 0;
2200 dex_debug->relevant_entry = 0;
2201 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2202
2203 // This sets the magic dex pc value for register 0, using the value
2204 // of register 1 + 0x102.
2205 asm(".cfi_escape "
2206 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2207 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2208 "0x13 /* DW_OP_drop */,"
2209 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2210
2211 // For each different architecture, set register one to the dex ptr mmap
2212 // created above. Then do a nullptr dereference to force a crash.
2213#if defined(__arm__)
2214 asm volatile(
2215 "mov r1, %[base]\n"
2216 "mov r2, 0\n"
2217 "str r3, [r2]\n"
2218 : [base] "+r"(ptr)
2219 :
2220 : "r1", "r2", "r3", "memory");
2221#elif defined(__aarch64__)
2222 asm volatile(
2223 "mov x1, %[base]\n"
2224 "mov x2, 0\n"
2225 "str x3, [x2]\n"
2226 : [base] "+r"(ptr)
2227 :
2228 : "x1", "x2", "x3", "memory");
2229#elif defined(__i386__)
2230 asm volatile(
2231 "mov %[base], %%ecx\n"
2232 "movl $0, %%edi\n"
2233 "movl 0(%%edi), %%edx\n"
2234 : [base] "+r"(ptr)
2235 :
2236 : "edi", "ecx", "edx", "memory");
2237#elif defined(__x86_64__)
2238 asm volatile(
2239 "mov %[base], %%rdx\n"
2240 "movq 0, %%rdi\n"
2241 "movq 0(%%rdi), %%rcx\n"
2242 : [base] "+r"(ptr)
2243 :
2244 : "rcx", "rdx", "rdi", "memory");
2245#else
2246#error "Unsupported architecture"
2247#endif
2248 _exit(0);
2249 });
2250
2251 unique_fd output_fd;
2252 StartIntercept(&output_fd);
2253 FinishCrasher();
2254 AssertDeath(SIGSEGV);
2255
2256 int intercept_result;
2257 FinishIntercept(&intercept_result);
2258 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2259
2260 std::string result;
2261 ConsumeFd(std::move(output_fd), &result);
2262
2263 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002264 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002265
2266 // Now verify that the dex_pc frame includes a proper function name.
2267 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2268}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002269
2270static std::string format_map_pointer(uintptr_t ptr) {
2271#if defined(__LP64__)
2272 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2273 static_cast<uint32_t>(ptr & 0xffffffff));
2274#else
2275 return android::base::StringPrintf("%08x", ptr);
2276#endif
2277}
2278
2279// Verify that map data is properly formatted.
2280TEST_F(CrasherTest, verify_map_format) {
2281 // Create multiple maps to make sure that the map data is formatted properly.
2282 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2283 ASSERT_NE(MAP_FAILED, none_map);
2284 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2285 ASSERT_NE(MAP_FAILED, r_map);
2286 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2287 ASSERT_NE(MAP_FAILED, w_map);
2288 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2289 ASSERT_NE(MAP_FAILED, x_map);
2290
2291 TemporaryFile tf;
2292 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2293 char c = 'f';
2294 ASSERT_EQ(1, write(tf.fd, &c, 1));
2295 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2296 ASSERT_EQ(1, write(tf.fd, &c, 1));
2297 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2298 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2299 ASSERT_NE(MAP_FAILED, file_map);
2300
2301 StartProcess([]() { abort(); });
2302
2303 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2304 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2305 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2306 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2307 ASSERT_EQ(0, munmap(file_map, 0x3001));
2308
2309 unique_fd output_fd;
2310 StartIntercept(&output_fd);
2311 FinishCrasher();
2312 AssertDeath(SIGABRT);
2313 int intercept_result;
2314 FinishIntercept(&intercept_result);
2315
2316 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2317
2318 std::string result;
2319 ConsumeFd(std::move(output_fd), &result);
2320
2321 std::string match_str;
2322 // Verify none.
2323 match_str = android::base::StringPrintf(
2324 " %s-%s --- 0 1000\\n",
2325 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2326 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2327 ASSERT_MATCH(result, match_str);
2328
2329 // Verify read-only.
2330 match_str = android::base::StringPrintf(
2331 " %s-%s r-- 0 1000\\n",
2332 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2333 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2334 ASSERT_MATCH(result, match_str);
2335
2336 // Verify write-only.
2337 match_str = android::base::StringPrintf(
2338 " %s-%s -w- 0 1000\\n",
2339 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2340 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2341 ASSERT_MATCH(result, match_str);
2342
2343 // Verify exec-only.
2344 match_str = android::base::StringPrintf(
2345 " %s-%s --x 0 1000\\n",
2346 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2347 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2348 ASSERT_MATCH(result, match_str);
2349
2350 // Verify file map with non-zero offset and a name.
2351 match_str = android::base::StringPrintf(
2352 " %s-%s r-- 2000 4000 %s\\n",
2353 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2354 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2355 ASSERT_MATCH(result, match_str);
2356}
2357
2358// Verify that the tombstone map data is correct.
2359TEST_F(CrasherTest, verify_header) {
2360 StartProcess([]() { abort(); });
2361
2362 unique_fd output_fd;
2363 StartIntercept(&output_fd);
2364 FinishCrasher();
2365 AssertDeath(SIGABRT);
2366 int intercept_result;
2367 FinishIntercept(&intercept_result);
2368
2369 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2370
2371 std::string result;
2372 ConsumeFd(std::move(output_fd), &result);
2373
2374 std::string match_str = android::base::StringPrintf(
2375 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2376 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2377 android::base::GetProperty("ro.revision", "unknown").c_str());
2378 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2379 ASSERT_MATCH(result, match_str);
2380}
2381
2382// Verify that the thread header is formatted properly.
2383TEST_F(CrasherTest, verify_thread_header) {
2384 void* shared_map =
2385 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2386 ASSERT_NE(MAP_FAILED, shared_map);
2387 memset(shared_map, 0, sizeof(pid_t));
2388
2389 StartProcess([&shared_map]() {
2390 std::atomic_bool tid_written;
2391 std::thread thread([&tid_written, &shared_map]() {
2392 pid_t tid = gettid();
2393 memcpy(shared_map, &tid, sizeof(pid_t));
2394 tid_written = true;
2395 volatile bool done = false;
2396 while (!done)
2397 ;
2398 });
2399 thread.detach();
2400 while (!tid_written.load(std::memory_order_acquire))
2401 ;
2402 abort();
2403 });
2404
2405 pid_t primary_pid = crasher_pid;
2406
2407 unique_fd output_fd;
2408 StartIntercept(&output_fd);
2409 FinishCrasher();
2410 AssertDeath(SIGABRT);
2411 int intercept_result;
2412 FinishIntercept(&intercept_result);
2413 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2414
2415 // Read the tid data out.
2416 pid_t tid;
2417 memcpy(&tid, shared_map, sizeof(pid_t));
2418 ASSERT_NE(0, tid);
2419
2420 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2421
2422 std::string result;
2423 ConsumeFd(std::move(output_fd), &result);
2424
2425 // Verify that there are two headers, one where the tid is "primary_pid"
2426 // and the other where the tid is "tid".
2427 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2428 primary_pid, primary_pid);
2429 ASSERT_MATCH(result, match_str);
2430
2431 match_str =
2432 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2433 ASSERT_MATCH(result, match_str);
2434}
2435
2436// Verify that there is a BuildID present in the map section and set properly.
2437TEST_F(CrasherTest, verify_build_id) {
2438 StartProcess([]() { abort(); });
2439
2440 unique_fd output_fd;
2441 StartIntercept(&output_fd);
2442 FinishCrasher();
2443 AssertDeath(SIGABRT);
2444 int intercept_result;
2445 FinishIntercept(&intercept_result);
2446 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2447
2448 std::string result;
2449 ConsumeFd(std::move(output_fd), &result);
2450
2451 // Find every /system or /apex lib and verify the BuildID is displayed
2452 // properly.
2453 bool found_valid_elf = false;
2454 std::smatch match;
2455 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2456 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2457 result = match.suffix()) {
2458 if (prev_file == match[1]) {
2459 // Already checked this file.
2460 continue;
2461 }
2462
2463 prev_file = match[1];
2464 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2465 if (!elf.Init() || !elf.valid()) {
2466 // Skipping invalid elf files.
2467 continue;
2468 }
2469 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2470
2471 found_valid_elf = true;
2472 }
2473 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2474}