blob: f4ba34790486d89d270074e8d78ba102906643b7 [file] [log] [blame]
Josh Gaocbe70cb2016-10-18 18:17:52 -07001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Christopher Ferris35da2882021-02-17 15:39:06 -080017#include <dirent.h>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070018#include <dlfcn.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070019#include <err.h>
20#include <fcntl.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000021#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080022#include <malloc.h>
Josh Gaocdea7502017-11-01 15:00:40 -070023#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080024#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070025#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080026#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070027#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080028#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070029#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070030#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070031#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070032
33#include <chrono>
34#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000035#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070036#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070037#include <thread>
38
Josh Gaobf06a402018-08-27 16:34:01 -070039#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080040#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080041#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070042#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080043#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080044
Josh Gao5f87bbd2019-01-09 17:01:49 -080045#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070046#include <android-base/file.h>
47#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070048#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070049#include <android-base/parseint.h>
50#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070051#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070053#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/unique_fd.h>
55#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070056#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070057#include <gtest/gtest.h>
58
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000059#include <unwindstack/Elf.h>
60#include <unwindstack/Memory.h>
61
Josh Gaoe04ca272018-01-16 15:38:17 -080062#include <libminijail.h>
63#include <scoped_minijail.h>
64
Christopher Ferris2038cc72021-09-15 03:57:10 +000065#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010066#include "debuggerd/handler.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070067#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010068#include "protocol.h"
69#include "tombstoned/tombstoned.h"
70#include "util.h"
71
Josh Gaocbe70cb2016-10-18 18:17:52 -070072using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080073
74using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070075using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070076using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070077
78#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070079#define ARCH_SUFFIX "64"
80#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070081#define ARCH_SUFFIX ""
82#endif
83
Elliott Hughese4781d52021-03-17 09:15:15 -070084constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070085
86#define TIMEOUT(seconds, expr) \
87 [&]() { \
88 struct sigaction old_sigaction; \
89 struct sigaction new_sigaction = {}; \
90 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080091 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070092 err(1, "sigaction failed"); \
93 } \
94 alarm(seconds); \
95 auto value = expr; \
96 int saved_errno = errno; \
97 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
98 err(1, "sigaction failed"); \
99 } \
100 alarm(0); \
101 errno = saved_errno; \
102 return value; \
103 }()
104
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700105// Backtrace frame dump could contain:
106// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
107// or
108// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800109#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700110 ASSERT_MATCH(result, \
111 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900112
Mitch Phillips7168a212021-03-09 16:53:23 -0800113// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
114// process sampling, so we need to ensure we force GWP-ASan on.
115__attribute__((constructor)) static void enable_gwp_asan() {
Mitch Phillips1e096992022-03-22 15:59:31 -0700116 android_mallopt_gwp_asan_options_t opts;
117 // No, we're not an app, but let's turn ourselves on without sampling.
118 // Technically, if someone's using the *.default_app sysprops, they'll adjust
119 // our settings, but I don't think this will be common on a device that's
120 // running debuggerd_tests.
121 opts.desire = android_mallopt_gwp_asan_options_t::Action::TURN_ON_FOR_APP;
122 opts.program_name = "";
123 android_mallopt(M_INITIALIZE_GWP_ASAN, &opts, sizeof(android_mallopt_gwp_asan_options_t));
Mitch Phillips7168a212021-03-09 16:53:23 -0800124}
125
Narayan Kamatha73df602017-05-24 15:07:25 +0100126static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100127 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700128 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
129 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
130 if (intercept_fd->get() == -1) {
131 FAIL() << "failed to contact tombstoned: " << strerror(errno);
132 }
133
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700134 InterceptRequest req = {
135 .dump_type = intercept_type,
136 .pid = target_pid,
137 };
Josh Gao460b3362017-03-30 16:40:47 -0700138
139 unique_fd output_pipe_write;
140 if (!Pipe(output_fd, &output_pipe_write)) {
141 FAIL() << "failed to create output pipe: " << strerror(errno);
142 }
143
144 std::string pipe_size_str;
145 int pipe_buffer_size;
146 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
147 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
148 }
149
150 pipe_size_str = android::base::Trim(pipe_size_str);
151
152 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
153 FAIL() << "failed to parse pipe max size";
154 }
155
156 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
157 FAIL() << "failed to set pipe size: " << strerror(errno);
158 }
159
Josh Gao5675f3c2017-06-01 12:19:53 -0700160 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
161
Josh Gao5f87bbd2019-01-09 17:01:49 -0800162 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
163 output_pipe_write.reset();
164 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700165 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
166 }
167
168 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800169 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700170 if (rc == -1) {
171 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
172 } else if (rc == 0) {
173 FAIL() << "failed to read response from tombstoned (EOF)";
174 } else if (rc != sizeof(response)) {
175 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
176 << ", received " << rc;
177 }
178
Narayan Kamathca5e9082017-06-02 15:42:06 +0100179 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700180}
181
Elliott Hughesd13ea522022-01-13 09:20:26 -0800182static bool pac_supported() {
183#if defined(__aarch64__)
184 return getauxval(AT_HWCAP) & HWCAP_PACA;
185#else
186 return false;
187#endif
188}
189
Josh Gaocbe70cb2016-10-18 18:17:52 -0700190class CrasherTest : public ::testing::Test {
191 public:
192 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700193 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700194 unique_fd crasher_pipe;
195 unique_fd intercept_fd;
196
197 CrasherTest();
198 ~CrasherTest();
199
Narayan Kamatha73df602017-05-24 15:07:25 +0100200 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700201
202 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
203 void FinishIntercept(int* result);
204
Josh Gao2e7b8e22017-05-04 17:12:57 -0700205 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700206 void StartCrasher(const std::string& crash_type);
207 void FinishCrasher();
208 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700209
210 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700211};
212
213CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700214 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
215 android::base::SetProperty(kWaitForDebuggerKey, "0");
216
217 // Clear the old property too, just in case someone's been using it
218 // on this device. (We only document the new name, but we still support
219 // the old name so we don't break anyone's existing setups.)
220 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221}
222
223CrasherTest::~CrasherTest() {
224 if (crasher_pid != -1) {
225 kill(crasher_pid, SIGKILL);
226 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700227 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 }
229
Elliott Hughese4781d52021-03-17 09:15:15 -0700230 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700231}
232
Narayan Kamatha73df602017-05-24 15:07:25 +0100233void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700234 if (crasher_pid == -1) {
235 FAIL() << "crasher hasn't been started";
236 }
237
Narayan Kamathca5e9082017-06-02 15:42:06 +0100238 InterceptStatus status;
239 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
240 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700241}
242
243void CrasherTest::FinishIntercept(int* result) {
244 InterceptResponse response;
245
Christopher Ferris11555f02019-09-20 14:18:55 -0700246 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700247 if (rc == -1) {
248 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
249 } else if (rc == 0) {
250 *result = -1;
251 } else if (rc != sizeof(response)) {
252 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
253 << ", received " << rc;
254 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700255 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700256 }
257}
258
Josh Gao2e7b8e22017-05-04 17:12:57 -0700259void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800260 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 unique_fd crasher_read_pipe;
262 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
263 FAIL() << "failed to create pipe: " << strerror(errno);
264 }
265
Josh Gao2e7b8e22017-05-04 17:12:57 -0700266 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700267 if (crasher_pid == -1) {
268 FAIL() << "fork failed: " << strerror(errno);
269 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800270 char dummy;
271 crasher_pipe.reset();
272 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800273 function();
274 _exit(0);
275 }
276}
277
Josh Gaocbe70cb2016-10-18 18:17:52 -0700278void CrasherTest::FinishCrasher() {
279 if (crasher_pipe == -1) {
280 FAIL() << "crasher pipe uninitialized";
281 }
282
Christopher Ferris172b0a02019-09-18 17:48:30 -0700283 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700284 if (rc == -1) {
285 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
286 } else if (rc == 0) {
287 FAIL() << "crasher pipe was closed";
288 }
289}
290
291void CrasherTest::AssertDeath(int signo) {
292 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700293 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700294 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700295 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
296 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700297 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 FAIL() << "failed to wait for crasher: " << strerror(errno);
299 }
300
Josh Gaoe06f2a42017-04-27 16:50:38 -0700301 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700302 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700303 ASSERT_EQ(0, WEXITSTATUS(signo));
304 } else {
305 ASSERT_FALSE(WIFEXITED(status));
306 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
307 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700308 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700309 crasher_pid = -1;
310}
311
312static void ConsumeFd(unique_fd fd, std::string* output) {
313 constexpr size_t read_length = PAGE_SIZE;
314 std::string result;
315
316 while (true) {
317 size_t offset = result.size();
318 result.resize(result.size() + PAGE_SIZE);
319 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
320 if (rc == -1) {
321 FAIL() << "read failed: " << strerror(errno);
322 } else if (rc == 0) {
323 result.resize(result.size() - PAGE_SIZE);
324 break;
325 }
326
327 result.resize(result.size() - PAGE_SIZE + rc);
328 }
329
330 *output = std::move(result);
331}
332
Mitch Phillips78f06702021-06-01 14:35:43 -0700333class LogcatCollector {
334 public:
335 LogcatCollector() { system("logcat -c"); }
336
337 void Collect(std::string* output) {
338 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
339 ASSERT_NE(cmd_stdout, nullptr);
340 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
341 ConsumeFd(std::move(tmp_fd), output);
342 pclose(cmd_stdout);
343 }
344};
345
Josh Gaocbe70cb2016-10-18 18:17:52 -0700346TEST_F(CrasherTest, smoke) {
347 int intercept_result;
348 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800349 StartProcess([]() {
350 *reinterpret_cast<volatile char*>(0xdead) = '1';
351 });
352
Josh Gaocbe70cb2016-10-18 18:17:52 -0700353 StartIntercept(&output_fd);
354 FinishCrasher();
355 AssertDeath(SIGSEGV);
356 FinishIntercept(&intercept_result);
357
358 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
359
360 std::string result;
361 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800362#ifdef __LP64__
363 ASSERT_MATCH(result,
364 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
365#else
366 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
367#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700368
369 if (mte_supported()) {
370 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700371 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
372 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700373 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800374
375 if (pac_supported()) {
376 // Test that the default PAC_ENABLED_KEYS value is set.
377 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
378 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
379 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700380}
381
Peter Collingbournef03af882020-03-20 18:09:00 -0700382TEST_F(CrasherTest, tagged_fault_addr) {
383#if !defined(__aarch64__)
384 GTEST_SKIP() << "Requires aarch64";
385#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700386 // HWASan crashes with SIGABRT on tag mismatch.
387 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700388 int intercept_result;
389 unique_fd output_fd;
390 StartProcess([]() {
391 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
392 });
393
394 StartIntercept(&output_fd);
395 FinishCrasher();
396 AssertDeath(SIGSEGV);
397 FinishIntercept(&intercept_result);
398
399 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
400
401 std::string result;
402 ConsumeFd(std::move(output_fd), &result);
403
404 // The address can either be tagged (new kernels) or untagged (old kernels).
405 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800406 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700407}
408
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700409// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
410// compiler could still clobber the argument register before trapping, but that's unlikely.
411__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
412 __builtin_trap();
413}
414
415TEST_F(CrasherTest, heap_addr_in_register) {
416#if defined(__i386__)
417 GTEST_SKIP() << "architecture does not pass arguments in registers";
418#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700419 // The memory dump in HWASan crashes sadly shows the memory near the registers
420 // in the HWASan dump function, rather the faulting context. This is a known
421 // issue.
422 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700423 int intercept_result;
424 unique_fd output_fd;
425 StartProcess([]() {
426 // Crash with a heap pointer in the first argument register.
427 Trap(malloc(1));
428 });
429
430 StartIntercept(&output_fd);
431 FinishCrasher();
432 int status;
433 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
434 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
435 // Don't test the signal number because different architectures use different signals for
436 // __builtin_trap().
437 FinishIntercept(&intercept_result);
438
439 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
440
441 std::string result;
442 ConsumeFd(std::move(output_fd), &result);
443
444#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800445 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700446#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800447 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700448#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800449 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700450#else
451 ASSERT_TRUE(false) << "unsupported architecture";
452#endif
453}
454
Peter Collingbournecd278072020-12-21 14:08:38 -0800455#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700456static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800457 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700458 abort();
459 }
460}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800461
462static void SetTagCheckingLevelAsync() {
463 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
464 abort();
465 }
466}
Peter Collingbournef8622522020-04-07 14:07:32 -0700467#endif
468
Mitch Phillips7168a212021-03-09 16:53:23 -0800469// Number of iterations required to reliably guarantee a GWP-ASan crash.
470// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
471// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
472// the counter reaches zero, we provide a sampled allocation. Then, double that
473// figure to allow for left/right allocation alignment, as this is done randomly
474// without bias.
475#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
476
477struct GwpAsanTestParameters {
478 size_t alloc_size;
479 bool free_before_access;
480 int access_offset;
481 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
482};
483
484struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
485
486GwpAsanTestParameters gwp_asan_tests[] = {
487 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
488 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
489 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
490 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
491};
492
493INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
494
495TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
496 if (mte_supported()) {
497 // Skip this test on MTE hardware, as MTE will reliably catch these errors
498 // instead of GWP-ASan.
499 GTEST_SKIP() << "Skipped on MTE.";
500 }
Florian Mayerb4979292022-04-15 14:35:17 -0700501 // Skip this test on HWASan, which will reliably catch test errors as well.
502 SKIP_WITH_HWASAN;
Mitch Phillips7168a212021-03-09 16:53:23 -0800503
504 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700505 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800506
507 int intercept_result;
508 unique_fd output_fd;
509 StartProcess([&params]() {
510 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
511 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
512 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
513 p[params.access_offset] = 42;
514 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
515 }
516 });
517
518 StartIntercept(&output_fd);
519 FinishCrasher();
520 AssertDeath(SIGSEGV);
521 FinishIntercept(&intercept_result);
522
523 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
524
Mitch Phillips78f06702021-06-01 14:35:43 -0700525 std::vector<std::string> log_sources(2);
526 ConsumeFd(std::move(output_fd), &log_sources[0]);
527 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800528
Mitch Phillips78f06702021-06-01 14:35:43 -0700529 for (const auto& result : log_sources) {
530 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
531 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
532 if (params.free_before_access) {
533 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
534 }
535 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800536 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800537}
538
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800539struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
540
Peter Collingbourneaa544792021-05-13 13:53:37 -0700541INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800542
543TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800544#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700545 if (!mte_supported()) {
546 GTEST_SKIP() << "Requires MTE";
547 }
548
Peter Collingbourneaa544792021-05-13 13:53:37 -0700549 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
550 if (GetParam() == 0) {
551 return;
552 }
553
Mitch Phillips78f06702021-06-01 14:35:43 -0700554 LogcatCollector logcat_collector;
555
Peter Collingbournef8622522020-04-07 14:07:32 -0700556 int intercept_result;
557 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800558 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700559 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800560 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700561 free((void *)p);
562 p[0] = 42;
563 });
564
565 StartIntercept(&output_fd);
566 FinishCrasher();
567 AssertDeath(SIGSEGV);
568 FinishIntercept(&intercept_result);
569
570 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
571
Mitch Phillips78f06702021-06-01 14:35:43 -0700572 std::vector<std::string> log_sources(2);
573 ConsumeFd(std::move(output_fd), &log_sources[0]);
574 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700575 // Tag dump only available in the tombstone, not logcat.
576 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700577
Mitch Phillips78f06702021-06-01 14:35:43 -0700578 for (const auto& result : log_sources) {
579 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
580 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
581 std::to_string(GetParam()) + R"(-byte allocation)");
582 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
583 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
584 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700585#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800586 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700587#endif
588}
589
Peter Collingbournedc476342021-05-12 15:56:43 -0700590TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
591#if defined(__aarch64__)
592 if (!mte_supported()) {
593 GTEST_SKIP() << "Requires MTE";
594 }
595
596 int intercept_result;
597 unique_fd output_fd;
598 StartProcess([&]() {
599 SetTagCheckingLevelSync();
600 volatile int* p = (volatile int*)malloc(GetParam());
601 free((void *)p);
602 p[-1] = 42;
603 });
604
605 StartIntercept(&output_fd);
606 FinishCrasher();
607 AssertDeath(SIGSEGV);
608 FinishIntercept(&intercept_result);
609
610 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
611
612 std::string result;
613 ConsumeFd(std::move(output_fd), &result);
614
615 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
616 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
617#else
618 GTEST_SKIP() << "Requires aarch64";
619#endif
620}
621
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800622TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800623#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700624 if (!mte_supported()) {
625 GTEST_SKIP() << "Requires MTE";
626 }
627
Mitch Phillips78f06702021-06-01 14:35:43 -0700628 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700629 int intercept_result;
630 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800631 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700632 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800633 volatile char* p = (volatile char*)malloc(GetParam());
634 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700635 });
636
637 StartIntercept(&output_fd);
638 FinishCrasher();
639 AssertDeath(SIGSEGV);
640 FinishIntercept(&intercept_result);
641
642 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
643
Mitch Phillips78f06702021-06-01 14:35:43 -0700644 std::vector<std::string> log_sources(2);
645 ConsumeFd(std::move(output_fd), &log_sources[0]);
646 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700647
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700648 // Tag dump only in tombstone, not logcat, and tagging is not used for
649 // overflow protection in the scudo secondary (guard pages are used instead).
650 if (GetParam() < 0x10000) {
651 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
652 }
653
Mitch Phillips78f06702021-06-01 14:35:43 -0700654 for (const auto& result : log_sources) {
655 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
656 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
657 std::to_string(GetParam()) + R"(-byte allocation)");
658 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
659 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700660#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800661 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700662#endif
663}
664
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800665TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800666#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700667 if (!mte_supported()) {
668 GTEST_SKIP() << "Requires MTE";
669 }
670
671 int intercept_result;
672 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800673 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700674 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800675 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700676 p[-1] = 42;
677 });
678
679 StartIntercept(&output_fd);
680 FinishCrasher();
681 AssertDeath(SIGSEGV);
682 FinishIntercept(&intercept_result);
683
684 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
685
686 std::string result;
687 ConsumeFd(std::move(output_fd), &result);
688
689 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800690 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800691 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700692 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700693 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700694 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700695#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800696 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700697#endif
698}
699
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800700TEST_F(CrasherTest, mte_async) {
701#if defined(__aarch64__)
702 if (!mte_supported()) {
703 GTEST_SKIP() << "Requires MTE";
704 }
705
706 int intercept_result;
707 unique_fd output_fd;
708 StartProcess([&]() {
709 SetTagCheckingLevelAsync();
710 volatile int* p = (volatile int*)malloc(16);
711 p[-1] = 42;
712 });
713
714 StartIntercept(&output_fd);
715 FinishCrasher();
716 AssertDeath(SIGSEGV);
717 FinishIntercept(&intercept_result);
718
719 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
720
721 std::string result;
722 ConsumeFd(std::move(output_fd), &result);
723
724 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
725#else
726 GTEST_SKIP() << "Requires aarch64";
727#endif
728}
729
Peter Collingbournef8622522020-04-07 14:07:32 -0700730TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800731#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700732 if (!mte_supported()) {
733 GTEST_SKIP() << "Requires MTE";
734 }
735
Mitch Phillips78f06702021-06-01 14:35:43 -0700736 LogcatCollector logcat_collector;
737
Peter Collingbournef8622522020-04-07 14:07:32 -0700738 int intercept_result;
739 unique_fd output_fd;
740 StartProcess([]() {
741 SetTagCheckingLevelSync();
742
743 // Make two allocations with the same tag and close to one another. Check for both properties
744 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
745 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
746 // (some non-zero value << 56) apart.
747 //
748 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
749 // other.
750 std::set<uintptr_t> allocs;
751 for (int i = 0; i != 4096; ++i) {
752 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
753 auto it = allocs.insert(alloc).first;
754 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
755 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
756 }
757 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
758 *reinterpret_cast<int*>(alloc + 16) = 42;
759 }
760 }
761 });
762
763 StartIntercept(&output_fd);
764 FinishCrasher();
765 AssertDeath(SIGSEGV);
766 FinishIntercept(&intercept_result);
767
768 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
769
Mitch Phillips78f06702021-06-01 14:35:43 -0700770 std::vector<std::string> log_sources(2);
771 ConsumeFd(std::move(output_fd), &log_sources[0]);
772 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700773
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700774 // Tag dump only in the tombstone, not logcat.
775 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
776
Mitch Phillips78f06702021-06-01 14:35:43 -0700777 for (const auto& result : log_sources) {
778 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
779 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800780 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700781 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
782 // overflows), so we can't match explicitly for an underflow message.
783 ASSERT_MATCH(result,
784 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
785 // Ensure there's at least two allocation traces (one for each cause).
786 ASSERT_MATCH(
787 result,
788 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
789 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700790#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800791 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700792#endif
793}
794
Peter Collingbournecd278072020-12-21 14:08:38 -0800795#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700796static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700797 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
798 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
799 size_t page_size = getpagesize();
800 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
801 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
802 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700803 return 0;
804 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700805 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
806 PROT_READ | PROT_WRITE | PROT_MTE);
807 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
808 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
809 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
810 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
811 }
812 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700813}
814#endif
815
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700816TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800817#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700818 if (!mte_supported()) {
819 GTEST_SKIP() << "Requires MTE";
820 }
821
822 int intercept_result;
823 unique_fd output_fd;
824 StartProcess([&]() {
825 SetTagCheckingLevelSync();
826 Trap(reinterpret_cast<void *>(CreateTagMapping()));
827 });
828
829 StartIntercept(&output_fd);
830 FinishCrasher();
831 AssertDeath(SIGTRAP);
832 FinishIntercept(&intercept_result);
833
834 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
835
836 std::string result;
837 ConsumeFd(std::move(output_fd), &result);
838
839 ASSERT_MATCH(result, R"(memory near x0:
840.*
841.*
842 01.............0 0000000000000000 0000000000000000 ................
843 00.............0)");
844#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800845 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700846#endif
847}
848
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700849TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
850#if defined(__aarch64__)
851 if (!mte_supported()) {
852 GTEST_SKIP() << "Requires MTE";
853 }
854
855 int intercept_result;
856 unique_fd output_fd;
857 StartProcess([&]() {
858 SetTagCheckingLevelSync();
859 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
860 p[0] = 0; // Untagged pointer, tagged memory.
861 });
862
863 StartIntercept(&output_fd);
864 FinishCrasher();
865 AssertDeath(SIGSEGV);
866 FinishIntercept(&intercept_result);
867
868 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
869
870 std::string result;
871 ConsumeFd(std::move(output_fd), &result);
872
873 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
874\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
875#else
876 GTEST_SKIP() << "Requires aarch64";
877#endif
878}
879
880TEST_F(CrasherTest, mte_fault_tag_dump) {
881#if defined(__aarch64__)
882 if (!mte_supported()) {
883 GTEST_SKIP() << "Requires MTE";
884 }
885
886 int intercept_result;
887 unique_fd output_fd;
888 StartProcess([&]() {
889 SetTagCheckingLevelSync();
890 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
891 p[320] = 0; // Untagged pointer, tagged memory.
892 });
893
894 StartIntercept(&output_fd);
895 FinishCrasher();
896 AssertDeath(SIGSEGV);
897 FinishIntercept(&intercept_result);
898
899 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
900
901 std::string result;
902 ConsumeFd(std::move(output_fd), &result);
903
904 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
905\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
906\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
907\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
908)");
909#else
910 GTEST_SKIP() << "Requires aarch64";
911#endif
912}
913
914TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
915#if defined(__aarch64__)
916 if (!mte_supported()) {
917 GTEST_SKIP() << "Requires MTE";
918 }
919
920 int intercept_result;
921 unique_fd output_fd;
922 StartProcess([&]() {
923 SetTagCheckingLevelSync();
924 size_t page_size = getpagesize();
925 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
926 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
927 });
928
929 StartIntercept(&output_fd);
930 FinishCrasher();
931 AssertDeath(SIGSEGV);
932 FinishIntercept(&intercept_result);
933
934 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
935
936 std::string result;
937 ConsumeFd(std::move(output_fd), &result);
938
939 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
940 ASSERT_MATCH(result,
941 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
942\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
943
944)"); // Ensure truncation happened and there's a newline after the tag fault.
945#else
946 GTEST_SKIP() << "Requires aarch64";
947#endif
948}
949
Josh Gaocdea7502017-11-01 15:00:40 -0700950TEST_F(CrasherTest, LD_PRELOAD) {
951 int intercept_result;
952 unique_fd output_fd;
953 StartProcess([]() {
954 setenv("LD_PRELOAD", "nonexistent.so", 1);
955 *reinterpret_cast<volatile char*>(0xdead) = '1';
956 });
957
958 StartIntercept(&output_fd);
959 FinishCrasher();
960 AssertDeath(SIGSEGV);
961 FinishIntercept(&intercept_result);
962
963 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
964
965 std::string result;
966 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800967 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700968}
969
Josh Gaocbe70cb2016-10-18 18:17:52 -0700970TEST_F(CrasherTest, abort) {
971 int intercept_result;
972 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800973 StartProcess([]() {
974 abort();
975 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700976 StartIntercept(&output_fd);
977 FinishCrasher();
978 AssertDeath(SIGABRT);
979 FinishIntercept(&intercept_result);
980
981 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
982
983 std::string result;
984 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700985 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700986}
987
988TEST_F(CrasherTest, signal) {
989 int intercept_result;
990 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800991 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700992 while (true) {
993 sleep(1);
994 }
Josh Gao502cfd22017-02-17 01:39:15 -0800995 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700996 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700997 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700998 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
999
1000 AssertDeath(SIGSEGV);
1001 FinishIntercept(&intercept_result);
1002
1003 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1004
1005 std::string result;
1006 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -07001007 ASSERT_MATCH(
1008 result,
1009 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001010 ASSERT_MATCH(result, R"(backtrace:)");
1011}
1012
1013TEST_F(CrasherTest, abort_message) {
1014 int intercept_result;
1015 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001016 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001017 // Arrived at experimentally;
1018 // logd truncates at 4062.
1019 // strlen("Abort message: ''") is 17.
1020 // That's 4045, but we also want a NUL.
1021 char buf[4045 + 1];
1022 memset(buf, 'x', sizeof(buf));
1023 buf[sizeof(buf) - 1] = '\0';
1024 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001025 abort();
1026 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001027 StartIntercept(&output_fd);
1028 FinishCrasher();
1029 AssertDeath(SIGABRT);
1030 FinishIntercept(&intercept_result);
1031
1032 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1033
1034 std::string result;
1035 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001036 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001037}
1038
Christopher Ferrise8891452021-08-17 17:34:53 -07001039TEST_F(CrasherTest, abort_message_newline_trimmed) {
1040 int intercept_result;
1041 unique_fd output_fd;
1042 StartProcess([]() {
1043 android_set_abort_message("Message with a newline.\n");
1044 abort();
1045 });
1046 StartIntercept(&output_fd);
1047 FinishCrasher();
1048 AssertDeath(SIGABRT);
1049 FinishIntercept(&intercept_result);
1050
1051 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1052
1053 std::string result;
1054 ConsumeFd(std::move(output_fd), &result);
1055 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1056}
1057
1058TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1059 int intercept_result;
1060 unique_fd output_fd;
1061 StartProcess([]() {
1062 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1063 abort();
1064 });
1065 StartIntercept(&output_fd);
1066 FinishCrasher();
1067 AssertDeath(SIGABRT);
1068 FinishIntercept(&intercept_result);
1069
1070 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1071
1072 std::string result;
1073 ConsumeFd(std::move(output_fd), &result);
1074 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1075}
1076
Josh Gaoe06f2a42017-04-27 16:50:38 -07001077TEST_F(CrasherTest, abort_message_backtrace) {
1078 int intercept_result;
1079 unique_fd output_fd;
1080 StartProcess([]() {
1081 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001082 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001083 exit(0);
1084 });
1085 StartIntercept(&output_fd);
1086 FinishCrasher();
1087 AssertDeath(0);
1088 FinishIntercept(&intercept_result);
1089
1090 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1091
1092 std::string result;
1093 ConsumeFd(std::move(output_fd), &result);
1094 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1095}
1096
Josh Gaocbe70cb2016-10-18 18:17:52 -07001097TEST_F(CrasherTest, intercept_timeout) {
1098 int intercept_result;
1099 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001100 StartProcess([]() {
1101 abort();
1102 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001103 StartIntercept(&output_fd);
1104
1105 // Don't let crasher finish until we timeout.
1106 FinishIntercept(&intercept_result);
1107
1108 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1109 << intercept_result << ")";
1110
1111 FinishCrasher();
1112 AssertDeath(SIGABRT);
1113}
1114
Elliott Hughese4781d52021-03-17 09:15:15 -07001115TEST_F(CrasherTest, wait_for_debugger) {
1116 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1117 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001118 }
1119 sleep(1);
1120
Josh Gao502cfd22017-02-17 01:39:15 -08001121 StartProcess([]() {
1122 abort();
1123 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001124 FinishCrasher();
1125
1126 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001127 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001128 ASSERT_TRUE(WIFSTOPPED(status));
1129 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1130
1131 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1132
1133 AssertDeath(SIGABRT);
1134}
1135
Josh Gaocbe70cb2016-10-18 18:17:52 -07001136TEST_F(CrasherTest, backtrace) {
1137 std::string result;
1138 int intercept_result;
1139 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001140
1141 StartProcess([]() {
1142 abort();
1143 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001144 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001145
1146 std::this_thread::sleep_for(500ms);
1147
1148 sigval val;
1149 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001150 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001151 FinishIntercept(&intercept_result);
1152 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1153 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001154 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001155
1156 int status;
1157 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1158
1159 StartIntercept(&output_fd);
1160 FinishCrasher();
1161 AssertDeath(SIGABRT);
1162 FinishIntercept(&intercept_result);
1163 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1164 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001165 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001166}
Josh Gaofca7ca32017-01-23 12:05:35 -08001167
1168TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001169 int intercept_result;
1170 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001171 StartProcess([]() {
1172 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001173 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001174 });
Josh Gao502cfd22017-02-17 01:39:15 -08001175
1176 StartIntercept(&output_fd);
1177 FinishCrasher();
1178 AssertDeath(SIGABRT);
1179 FinishIntercept(&intercept_result);
1180
1181 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1182
1183 std::string result;
1184 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001185 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001186}
1187
Josh Gao502cfd22017-02-17 01:39:15 -08001188TEST_F(CrasherTest, capabilities) {
1189 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1190
Josh Gaofca7ca32017-01-23 12:05:35 -08001191 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001192 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1193 err(1, "failed to set PR_SET_KEEPCAPS");
1194 }
1195
1196 if (setresuid(1, 1, 1) != 0) {
1197 err(1, "setresuid failed");
1198 }
1199
1200 __user_cap_header_struct capheader;
1201 __user_cap_data_struct capdata[2];
1202 memset(&capheader, 0, sizeof(capheader));
1203 memset(&capdata, 0, sizeof(capdata));
1204
1205 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1206 capheader.pid = 0;
1207
1208 // Turn on every third capability.
1209 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1210 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1211 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1212 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1213 }
1214
1215 // Make sure CAP_SYS_PTRACE is off.
1216 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1217 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1218
1219 if (capset(&capheader, &capdata[0]) != 0) {
1220 err(1, "capset failed");
1221 }
1222
1223 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1224 err(1, "failed to drop ambient capabilities");
1225 }
1226
Josh Gaoa5199a92017-04-03 13:18:34 -07001227 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001228 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001229 });
Josh Gao502cfd22017-02-17 01:39:15 -08001230
1231 unique_fd output_fd;
1232 StartIntercept(&output_fd);
1233 FinishCrasher();
1234 AssertDeath(SIGSYS);
1235
1236 std::string result;
1237 int intercept_result;
1238 FinishIntercept(&intercept_result);
1239 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1240 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001241 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001242 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001243}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001244
Josh Gao2e7b8e22017-05-04 17:12:57 -07001245TEST_F(CrasherTest, fake_pid) {
1246 int intercept_result;
1247 unique_fd output_fd;
1248
1249 // Prime the getpid/gettid caches.
1250 UNUSED(getpid());
1251 UNUSED(gettid());
1252
1253 std::function<pid_t()> clone_fn = []() {
1254 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1255 };
1256 StartProcess(
1257 []() {
1258 ASSERT_NE(getpid(), syscall(__NR_getpid));
1259 ASSERT_NE(gettid(), syscall(__NR_gettid));
1260 raise(SIGSEGV);
1261 },
1262 clone_fn);
1263
1264 StartIntercept(&output_fd);
1265 FinishCrasher();
1266 AssertDeath(SIGSEGV);
1267 FinishIntercept(&intercept_result);
1268
1269 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1270
1271 std::string result;
1272 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001273 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001274}
1275
Josh Gaoe04ca272018-01-16 15:38:17 -08001276static const char* const kDebuggerdSeccompPolicy =
1277 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1278
Josh Gao70adac62018-02-22 11:38:33 -08001279static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001280 std::string policy;
1281 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1282 PLOG(FATAL) << "failed to read policy file";
1283 }
1284
1285 // Allow a bunch of syscalls used by the tests.
1286 policy += "\nclone: 1";
1287 policy += "\nsigaltstack: 1";
1288 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001289 policy += "\ngetrlimit: 1";
1290 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001291
1292 FILE* tmp_file = tmpfile();
1293 if (!tmp_file) {
1294 PLOG(FATAL) << "tmpfile failed";
1295 }
1296
Christopher Ferris172b0a02019-09-18 17:48:30 -07001297 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001298 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1299 PLOG(FATAL) << "failed to write policy to tmpfile";
1300 }
1301
1302 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1303 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001304 }
1305
1306 ScopedMinijail jail{minijail_new()};
1307 if (!jail) {
1308 LOG(FATAL) << "failed to create minijail";
1309 }
1310
1311 minijail_no_new_privs(jail.get());
1312 minijail_log_seccomp_filter_failures(jail.get());
1313 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001314 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001315
1316 pid_t result = fork();
1317 if (result == -1) {
1318 return result;
1319 } else if (result != 0) {
1320 return result;
1321 }
1322
1323 // Spawn and detach a thread that spins forever.
1324 std::atomic<bool> thread_ready(false);
1325 std::thread thread([&jail, &thread_ready]() {
1326 minijail_enter(jail.get());
1327 thread_ready = true;
1328 for (;;)
1329 ;
1330 });
1331 thread.detach();
1332
1333 while (!thread_ready) {
1334 continue;
1335 }
1336
Josh Gao70adac62018-02-22 11:38:33 -08001337 if (prejail) {
1338 prejail();
1339 }
1340
Josh Gaoe04ca272018-01-16 15:38:17 -08001341 minijail_enter(jail.get());
1342 return result;
1343}
1344
Josh Gao70adac62018-02-22 11:38:33 -08001345static pid_t seccomp_fork() {
1346 return seccomp_fork_impl(nullptr);
1347}
1348
Josh Gaoe04ca272018-01-16 15:38:17 -08001349TEST_F(CrasherTest, seccomp_crash) {
1350 int intercept_result;
1351 unique_fd output_fd;
1352
1353 StartProcess([]() { abort(); }, &seccomp_fork);
1354
1355 StartIntercept(&output_fd);
1356 FinishCrasher();
1357 AssertDeath(SIGABRT);
1358 FinishIntercept(&intercept_result);
1359 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1360
1361 std::string result;
1362 ConsumeFd(std::move(output_fd), &result);
1363 ASSERT_BACKTRACE_FRAME(result, "abort");
1364}
1365
Josh Gao70adac62018-02-22 11:38:33 -08001366static pid_t seccomp_fork_rlimit() {
1367 return seccomp_fork_impl([]() {
1368 struct rlimit rlim = {
1369 .rlim_cur = 512 * 1024 * 1024,
1370 .rlim_max = 512 * 1024 * 1024,
1371 };
1372
1373 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1374 raise(SIGINT);
1375 }
1376 });
1377}
1378
1379TEST_F(CrasherTest, seccomp_crash_oom) {
1380 int intercept_result;
1381 unique_fd output_fd;
1382
1383 StartProcess(
1384 []() {
1385 std::vector<void*> vec;
1386 for (int i = 0; i < 512; ++i) {
1387 char* buf = static_cast<char*>(malloc(1024 * 1024));
1388 if (!buf) {
1389 abort();
1390 }
1391 memset(buf, 0xff, 1024 * 1024);
1392 vec.push_back(buf);
1393 }
1394 },
1395 &seccomp_fork_rlimit);
1396
1397 StartIntercept(&output_fd);
1398 FinishCrasher();
1399 AssertDeath(SIGABRT);
1400 FinishIntercept(&intercept_result);
1401 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1402
1403 // We can't actually generate a backtrace, just make sure that the process terminates.
1404}
1405
Josh Gaoe04ca272018-01-16 15:38:17 -08001406__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1407 siginfo_t siginfo;
1408 siginfo.si_code = SI_QUEUE;
1409 siginfo.si_pid = getpid();
1410 siginfo.si_uid = getuid();
1411
1412 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1413 PLOG(FATAL) << "invalid dump type";
1414 }
1415
1416 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1417
Josh Gaoa48b41b2019-12-13 14:11:04 -08001418 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001419 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1420 return false;
1421 }
1422
1423 return true;
1424}
1425
Christopher Ferrisb999b822022-02-09 17:57:21 -08001426extern "C" void foo() {
1427 LOG(INFO) << "foo";
1428 std::this_thread::sleep_for(1s);
1429}
1430
1431extern "C" void bar() {
1432 LOG(INFO) << "bar";
1433 std::this_thread::sleep_for(1s);
1434}
1435
Josh Gaoe04ca272018-01-16 15:38:17 -08001436TEST_F(CrasherTest, seccomp_tombstone) {
1437 int intercept_result;
1438 unique_fd output_fd;
1439
1440 static const auto dump_type = kDebuggerdTombstone;
1441 StartProcess(
1442 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001443 std::thread a(foo);
1444 std::thread b(bar);
1445
1446 std::this_thread::sleep_for(100ms);
1447
Josh Gaoe04ca272018-01-16 15:38:17 -08001448 raise_debugger_signal(dump_type);
1449 _exit(0);
1450 },
1451 &seccomp_fork);
1452
1453 StartIntercept(&output_fd, dump_type);
1454 FinishCrasher();
1455 AssertDeath(0);
1456 FinishIntercept(&intercept_result);
1457 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1458
1459 std::string result;
1460 ConsumeFd(std::move(output_fd), &result);
1461 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001462 ASSERT_BACKTRACE_FRAME(result, "foo");
1463 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001464}
1465
Josh Gaoe04ca272018-01-16 15:38:17 -08001466TEST_F(CrasherTest, seccomp_backtrace) {
1467 int intercept_result;
1468 unique_fd output_fd;
1469
1470 static const auto dump_type = kDebuggerdNativeBacktrace;
1471 StartProcess(
1472 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001473 std::thread a(foo);
1474 std::thread b(bar);
1475
1476 std::this_thread::sleep_for(100ms);
1477
Josh Gaoe04ca272018-01-16 15:38:17 -08001478 raise_debugger_signal(dump_type);
1479 _exit(0);
1480 },
1481 &seccomp_fork);
1482
1483 StartIntercept(&output_fd, dump_type);
1484 FinishCrasher();
1485 AssertDeath(0);
1486 FinishIntercept(&intercept_result);
1487 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1488
1489 std::string result;
1490 ConsumeFd(std::move(output_fd), &result);
1491 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001492 ASSERT_BACKTRACE_FRAME(result, "foo");
1493 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001494}
1495
1496TEST_F(CrasherTest, seccomp_crash_logcat) {
1497 StartProcess([]() { abort(); }, &seccomp_fork);
1498 FinishCrasher();
1499
1500 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1501 AssertDeath(SIGABRT);
1502}
1503
Josh Gaofd13bf02017-08-18 15:37:26 -07001504TEST_F(CrasherTest, competing_tracer) {
1505 int intercept_result;
1506 unique_fd output_fd;
1507 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001508 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001509 });
1510
1511 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001512
1513 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001514 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001515
1516 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001517 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001518 ASSERT_TRUE(WIFSTOPPED(status));
1519 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1520
1521 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1522 FinishIntercept(&intercept_result);
1523 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1524
1525 std::string result;
1526 ConsumeFd(std::move(output_fd), &result);
1527 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1528 regex += std::to_string(gettid());
1529 regex += R"( \(.+debuggerd_test)";
1530 ASSERT_MATCH(result, regex.c_str());
1531
Christopher Ferris172b0a02019-09-18 17:48:30 -07001532 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001533 ASSERT_TRUE(WIFSTOPPED(status));
1534 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1535
Josh Gaofd13bf02017-08-18 15:37:26 -07001536 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1537 AssertDeath(SIGABRT);
1538}
1539
Josh Gaobf06a402018-08-27 16:34:01 -07001540TEST_F(CrasherTest, fdsan_warning_abort_message) {
1541 int intercept_result;
1542 unique_fd output_fd;
1543
1544 StartProcess([]() {
1545 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001546 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001547 if (fd == -1) {
1548 abort();
1549 }
1550 close(fd.get());
1551 _exit(0);
1552 });
1553
1554 StartIntercept(&output_fd);
1555 FinishCrasher();
1556 AssertDeath(0);
1557 FinishIntercept(&intercept_result);
1558 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1559
1560 std::string result;
1561 ConsumeFd(std::move(output_fd), &result);
1562 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1563}
1564
Josh Gaoc3c8c022017-02-13 16:36:18 -08001565TEST(crash_dump, zombie) {
1566 pid_t forkpid = fork();
1567
Josh Gaoc3c8c022017-02-13 16:36:18 -08001568 pid_t rc;
1569 int status;
1570
1571 if (forkpid == 0) {
1572 errno = 0;
1573 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1574 if (rc != -1 || errno != ECHILD) {
1575 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1576 }
1577
Josh Gaoa48b41b2019-12-13 14:11:04 -08001578 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001579
1580 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001581 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001582 if (rc != -1 || errno != ECHILD) {
1583 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1584 }
1585 _exit(0);
1586 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001587 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001588 ASSERT_EQ(forkpid, rc);
1589 ASSERT_TRUE(WIFEXITED(status));
1590 ASSERT_EQ(0, WEXITSTATUS(status));
1591 }
1592}
Josh Gao352a8452017-03-30 16:46:21 -07001593
1594TEST(tombstoned, no_notify) {
1595 // Do this a few times.
1596 for (int i = 0; i < 3; ++i) {
1597 pid_t pid = 123'456'789 + i;
1598
1599 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001600 InterceptStatus status;
1601 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1602 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001603
1604 {
1605 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001606 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001607 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1608 }
1609
1610 pid_t read_pid;
1611 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1612 ASSERT_EQ(read_pid, pid);
1613 }
1614}
1615
1616TEST(tombstoned, stress) {
1617 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1618 static constexpr int kDumpCount = 100;
1619
1620 std::atomic<bool> start(false);
1621 std::vector<std::thread> threads;
1622 threads.emplace_back([&start]() {
1623 while (!start) {
1624 continue;
1625 }
1626
1627 // Use a way out of range pid, to avoid stomping on an actual process.
1628 pid_t pid_base = 1'000'000;
1629
1630 for (int dump = 0; dump < kDumpCount; ++dump) {
1631 pid_t pid = pid_base + dump;
1632
1633 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001634 InterceptStatus status;
1635 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1636 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001637
1638 // Pretend to crash, and then immediately close the socket.
1639 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1640 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1641 if (sockfd == -1) {
1642 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1643 }
1644 TombstonedCrashPacket packet = {};
1645 packet.packet_type = CrashPacketType::kDumpRequest;
1646 packet.packet.dump_request.pid = pid;
1647 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1648 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1649 }
1650
1651 continue;
1652 }
1653 });
1654
1655 threads.emplace_back([&start]() {
1656 while (!start) {
1657 continue;
1658 }
1659
1660 // Use a way out of range pid, to avoid stomping on an actual process.
1661 pid_t pid_base = 2'000'000;
1662
1663 for (int dump = 0; dump < kDumpCount; ++dump) {
1664 pid_t pid = pid_base + dump;
1665
1666 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001667 InterceptStatus status;
1668 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1669 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001670
1671 {
1672 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001673 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001674 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1675 tombstoned_notify_completion(tombstoned_socket.get());
1676 }
1677
1678 // TODO: Fix the race that requires this sleep.
1679 std::this_thread::sleep_for(50ms);
1680
1681 pid_t read_pid;
1682 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1683 ASSERT_EQ(read_pid, pid);
1684 }
1685 });
1686
1687 start = true;
1688
1689 for (std::thread& thread : threads) {
1690 thread.join();
1691 }
1692}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001693
1694TEST(tombstoned, java_trace_intercept_smoke) {
1695 // Using a "real" PID is a little dangerous here - if the test fails
1696 // or crashes, we might end up getting a bogus / unreliable stack
1697 // trace.
1698 const pid_t self = getpid();
1699
1700 unique_fd intercept_fd, output_fd;
1701 InterceptStatus status;
1702 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1703 ASSERT_EQ(InterceptStatus::kRegistered, status);
1704
Josh Gao76e1e302021-01-26 15:53:11 -08001705 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001706 // should result in a "regular" FD and not the installed intercept.
1707 const char native[] = "native";
1708 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001709 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001710 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1711 tombstoned_notify_completion(tombstoned_socket.get());
1712
1713 // Then, connect to tombstoned asking for a java backtrace. This *should*
1714 // trigger the intercept.
1715 const char java[] = "java";
1716 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1717 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1718 tombstoned_notify_completion(tombstoned_socket.get());
1719
1720 char outbuf[sizeof(java)];
1721 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1722 ASSERT_STREQ("java", outbuf);
1723}
1724
1725TEST(tombstoned, multiple_intercepts) {
1726 const pid_t fake_pid = 1'234'567;
1727 unique_fd intercept_fd, output_fd;
1728 InterceptStatus status;
1729 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1730 ASSERT_EQ(InterceptStatus::kRegistered, status);
1731
1732 unique_fd intercept_fd_2, output_fd_2;
1733 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1734 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1735}
1736
1737TEST(tombstoned, intercept_any) {
1738 const pid_t fake_pid = 1'234'567;
1739
1740 unique_fd intercept_fd, output_fd;
1741 InterceptStatus status;
1742 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1743 ASSERT_EQ(InterceptStatus::kRegistered, status);
1744
1745 const char any[] = "any";
1746 unique_fd tombstoned_socket, input_fd;
1747 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1748 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1749 tombstoned_notify_completion(tombstoned_socket.get());
1750
1751 char outbuf[sizeof(any)];
1752 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1753 ASSERT_STREQ("any", outbuf);
1754}
Josh Gao2b22ae12018-09-12 14:51:03 -07001755
1756TEST(tombstoned, interceptless_backtrace) {
1757 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1758 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1759 std::map<int, time_t> result;
1760 for (int i = 0; i < 99; ++i) {
1761 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1762 struct stat st;
1763 if (stat(path.c_str(), &st) == 0) {
1764 result[i] = st.st_mtim.tv_sec;
1765 }
1766 }
1767 return result;
1768 };
1769
1770 auto before = get_tombstone_timestamps();
1771 for (int i = 0; i < 50; ++i) {
1772 raise_debugger_signal(kDebuggerdNativeBacktrace);
1773 }
1774 auto after = get_tombstone_timestamps();
1775
1776 int diff = 0;
1777 for (int i = 0; i < 99; ++i) {
1778 if (after.count(i) == 0) {
1779 continue;
1780 }
1781 if (before.count(i) == 0) {
1782 ++diff;
1783 continue;
1784 }
1785 if (before[i] != after[i]) {
1786 ++diff;
1787 }
1788 }
1789
1790 // We can't be sure that nothing's crash looping in the background.
1791 // This should be good enough, though...
1792 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1793}
Christopher Ferris481e8372019-07-15 17:13:24 -07001794
1795static __attribute__((__noinline__)) void overflow_stack(void* p) {
1796 void* buf[1];
1797 buf[0] = p;
1798 static volatile void* global = buf;
1799 if (global) {
1800 global = buf;
1801 overflow_stack(&buf);
1802 }
1803}
1804
1805TEST_F(CrasherTest, stack_overflow) {
1806 int intercept_result;
1807 unique_fd output_fd;
1808 StartProcess([]() { overflow_stack(nullptr); });
1809
1810 StartIntercept(&output_fd);
1811 FinishCrasher();
1812 AssertDeath(SIGSEGV);
1813 FinishIntercept(&intercept_result);
1814
1815 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1816
1817 std::string result;
1818 ConsumeFd(std::move(output_fd), &result);
1819 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1820}
Josh Gao76e1e302021-01-26 15:53:11 -08001821
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001822static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1823 std::string test_lib(testing::internal::GetArgvs()[0]);
1824 auto const value = test_lib.find_last_of('/');
1825 if (value == std::string::npos) {
1826 test_lib = "./";
1827 } else {
1828 test_lib = test_lib.substr(0, value + 1) + "./";
1829 }
1830 test_lib += "libcrash_test.so";
1831
1832 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1833 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1834
1835 // Copy the shared so to a tempory directory.
1836 return system(cp_cmd.c_str()) == 0;
1837}
1838
1839TEST_F(CrasherTest, unreadable_elf) {
1840 int intercept_result;
1841 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001842 std::string tmp_so_name;
1843 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001844 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001845 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1846 _exit(1);
1847 }
1848 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1849 if (handle == nullptr) {
1850 _exit(1);
1851 }
1852 // Delete the original shared library so that we get the warning
1853 // about unreadable elf files.
1854 if (unlink(tmp_so_name.c_str()) == -1) {
1855 _exit(1);
1856 }
1857 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1858 if (crash_func == nullptr) {
1859 _exit(1);
1860 }
1861 crash_func();
1862 });
1863
1864 StartIntercept(&output_fd);
1865 FinishCrasher();
1866 AssertDeath(SIGSEGV);
1867 FinishIntercept(&intercept_result);
1868
1869 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1870
1871 std::string result;
1872 ConsumeFd(std::move(output_fd), &result);
1873 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001874 std::string match_str = "NOTE: " + tmp_so_name;
1875 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001876}
1877
Josh Gao76e1e302021-01-26 15:53:11 -08001878TEST(tombstoned, proto) {
1879 const pid_t self = getpid();
1880 unique_fd tombstoned_socket, text_fd, proto_fd;
1881 ASSERT_TRUE(
1882 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1883
1884 tombstoned_notify_completion(tombstoned_socket.get());
1885
1886 ASSERT_NE(-1, text_fd.get());
1887 ASSERT_NE(-1, proto_fd.get());
1888
1889 struct stat text_st;
1890 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1891
1892 // Give tombstoned some time to link the files into place.
1893 std::this_thread::sleep_for(100ms);
1894
1895 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001896 std::optional<std::string> tombstone_file;
1897 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1898 ASSERT_TRUE(dir_h != nullptr);
1899 std::regex tombstone_re("tombstone_\\d+");
1900 dirent* entry;
1901 while ((entry = readdir(dir_h.get())) != nullptr) {
1902 if (!std::regex_match(entry->d_name, tombstone_re)) {
1903 continue;
1904 }
1905 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001906
1907 struct stat st;
1908 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1909 continue;
1910 }
1911
1912 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001913 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001914 break;
1915 }
1916 }
1917
Christopher Ferris35da2882021-02-17 15:39:06 -08001918 ASSERT_TRUE(tombstone_file);
1919 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001920
1921 struct stat proto_fd_st;
1922 struct stat proto_file_st;
1923 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1924 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1925
1926 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1927 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1928}
1929
1930TEST(tombstoned, proto_intercept) {
1931 const pid_t self = getpid();
1932 unique_fd intercept_fd, output_fd;
1933 InterceptStatus status;
1934
1935 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1936 ASSERT_EQ(InterceptStatus::kRegistered, status);
1937
1938 unique_fd tombstoned_socket, text_fd, proto_fd;
1939 ASSERT_TRUE(
1940 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1941 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1942 tombstoned_notify_completion(tombstoned_socket.get());
1943
1944 text_fd.reset();
1945
1946 std::string output;
1947 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1948 ASSERT_EQ("foo", output);
1949}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001950
1951// Verify that when an intercept is present for the main thread, and the signal
1952// is received on a different thread, the intercept still works.
1953TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1954 StartProcess([]() {
1955 std::thread thread([]() {
1956 // Raise the signal on the side thread.
1957 raise_debugger_signal(kDebuggerdNativeBacktrace);
1958 });
1959 thread.join();
1960 _exit(0);
1961 });
1962
1963 unique_fd output_fd;
1964 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1965 FinishCrasher();
1966 AssertDeath(0);
1967
1968 int intercept_result;
1969 FinishIntercept(&intercept_result);
1970 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1971
1972 std::string result;
1973 ConsumeFd(std::move(output_fd), &result);
1974 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1975}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001976
1977static std::string format_pointer(uintptr_t ptr) {
1978#if defined(__LP64__)
1979 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1980 static_cast<uint32_t>(ptr & 0xffffffff));
1981#else
1982 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1983#endif
1984}
1985
1986static std::string format_pointer(void* ptr) {
1987 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1988}
1989
1990static std::string format_full_pointer(uintptr_t ptr) {
1991#if defined(__LP64__)
1992 return android::base::StringPrintf("%016" PRIx64, ptr);
1993#else
1994 return android::base::StringPrintf("%08x", ptr);
1995#endif
1996}
1997
1998static std::string format_full_pointer(void* ptr) {
1999 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2000}
2001
2002__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2003 int* crash_ptr = reinterpret_cast<int*>(ptr);
2004 *crash_ptr = 1;
2005 return *crash_ptr;
2006}
2007
2008// Verify that a fault address before the first map is properly handled.
2009TEST_F(CrasherTest, fault_address_before_first_map) {
2010 StartProcess([]() {
2011 ASSERT_EQ(0, crash_call(0x1024));
2012 _exit(0);
2013 });
2014
2015 unique_fd output_fd;
2016 StartIntercept(&output_fd);
2017 FinishCrasher();
2018 AssertDeath(SIGSEGV);
2019
2020 int intercept_result;
2021 FinishIntercept(&intercept_result);
2022 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2023
2024 std::string result;
2025 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002026 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002027
2028 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2029
2030 std::string match_str = android::base::StringPrintf(
2031 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2032 format_pointer(0x1024).c_str());
2033 ASSERT_MATCH(result, match_str);
2034}
2035
2036// Verify that a fault address after the last map is properly handled.
2037TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002038 // This makes assumptions about the memory layout that are not true in HWASan
2039 // processes.
2040 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002041 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2042 StartProcess([crash_uptr]() {
2043 ASSERT_EQ(0, crash_call(crash_uptr));
2044 _exit(0);
2045 });
2046
2047 unique_fd output_fd;
2048 StartIntercept(&output_fd);
2049 FinishCrasher();
2050 AssertDeath(SIGSEGV);
2051
2052 int intercept_result;
2053 FinishIntercept(&intercept_result);
2054 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2055
2056 std::string result;
2057 ConsumeFd(std::move(output_fd), &result);
2058
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002059 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2060 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002061 ASSERT_MATCH(result, match_str);
2062
2063 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2064
2065 // Assumes that the open files section comes after the map section.
2066 // If that assumption changes, the regex below needs to change.
2067 match_str = android::base::StringPrintf(
2068 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2069 format_pointer(crash_uptr).c_str());
2070 ASSERT_MATCH(result, match_str);
2071}
2072
2073// Verify that a fault address between maps is properly handled.
2074TEST_F(CrasherTest, fault_address_between_maps) {
2075 // Create a map before the fork so it will be present in the child.
2076 void* start_ptr =
2077 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2078 ASSERT_NE(MAP_FAILED, start_ptr);
2079 // Unmap the page in the middle.
2080 void* middle_ptr =
2081 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2082 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2083
2084 StartProcess([middle_ptr]() {
2085 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2086 _exit(0);
2087 });
2088
2089 // Unmap the two maps.
2090 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2091 void* end_ptr =
2092 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2093 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2094
2095 unique_fd output_fd;
2096 StartIntercept(&output_fd);
2097 FinishCrasher();
2098 AssertDeath(SIGSEGV);
2099
2100 int intercept_result;
2101 FinishIntercept(&intercept_result);
2102 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2103
2104 std::string result;
2105 ConsumeFd(std::move(output_fd), &result);
2106
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002107 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2108 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002109 ASSERT_MATCH(result, match_str);
2110
2111 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2112
2113 match_str = android::base::StringPrintf(
2114 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2115 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2116 format_pointer(end_ptr).c_str());
2117 ASSERT_MATCH(result, match_str);
2118}
2119
2120// Verify that a fault address happens in the correct map.
2121TEST_F(CrasherTest, fault_address_in_map) {
2122 // Create a map before the fork so it will be present in the child.
2123 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2124 ASSERT_NE(MAP_FAILED, ptr);
2125
2126 StartProcess([ptr]() {
2127 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2128 _exit(0);
2129 });
2130
2131 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2132
2133 unique_fd output_fd;
2134 StartIntercept(&output_fd);
2135 FinishCrasher();
2136 AssertDeath(SIGSEGV);
2137
2138 int intercept_result;
2139 FinishIntercept(&intercept_result);
2140 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2141
2142 std::string result;
2143 ConsumeFd(std::move(output_fd), &result);
2144
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002145 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2146 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002147 ASSERT_MATCH(result, match_str);
2148
2149 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2150
2151 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2152 ASSERT_MATCH(result, match_str);
2153}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002154
2155static constexpr uint32_t kDexData[] = {
2156 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2157 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2158 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2159 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2160 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2161 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2162 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2163 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2164 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2165 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2166 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2167 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2168 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2169 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2170 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2171 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2172 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2173};
2174
2175TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2176 StartProcess([]() {
2177 TemporaryDir td;
2178 std::string tmp_so_name;
2179 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2180 _exit(1);
2181 }
2182
2183 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2184 // move the library to which has a basename of libart.so.
2185 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2186 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2187 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2188 if (handle == nullptr) {
2189 _exit(1);
2190 }
2191
2192 void* ptr =
2193 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2194 ASSERT_TRUE(ptr != MAP_FAILED);
2195 memcpy(ptr, kDexData, sizeof(kDexData));
2196 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2197
2198 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2199 .symfile_size = sizeof(kDexData)};
2200
2201 JITDescriptor* dex_debug =
2202 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2203 ASSERT_TRUE(dex_debug != nullptr);
2204 dex_debug->version = 1;
2205 dex_debug->action_flag = 0;
2206 dex_debug->relevant_entry = 0;
2207 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2208
2209 // This sets the magic dex pc value for register 0, using the value
2210 // of register 1 + 0x102.
2211 asm(".cfi_escape "
2212 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2213 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2214 "0x13 /* DW_OP_drop */,"
2215 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2216
2217 // For each different architecture, set register one to the dex ptr mmap
2218 // created above. Then do a nullptr dereference to force a crash.
2219#if defined(__arm__)
2220 asm volatile(
2221 "mov r1, %[base]\n"
2222 "mov r2, 0\n"
2223 "str r3, [r2]\n"
2224 : [base] "+r"(ptr)
2225 :
2226 : "r1", "r2", "r3", "memory");
2227#elif defined(__aarch64__)
2228 asm volatile(
2229 "mov x1, %[base]\n"
2230 "mov x2, 0\n"
2231 "str x3, [x2]\n"
2232 : [base] "+r"(ptr)
2233 :
2234 : "x1", "x2", "x3", "memory");
2235#elif defined(__i386__)
2236 asm volatile(
2237 "mov %[base], %%ecx\n"
2238 "movl $0, %%edi\n"
2239 "movl 0(%%edi), %%edx\n"
2240 : [base] "+r"(ptr)
2241 :
2242 : "edi", "ecx", "edx", "memory");
2243#elif defined(__x86_64__)
2244 asm volatile(
2245 "mov %[base], %%rdx\n"
2246 "movq 0, %%rdi\n"
2247 "movq 0(%%rdi), %%rcx\n"
2248 : [base] "+r"(ptr)
2249 :
2250 : "rcx", "rdx", "rdi", "memory");
2251#else
2252#error "Unsupported architecture"
2253#endif
2254 _exit(0);
2255 });
2256
2257 unique_fd output_fd;
2258 StartIntercept(&output_fd);
2259 FinishCrasher();
2260 AssertDeath(SIGSEGV);
2261
2262 int intercept_result;
2263 FinishIntercept(&intercept_result);
2264 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2265
2266 std::string result;
2267 ConsumeFd(std::move(output_fd), &result);
2268
2269 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002270 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002271
2272 // Now verify that the dex_pc frame includes a proper function name.
2273 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2274}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002275
2276static std::string format_map_pointer(uintptr_t ptr) {
2277#if defined(__LP64__)
2278 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2279 static_cast<uint32_t>(ptr & 0xffffffff));
2280#else
2281 return android::base::StringPrintf("%08x", ptr);
2282#endif
2283}
2284
2285// Verify that map data is properly formatted.
2286TEST_F(CrasherTest, verify_map_format) {
2287 // Create multiple maps to make sure that the map data is formatted properly.
2288 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2289 ASSERT_NE(MAP_FAILED, none_map);
2290 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2291 ASSERT_NE(MAP_FAILED, r_map);
2292 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2293 ASSERT_NE(MAP_FAILED, w_map);
2294 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2295 ASSERT_NE(MAP_FAILED, x_map);
2296
2297 TemporaryFile tf;
2298 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2299 char c = 'f';
2300 ASSERT_EQ(1, write(tf.fd, &c, 1));
2301 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2302 ASSERT_EQ(1, write(tf.fd, &c, 1));
2303 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2304 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2305 ASSERT_NE(MAP_FAILED, file_map);
2306
2307 StartProcess([]() { abort(); });
2308
2309 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2310 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2311 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2312 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2313 ASSERT_EQ(0, munmap(file_map, 0x3001));
2314
2315 unique_fd output_fd;
2316 StartIntercept(&output_fd);
2317 FinishCrasher();
2318 AssertDeath(SIGABRT);
2319 int intercept_result;
2320 FinishIntercept(&intercept_result);
2321
2322 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2323
2324 std::string result;
2325 ConsumeFd(std::move(output_fd), &result);
2326
2327 std::string match_str;
2328 // Verify none.
2329 match_str = android::base::StringPrintf(
2330 " %s-%s --- 0 1000\\n",
2331 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2332 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2333 ASSERT_MATCH(result, match_str);
2334
2335 // Verify read-only.
2336 match_str = android::base::StringPrintf(
2337 " %s-%s r-- 0 1000\\n",
2338 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2339 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2340 ASSERT_MATCH(result, match_str);
2341
2342 // Verify write-only.
2343 match_str = android::base::StringPrintf(
2344 " %s-%s -w- 0 1000\\n",
2345 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2346 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2347 ASSERT_MATCH(result, match_str);
2348
2349 // Verify exec-only.
2350 match_str = android::base::StringPrintf(
2351 " %s-%s --x 0 1000\\n",
2352 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2353 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2354 ASSERT_MATCH(result, match_str);
2355
2356 // Verify file map with non-zero offset and a name.
2357 match_str = android::base::StringPrintf(
2358 " %s-%s r-- 2000 4000 %s\\n",
2359 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2360 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2361 ASSERT_MATCH(result, match_str);
2362}
2363
2364// Verify that the tombstone map data is correct.
2365TEST_F(CrasherTest, verify_header) {
2366 StartProcess([]() { abort(); });
2367
2368 unique_fd output_fd;
2369 StartIntercept(&output_fd);
2370 FinishCrasher();
2371 AssertDeath(SIGABRT);
2372 int intercept_result;
2373 FinishIntercept(&intercept_result);
2374
2375 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2376
2377 std::string result;
2378 ConsumeFd(std::move(output_fd), &result);
2379
2380 std::string match_str = android::base::StringPrintf(
2381 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2382 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2383 android::base::GetProperty("ro.revision", "unknown").c_str());
2384 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2385 ASSERT_MATCH(result, match_str);
2386}
2387
2388// Verify that the thread header is formatted properly.
2389TEST_F(CrasherTest, verify_thread_header) {
2390 void* shared_map =
2391 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2392 ASSERT_NE(MAP_FAILED, shared_map);
2393 memset(shared_map, 0, sizeof(pid_t));
2394
2395 StartProcess([&shared_map]() {
2396 std::atomic_bool tid_written;
2397 std::thread thread([&tid_written, &shared_map]() {
2398 pid_t tid = gettid();
2399 memcpy(shared_map, &tid, sizeof(pid_t));
2400 tid_written = true;
2401 volatile bool done = false;
2402 while (!done)
2403 ;
2404 });
2405 thread.detach();
2406 while (!tid_written.load(std::memory_order_acquire))
2407 ;
2408 abort();
2409 });
2410
2411 pid_t primary_pid = crasher_pid;
2412
2413 unique_fd output_fd;
2414 StartIntercept(&output_fd);
2415 FinishCrasher();
2416 AssertDeath(SIGABRT);
2417 int intercept_result;
2418 FinishIntercept(&intercept_result);
2419 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2420
2421 // Read the tid data out.
2422 pid_t tid;
2423 memcpy(&tid, shared_map, sizeof(pid_t));
2424 ASSERT_NE(0, tid);
2425
2426 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2427
2428 std::string result;
2429 ConsumeFd(std::move(output_fd), &result);
2430
2431 // Verify that there are two headers, one where the tid is "primary_pid"
2432 // and the other where the tid is "tid".
2433 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2434 primary_pid, primary_pid);
2435 ASSERT_MATCH(result, match_str);
2436
2437 match_str =
2438 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2439 ASSERT_MATCH(result, match_str);
2440}
2441
2442// Verify that there is a BuildID present in the map section and set properly.
2443TEST_F(CrasherTest, verify_build_id) {
2444 StartProcess([]() { abort(); });
2445
2446 unique_fd output_fd;
2447 StartIntercept(&output_fd);
2448 FinishCrasher();
2449 AssertDeath(SIGABRT);
2450 int intercept_result;
2451 FinishIntercept(&intercept_result);
2452 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2453
2454 std::string result;
2455 ConsumeFd(std::move(output_fd), &result);
2456
2457 // Find every /system or /apex lib and verify the BuildID is displayed
2458 // properly.
2459 bool found_valid_elf = false;
2460 std::smatch match;
2461 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2462 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2463 result = match.suffix()) {
2464 if (prev_file == match[1]) {
2465 // Already checked this file.
2466 continue;
2467 }
2468
2469 prev_file = match[1];
2470 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2471 if (!elf.Init() || !elf.valid()) {
2472 // Skipping invalid elf files.
2473 continue;
2474 }
2475 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2476
2477 found_valid_elf = true;
2478 }
2479 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2480}