blob: 9c1b1361dc27649bd73533cd5071633a6160dff2 [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
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700409void CrasherTest::Trap(void* ptr) {
410 void (*volatile f)(void*) = nullptr;
411 __asm__ __volatile__("" : : "r"(f) : "memory");
412 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700413}
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:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800448#elif defined(__riscv)
449 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700450#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800451 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700452#else
453 ASSERT_TRUE(false) << "unsupported architecture";
454#endif
455}
456
Peter Collingbournecd278072020-12-21 14:08:38 -0800457#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700458static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800459 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700460 abort();
461 }
462}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800463
464static void SetTagCheckingLevelAsync() {
465 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
466 abort();
467 }
468}
Peter Collingbournef8622522020-04-07 14:07:32 -0700469#endif
470
Mitch Phillips7168a212021-03-09 16:53:23 -0800471// Number of iterations required to reliably guarantee a GWP-ASan crash.
472// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
473// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
474// the counter reaches zero, we provide a sampled allocation. Then, double that
475// figure to allow for left/right allocation alignment, as this is done randomly
476// without bias.
477#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
478
479struct GwpAsanTestParameters {
480 size_t alloc_size;
481 bool free_before_access;
482 int access_offset;
483 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
484};
485
486struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
487
488GwpAsanTestParameters gwp_asan_tests[] = {
489 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
490 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
491 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
492 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
493};
494
495INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
496
497TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
498 if (mte_supported()) {
499 // Skip this test on MTE hardware, as MTE will reliably catch these errors
500 // instead of GWP-ASan.
501 GTEST_SKIP() << "Skipped on MTE.";
502 }
Florian Mayerb4979292022-04-15 14:35:17 -0700503 // Skip this test on HWASan, which will reliably catch test errors as well.
504 SKIP_WITH_HWASAN;
Mitch Phillips7168a212021-03-09 16:53:23 -0800505
506 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700507 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800508
509 int intercept_result;
510 unique_fd output_fd;
511 StartProcess([&params]() {
512 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
513 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
514 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
515 p[params.access_offset] = 42;
516 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
517 }
518 });
519
520 StartIntercept(&output_fd);
521 FinishCrasher();
522 AssertDeath(SIGSEGV);
523 FinishIntercept(&intercept_result);
524
525 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
526
Mitch Phillips78f06702021-06-01 14:35:43 -0700527 std::vector<std::string> log_sources(2);
528 ConsumeFd(std::move(output_fd), &log_sources[0]);
529 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800530
Mitch Phillips78f06702021-06-01 14:35:43 -0700531 for (const auto& result : log_sources) {
532 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
533 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
534 if (params.free_before_access) {
535 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
536 }
537 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800538 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800539}
540
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800541struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
542
Peter Collingbourneaa544792021-05-13 13:53:37 -0700543INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800544
545TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800546#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700547 if (!mte_supported()) {
548 GTEST_SKIP() << "Requires MTE";
549 }
550
Peter Collingbourneaa544792021-05-13 13:53:37 -0700551 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
552 if (GetParam() == 0) {
553 return;
554 }
555
Mitch Phillips78f06702021-06-01 14:35:43 -0700556 LogcatCollector logcat_collector;
557
Peter Collingbournef8622522020-04-07 14:07:32 -0700558 int intercept_result;
559 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800560 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700561 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800562 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700563 free((void *)p);
564 p[0] = 42;
565 });
566
567 StartIntercept(&output_fd);
568 FinishCrasher();
569 AssertDeath(SIGSEGV);
570 FinishIntercept(&intercept_result);
571
572 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
573
Mitch Phillips78f06702021-06-01 14:35:43 -0700574 std::vector<std::string> log_sources(2);
575 ConsumeFd(std::move(output_fd), &log_sources[0]);
576 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700577 // Tag dump only available in the tombstone, not logcat.
578 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700579
Mitch Phillips78f06702021-06-01 14:35:43 -0700580 for (const auto& result : log_sources) {
581 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
582 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
583 std::to_string(GetParam()) + R"(-byte allocation)");
584 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
585 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
586 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700587#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800588 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700589#endif
590}
591
Peter Collingbournedc476342021-05-12 15:56:43 -0700592TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
593#if defined(__aarch64__)
594 if (!mte_supported()) {
595 GTEST_SKIP() << "Requires MTE";
596 }
597
598 int intercept_result;
599 unique_fd output_fd;
600 StartProcess([&]() {
601 SetTagCheckingLevelSync();
602 volatile int* p = (volatile int*)malloc(GetParam());
603 free((void *)p);
604 p[-1] = 42;
605 });
606
607 StartIntercept(&output_fd);
608 FinishCrasher();
609 AssertDeath(SIGSEGV);
610 FinishIntercept(&intercept_result);
611
612 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
613
614 std::string result;
615 ConsumeFd(std::move(output_fd), &result);
616
617 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
618 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
619#else
620 GTEST_SKIP() << "Requires aarch64";
621#endif
622}
623
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800624TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800625#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700626 if (!mte_supported()) {
627 GTEST_SKIP() << "Requires MTE";
628 }
629
Mitch Phillips78f06702021-06-01 14:35:43 -0700630 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700631 int intercept_result;
632 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800633 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700634 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800635 volatile char* p = (volatile char*)malloc(GetParam());
636 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700637 });
638
639 StartIntercept(&output_fd);
640 FinishCrasher();
641 AssertDeath(SIGSEGV);
642 FinishIntercept(&intercept_result);
643
644 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
645
Mitch Phillips78f06702021-06-01 14:35:43 -0700646 std::vector<std::string> log_sources(2);
647 ConsumeFd(std::move(output_fd), &log_sources[0]);
648 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700649
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700650 // Tag dump only in tombstone, not logcat, and tagging is not used for
651 // overflow protection in the scudo secondary (guard pages are used instead).
652 if (GetParam() < 0x10000) {
653 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
654 }
655
Mitch Phillips78f06702021-06-01 14:35:43 -0700656 for (const auto& result : log_sources) {
657 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
658 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
659 std::to_string(GetParam()) + R"(-byte allocation)");
660 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
661 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700662#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800663 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700664#endif
665}
666
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800667TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800668#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700669 if (!mte_supported()) {
670 GTEST_SKIP() << "Requires MTE";
671 }
672
673 int intercept_result;
674 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800675 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700676 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800677 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700678 p[-1] = 42;
679 });
680
681 StartIntercept(&output_fd);
682 FinishCrasher();
683 AssertDeath(SIGSEGV);
684 FinishIntercept(&intercept_result);
685
686 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
687
688 std::string result;
689 ConsumeFd(std::move(output_fd), &result);
690
691 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800692 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800693 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700694 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700695 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700696 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700697#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800698 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700699#endif
700}
701
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800702TEST_F(CrasherTest, mte_async) {
703#if defined(__aarch64__)
704 if (!mte_supported()) {
705 GTEST_SKIP() << "Requires MTE";
706 }
707
708 int intercept_result;
709 unique_fd output_fd;
710 StartProcess([&]() {
711 SetTagCheckingLevelAsync();
712 volatile int* p = (volatile int*)malloc(16);
713 p[-1] = 42;
714 });
715
716 StartIntercept(&output_fd);
717 FinishCrasher();
718 AssertDeath(SIGSEGV);
719 FinishIntercept(&intercept_result);
720
721 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
722
723 std::string result;
724 ConsumeFd(std::move(output_fd), &result);
725
726 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
727#else
728 GTEST_SKIP() << "Requires aarch64";
729#endif
730}
731
Peter Collingbournef8622522020-04-07 14:07:32 -0700732TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800733#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700734 if (!mte_supported()) {
735 GTEST_SKIP() << "Requires MTE";
736 }
737
Mitch Phillips78f06702021-06-01 14:35:43 -0700738 LogcatCollector logcat_collector;
739
Peter Collingbournef8622522020-04-07 14:07:32 -0700740 int intercept_result;
741 unique_fd output_fd;
742 StartProcess([]() {
743 SetTagCheckingLevelSync();
744
745 // Make two allocations with the same tag and close to one another. Check for both properties
746 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
747 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
748 // (some non-zero value << 56) apart.
749 //
750 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
751 // other.
752 std::set<uintptr_t> allocs;
753 for (int i = 0; i != 4096; ++i) {
754 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
755 auto it = allocs.insert(alloc).first;
756 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
757 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
758 }
759 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
760 *reinterpret_cast<int*>(alloc + 16) = 42;
761 }
762 }
763 });
764
765 StartIntercept(&output_fd);
766 FinishCrasher();
767 AssertDeath(SIGSEGV);
768 FinishIntercept(&intercept_result);
769
770 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
771
Mitch Phillips78f06702021-06-01 14:35:43 -0700772 std::vector<std::string> log_sources(2);
773 ConsumeFd(std::move(output_fd), &log_sources[0]);
774 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700775
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700776 // Tag dump only in the tombstone, not logcat.
777 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
778
Mitch Phillips78f06702021-06-01 14:35:43 -0700779 for (const auto& result : log_sources) {
780 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
781 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800782 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700783 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
784 // overflows), so we can't match explicitly for an underflow message.
785 ASSERT_MATCH(result,
786 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
787 // Ensure there's at least two allocation traces (one for each cause).
788 ASSERT_MATCH(
789 result,
790 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
791 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700792#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800793 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700794#endif
795}
796
Peter Collingbournecd278072020-12-21 14:08:38 -0800797#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700798static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700799 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
800 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
801 size_t page_size = getpagesize();
802 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
803 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
804 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700805 return 0;
806 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700807 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
808 PROT_READ | PROT_WRITE | PROT_MTE);
809 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
810 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
811 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
812 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
813 }
814 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700815}
816#endif
817
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700818TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800819#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700820 if (!mte_supported()) {
821 GTEST_SKIP() << "Requires MTE";
822 }
823
824 int intercept_result;
825 unique_fd output_fd;
826 StartProcess([&]() {
827 SetTagCheckingLevelSync();
828 Trap(reinterpret_cast<void *>(CreateTagMapping()));
829 });
830
831 StartIntercept(&output_fd);
832 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700833 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700834 FinishIntercept(&intercept_result);
835
836 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
837
838 std::string result;
839 ConsumeFd(std::move(output_fd), &result);
840
841 ASSERT_MATCH(result, R"(memory near x0:
842.*
843.*
844 01.............0 0000000000000000 0000000000000000 ................
845 00.............0)");
846#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800847 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700848#endif
849}
850
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700851TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
852#if defined(__aarch64__)
853 if (!mte_supported()) {
854 GTEST_SKIP() << "Requires MTE";
855 }
856
857 int intercept_result;
858 unique_fd output_fd;
859 StartProcess([&]() {
860 SetTagCheckingLevelSync();
861 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
862 p[0] = 0; // Untagged pointer, tagged memory.
863 });
864
865 StartIntercept(&output_fd);
866 FinishCrasher();
867 AssertDeath(SIGSEGV);
868 FinishIntercept(&intercept_result);
869
870 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
871
872 std::string result;
873 ConsumeFd(std::move(output_fd), &result);
874
875 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
876\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
877#else
878 GTEST_SKIP() << "Requires aarch64";
879#endif
880}
881
882TEST_F(CrasherTest, mte_fault_tag_dump) {
883#if defined(__aarch64__)
884 if (!mte_supported()) {
885 GTEST_SKIP() << "Requires MTE";
886 }
887
888 int intercept_result;
889 unique_fd output_fd;
890 StartProcess([&]() {
891 SetTagCheckingLevelSync();
892 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
893 p[320] = 0; // Untagged pointer, tagged memory.
894 });
895
896 StartIntercept(&output_fd);
897 FinishCrasher();
898 AssertDeath(SIGSEGV);
899 FinishIntercept(&intercept_result);
900
901 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
902
903 std::string result;
904 ConsumeFd(std::move(output_fd), &result);
905
906 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
907\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
908\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
909\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
910)");
911#else
912 GTEST_SKIP() << "Requires aarch64";
913#endif
914}
915
916TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
917#if defined(__aarch64__)
918 if (!mte_supported()) {
919 GTEST_SKIP() << "Requires MTE";
920 }
921
922 int intercept_result;
923 unique_fd output_fd;
924 StartProcess([&]() {
925 SetTagCheckingLevelSync();
926 size_t page_size = getpagesize();
927 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
928 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
929 });
930
931 StartIntercept(&output_fd);
932 FinishCrasher();
933 AssertDeath(SIGSEGV);
934 FinishIntercept(&intercept_result);
935
936 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
937
938 std::string result;
939 ConsumeFd(std::move(output_fd), &result);
940
941 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
942 ASSERT_MATCH(result,
943 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
944\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
945
946)"); // Ensure truncation happened and there's a newline after the tag fault.
947#else
948 GTEST_SKIP() << "Requires aarch64";
949#endif
950}
951
Josh Gaocdea7502017-11-01 15:00:40 -0700952TEST_F(CrasherTest, LD_PRELOAD) {
953 int intercept_result;
954 unique_fd output_fd;
955 StartProcess([]() {
956 setenv("LD_PRELOAD", "nonexistent.so", 1);
957 *reinterpret_cast<volatile char*>(0xdead) = '1';
958 });
959
960 StartIntercept(&output_fd);
961 FinishCrasher();
962 AssertDeath(SIGSEGV);
963 FinishIntercept(&intercept_result);
964
965 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
966
967 std::string result;
968 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800969 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700970}
971
Josh Gaocbe70cb2016-10-18 18:17:52 -0700972TEST_F(CrasherTest, abort) {
973 int intercept_result;
974 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800975 StartProcess([]() {
976 abort();
977 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700978 StartIntercept(&output_fd);
979 FinishCrasher();
980 AssertDeath(SIGABRT);
981 FinishIntercept(&intercept_result);
982
983 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
984
985 std::string result;
986 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700987 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700988}
989
990TEST_F(CrasherTest, signal) {
991 int intercept_result;
992 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800993 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700994 while (true) {
995 sleep(1);
996 }
Josh Gao502cfd22017-02-17 01:39:15 -0800997 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700998 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700999 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -07001000 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
1001
1002 AssertDeath(SIGSEGV);
1003 FinishIntercept(&intercept_result);
1004
1005 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1006
1007 std::string result;
1008 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -07001009 ASSERT_MATCH(
1010 result,
1011 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001012 ASSERT_MATCH(result, R"(backtrace:)");
1013}
1014
1015TEST_F(CrasherTest, abort_message) {
1016 int intercept_result;
1017 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001018 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001019 // Arrived at experimentally;
1020 // logd truncates at 4062.
1021 // strlen("Abort message: ''") is 17.
1022 // That's 4045, but we also want a NUL.
1023 char buf[4045 + 1];
1024 memset(buf, 'x', sizeof(buf));
1025 buf[sizeof(buf) - 1] = '\0';
1026 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001027 abort();
1028 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001029 StartIntercept(&output_fd);
1030 FinishCrasher();
1031 AssertDeath(SIGABRT);
1032 FinishIntercept(&intercept_result);
1033
1034 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1035
1036 std::string result;
1037 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001038 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001039}
1040
Christopher Ferrise8891452021-08-17 17:34:53 -07001041TEST_F(CrasherTest, abort_message_newline_trimmed) {
1042 int intercept_result;
1043 unique_fd output_fd;
1044 StartProcess([]() {
1045 android_set_abort_message("Message with a newline.\n");
1046 abort();
1047 });
1048 StartIntercept(&output_fd);
1049 FinishCrasher();
1050 AssertDeath(SIGABRT);
1051 FinishIntercept(&intercept_result);
1052
1053 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1054
1055 std::string result;
1056 ConsumeFd(std::move(output_fd), &result);
1057 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1058}
1059
1060TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1061 int intercept_result;
1062 unique_fd output_fd;
1063 StartProcess([]() {
1064 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1065 abort();
1066 });
1067 StartIntercept(&output_fd);
1068 FinishCrasher();
1069 AssertDeath(SIGABRT);
1070 FinishIntercept(&intercept_result);
1071
1072 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1073
1074 std::string result;
1075 ConsumeFd(std::move(output_fd), &result);
1076 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1077}
1078
Josh Gaoe06f2a42017-04-27 16:50:38 -07001079TEST_F(CrasherTest, abort_message_backtrace) {
1080 int intercept_result;
1081 unique_fd output_fd;
1082 StartProcess([]() {
1083 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001084 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001085 exit(0);
1086 });
1087 StartIntercept(&output_fd);
1088 FinishCrasher();
1089 AssertDeath(0);
1090 FinishIntercept(&intercept_result);
1091
1092 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1093
1094 std::string result;
1095 ConsumeFd(std::move(output_fd), &result);
1096 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1097}
1098
Josh Gaocbe70cb2016-10-18 18:17:52 -07001099TEST_F(CrasherTest, intercept_timeout) {
1100 int intercept_result;
1101 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001102 StartProcess([]() {
1103 abort();
1104 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001105 StartIntercept(&output_fd);
1106
1107 // Don't let crasher finish until we timeout.
1108 FinishIntercept(&intercept_result);
1109
1110 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1111 << intercept_result << ")";
1112
1113 FinishCrasher();
1114 AssertDeath(SIGABRT);
1115}
1116
Elliott Hughese4781d52021-03-17 09:15:15 -07001117TEST_F(CrasherTest, wait_for_debugger) {
1118 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1119 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001120 }
1121 sleep(1);
1122
Josh Gao502cfd22017-02-17 01:39:15 -08001123 StartProcess([]() {
1124 abort();
1125 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001126 FinishCrasher();
1127
1128 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001129 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001130 ASSERT_TRUE(WIFSTOPPED(status));
1131 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1132
1133 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1134
1135 AssertDeath(SIGABRT);
1136}
1137
Josh Gaocbe70cb2016-10-18 18:17:52 -07001138TEST_F(CrasherTest, backtrace) {
1139 std::string result;
1140 int intercept_result;
1141 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001142
1143 StartProcess([]() {
1144 abort();
1145 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001146 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001147
1148 std::this_thread::sleep_for(500ms);
1149
1150 sigval val;
1151 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001152 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001153 FinishIntercept(&intercept_result);
1154 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1155 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001156 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001157
1158 int status;
1159 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1160
1161 StartIntercept(&output_fd);
1162 FinishCrasher();
1163 AssertDeath(SIGABRT);
1164 FinishIntercept(&intercept_result);
1165 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1166 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001167 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001168}
Josh Gaofca7ca32017-01-23 12:05:35 -08001169
1170TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001171 int intercept_result;
1172 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001173 StartProcess([]() {
1174 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001175 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001176 });
Josh Gao502cfd22017-02-17 01:39:15 -08001177
1178 StartIntercept(&output_fd);
1179 FinishCrasher();
1180 AssertDeath(SIGABRT);
1181 FinishIntercept(&intercept_result);
1182
1183 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1184
1185 std::string result;
1186 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001187 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001188}
1189
Josh Gao502cfd22017-02-17 01:39:15 -08001190TEST_F(CrasherTest, capabilities) {
1191 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1192
Josh Gaofca7ca32017-01-23 12:05:35 -08001193 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001194 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1195 err(1, "failed to set PR_SET_KEEPCAPS");
1196 }
1197
1198 if (setresuid(1, 1, 1) != 0) {
1199 err(1, "setresuid failed");
1200 }
1201
1202 __user_cap_header_struct capheader;
1203 __user_cap_data_struct capdata[2];
1204 memset(&capheader, 0, sizeof(capheader));
1205 memset(&capdata, 0, sizeof(capdata));
1206
1207 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1208 capheader.pid = 0;
1209
1210 // Turn on every third capability.
1211 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1212 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1213 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1214 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1215 }
1216
1217 // Make sure CAP_SYS_PTRACE is off.
1218 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1219 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1220
1221 if (capset(&capheader, &capdata[0]) != 0) {
1222 err(1, "capset failed");
1223 }
1224
1225 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1226 err(1, "failed to drop ambient capabilities");
1227 }
1228
Josh Gaoa5199a92017-04-03 13:18:34 -07001229 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001230 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001231 });
Josh Gao502cfd22017-02-17 01:39:15 -08001232
1233 unique_fd output_fd;
1234 StartIntercept(&output_fd);
1235 FinishCrasher();
1236 AssertDeath(SIGSYS);
1237
1238 std::string result;
1239 int intercept_result;
1240 FinishIntercept(&intercept_result);
1241 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1242 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001243 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001244 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001245}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001246
Josh Gao2e7b8e22017-05-04 17:12:57 -07001247TEST_F(CrasherTest, fake_pid) {
1248 int intercept_result;
1249 unique_fd output_fd;
1250
1251 // Prime the getpid/gettid caches.
1252 UNUSED(getpid());
1253 UNUSED(gettid());
1254
1255 std::function<pid_t()> clone_fn = []() {
1256 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1257 };
1258 StartProcess(
1259 []() {
1260 ASSERT_NE(getpid(), syscall(__NR_getpid));
1261 ASSERT_NE(gettid(), syscall(__NR_gettid));
1262 raise(SIGSEGV);
1263 },
1264 clone_fn);
1265
1266 StartIntercept(&output_fd);
1267 FinishCrasher();
1268 AssertDeath(SIGSEGV);
1269 FinishIntercept(&intercept_result);
1270
1271 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1272
1273 std::string result;
1274 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001275 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001276}
1277
Josh Gaoe04ca272018-01-16 15:38:17 -08001278static const char* const kDebuggerdSeccompPolicy =
1279 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1280
Josh Gao70adac62018-02-22 11:38:33 -08001281static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001282 std::string policy;
1283 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1284 PLOG(FATAL) << "failed to read policy file";
1285 }
1286
1287 // Allow a bunch of syscalls used by the tests.
1288 policy += "\nclone: 1";
1289 policy += "\nsigaltstack: 1";
1290 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001291 policy += "\ngetrlimit: 1";
1292 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001293
1294 FILE* tmp_file = tmpfile();
1295 if (!tmp_file) {
1296 PLOG(FATAL) << "tmpfile failed";
1297 }
1298
Christopher Ferris172b0a02019-09-18 17:48:30 -07001299 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001300 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1301 PLOG(FATAL) << "failed to write policy to tmpfile";
1302 }
1303
1304 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1305 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001306 }
1307
1308 ScopedMinijail jail{minijail_new()};
1309 if (!jail) {
1310 LOG(FATAL) << "failed to create minijail";
1311 }
1312
1313 minijail_no_new_privs(jail.get());
1314 minijail_log_seccomp_filter_failures(jail.get());
1315 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001316 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001317
1318 pid_t result = fork();
1319 if (result == -1) {
1320 return result;
1321 } else if (result != 0) {
1322 return result;
1323 }
1324
1325 // Spawn and detach a thread that spins forever.
1326 std::atomic<bool> thread_ready(false);
1327 std::thread thread([&jail, &thread_ready]() {
1328 minijail_enter(jail.get());
1329 thread_ready = true;
1330 for (;;)
1331 ;
1332 });
1333 thread.detach();
1334
1335 while (!thread_ready) {
1336 continue;
1337 }
1338
Josh Gao70adac62018-02-22 11:38:33 -08001339 if (prejail) {
1340 prejail();
1341 }
1342
Josh Gaoe04ca272018-01-16 15:38:17 -08001343 minijail_enter(jail.get());
1344 return result;
1345}
1346
Josh Gao70adac62018-02-22 11:38:33 -08001347static pid_t seccomp_fork() {
1348 return seccomp_fork_impl(nullptr);
1349}
1350
Josh Gaoe04ca272018-01-16 15:38:17 -08001351TEST_F(CrasherTest, seccomp_crash) {
1352 int intercept_result;
1353 unique_fd output_fd;
1354
1355 StartProcess([]() { abort(); }, &seccomp_fork);
1356
1357 StartIntercept(&output_fd);
1358 FinishCrasher();
1359 AssertDeath(SIGABRT);
1360 FinishIntercept(&intercept_result);
1361 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1362
1363 std::string result;
1364 ConsumeFd(std::move(output_fd), &result);
1365 ASSERT_BACKTRACE_FRAME(result, "abort");
1366}
1367
Josh Gao70adac62018-02-22 11:38:33 -08001368static pid_t seccomp_fork_rlimit() {
1369 return seccomp_fork_impl([]() {
1370 struct rlimit rlim = {
1371 .rlim_cur = 512 * 1024 * 1024,
1372 .rlim_max = 512 * 1024 * 1024,
1373 };
1374
1375 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1376 raise(SIGINT);
1377 }
1378 });
1379}
1380
1381TEST_F(CrasherTest, seccomp_crash_oom) {
1382 int intercept_result;
1383 unique_fd output_fd;
1384
1385 StartProcess(
1386 []() {
1387 std::vector<void*> vec;
1388 for (int i = 0; i < 512; ++i) {
1389 char* buf = static_cast<char*>(malloc(1024 * 1024));
1390 if (!buf) {
1391 abort();
1392 }
1393 memset(buf, 0xff, 1024 * 1024);
1394 vec.push_back(buf);
1395 }
1396 },
1397 &seccomp_fork_rlimit);
1398
1399 StartIntercept(&output_fd);
1400 FinishCrasher();
1401 AssertDeath(SIGABRT);
1402 FinishIntercept(&intercept_result);
1403 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1404
1405 // We can't actually generate a backtrace, just make sure that the process terminates.
1406}
1407
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001408__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001409 siginfo_t siginfo;
1410 siginfo.si_code = SI_QUEUE;
1411 siginfo.si_pid = getpid();
1412 siginfo.si_uid = getuid();
1413
1414 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1415 PLOG(FATAL) << "invalid dump type";
1416 }
1417
1418 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1419
Josh Gaoa48b41b2019-12-13 14:11:04 -08001420 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001421 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1422 return false;
1423 }
1424
1425 return true;
1426}
1427
Christopher Ferrisb999b822022-02-09 17:57:21 -08001428extern "C" void foo() {
1429 LOG(INFO) << "foo";
1430 std::this_thread::sleep_for(1s);
1431}
1432
1433extern "C" void bar() {
1434 LOG(INFO) << "bar";
1435 std::this_thread::sleep_for(1s);
1436}
1437
Josh Gaoe04ca272018-01-16 15:38:17 -08001438TEST_F(CrasherTest, seccomp_tombstone) {
1439 int intercept_result;
1440 unique_fd output_fd;
1441
1442 static const auto dump_type = kDebuggerdTombstone;
1443 StartProcess(
1444 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001445 std::thread a(foo);
1446 std::thread b(bar);
1447
1448 std::this_thread::sleep_for(100ms);
1449
Josh Gaoe04ca272018-01-16 15:38:17 -08001450 raise_debugger_signal(dump_type);
1451 _exit(0);
1452 },
1453 &seccomp_fork);
1454
1455 StartIntercept(&output_fd, dump_type);
1456 FinishCrasher();
1457 AssertDeath(0);
1458 FinishIntercept(&intercept_result);
1459 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1460
1461 std::string result;
1462 ConsumeFd(std::move(output_fd), &result);
1463 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001464 ASSERT_BACKTRACE_FRAME(result, "foo");
1465 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001466}
1467
Christopher Ferris303c6be2022-05-24 17:08:33 -07001468TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1469 int intercept_result;
1470 unique_fd output_fd;
1471
1472 static const auto dump_type = kDebuggerdTombstone;
1473 StartProcess(
1474 []() {
1475 std::thread abort_thread([] { abort(); });
1476 abort_thread.join();
1477 },
1478 &seccomp_fork);
1479
1480 StartIntercept(&output_fd, dump_type);
1481 FinishCrasher();
1482 AssertDeath(SIGABRT);
1483 FinishIntercept(&intercept_result);
1484 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1485
1486 std::string result;
1487 ConsumeFd(std::move(output_fd), &result);
1488 ASSERT_BACKTRACE_FRAME(result, "abort");
1489}
1490
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001491TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1492 int intercept_result;
1493 unique_fd output_fd;
1494
1495 static const auto dump_type = kDebuggerdTombstone;
1496 StartProcess(
1497 []() {
1498 std::thread a(foo);
1499 std::thread b(bar);
1500
1501 std::this_thread::sleep_for(100ms);
1502
1503 std::thread abort_thread([] { abort(); });
1504 abort_thread.join();
1505 },
1506 &seccomp_fork);
1507
1508 StartIntercept(&output_fd, dump_type);
1509 FinishCrasher();
1510 AssertDeath(SIGABRT);
1511 FinishIntercept(&intercept_result);
1512 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1513
1514 std::string result;
1515 ConsumeFd(std::move(output_fd), &result);
1516 ASSERT_BACKTRACE_FRAME(result, "abort");
1517 ASSERT_BACKTRACE_FRAME(result, "foo");
1518 ASSERT_BACKTRACE_FRAME(result, "bar");
1519 ASSERT_BACKTRACE_FRAME(result, "main");
1520}
1521
Josh Gaoe04ca272018-01-16 15:38:17 -08001522TEST_F(CrasherTest, seccomp_backtrace) {
1523 int intercept_result;
1524 unique_fd output_fd;
1525
1526 static const auto dump_type = kDebuggerdNativeBacktrace;
1527 StartProcess(
1528 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001529 std::thread a(foo);
1530 std::thread b(bar);
1531
1532 std::this_thread::sleep_for(100ms);
1533
Josh Gaoe04ca272018-01-16 15:38:17 -08001534 raise_debugger_signal(dump_type);
1535 _exit(0);
1536 },
1537 &seccomp_fork);
1538
1539 StartIntercept(&output_fd, dump_type);
1540 FinishCrasher();
1541 AssertDeath(0);
1542 FinishIntercept(&intercept_result);
1543 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1544
1545 std::string result;
1546 ConsumeFd(std::move(output_fd), &result);
1547 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001548 ASSERT_BACKTRACE_FRAME(result, "foo");
1549 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001550}
1551
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001552TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1553 int intercept_result;
1554 unique_fd output_fd;
1555
1556 static const auto dump_type = kDebuggerdNativeBacktrace;
1557 StartProcess(
1558 []() {
1559 std::thread a(foo);
1560 std::thread b(bar);
1561
1562 std::this_thread::sleep_for(100ms);
1563
1564 std::thread raise_thread([] {
1565 raise_debugger_signal(dump_type);
1566 _exit(0);
1567 });
1568 raise_thread.join();
1569 },
1570 &seccomp_fork);
1571
1572 StartIntercept(&output_fd, dump_type);
1573 FinishCrasher();
1574 AssertDeath(0);
1575 FinishIntercept(&intercept_result);
1576 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1577
1578 std::string result;
1579 ConsumeFd(std::move(output_fd), &result);
1580 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1581 ASSERT_BACKTRACE_FRAME(result, "foo");
1582 ASSERT_BACKTRACE_FRAME(result, "bar");
1583 ASSERT_BACKTRACE_FRAME(result, "main");
1584}
1585
Josh Gaoe04ca272018-01-16 15:38:17 -08001586TEST_F(CrasherTest, seccomp_crash_logcat) {
1587 StartProcess([]() { abort(); }, &seccomp_fork);
1588 FinishCrasher();
1589
1590 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1591 AssertDeath(SIGABRT);
1592}
1593
Josh Gaofd13bf02017-08-18 15:37:26 -07001594TEST_F(CrasherTest, competing_tracer) {
1595 int intercept_result;
1596 unique_fd output_fd;
1597 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001598 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001599 });
1600
1601 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001602
1603 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001604 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001605
1606 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001607 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001608 ASSERT_TRUE(WIFSTOPPED(status));
1609 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1610
1611 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1612 FinishIntercept(&intercept_result);
1613 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1614
1615 std::string result;
1616 ConsumeFd(std::move(output_fd), &result);
1617 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1618 regex += std::to_string(gettid());
1619 regex += R"( \(.+debuggerd_test)";
1620 ASSERT_MATCH(result, regex.c_str());
1621
Christopher Ferris172b0a02019-09-18 17:48:30 -07001622 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001623 ASSERT_TRUE(WIFSTOPPED(status));
1624 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1625
Josh Gaofd13bf02017-08-18 15:37:26 -07001626 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1627 AssertDeath(SIGABRT);
1628}
1629
Josh Gaobf06a402018-08-27 16:34:01 -07001630TEST_F(CrasherTest, fdsan_warning_abort_message) {
1631 int intercept_result;
1632 unique_fd output_fd;
1633
1634 StartProcess([]() {
1635 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001636 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001637 if (fd == -1) {
1638 abort();
1639 }
1640 close(fd.get());
1641 _exit(0);
1642 });
1643
1644 StartIntercept(&output_fd);
1645 FinishCrasher();
1646 AssertDeath(0);
1647 FinishIntercept(&intercept_result);
1648 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1649
1650 std::string result;
1651 ConsumeFd(std::move(output_fd), &result);
1652 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1653}
1654
Josh Gaoc3c8c022017-02-13 16:36:18 -08001655TEST(crash_dump, zombie) {
1656 pid_t forkpid = fork();
1657
Josh Gaoc3c8c022017-02-13 16:36:18 -08001658 pid_t rc;
1659 int status;
1660
1661 if (forkpid == 0) {
1662 errno = 0;
1663 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1664 if (rc != -1 || errno != ECHILD) {
1665 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1666 }
1667
Josh Gaoa48b41b2019-12-13 14:11:04 -08001668 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001669
1670 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001671 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001672 if (rc != -1 || errno != ECHILD) {
1673 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1674 }
1675 _exit(0);
1676 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001677 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001678 ASSERT_EQ(forkpid, rc);
1679 ASSERT_TRUE(WIFEXITED(status));
1680 ASSERT_EQ(0, WEXITSTATUS(status));
1681 }
1682}
Josh Gao352a8452017-03-30 16:46:21 -07001683
1684TEST(tombstoned, no_notify) {
1685 // Do this a few times.
1686 for (int i = 0; i < 3; ++i) {
1687 pid_t pid = 123'456'789 + i;
1688
1689 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001690 InterceptStatus status;
1691 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1692 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001693
1694 {
1695 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001696 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001697 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1698 }
1699
1700 pid_t read_pid;
1701 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1702 ASSERT_EQ(read_pid, pid);
1703 }
1704}
1705
1706TEST(tombstoned, stress) {
1707 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1708 static constexpr int kDumpCount = 100;
1709
1710 std::atomic<bool> start(false);
1711 std::vector<std::thread> threads;
1712 threads.emplace_back([&start]() {
1713 while (!start) {
1714 continue;
1715 }
1716
1717 // Use a way out of range pid, to avoid stomping on an actual process.
1718 pid_t pid_base = 1'000'000;
1719
1720 for (int dump = 0; dump < kDumpCount; ++dump) {
1721 pid_t pid = pid_base + dump;
1722
1723 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001724 InterceptStatus status;
1725 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1726 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001727
1728 // Pretend to crash, and then immediately close the socket.
1729 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1730 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1731 if (sockfd == -1) {
1732 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1733 }
1734 TombstonedCrashPacket packet = {};
1735 packet.packet_type = CrashPacketType::kDumpRequest;
1736 packet.packet.dump_request.pid = pid;
1737 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1738 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1739 }
1740
1741 continue;
1742 }
1743 });
1744
1745 threads.emplace_back([&start]() {
1746 while (!start) {
1747 continue;
1748 }
1749
1750 // Use a way out of range pid, to avoid stomping on an actual process.
1751 pid_t pid_base = 2'000'000;
1752
1753 for (int dump = 0; dump < kDumpCount; ++dump) {
1754 pid_t pid = pid_base + dump;
1755
1756 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001757 InterceptStatus status;
1758 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1759 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001760
1761 {
1762 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001763 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001764 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1765 tombstoned_notify_completion(tombstoned_socket.get());
1766 }
1767
1768 // TODO: Fix the race that requires this sleep.
1769 std::this_thread::sleep_for(50ms);
1770
1771 pid_t read_pid;
1772 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1773 ASSERT_EQ(read_pid, pid);
1774 }
1775 });
1776
1777 start = true;
1778
1779 for (std::thread& thread : threads) {
1780 thread.join();
1781 }
1782}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001783
1784TEST(tombstoned, java_trace_intercept_smoke) {
1785 // Using a "real" PID is a little dangerous here - if the test fails
1786 // or crashes, we might end up getting a bogus / unreliable stack
1787 // trace.
1788 const pid_t self = getpid();
1789
1790 unique_fd intercept_fd, output_fd;
1791 InterceptStatus status;
1792 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1793 ASSERT_EQ(InterceptStatus::kRegistered, status);
1794
Josh Gao76e1e302021-01-26 15:53:11 -08001795 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001796 // should result in a "regular" FD and not the installed intercept.
1797 const char native[] = "native";
1798 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001799 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001800 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1801 tombstoned_notify_completion(tombstoned_socket.get());
1802
1803 // Then, connect to tombstoned asking for a java backtrace. This *should*
1804 // trigger the intercept.
1805 const char java[] = "java";
1806 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1807 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1808 tombstoned_notify_completion(tombstoned_socket.get());
1809
1810 char outbuf[sizeof(java)];
1811 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1812 ASSERT_STREQ("java", outbuf);
1813}
1814
1815TEST(tombstoned, multiple_intercepts) {
1816 const pid_t fake_pid = 1'234'567;
1817 unique_fd intercept_fd, output_fd;
1818 InterceptStatus status;
1819 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1820 ASSERT_EQ(InterceptStatus::kRegistered, status);
1821
1822 unique_fd intercept_fd_2, output_fd_2;
1823 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1824 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1825}
1826
1827TEST(tombstoned, intercept_any) {
1828 const pid_t fake_pid = 1'234'567;
1829
1830 unique_fd intercept_fd, output_fd;
1831 InterceptStatus status;
1832 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1833 ASSERT_EQ(InterceptStatus::kRegistered, status);
1834
1835 const char any[] = "any";
1836 unique_fd tombstoned_socket, input_fd;
1837 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1838 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1839 tombstoned_notify_completion(tombstoned_socket.get());
1840
1841 char outbuf[sizeof(any)];
1842 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1843 ASSERT_STREQ("any", outbuf);
1844}
Josh Gao2b22ae12018-09-12 14:51:03 -07001845
1846TEST(tombstoned, interceptless_backtrace) {
1847 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1848 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1849 std::map<int, time_t> result;
1850 for (int i = 0; i < 99; ++i) {
1851 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1852 struct stat st;
1853 if (stat(path.c_str(), &st) == 0) {
1854 result[i] = st.st_mtim.tv_sec;
1855 }
1856 }
1857 return result;
1858 };
1859
1860 auto before = get_tombstone_timestamps();
1861 for (int i = 0; i < 50; ++i) {
1862 raise_debugger_signal(kDebuggerdNativeBacktrace);
1863 }
1864 auto after = get_tombstone_timestamps();
1865
1866 int diff = 0;
1867 for (int i = 0; i < 99; ++i) {
1868 if (after.count(i) == 0) {
1869 continue;
1870 }
1871 if (before.count(i) == 0) {
1872 ++diff;
1873 continue;
1874 }
1875 if (before[i] != after[i]) {
1876 ++diff;
1877 }
1878 }
1879
1880 // We can't be sure that nothing's crash looping in the background.
1881 // This should be good enough, though...
1882 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1883}
Christopher Ferris481e8372019-07-15 17:13:24 -07001884
1885static __attribute__((__noinline__)) void overflow_stack(void* p) {
1886 void* buf[1];
1887 buf[0] = p;
1888 static volatile void* global = buf;
1889 if (global) {
1890 global = buf;
1891 overflow_stack(&buf);
1892 }
1893}
1894
1895TEST_F(CrasherTest, stack_overflow) {
1896 int intercept_result;
1897 unique_fd output_fd;
1898 StartProcess([]() { overflow_stack(nullptr); });
1899
1900 StartIntercept(&output_fd);
1901 FinishCrasher();
1902 AssertDeath(SIGSEGV);
1903 FinishIntercept(&intercept_result);
1904
1905 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1906
1907 std::string result;
1908 ConsumeFd(std::move(output_fd), &result);
1909 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1910}
Josh Gao76e1e302021-01-26 15:53:11 -08001911
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001912static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1913 std::string test_lib(testing::internal::GetArgvs()[0]);
1914 auto const value = test_lib.find_last_of('/');
1915 if (value == std::string::npos) {
1916 test_lib = "./";
1917 } else {
1918 test_lib = test_lib.substr(0, value + 1) + "./";
1919 }
1920 test_lib += "libcrash_test.so";
1921
1922 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1923 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1924
1925 // Copy the shared so to a tempory directory.
1926 return system(cp_cmd.c_str()) == 0;
1927}
1928
1929TEST_F(CrasherTest, unreadable_elf) {
1930 int intercept_result;
1931 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001932 std::string tmp_so_name;
1933 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001934 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001935 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1936 _exit(1);
1937 }
1938 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1939 if (handle == nullptr) {
1940 _exit(1);
1941 }
1942 // Delete the original shared library so that we get the warning
1943 // about unreadable elf files.
1944 if (unlink(tmp_so_name.c_str()) == -1) {
1945 _exit(1);
1946 }
1947 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1948 if (crash_func == nullptr) {
1949 _exit(1);
1950 }
1951 crash_func();
1952 });
1953
1954 StartIntercept(&output_fd);
1955 FinishCrasher();
1956 AssertDeath(SIGSEGV);
1957 FinishIntercept(&intercept_result);
1958
1959 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1960
1961 std::string result;
1962 ConsumeFd(std::move(output_fd), &result);
1963 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001964 std::string match_str = "NOTE: " + tmp_so_name;
1965 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001966}
1967
Josh Gao76e1e302021-01-26 15:53:11 -08001968TEST(tombstoned, proto) {
1969 const pid_t self = getpid();
1970 unique_fd tombstoned_socket, text_fd, proto_fd;
1971 ASSERT_TRUE(
1972 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1973
1974 tombstoned_notify_completion(tombstoned_socket.get());
1975
1976 ASSERT_NE(-1, text_fd.get());
1977 ASSERT_NE(-1, proto_fd.get());
1978
1979 struct stat text_st;
1980 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1981
1982 // Give tombstoned some time to link the files into place.
1983 std::this_thread::sleep_for(100ms);
1984
1985 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001986 std::optional<std::string> tombstone_file;
1987 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1988 ASSERT_TRUE(dir_h != nullptr);
1989 std::regex tombstone_re("tombstone_\\d+");
1990 dirent* entry;
1991 while ((entry = readdir(dir_h.get())) != nullptr) {
1992 if (!std::regex_match(entry->d_name, tombstone_re)) {
1993 continue;
1994 }
1995 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001996
1997 struct stat st;
1998 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1999 continue;
2000 }
2001
2002 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002003 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002004 break;
2005 }
2006 }
2007
Christopher Ferris35da2882021-02-17 15:39:06 -08002008 ASSERT_TRUE(tombstone_file);
2009 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002010
2011 struct stat proto_fd_st;
2012 struct stat proto_file_st;
2013 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2014 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2015
2016 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2017 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2018}
2019
2020TEST(tombstoned, proto_intercept) {
2021 const pid_t self = getpid();
2022 unique_fd intercept_fd, output_fd;
2023 InterceptStatus status;
2024
2025 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2026 ASSERT_EQ(InterceptStatus::kRegistered, status);
2027
2028 unique_fd tombstoned_socket, text_fd, proto_fd;
2029 ASSERT_TRUE(
2030 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2031 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2032 tombstoned_notify_completion(tombstoned_socket.get());
2033
2034 text_fd.reset();
2035
2036 std::string output;
2037 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2038 ASSERT_EQ("foo", output);
2039}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002040
2041// Verify that when an intercept is present for the main thread, and the signal
2042// is received on a different thread, the intercept still works.
2043TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2044 StartProcess([]() {
2045 std::thread thread([]() {
2046 // Raise the signal on the side thread.
2047 raise_debugger_signal(kDebuggerdNativeBacktrace);
2048 });
2049 thread.join();
2050 _exit(0);
2051 });
2052
2053 unique_fd output_fd;
2054 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2055 FinishCrasher();
2056 AssertDeath(0);
2057
2058 int intercept_result;
2059 FinishIntercept(&intercept_result);
2060 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2061
2062 std::string result;
2063 ConsumeFd(std::move(output_fd), &result);
2064 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2065}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002066
2067static std::string format_pointer(uintptr_t ptr) {
2068#if defined(__LP64__)
2069 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2070 static_cast<uint32_t>(ptr & 0xffffffff));
2071#else
2072 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2073#endif
2074}
2075
2076static std::string format_pointer(void* ptr) {
2077 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2078}
2079
2080static std::string format_full_pointer(uintptr_t ptr) {
2081#if defined(__LP64__)
2082 return android::base::StringPrintf("%016" PRIx64, ptr);
2083#else
2084 return android::base::StringPrintf("%08x", ptr);
2085#endif
2086}
2087
2088static std::string format_full_pointer(void* ptr) {
2089 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2090}
2091
2092__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2093 int* crash_ptr = reinterpret_cast<int*>(ptr);
2094 *crash_ptr = 1;
2095 return *crash_ptr;
2096}
2097
2098// Verify that a fault address before the first map is properly handled.
2099TEST_F(CrasherTest, fault_address_before_first_map) {
2100 StartProcess([]() {
2101 ASSERT_EQ(0, crash_call(0x1024));
2102 _exit(0);
2103 });
2104
2105 unique_fd output_fd;
2106 StartIntercept(&output_fd);
2107 FinishCrasher();
2108 AssertDeath(SIGSEGV);
2109
2110 int intercept_result;
2111 FinishIntercept(&intercept_result);
2112 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2113
2114 std::string result;
2115 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002116 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002117
2118 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2119
2120 std::string match_str = android::base::StringPrintf(
2121 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2122 format_pointer(0x1024).c_str());
2123 ASSERT_MATCH(result, match_str);
2124}
2125
2126// Verify that a fault address after the last map is properly handled.
2127TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002128 // This makes assumptions about the memory layout that are not true in HWASan
2129 // processes.
2130 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002131 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2132 StartProcess([crash_uptr]() {
2133 ASSERT_EQ(0, crash_call(crash_uptr));
2134 _exit(0);
2135 });
2136
2137 unique_fd output_fd;
2138 StartIntercept(&output_fd);
2139 FinishCrasher();
2140 AssertDeath(SIGSEGV);
2141
2142 int intercept_result;
2143 FinishIntercept(&intercept_result);
2144 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2145
2146 std::string result;
2147 ConsumeFd(std::move(output_fd), &result);
2148
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002149 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2150 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002151 ASSERT_MATCH(result, match_str);
2152
2153 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2154
2155 // Assumes that the open files section comes after the map section.
2156 // If that assumption changes, the regex below needs to change.
2157 match_str = android::base::StringPrintf(
2158 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2159 format_pointer(crash_uptr).c_str());
2160 ASSERT_MATCH(result, match_str);
2161}
2162
2163// Verify that a fault address between maps is properly handled.
2164TEST_F(CrasherTest, fault_address_between_maps) {
2165 // Create a map before the fork so it will be present in the child.
2166 void* start_ptr =
2167 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2168 ASSERT_NE(MAP_FAILED, start_ptr);
2169 // Unmap the page in the middle.
2170 void* middle_ptr =
2171 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2172 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2173
2174 StartProcess([middle_ptr]() {
2175 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2176 _exit(0);
2177 });
2178
2179 // Unmap the two maps.
2180 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2181 void* end_ptr =
2182 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2183 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2184
2185 unique_fd output_fd;
2186 StartIntercept(&output_fd);
2187 FinishCrasher();
2188 AssertDeath(SIGSEGV);
2189
2190 int intercept_result;
2191 FinishIntercept(&intercept_result);
2192 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2193
2194 std::string result;
2195 ConsumeFd(std::move(output_fd), &result);
2196
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002197 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2198 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002199 ASSERT_MATCH(result, match_str);
2200
2201 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2202
2203 match_str = android::base::StringPrintf(
2204 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2205 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2206 format_pointer(end_ptr).c_str());
2207 ASSERT_MATCH(result, match_str);
2208}
2209
2210// Verify that a fault address happens in the correct map.
2211TEST_F(CrasherTest, fault_address_in_map) {
2212 // Create a map before the fork so it will be present in the child.
2213 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2214 ASSERT_NE(MAP_FAILED, ptr);
2215
2216 StartProcess([ptr]() {
2217 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2218 _exit(0);
2219 });
2220
2221 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2222
2223 unique_fd output_fd;
2224 StartIntercept(&output_fd);
2225 FinishCrasher();
2226 AssertDeath(SIGSEGV);
2227
2228 int intercept_result;
2229 FinishIntercept(&intercept_result);
2230 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2231
2232 std::string result;
2233 ConsumeFd(std::move(output_fd), &result);
2234
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002235 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2236 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002237 ASSERT_MATCH(result, match_str);
2238
2239 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2240
2241 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2242 ASSERT_MATCH(result, match_str);
2243}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002244
2245static constexpr uint32_t kDexData[] = {
2246 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2247 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2248 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2249 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2250 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2251 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2252 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2253 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2254 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2255 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2256 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2257 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2258 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2259 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2260 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2261 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2262 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2263};
2264
2265TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2266 StartProcess([]() {
2267 TemporaryDir td;
2268 std::string tmp_so_name;
2269 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2270 _exit(1);
2271 }
2272
2273 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2274 // move the library to which has a basename of libart.so.
2275 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2276 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2277 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2278 if (handle == nullptr) {
2279 _exit(1);
2280 }
2281
2282 void* ptr =
2283 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2284 ASSERT_TRUE(ptr != MAP_FAILED);
2285 memcpy(ptr, kDexData, sizeof(kDexData));
2286 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2287
2288 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2289 .symfile_size = sizeof(kDexData)};
2290
2291 JITDescriptor* dex_debug =
2292 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2293 ASSERT_TRUE(dex_debug != nullptr);
2294 dex_debug->version = 1;
2295 dex_debug->action_flag = 0;
2296 dex_debug->relevant_entry = 0;
2297 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2298
2299 // This sets the magic dex pc value for register 0, using the value
2300 // of register 1 + 0x102.
2301 asm(".cfi_escape "
2302 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2303 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2304 "0x13 /* DW_OP_drop */,"
2305 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2306
2307 // For each different architecture, set register one to the dex ptr mmap
2308 // created above. Then do a nullptr dereference to force a crash.
2309#if defined(__arm__)
2310 asm volatile(
2311 "mov r1, %[base]\n"
2312 "mov r2, 0\n"
2313 "str r3, [r2]\n"
2314 : [base] "+r"(ptr)
2315 :
2316 : "r1", "r2", "r3", "memory");
2317#elif defined(__aarch64__)
2318 asm volatile(
2319 "mov x1, %[base]\n"
2320 "mov x2, 0\n"
2321 "str x3, [x2]\n"
2322 : [base] "+r"(ptr)
2323 :
2324 : "x1", "x2", "x3", "memory");
2325#elif defined(__i386__)
2326 asm volatile(
2327 "mov %[base], %%ecx\n"
2328 "movl $0, %%edi\n"
2329 "movl 0(%%edi), %%edx\n"
2330 : [base] "+r"(ptr)
2331 :
2332 : "edi", "ecx", "edx", "memory");
2333#elif defined(__x86_64__)
2334 asm volatile(
2335 "mov %[base], %%rdx\n"
2336 "movq 0, %%rdi\n"
2337 "movq 0(%%rdi), %%rcx\n"
2338 : [base] "+r"(ptr)
2339 :
2340 : "rcx", "rdx", "rdi", "memory");
2341#else
2342#error "Unsupported architecture"
2343#endif
2344 _exit(0);
2345 });
2346
2347 unique_fd output_fd;
2348 StartIntercept(&output_fd);
2349 FinishCrasher();
2350 AssertDeath(SIGSEGV);
2351
2352 int intercept_result;
2353 FinishIntercept(&intercept_result);
2354 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2355
2356 std::string result;
2357 ConsumeFd(std::move(output_fd), &result);
2358
2359 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002360 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002361
2362 // Now verify that the dex_pc frame includes a proper function name.
2363 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2364}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002365
2366static std::string format_map_pointer(uintptr_t ptr) {
2367#if defined(__LP64__)
2368 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2369 static_cast<uint32_t>(ptr & 0xffffffff));
2370#else
2371 return android::base::StringPrintf("%08x", ptr);
2372#endif
2373}
2374
2375// Verify that map data is properly formatted.
2376TEST_F(CrasherTest, verify_map_format) {
2377 // Create multiple maps to make sure that the map data is formatted properly.
2378 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2379 ASSERT_NE(MAP_FAILED, none_map);
2380 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2381 ASSERT_NE(MAP_FAILED, r_map);
2382 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2383 ASSERT_NE(MAP_FAILED, w_map);
2384 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2385 ASSERT_NE(MAP_FAILED, x_map);
2386
2387 TemporaryFile tf;
2388 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2389 char c = 'f';
2390 ASSERT_EQ(1, write(tf.fd, &c, 1));
2391 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2392 ASSERT_EQ(1, write(tf.fd, &c, 1));
2393 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2394 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2395 ASSERT_NE(MAP_FAILED, file_map);
2396
2397 StartProcess([]() { abort(); });
2398
2399 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2400 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2401 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2402 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2403 ASSERT_EQ(0, munmap(file_map, 0x3001));
2404
2405 unique_fd output_fd;
2406 StartIntercept(&output_fd);
2407 FinishCrasher();
2408 AssertDeath(SIGABRT);
2409 int intercept_result;
2410 FinishIntercept(&intercept_result);
2411
2412 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2413
2414 std::string result;
2415 ConsumeFd(std::move(output_fd), &result);
2416
2417 std::string match_str;
2418 // Verify none.
2419 match_str = android::base::StringPrintf(
2420 " %s-%s --- 0 1000\\n",
2421 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2422 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2423 ASSERT_MATCH(result, match_str);
2424
2425 // Verify read-only.
2426 match_str = android::base::StringPrintf(
2427 " %s-%s r-- 0 1000\\n",
2428 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2429 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2430 ASSERT_MATCH(result, match_str);
2431
2432 // Verify write-only.
2433 match_str = android::base::StringPrintf(
2434 " %s-%s -w- 0 1000\\n",
2435 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2436 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2437 ASSERT_MATCH(result, match_str);
2438
2439 // Verify exec-only.
2440 match_str = android::base::StringPrintf(
2441 " %s-%s --x 0 1000\\n",
2442 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2443 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2444 ASSERT_MATCH(result, match_str);
2445
2446 // Verify file map with non-zero offset and a name.
2447 match_str = android::base::StringPrintf(
2448 " %s-%s r-- 2000 4000 %s\\n",
2449 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2450 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2451 ASSERT_MATCH(result, match_str);
2452}
2453
2454// Verify that the tombstone map data is correct.
2455TEST_F(CrasherTest, verify_header) {
2456 StartProcess([]() { abort(); });
2457
2458 unique_fd output_fd;
2459 StartIntercept(&output_fd);
2460 FinishCrasher();
2461 AssertDeath(SIGABRT);
2462 int intercept_result;
2463 FinishIntercept(&intercept_result);
2464
2465 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2466
2467 std::string result;
2468 ConsumeFd(std::move(output_fd), &result);
2469
2470 std::string match_str = android::base::StringPrintf(
2471 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2472 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2473 android::base::GetProperty("ro.revision", "unknown").c_str());
2474 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2475 ASSERT_MATCH(result, match_str);
2476}
2477
2478// Verify that the thread header is formatted properly.
2479TEST_F(CrasherTest, verify_thread_header) {
2480 void* shared_map =
2481 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2482 ASSERT_NE(MAP_FAILED, shared_map);
2483 memset(shared_map, 0, sizeof(pid_t));
2484
2485 StartProcess([&shared_map]() {
2486 std::atomic_bool tid_written;
2487 std::thread thread([&tid_written, &shared_map]() {
2488 pid_t tid = gettid();
2489 memcpy(shared_map, &tid, sizeof(pid_t));
2490 tid_written = true;
2491 volatile bool done = false;
2492 while (!done)
2493 ;
2494 });
2495 thread.detach();
2496 while (!tid_written.load(std::memory_order_acquire))
2497 ;
2498 abort();
2499 });
2500
2501 pid_t primary_pid = crasher_pid;
2502
2503 unique_fd output_fd;
2504 StartIntercept(&output_fd);
2505 FinishCrasher();
2506 AssertDeath(SIGABRT);
2507 int intercept_result;
2508 FinishIntercept(&intercept_result);
2509 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2510
2511 // Read the tid data out.
2512 pid_t tid;
2513 memcpy(&tid, shared_map, sizeof(pid_t));
2514 ASSERT_NE(0, tid);
2515
2516 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2517
2518 std::string result;
2519 ConsumeFd(std::move(output_fd), &result);
2520
2521 // Verify that there are two headers, one where the tid is "primary_pid"
2522 // and the other where the tid is "tid".
2523 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2524 primary_pid, primary_pid);
2525 ASSERT_MATCH(result, match_str);
2526
2527 match_str =
2528 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2529 ASSERT_MATCH(result, match_str);
2530}
2531
2532// Verify that there is a BuildID present in the map section and set properly.
2533TEST_F(CrasherTest, verify_build_id) {
2534 StartProcess([]() { abort(); });
2535
2536 unique_fd output_fd;
2537 StartIntercept(&output_fd);
2538 FinishCrasher();
2539 AssertDeath(SIGABRT);
2540 int intercept_result;
2541 FinishIntercept(&intercept_result);
2542 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2543
2544 std::string result;
2545 ConsumeFd(std::move(output_fd), &result);
2546
2547 // Find every /system or /apex lib and verify the BuildID is displayed
2548 // properly.
2549 bool found_valid_elf = false;
2550 std::smatch match;
2551 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2552 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2553 result = match.suffix()) {
2554 if (prev_file == match[1]) {
2555 // Already checked this file.
2556 continue;
2557 }
2558
2559 prev_file = match[1];
2560 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2561 if (!elf.Init() || !elf.valid()) {
2562 // Skipping invalid elf files.
2563 continue;
2564 }
2565 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2566
2567 found_valid_elf = true;
2568 }
2569 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2570}