blob: f415b68c4448ab75c6b47f27749a9e0d2ee99368 [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>
Elliott Hughes03b283a2021-01-15 11:34:26 -080021#include <malloc.h>
Josh Gaocdea7502017-11-01 15:00:40 -070022#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080023#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070024#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080025#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070026#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080027#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070028#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070029#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070030#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070031
32#include <chrono>
33#include <regex>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070034#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070035#include <thread>
36
Josh Gaobf06a402018-08-27 16:34:01 -070037#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080038#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080039#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070040#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080041#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080042
Josh Gao5f87bbd2019-01-09 17:01:49 -080043#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070044#include <android-base/file.h>
45#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070046#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070047#include <android-base/parseint.h>
48#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070049#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070050#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070051#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#include <android-base/unique_fd.h>
53#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070054#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070055#include <gtest/gtest.h>
56
Josh Gaoe04ca272018-01-16 15:38:17 -080057#include <libminijail.h>
58#include <scoped_minijail.h>
59
Christopher Ferris2038cc72021-09-15 03:57:10 +000060#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010061#include "debuggerd/handler.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070062#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010063#include "protocol.h"
64#include "tombstoned/tombstoned.h"
65#include "util.h"
66
Josh Gaocbe70cb2016-10-18 18:17:52 -070067using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080068
69using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070070using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070071using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070072
73#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070074#define ARCH_SUFFIX "64"
75#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070076#define ARCH_SUFFIX ""
77#endif
78
Elliott Hughese4781d52021-03-17 09:15:15 -070079constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070080
81#define TIMEOUT(seconds, expr) \
82 [&]() { \
83 struct sigaction old_sigaction; \
84 struct sigaction new_sigaction = {}; \
85 new_sigaction.sa_handler = [](int) {}; \
86 if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
87 err(1, "sigaction failed"); \
88 } \
89 alarm(seconds); \
90 auto value = expr; \
91 int saved_errno = errno; \
92 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
93 err(1, "sigaction failed"); \
94 } \
95 alarm(0); \
96 errno = saved_errno; \
97 return value; \
98 }()
99
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700100// Backtrace frame dump could contain:
101// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
102// or
103// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800104#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700105 ASSERT_MATCH(result, \
106 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900107
Mitch Phillips7168a212021-03-09 16:53:23 -0800108// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
109// process sampling, so we need to ensure we force GWP-ASan on.
110__attribute__((constructor)) static void enable_gwp_asan() {
111 bool force = true;
112 android_mallopt(M_INITIALIZE_GWP_ASAN, &force, sizeof(force));
113}
114
Narayan Kamatha73df602017-05-24 15:07:25 +0100115static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100116 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700117 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
118 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
119 if (intercept_fd->get() == -1) {
120 FAIL() << "failed to contact tombstoned: " << strerror(errno);
121 }
122
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700123 InterceptRequest req = {
124 .dump_type = intercept_type,
125 .pid = target_pid,
126 };
Josh Gao460b3362017-03-30 16:40:47 -0700127
128 unique_fd output_pipe_write;
129 if (!Pipe(output_fd, &output_pipe_write)) {
130 FAIL() << "failed to create output pipe: " << strerror(errno);
131 }
132
133 std::string pipe_size_str;
134 int pipe_buffer_size;
135 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
136 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
137 }
138
139 pipe_size_str = android::base::Trim(pipe_size_str);
140
141 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
142 FAIL() << "failed to parse pipe max size";
143 }
144
145 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
146 FAIL() << "failed to set pipe size: " << strerror(errno);
147 }
148
Josh Gao5675f3c2017-06-01 12:19:53 -0700149 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
150
Josh Gao5f87bbd2019-01-09 17:01:49 -0800151 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
152 output_pipe_write.reset();
153 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700154 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
155 }
156
157 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800158 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700159 if (rc == -1) {
160 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
161 } else if (rc == 0) {
162 FAIL() << "failed to read response from tombstoned (EOF)";
163 } else if (rc != sizeof(response)) {
164 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
165 << ", received " << rc;
166 }
167
Narayan Kamathca5e9082017-06-02 15:42:06 +0100168 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700169}
170
Josh Gaocbe70cb2016-10-18 18:17:52 -0700171class CrasherTest : public ::testing::Test {
172 public:
173 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700174 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700175 unique_fd crasher_pipe;
176 unique_fd intercept_fd;
177
178 CrasherTest();
179 ~CrasherTest();
180
Narayan Kamatha73df602017-05-24 15:07:25 +0100181 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700182
183 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
184 void FinishIntercept(int* result);
185
Josh Gao2e7b8e22017-05-04 17:12:57 -0700186 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700187 void StartCrasher(const std::string& crash_type);
188 void FinishCrasher();
189 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700190
191 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700192};
193
194CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700195 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
196 android::base::SetProperty(kWaitForDebuggerKey, "0");
197
198 // Clear the old property too, just in case someone's been using it
199 // on this device. (We only document the new name, but we still support
200 // the old name so we don't break anyone's existing setups.)
201 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700202}
203
204CrasherTest::~CrasherTest() {
205 if (crasher_pid != -1) {
206 kill(crasher_pid, SIGKILL);
207 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700208 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700209 }
210
Elliott Hughese4781d52021-03-17 09:15:15 -0700211 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700212}
213
Narayan Kamatha73df602017-05-24 15:07:25 +0100214void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700215 if (crasher_pid == -1) {
216 FAIL() << "crasher hasn't been started";
217 }
218
Narayan Kamathca5e9082017-06-02 15:42:06 +0100219 InterceptStatus status;
220 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
221 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222}
223
224void CrasherTest::FinishIntercept(int* result) {
225 InterceptResponse response;
226
Christopher Ferris11555f02019-09-20 14:18:55 -0700227 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 if (rc == -1) {
229 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
230 } else if (rc == 0) {
231 *result = -1;
232 } else if (rc != sizeof(response)) {
233 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
234 << ", received " << rc;
235 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700236 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700237 }
238}
239
Josh Gao2e7b8e22017-05-04 17:12:57 -0700240void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800241 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700242 unique_fd crasher_read_pipe;
243 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
244 FAIL() << "failed to create pipe: " << strerror(errno);
245 }
246
Josh Gao2e7b8e22017-05-04 17:12:57 -0700247 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700248 if (crasher_pid == -1) {
249 FAIL() << "fork failed: " << strerror(errno);
250 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800251 char dummy;
252 crasher_pipe.reset();
253 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800254 function();
255 _exit(0);
256 }
257}
258
Josh Gaocbe70cb2016-10-18 18:17:52 -0700259void CrasherTest::FinishCrasher() {
260 if (crasher_pipe == -1) {
261 FAIL() << "crasher pipe uninitialized";
262 }
263
Christopher Ferris172b0a02019-09-18 17:48:30 -0700264 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700265 if (rc == -1) {
266 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
267 } else if (rc == 0) {
268 FAIL() << "crasher pipe was closed";
269 }
270}
271
272void CrasherTest::AssertDeath(int signo) {
273 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700274 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700275 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700276 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
277 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700278 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700279 FAIL() << "failed to wait for crasher: " << strerror(errno);
280 }
281
Josh Gaoe06f2a42017-04-27 16:50:38 -0700282 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700283 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700284 ASSERT_EQ(0, WEXITSTATUS(signo));
285 } else {
286 ASSERT_FALSE(WIFEXITED(status));
287 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
288 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700289 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700290 crasher_pid = -1;
291}
292
293static void ConsumeFd(unique_fd fd, std::string* output) {
294 constexpr size_t read_length = PAGE_SIZE;
295 std::string result;
296
297 while (true) {
298 size_t offset = result.size();
299 result.resize(result.size() + PAGE_SIZE);
300 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
301 if (rc == -1) {
302 FAIL() << "read failed: " << strerror(errno);
303 } else if (rc == 0) {
304 result.resize(result.size() - PAGE_SIZE);
305 break;
306 }
307
308 result.resize(result.size() - PAGE_SIZE + rc);
309 }
310
311 *output = std::move(result);
312}
313
Mitch Phillips78f06702021-06-01 14:35:43 -0700314class LogcatCollector {
315 public:
316 LogcatCollector() { system("logcat -c"); }
317
318 void Collect(std::string* output) {
319 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
320 ASSERT_NE(cmd_stdout, nullptr);
321 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
322 ConsumeFd(std::move(tmp_fd), output);
323 pclose(cmd_stdout);
324 }
325};
326
Josh Gaocbe70cb2016-10-18 18:17:52 -0700327TEST_F(CrasherTest, smoke) {
328 int intercept_result;
329 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800330 StartProcess([]() {
331 *reinterpret_cast<volatile char*>(0xdead) = '1';
332 });
333
Josh Gaocbe70cb2016-10-18 18:17:52 -0700334 StartIntercept(&output_fd);
335 FinishCrasher();
336 AssertDeath(SIGSEGV);
337 FinishIntercept(&intercept_result);
338
339 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
340
341 std::string result;
342 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800343#ifdef __LP64__
344 ASSERT_MATCH(result,
345 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
346#else
347 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
348#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700349
350 if (mte_supported()) {
351 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700352 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
353 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700354 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700355}
356
Peter Collingbournef03af882020-03-20 18:09:00 -0700357TEST_F(CrasherTest, tagged_fault_addr) {
358#if !defined(__aarch64__)
359 GTEST_SKIP() << "Requires aarch64";
360#endif
361 int intercept_result;
362 unique_fd output_fd;
363 StartProcess([]() {
364 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
365 });
366
367 StartIntercept(&output_fd);
368 FinishCrasher();
369 AssertDeath(SIGSEGV);
370 FinishIntercept(&intercept_result);
371
372 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
373
374 std::string result;
375 ConsumeFd(std::move(output_fd), &result);
376
377 // The address can either be tagged (new kernels) or untagged (old kernels).
378 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800379 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700380}
381
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700382// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
383// compiler could still clobber the argument register before trapping, but that's unlikely.
384__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
385 __builtin_trap();
386}
387
388TEST_F(CrasherTest, heap_addr_in_register) {
389#if defined(__i386__)
390 GTEST_SKIP() << "architecture does not pass arguments in registers";
391#endif
392 int intercept_result;
393 unique_fd output_fd;
394 StartProcess([]() {
395 // Crash with a heap pointer in the first argument register.
396 Trap(malloc(1));
397 });
398
399 StartIntercept(&output_fd);
400 FinishCrasher();
401 int status;
402 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
403 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
404 // Don't test the signal number because different architectures use different signals for
405 // __builtin_trap().
406 FinishIntercept(&intercept_result);
407
408 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
409
410 std::string result;
411 ConsumeFd(std::move(output_fd), &result);
412
413#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800414 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700415#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800416 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700417#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800418 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700419#else
420 ASSERT_TRUE(false) << "unsupported architecture";
421#endif
422}
423
Peter Collingbournecd278072020-12-21 14:08:38 -0800424#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700425static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800426 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700427 abort();
428 }
429}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800430
431static void SetTagCheckingLevelAsync() {
432 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
433 abort();
434 }
435}
Peter Collingbournef8622522020-04-07 14:07:32 -0700436#endif
437
Mitch Phillips7168a212021-03-09 16:53:23 -0800438// Number of iterations required to reliably guarantee a GWP-ASan crash.
439// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
440// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
441// the counter reaches zero, we provide a sampled allocation. Then, double that
442// figure to allow for left/right allocation alignment, as this is done randomly
443// without bias.
444#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
445
446struct GwpAsanTestParameters {
447 size_t alloc_size;
448 bool free_before_access;
449 int access_offset;
450 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
451};
452
453struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
454
455GwpAsanTestParameters gwp_asan_tests[] = {
456 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
457 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
458 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
459 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
460};
461
462INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
463
464TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
465 if (mte_supported()) {
466 // Skip this test on MTE hardware, as MTE will reliably catch these errors
467 // instead of GWP-ASan.
468 GTEST_SKIP() << "Skipped on MTE.";
469 }
470
471 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700472 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800473
474 int intercept_result;
475 unique_fd output_fd;
476 StartProcess([&params]() {
477 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
478 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
479 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
480 p[params.access_offset] = 42;
481 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
482 }
483 });
484
485 StartIntercept(&output_fd);
486 FinishCrasher();
487 AssertDeath(SIGSEGV);
488 FinishIntercept(&intercept_result);
489
490 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
491
Mitch Phillips78f06702021-06-01 14:35:43 -0700492 std::vector<std::string> log_sources(2);
493 ConsumeFd(std::move(output_fd), &log_sources[0]);
494 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800495
Mitch Phillips78f06702021-06-01 14:35:43 -0700496 for (const auto& result : log_sources) {
497 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
498 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
499 if (params.free_before_access) {
500 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
501 }
502 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800503 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800504}
505
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800506struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
507
Peter Collingbourneaa544792021-05-13 13:53:37 -0700508INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800509
510TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800511#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700512 if (!mte_supported()) {
513 GTEST_SKIP() << "Requires MTE";
514 }
515
Peter Collingbourneaa544792021-05-13 13:53:37 -0700516 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
517 if (GetParam() == 0) {
518 return;
519 }
520
Mitch Phillips78f06702021-06-01 14:35:43 -0700521 LogcatCollector logcat_collector;
522
Peter Collingbournef8622522020-04-07 14:07:32 -0700523 int intercept_result;
524 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800525 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700526 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800527 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700528 free((void *)p);
529 p[0] = 42;
530 });
531
532 StartIntercept(&output_fd);
533 FinishCrasher();
534 AssertDeath(SIGSEGV);
535 FinishIntercept(&intercept_result);
536
537 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
538
Mitch Phillips78f06702021-06-01 14:35:43 -0700539 std::vector<std::string> log_sources(2);
540 ConsumeFd(std::move(output_fd), &log_sources[0]);
541 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700542 // Tag dump only available in the tombstone, not logcat.
543 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700544
Mitch Phillips78f06702021-06-01 14:35:43 -0700545 for (const auto& result : log_sources) {
546 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
547 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
548 std::to_string(GetParam()) + R"(-byte allocation)");
549 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
550 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
551 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700552#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800553 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700554#endif
555}
556
Peter Collingbournedc476342021-05-12 15:56:43 -0700557TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
558#if defined(__aarch64__)
559 if (!mte_supported()) {
560 GTEST_SKIP() << "Requires MTE";
561 }
562
563 int intercept_result;
564 unique_fd output_fd;
565 StartProcess([&]() {
566 SetTagCheckingLevelSync();
567 volatile int* p = (volatile int*)malloc(GetParam());
568 free((void *)p);
569 p[-1] = 42;
570 });
571
572 StartIntercept(&output_fd);
573 FinishCrasher();
574 AssertDeath(SIGSEGV);
575 FinishIntercept(&intercept_result);
576
577 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
578
579 std::string result;
580 ConsumeFd(std::move(output_fd), &result);
581
582 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
583 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
584#else
585 GTEST_SKIP() << "Requires aarch64";
586#endif
587}
588
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800589TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800590#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700591 if (!mte_supported()) {
592 GTEST_SKIP() << "Requires MTE";
593 }
594
Mitch Phillips78f06702021-06-01 14:35:43 -0700595 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700596 int intercept_result;
597 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800598 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700599 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800600 volatile char* p = (volatile char*)malloc(GetParam());
601 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700602 });
603
604 StartIntercept(&output_fd);
605 FinishCrasher();
606 AssertDeath(SIGSEGV);
607 FinishIntercept(&intercept_result);
608
609 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
610
Mitch Phillips78f06702021-06-01 14:35:43 -0700611 std::vector<std::string> log_sources(2);
612 ConsumeFd(std::move(output_fd), &log_sources[0]);
613 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700614
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700615 // Tag dump only in tombstone, not logcat, and tagging is not used for
616 // overflow protection in the scudo secondary (guard pages are used instead).
617 if (GetParam() < 0x10000) {
618 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
619 }
620
Mitch Phillips78f06702021-06-01 14:35:43 -0700621 for (const auto& result : log_sources) {
622 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
623 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
624 std::to_string(GetParam()) + R"(-byte allocation)");
625 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
626 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700627#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800628 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700629#endif
630}
631
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800632TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800633#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700634 if (!mte_supported()) {
635 GTEST_SKIP() << "Requires MTE";
636 }
637
638 int intercept_result;
639 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800640 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700641 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800642 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700643 p[-1] = 42;
644 });
645
646 StartIntercept(&output_fd);
647 FinishCrasher();
648 AssertDeath(SIGSEGV);
649 FinishIntercept(&intercept_result);
650
651 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
652
653 std::string result;
654 ConsumeFd(std::move(output_fd), &result);
655
656 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800657 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800658 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700659 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700660 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700661 ASSERT_MATCH(result, "Memory tags around the fault address");
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 Collingbourne773acaa2021-11-10 16:29:23 -0800667TEST_F(CrasherTest, mte_async) {
668#if defined(__aarch64__)
669 if (!mte_supported()) {
670 GTEST_SKIP() << "Requires MTE";
671 }
672
673 int intercept_result;
674 unique_fd output_fd;
675 StartProcess([&]() {
676 SetTagCheckingLevelAsync();
677 volatile int* p = (volatile int*)malloc(16);
678 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 8 \(SEGV_MTEAERR\), fault addr --------)");
692#else
693 GTEST_SKIP() << "Requires aarch64";
694#endif
695}
696
Peter Collingbournef8622522020-04-07 14:07:32 -0700697TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800698#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700699 if (!mte_supported()) {
700 GTEST_SKIP() << "Requires MTE";
701 }
702
Mitch Phillips78f06702021-06-01 14:35:43 -0700703 LogcatCollector logcat_collector;
704
Peter Collingbournef8622522020-04-07 14:07:32 -0700705 int intercept_result;
706 unique_fd output_fd;
707 StartProcess([]() {
708 SetTagCheckingLevelSync();
709
710 // Make two allocations with the same tag and close to one another. Check for both properties
711 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
712 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
713 // (some non-zero value << 56) apart.
714 //
715 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
716 // other.
717 std::set<uintptr_t> allocs;
718 for (int i = 0; i != 4096; ++i) {
719 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
720 auto it = allocs.insert(alloc).first;
721 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
722 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
723 }
724 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
725 *reinterpret_cast<int*>(alloc + 16) = 42;
726 }
727 }
728 });
729
730 StartIntercept(&output_fd);
731 FinishCrasher();
732 AssertDeath(SIGSEGV);
733 FinishIntercept(&intercept_result);
734
735 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
736
Mitch Phillips78f06702021-06-01 14:35:43 -0700737 std::vector<std::string> log_sources(2);
738 ConsumeFd(std::move(output_fd), &log_sources[0]);
739 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700740
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700741 // Tag dump only in the tombstone, not logcat.
742 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
743
Mitch Phillips78f06702021-06-01 14:35:43 -0700744 for (const auto& result : log_sources) {
745 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
746 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800747 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700748 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
749 // overflows), so we can't match explicitly for an underflow message.
750 ASSERT_MATCH(result,
751 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
752 // Ensure there's at least two allocation traces (one for each cause).
753 ASSERT_MATCH(
754 result,
755 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
756 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700757#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800758 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700759#endif
760}
761
Peter Collingbournecd278072020-12-21 14:08:38 -0800762#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700763static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700764 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
765 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
766 size_t page_size = getpagesize();
767 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
768 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
769 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700770 return 0;
771 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700772 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
773 PROT_READ | PROT_WRITE | PROT_MTE);
774 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
775 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
776 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
777 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
778 }
779 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700780}
781#endif
782
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700783TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800784#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700785 if (!mte_supported()) {
786 GTEST_SKIP() << "Requires MTE";
787 }
788
789 int intercept_result;
790 unique_fd output_fd;
791 StartProcess([&]() {
792 SetTagCheckingLevelSync();
793 Trap(reinterpret_cast<void *>(CreateTagMapping()));
794 });
795
796 StartIntercept(&output_fd);
797 FinishCrasher();
798 AssertDeath(SIGTRAP);
799 FinishIntercept(&intercept_result);
800
801 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
802
803 std::string result;
804 ConsumeFd(std::move(output_fd), &result);
805
806 ASSERT_MATCH(result, R"(memory near x0:
807.*
808.*
809 01.............0 0000000000000000 0000000000000000 ................
810 00.............0)");
811#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800812 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700813#endif
814}
815
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700816TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
817#if defined(__aarch64__)
818 if (!mte_supported()) {
819 GTEST_SKIP() << "Requires MTE";
820 }
821
822 int intercept_result;
823 unique_fd output_fd;
824 StartProcess([&]() {
825 SetTagCheckingLevelSync();
826 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
827 p[0] = 0; // Untagged pointer, tagged memory.
828 });
829
830 StartIntercept(&output_fd);
831 FinishCrasher();
832 AssertDeath(SIGSEGV);
833 FinishIntercept(&intercept_result);
834
835 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
836
837 std::string result;
838 ConsumeFd(std::move(output_fd), &result);
839
840 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
841\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
842#else
843 GTEST_SKIP() << "Requires aarch64";
844#endif
845}
846
847TEST_F(CrasherTest, mte_fault_tag_dump) {
848#if defined(__aarch64__)
849 if (!mte_supported()) {
850 GTEST_SKIP() << "Requires MTE";
851 }
852
853 int intercept_result;
854 unique_fd output_fd;
855 StartProcess([&]() {
856 SetTagCheckingLevelSync();
857 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
858 p[320] = 0; // Untagged pointer, tagged memory.
859 });
860
861 StartIntercept(&output_fd);
862 FinishCrasher();
863 AssertDeath(SIGSEGV);
864 FinishIntercept(&intercept_result);
865
866 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
867
868 std::string result;
869 ConsumeFd(std::move(output_fd), &result);
870
871 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
872\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
873\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
874\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
875)");
876#else
877 GTEST_SKIP() << "Requires aarch64";
878#endif
879}
880
881TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
882#if defined(__aarch64__)
883 if (!mte_supported()) {
884 GTEST_SKIP() << "Requires MTE";
885 }
886
887 int intercept_result;
888 unique_fd output_fd;
889 StartProcess([&]() {
890 SetTagCheckingLevelSync();
891 size_t page_size = getpagesize();
892 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
893 p[page_size - kTagGranuleSize * 2] = 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 ASSERT_MATCH(result,
908 R"(\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)"); // Ensure truncation happened and there's a newline after the tag fault.
912#else
913 GTEST_SKIP() << "Requires aarch64";
914#endif
915}
916
Josh Gaocdea7502017-11-01 15:00:40 -0700917TEST_F(CrasherTest, LD_PRELOAD) {
918 int intercept_result;
919 unique_fd output_fd;
920 StartProcess([]() {
921 setenv("LD_PRELOAD", "nonexistent.so", 1);
922 *reinterpret_cast<volatile char*>(0xdead) = '1';
923 });
924
925 StartIntercept(&output_fd);
926 FinishCrasher();
927 AssertDeath(SIGSEGV);
928 FinishIntercept(&intercept_result);
929
930 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
931
932 std::string result;
933 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800934 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700935}
936
Josh Gaocbe70cb2016-10-18 18:17:52 -0700937TEST_F(CrasherTest, abort) {
938 int intercept_result;
939 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800940 StartProcess([]() {
941 abort();
942 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700943 StartIntercept(&output_fd);
944 FinishCrasher();
945 AssertDeath(SIGABRT);
946 FinishIntercept(&intercept_result);
947
948 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
949
950 std::string result;
951 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700952 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700953}
954
955TEST_F(CrasherTest, signal) {
956 int intercept_result;
957 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800958 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700959 while (true) {
960 sleep(1);
961 }
Josh Gao502cfd22017-02-17 01:39:15 -0800962 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700963 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700964 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700965 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
966
967 AssertDeath(SIGSEGV);
968 FinishIntercept(&intercept_result);
969
970 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
971
972 std::string result;
973 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700974 ASSERT_MATCH(
975 result,
976 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700977 ASSERT_MATCH(result, R"(backtrace:)");
978}
979
980TEST_F(CrasherTest, abort_message) {
981 int intercept_result;
982 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800983 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800984 // Arrived at experimentally;
985 // logd truncates at 4062.
986 // strlen("Abort message: ''") is 17.
987 // That's 4045, but we also want a NUL.
988 char buf[4045 + 1];
989 memset(buf, 'x', sizeof(buf));
990 buf[sizeof(buf) - 1] = '\0';
991 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800992 abort();
993 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700994 StartIntercept(&output_fd);
995 FinishCrasher();
996 AssertDeath(SIGABRT);
997 FinishIntercept(&intercept_result);
998
999 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1000
1001 std::string result;
1002 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001003 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001004}
1005
Christopher Ferrise8891452021-08-17 17:34:53 -07001006TEST_F(CrasherTest, abort_message_newline_trimmed) {
1007 int intercept_result;
1008 unique_fd output_fd;
1009 StartProcess([]() {
1010 android_set_abort_message("Message with a newline.\n");
1011 abort();
1012 });
1013 StartIntercept(&output_fd);
1014 FinishCrasher();
1015 AssertDeath(SIGABRT);
1016 FinishIntercept(&intercept_result);
1017
1018 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1019
1020 std::string result;
1021 ConsumeFd(std::move(output_fd), &result);
1022 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1023}
1024
1025TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1026 int intercept_result;
1027 unique_fd output_fd;
1028 StartProcess([]() {
1029 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1030 abort();
1031 });
1032 StartIntercept(&output_fd);
1033 FinishCrasher();
1034 AssertDeath(SIGABRT);
1035 FinishIntercept(&intercept_result);
1036
1037 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1038
1039 std::string result;
1040 ConsumeFd(std::move(output_fd), &result);
1041 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1042}
1043
Josh Gaoe06f2a42017-04-27 16:50:38 -07001044TEST_F(CrasherTest, abort_message_backtrace) {
1045 int intercept_result;
1046 unique_fd output_fd;
1047 StartProcess([]() {
1048 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001049 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001050 exit(0);
1051 });
1052 StartIntercept(&output_fd);
1053 FinishCrasher();
1054 AssertDeath(0);
1055 FinishIntercept(&intercept_result);
1056
1057 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1058
1059 std::string result;
1060 ConsumeFd(std::move(output_fd), &result);
1061 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1062}
1063
Josh Gaocbe70cb2016-10-18 18:17:52 -07001064TEST_F(CrasherTest, intercept_timeout) {
1065 int intercept_result;
1066 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001067 StartProcess([]() {
1068 abort();
1069 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001070 StartIntercept(&output_fd);
1071
1072 // Don't let crasher finish until we timeout.
1073 FinishIntercept(&intercept_result);
1074
1075 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1076 << intercept_result << ")";
1077
1078 FinishCrasher();
1079 AssertDeath(SIGABRT);
1080}
1081
Elliott Hughese4781d52021-03-17 09:15:15 -07001082TEST_F(CrasherTest, wait_for_debugger) {
1083 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1084 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001085 }
1086 sleep(1);
1087
Josh Gao502cfd22017-02-17 01:39:15 -08001088 StartProcess([]() {
1089 abort();
1090 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001091 FinishCrasher();
1092
1093 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001094 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001095 ASSERT_TRUE(WIFSTOPPED(status));
1096 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1097
1098 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1099
1100 AssertDeath(SIGABRT);
1101}
1102
Josh Gaocbe70cb2016-10-18 18:17:52 -07001103TEST_F(CrasherTest, backtrace) {
1104 std::string result;
1105 int intercept_result;
1106 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001107
1108 StartProcess([]() {
1109 abort();
1110 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001111 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001112
1113 std::this_thread::sleep_for(500ms);
1114
1115 sigval val;
1116 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001117 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001118 FinishIntercept(&intercept_result);
1119 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1120 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001121 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001122
1123 int status;
1124 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1125
1126 StartIntercept(&output_fd);
1127 FinishCrasher();
1128 AssertDeath(SIGABRT);
1129 FinishIntercept(&intercept_result);
1130 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1131 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001132 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001133}
Josh Gaofca7ca32017-01-23 12:05:35 -08001134
1135TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001136 int intercept_result;
1137 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001138 StartProcess([]() {
1139 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001140 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001141 });
Josh Gao502cfd22017-02-17 01:39:15 -08001142
1143 StartIntercept(&output_fd);
1144 FinishCrasher();
1145 AssertDeath(SIGABRT);
1146 FinishIntercept(&intercept_result);
1147
1148 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1149
1150 std::string result;
1151 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001152 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001153}
1154
Josh Gao502cfd22017-02-17 01:39:15 -08001155TEST_F(CrasherTest, capabilities) {
1156 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1157
Josh Gaofca7ca32017-01-23 12:05:35 -08001158 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001159 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1160 err(1, "failed to set PR_SET_KEEPCAPS");
1161 }
1162
1163 if (setresuid(1, 1, 1) != 0) {
1164 err(1, "setresuid failed");
1165 }
1166
1167 __user_cap_header_struct capheader;
1168 __user_cap_data_struct capdata[2];
1169 memset(&capheader, 0, sizeof(capheader));
1170 memset(&capdata, 0, sizeof(capdata));
1171
1172 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1173 capheader.pid = 0;
1174
1175 // Turn on every third capability.
1176 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1177 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1178 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1179 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1180 }
1181
1182 // Make sure CAP_SYS_PTRACE is off.
1183 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1184 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1185
1186 if (capset(&capheader, &capdata[0]) != 0) {
1187 err(1, "capset failed");
1188 }
1189
1190 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1191 err(1, "failed to drop ambient capabilities");
1192 }
1193
Josh Gaoa5199a92017-04-03 13:18:34 -07001194 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001195 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001196 });
Josh Gao502cfd22017-02-17 01:39:15 -08001197
1198 unique_fd output_fd;
1199 StartIntercept(&output_fd);
1200 FinishCrasher();
1201 AssertDeath(SIGSYS);
1202
1203 std::string result;
1204 int intercept_result;
1205 FinishIntercept(&intercept_result);
1206 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1207 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001208 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001209 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001210}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001211
Josh Gao2e7b8e22017-05-04 17:12:57 -07001212TEST_F(CrasherTest, fake_pid) {
1213 int intercept_result;
1214 unique_fd output_fd;
1215
1216 // Prime the getpid/gettid caches.
1217 UNUSED(getpid());
1218 UNUSED(gettid());
1219
1220 std::function<pid_t()> clone_fn = []() {
1221 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1222 };
1223 StartProcess(
1224 []() {
1225 ASSERT_NE(getpid(), syscall(__NR_getpid));
1226 ASSERT_NE(gettid(), syscall(__NR_gettid));
1227 raise(SIGSEGV);
1228 },
1229 clone_fn);
1230
1231 StartIntercept(&output_fd);
1232 FinishCrasher();
1233 AssertDeath(SIGSEGV);
1234 FinishIntercept(&intercept_result);
1235
1236 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1237
1238 std::string result;
1239 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001240 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001241}
1242
Josh Gaoe04ca272018-01-16 15:38:17 -08001243static const char* const kDebuggerdSeccompPolicy =
1244 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1245
Josh Gao70adac62018-02-22 11:38:33 -08001246static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001247 std::string policy;
1248 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1249 PLOG(FATAL) << "failed to read policy file";
1250 }
1251
1252 // Allow a bunch of syscalls used by the tests.
1253 policy += "\nclone: 1";
1254 policy += "\nsigaltstack: 1";
1255 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001256 policy += "\ngetrlimit: 1";
1257 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001258
1259 FILE* tmp_file = tmpfile();
1260 if (!tmp_file) {
1261 PLOG(FATAL) << "tmpfile failed";
1262 }
1263
Christopher Ferris172b0a02019-09-18 17:48:30 -07001264 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001265 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1266 PLOG(FATAL) << "failed to write policy to tmpfile";
1267 }
1268
1269 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1270 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001271 }
1272
1273 ScopedMinijail jail{minijail_new()};
1274 if (!jail) {
1275 LOG(FATAL) << "failed to create minijail";
1276 }
1277
1278 minijail_no_new_privs(jail.get());
1279 minijail_log_seccomp_filter_failures(jail.get());
1280 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001281 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001282
1283 pid_t result = fork();
1284 if (result == -1) {
1285 return result;
1286 } else if (result != 0) {
1287 return result;
1288 }
1289
1290 // Spawn and detach a thread that spins forever.
1291 std::atomic<bool> thread_ready(false);
1292 std::thread thread([&jail, &thread_ready]() {
1293 minijail_enter(jail.get());
1294 thread_ready = true;
1295 for (;;)
1296 ;
1297 });
1298 thread.detach();
1299
1300 while (!thread_ready) {
1301 continue;
1302 }
1303
Josh Gao70adac62018-02-22 11:38:33 -08001304 if (prejail) {
1305 prejail();
1306 }
1307
Josh Gaoe04ca272018-01-16 15:38:17 -08001308 minijail_enter(jail.get());
1309 return result;
1310}
1311
Josh Gao70adac62018-02-22 11:38:33 -08001312static pid_t seccomp_fork() {
1313 return seccomp_fork_impl(nullptr);
1314}
1315
Josh Gaoe04ca272018-01-16 15:38:17 -08001316TEST_F(CrasherTest, seccomp_crash) {
1317 int intercept_result;
1318 unique_fd output_fd;
1319
1320 StartProcess([]() { abort(); }, &seccomp_fork);
1321
1322 StartIntercept(&output_fd);
1323 FinishCrasher();
1324 AssertDeath(SIGABRT);
1325 FinishIntercept(&intercept_result);
1326 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1327
1328 std::string result;
1329 ConsumeFd(std::move(output_fd), &result);
1330 ASSERT_BACKTRACE_FRAME(result, "abort");
1331}
1332
Josh Gao70adac62018-02-22 11:38:33 -08001333static pid_t seccomp_fork_rlimit() {
1334 return seccomp_fork_impl([]() {
1335 struct rlimit rlim = {
1336 .rlim_cur = 512 * 1024 * 1024,
1337 .rlim_max = 512 * 1024 * 1024,
1338 };
1339
1340 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1341 raise(SIGINT);
1342 }
1343 });
1344}
1345
1346TEST_F(CrasherTest, seccomp_crash_oom) {
1347 int intercept_result;
1348 unique_fd output_fd;
1349
1350 StartProcess(
1351 []() {
1352 std::vector<void*> vec;
1353 for (int i = 0; i < 512; ++i) {
1354 char* buf = static_cast<char*>(malloc(1024 * 1024));
1355 if (!buf) {
1356 abort();
1357 }
1358 memset(buf, 0xff, 1024 * 1024);
1359 vec.push_back(buf);
1360 }
1361 },
1362 &seccomp_fork_rlimit);
1363
1364 StartIntercept(&output_fd);
1365 FinishCrasher();
1366 AssertDeath(SIGABRT);
1367 FinishIntercept(&intercept_result);
1368 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1369
1370 // We can't actually generate a backtrace, just make sure that the process terminates.
1371}
1372
Josh Gaoe04ca272018-01-16 15:38:17 -08001373__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1374 siginfo_t siginfo;
1375 siginfo.si_code = SI_QUEUE;
1376 siginfo.si_pid = getpid();
1377 siginfo.si_uid = getuid();
1378
1379 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1380 PLOG(FATAL) << "invalid dump type";
1381 }
1382
1383 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1384
Josh Gaoa48b41b2019-12-13 14:11:04 -08001385 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001386 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1387 return false;
1388 }
1389
1390 return true;
1391}
1392
1393TEST_F(CrasherTest, seccomp_tombstone) {
1394 int intercept_result;
1395 unique_fd output_fd;
1396
1397 static const auto dump_type = kDebuggerdTombstone;
1398 StartProcess(
1399 []() {
1400 raise_debugger_signal(dump_type);
1401 _exit(0);
1402 },
1403 &seccomp_fork);
1404
1405 StartIntercept(&output_fd, dump_type);
1406 FinishCrasher();
1407 AssertDeath(0);
1408 FinishIntercept(&intercept_result);
1409 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1410
1411 std::string result;
1412 ConsumeFd(std::move(output_fd), &result);
1413 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1414}
1415
Josh Gao6f9eeec2018-09-12 13:55:47 -07001416extern "C" void foo() {
1417 LOG(INFO) << "foo";
1418 std::this_thread::sleep_for(1s);
1419}
1420
1421extern "C" void bar() {
1422 LOG(INFO) << "bar";
1423 std::this_thread::sleep_for(1s);
1424}
1425
Josh Gaoe04ca272018-01-16 15:38:17 -08001426TEST_F(CrasherTest, seccomp_backtrace) {
1427 int intercept_result;
1428 unique_fd output_fd;
1429
1430 static const auto dump_type = kDebuggerdNativeBacktrace;
1431 StartProcess(
1432 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001433 std::thread a(foo);
1434 std::thread b(bar);
1435
1436 std::this_thread::sleep_for(100ms);
1437
Josh Gaoe04ca272018-01-16 15:38:17 -08001438 raise_debugger_signal(dump_type);
1439 _exit(0);
1440 },
1441 &seccomp_fork);
1442
1443 StartIntercept(&output_fd, dump_type);
1444 FinishCrasher();
1445 AssertDeath(0);
1446 FinishIntercept(&intercept_result);
1447 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1448
1449 std::string result;
1450 ConsumeFd(std::move(output_fd), &result);
1451 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001452 ASSERT_BACKTRACE_FRAME(result, "foo");
1453 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001454}
1455
1456TEST_F(CrasherTest, seccomp_crash_logcat) {
1457 StartProcess([]() { abort(); }, &seccomp_fork);
1458 FinishCrasher();
1459
1460 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1461 AssertDeath(SIGABRT);
1462}
1463
Josh Gaofd13bf02017-08-18 15:37:26 -07001464TEST_F(CrasherTest, competing_tracer) {
1465 int intercept_result;
1466 unique_fd output_fd;
1467 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001468 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001469 });
1470
1471 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001472
1473 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001474 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001475
1476 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001477 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001478 ASSERT_TRUE(WIFSTOPPED(status));
1479 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1480
1481 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1482 FinishIntercept(&intercept_result);
1483 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1484
1485 std::string result;
1486 ConsumeFd(std::move(output_fd), &result);
1487 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1488 regex += std::to_string(gettid());
1489 regex += R"( \(.+debuggerd_test)";
1490 ASSERT_MATCH(result, regex.c_str());
1491
Christopher Ferris172b0a02019-09-18 17:48:30 -07001492 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001493 ASSERT_TRUE(WIFSTOPPED(status));
1494 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1495
Josh Gaofd13bf02017-08-18 15:37:26 -07001496 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1497 AssertDeath(SIGABRT);
1498}
1499
Josh Gaobf06a402018-08-27 16:34:01 -07001500TEST_F(CrasherTest, fdsan_warning_abort_message) {
1501 int intercept_result;
1502 unique_fd output_fd;
1503
1504 StartProcess([]() {
1505 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001506 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001507 if (fd == -1) {
1508 abort();
1509 }
1510 close(fd.get());
1511 _exit(0);
1512 });
1513
1514 StartIntercept(&output_fd);
1515 FinishCrasher();
1516 AssertDeath(0);
1517 FinishIntercept(&intercept_result);
1518 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1519
1520 std::string result;
1521 ConsumeFd(std::move(output_fd), &result);
1522 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1523}
1524
Josh Gaoc3c8c022017-02-13 16:36:18 -08001525TEST(crash_dump, zombie) {
1526 pid_t forkpid = fork();
1527
Josh Gaoc3c8c022017-02-13 16:36:18 -08001528 pid_t rc;
1529 int status;
1530
1531 if (forkpid == 0) {
1532 errno = 0;
1533 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1534 if (rc != -1 || errno != ECHILD) {
1535 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1536 }
1537
Josh Gaoa48b41b2019-12-13 14:11:04 -08001538 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001539
1540 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001541 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001542 if (rc != -1 || errno != ECHILD) {
1543 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1544 }
1545 _exit(0);
1546 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001547 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001548 ASSERT_EQ(forkpid, rc);
1549 ASSERT_TRUE(WIFEXITED(status));
1550 ASSERT_EQ(0, WEXITSTATUS(status));
1551 }
1552}
Josh Gao352a8452017-03-30 16:46:21 -07001553
1554TEST(tombstoned, no_notify) {
1555 // Do this a few times.
1556 for (int i = 0; i < 3; ++i) {
1557 pid_t pid = 123'456'789 + i;
1558
1559 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001560 InterceptStatus status;
1561 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1562 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001563
1564 {
1565 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001566 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001567 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1568 }
1569
1570 pid_t read_pid;
1571 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1572 ASSERT_EQ(read_pid, pid);
1573 }
1574}
1575
1576TEST(tombstoned, stress) {
1577 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1578 static constexpr int kDumpCount = 100;
1579
1580 std::atomic<bool> start(false);
1581 std::vector<std::thread> threads;
1582 threads.emplace_back([&start]() {
1583 while (!start) {
1584 continue;
1585 }
1586
1587 // Use a way out of range pid, to avoid stomping on an actual process.
1588 pid_t pid_base = 1'000'000;
1589
1590 for (int dump = 0; dump < kDumpCount; ++dump) {
1591 pid_t pid = pid_base + dump;
1592
1593 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001594 InterceptStatus status;
1595 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1596 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001597
1598 // Pretend to crash, and then immediately close the socket.
1599 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1600 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1601 if (sockfd == -1) {
1602 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1603 }
1604 TombstonedCrashPacket packet = {};
1605 packet.packet_type = CrashPacketType::kDumpRequest;
1606 packet.packet.dump_request.pid = pid;
1607 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1608 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1609 }
1610
1611 continue;
1612 }
1613 });
1614
1615 threads.emplace_back([&start]() {
1616 while (!start) {
1617 continue;
1618 }
1619
1620 // Use a way out of range pid, to avoid stomping on an actual process.
1621 pid_t pid_base = 2'000'000;
1622
1623 for (int dump = 0; dump < kDumpCount; ++dump) {
1624 pid_t pid = pid_base + dump;
1625
1626 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001627 InterceptStatus status;
1628 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1629 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001630
1631 {
1632 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001633 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001634 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1635 tombstoned_notify_completion(tombstoned_socket.get());
1636 }
1637
1638 // TODO: Fix the race that requires this sleep.
1639 std::this_thread::sleep_for(50ms);
1640
1641 pid_t read_pid;
1642 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1643 ASSERT_EQ(read_pid, pid);
1644 }
1645 });
1646
1647 start = true;
1648
1649 for (std::thread& thread : threads) {
1650 thread.join();
1651 }
1652}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001653
1654TEST(tombstoned, java_trace_intercept_smoke) {
1655 // Using a "real" PID is a little dangerous here - if the test fails
1656 // or crashes, we might end up getting a bogus / unreliable stack
1657 // trace.
1658 const pid_t self = getpid();
1659
1660 unique_fd intercept_fd, output_fd;
1661 InterceptStatus status;
1662 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1663 ASSERT_EQ(InterceptStatus::kRegistered, status);
1664
Josh Gao76e1e302021-01-26 15:53:11 -08001665 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001666 // should result in a "regular" FD and not the installed intercept.
1667 const char native[] = "native";
1668 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001669 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001670 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1671 tombstoned_notify_completion(tombstoned_socket.get());
1672
1673 // Then, connect to tombstoned asking for a java backtrace. This *should*
1674 // trigger the intercept.
1675 const char java[] = "java";
1676 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1677 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1678 tombstoned_notify_completion(tombstoned_socket.get());
1679
1680 char outbuf[sizeof(java)];
1681 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1682 ASSERT_STREQ("java", outbuf);
1683}
1684
1685TEST(tombstoned, multiple_intercepts) {
1686 const pid_t fake_pid = 1'234'567;
1687 unique_fd intercept_fd, output_fd;
1688 InterceptStatus status;
1689 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1690 ASSERT_EQ(InterceptStatus::kRegistered, status);
1691
1692 unique_fd intercept_fd_2, output_fd_2;
1693 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1694 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1695}
1696
1697TEST(tombstoned, intercept_any) {
1698 const pid_t fake_pid = 1'234'567;
1699
1700 unique_fd intercept_fd, output_fd;
1701 InterceptStatus status;
1702 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1703 ASSERT_EQ(InterceptStatus::kRegistered, status);
1704
1705 const char any[] = "any";
1706 unique_fd tombstoned_socket, input_fd;
1707 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1708 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1709 tombstoned_notify_completion(tombstoned_socket.get());
1710
1711 char outbuf[sizeof(any)];
1712 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1713 ASSERT_STREQ("any", outbuf);
1714}
Josh Gao2b22ae12018-09-12 14:51:03 -07001715
1716TEST(tombstoned, interceptless_backtrace) {
1717 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1718 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1719 std::map<int, time_t> result;
1720 for (int i = 0; i < 99; ++i) {
1721 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1722 struct stat st;
1723 if (stat(path.c_str(), &st) == 0) {
1724 result[i] = st.st_mtim.tv_sec;
1725 }
1726 }
1727 return result;
1728 };
1729
1730 auto before = get_tombstone_timestamps();
1731 for (int i = 0; i < 50; ++i) {
1732 raise_debugger_signal(kDebuggerdNativeBacktrace);
1733 }
1734 auto after = get_tombstone_timestamps();
1735
1736 int diff = 0;
1737 for (int i = 0; i < 99; ++i) {
1738 if (after.count(i) == 0) {
1739 continue;
1740 }
1741 if (before.count(i) == 0) {
1742 ++diff;
1743 continue;
1744 }
1745 if (before[i] != after[i]) {
1746 ++diff;
1747 }
1748 }
1749
1750 // We can't be sure that nothing's crash looping in the background.
1751 // This should be good enough, though...
1752 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1753}
Christopher Ferris481e8372019-07-15 17:13:24 -07001754
1755static __attribute__((__noinline__)) void overflow_stack(void* p) {
1756 void* buf[1];
1757 buf[0] = p;
1758 static volatile void* global = buf;
1759 if (global) {
1760 global = buf;
1761 overflow_stack(&buf);
1762 }
1763}
1764
1765TEST_F(CrasherTest, stack_overflow) {
1766 int intercept_result;
1767 unique_fd output_fd;
1768 StartProcess([]() { overflow_stack(nullptr); });
1769
1770 StartIntercept(&output_fd);
1771 FinishCrasher();
1772 AssertDeath(SIGSEGV);
1773 FinishIntercept(&intercept_result);
1774
1775 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1776
1777 std::string result;
1778 ConsumeFd(std::move(output_fd), &result);
1779 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1780}
Josh Gao76e1e302021-01-26 15:53:11 -08001781
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001782static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1783 std::string test_lib(testing::internal::GetArgvs()[0]);
1784 auto const value = test_lib.find_last_of('/');
1785 if (value == std::string::npos) {
1786 test_lib = "./";
1787 } else {
1788 test_lib = test_lib.substr(0, value + 1) + "./";
1789 }
1790 test_lib += "libcrash_test.so";
1791
1792 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1793 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1794
1795 // Copy the shared so to a tempory directory.
1796 return system(cp_cmd.c_str()) == 0;
1797}
1798
1799TEST_F(CrasherTest, unreadable_elf) {
1800 int intercept_result;
1801 unique_fd output_fd;
1802 StartProcess([]() {
1803 TemporaryDir td;
1804 std::string tmp_so_name;
1805 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1806 _exit(1);
1807 }
1808 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1809 if (handle == nullptr) {
1810 _exit(1);
1811 }
1812 // Delete the original shared library so that we get the warning
1813 // about unreadable elf files.
1814 if (unlink(tmp_so_name.c_str()) == -1) {
1815 _exit(1);
1816 }
1817 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1818 if (crash_func == nullptr) {
1819 _exit(1);
1820 }
1821 crash_func();
1822 });
1823
1824 StartIntercept(&output_fd);
1825 FinishCrasher();
1826 AssertDeath(SIGSEGV);
1827 FinishIntercept(&intercept_result);
1828
1829 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1830
1831 std::string result;
1832 ConsumeFd(std::move(output_fd), &result);
1833 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
1834}
1835
Josh Gao76e1e302021-01-26 15:53:11 -08001836TEST(tombstoned, proto) {
1837 const pid_t self = getpid();
1838 unique_fd tombstoned_socket, text_fd, proto_fd;
1839 ASSERT_TRUE(
1840 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1841
1842 tombstoned_notify_completion(tombstoned_socket.get());
1843
1844 ASSERT_NE(-1, text_fd.get());
1845 ASSERT_NE(-1, proto_fd.get());
1846
1847 struct stat text_st;
1848 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1849
1850 // Give tombstoned some time to link the files into place.
1851 std::this_thread::sleep_for(100ms);
1852
1853 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001854 std::optional<std::string> tombstone_file;
1855 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1856 ASSERT_TRUE(dir_h != nullptr);
1857 std::regex tombstone_re("tombstone_\\d+");
1858 dirent* entry;
1859 while ((entry = readdir(dir_h.get())) != nullptr) {
1860 if (!std::regex_match(entry->d_name, tombstone_re)) {
1861 continue;
1862 }
1863 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001864
1865 struct stat st;
1866 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1867 continue;
1868 }
1869
1870 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001871 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001872 break;
1873 }
1874 }
1875
Christopher Ferris35da2882021-02-17 15:39:06 -08001876 ASSERT_TRUE(tombstone_file);
1877 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001878
1879 struct stat proto_fd_st;
1880 struct stat proto_file_st;
1881 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1882 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1883
1884 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1885 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1886}
1887
1888TEST(tombstoned, proto_intercept) {
1889 const pid_t self = getpid();
1890 unique_fd intercept_fd, output_fd;
1891 InterceptStatus status;
1892
1893 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1894 ASSERT_EQ(InterceptStatus::kRegistered, status);
1895
1896 unique_fd tombstoned_socket, text_fd, proto_fd;
1897 ASSERT_TRUE(
1898 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1899 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1900 tombstoned_notify_completion(tombstoned_socket.get());
1901
1902 text_fd.reset();
1903
1904 std::string output;
1905 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1906 ASSERT_EQ("foo", output);
1907}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001908
1909// Verify that when an intercept is present for the main thread, and the signal
1910// is received on a different thread, the intercept still works.
1911TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1912 StartProcess([]() {
1913 std::thread thread([]() {
1914 // Raise the signal on the side thread.
1915 raise_debugger_signal(kDebuggerdNativeBacktrace);
1916 });
1917 thread.join();
1918 _exit(0);
1919 });
1920
1921 unique_fd output_fd;
1922 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1923 FinishCrasher();
1924 AssertDeath(0);
1925
1926 int intercept_result;
1927 FinishIntercept(&intercept_result);
1928 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1929
1930 std::string result;
1931 ConsumeFd(std::move(output_fd), &result);
1932 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1933}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001934
1935static std::string format_pointer(uintptr_t ptr) {
1936#if defined(__LP64__)
1937 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1938 static_cast<uint32_t>(ptr & 0xffffffff));
1939#else
1940 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1941#endif
1942}
1943
1944static std::string format_pointer(void* ptr) {
1945 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1946}
1947
1948static std::string format_full_pointer(uintptr_t ptr) {
1949#if defined(__LP64__)
1950 return android::base::StringPrintf("%016" PRIx64, ptr);
1951#else
1952 return android::base::StringPrintf("%08x", ptr);
1953#endif
1954}
1955
1956static std::string format_full_pointer(void* ptr) {
1957 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1958}
1959
1960__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1961 int* crash_ptr = reinterpret_cast<int*>(ptr);
1962 *crash_ptr = 1;
1963 return *crash_ptr;
1964}
1965
1966// Verify that a fault address before the first map is properly handled.
1967TEST_F(CrasherTest, fault_address_before_first_map) {
1968 StartProcess([]() {
1969 ASSERT_EQ(0, crash_call(0x1024));
1970 _exit(0);
1971 });
1972
1973 unique_fd output_fd;
1974 StartIntercept(&output_fd);
1975 FinishCrasher();
1976 AssertDeath(SIGSEGV);
1977
1978 int intercept_result;
1979 FinishIntercept(&intercept_result);
1980 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1981
1982 std::string result;
1983 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08001984 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001985
1986 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
1987
1988 std::string match_str = android::base::StringPrintf(
1989 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
1990 format_pointer(0x1024).c_str());
1991 ASSERT_MATCH(result, match_str);
1992}
1993
1994// Verify that a fault address after the last map is properly handled.
1995TEST_F(CrasherTest, fault_address_after_last_map) {
1996 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
1997 StartProcess([crash_uptr]() {
1998 ASSERT_EQ(0, crash_call(crash_uptr));
1999 _exit(0);
2000 });
2001
2002 unique_fd output_fd;
2003 StartIntercept(&output_fd);
2004 FinishCrasher();
2005 AssertDeath(SIGSEGV);
2006
2007 int intercept_result;
2008 FinishIntercept(&intercept_result);
2009 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2010
2011 std::string result;
2012 ConsumeFd(std::move(output_fd), &result);
2013
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002014 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2015 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002016 ASSERT_MATCH(result, match_str);
2017
2018 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2019
2020 // Assumes that the open files section comes after the map section.
2021 // If that assumption changes, the regex below needs to change.
2022 match_str = android::base::StringPrintf(
2023 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2024 format_pointer(crash_uptr).c_str());
2025 ASSERT_MATCH(result, match_str);
2026}
2027
2028// Verify that a fault address between maps is properly handled.
2029TEST_F(CrasherTest, fault_address_between_maps) {
2030 // Create a map before the fork so it will be present in the child.
2031 void* start_ptr =
2032 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2033 ASSERT_NE(MAP_FAILED, start_ptr);
2034 // Unmap the page in the middle.
2035 void* middle_ptr =
2036 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2037 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2038
2039 StartProcess([middle_ptr]() {
2040 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2041 _exit(0);
2042 });
2043
2044 // Unmap the two maps.
2045 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2046 void* end_ptr =
2047 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2048 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2049
2050 unique_fd output_fd;
2051 StartIntercept(&output_fd);
2052 FinishCrasher();
2053 AssertDeath(SIGSEGV);
2054
2055 int intercept_result;
2056 FinishIntercept(&intercept_result);
2057 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2058
2059 std::string result;
2060 ConsumeFd(std::move(output_fd), &result);
2061
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002062 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2063 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002064 ASSERT_MATCH(result, match_str);
2065
2066 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2067
2068 match_str = android::base::StringPrintf(
2069 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2070 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2071 format_pointer(end_ptr).c_str());
2072 ASSERT_MATCH(result, match_str);
2073}
2074
2075// Verify that a fault address happens in the correct map.
2076TEST_F(CrasherTest, fault_address_in_map) {
2077 // Create a map before the fork so it will be present in the child.
2078 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2079 ASSERT_NE(MAP_FAILED, ptr);
2080
2081 StartProcess([ptr]() {
2082 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2083 _exit(0);
2084 });
2085
2086 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2087
2088 unique_fd output_fd;
2089 StartIntercept(&output_fd);
2090 FinishCrasher();
2091 AssertDeath(SIGSEGV);
2092
2093 int intercept_result;
2094 FinishIntercept(&intercept_result);
2095 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2096
2097 std::string result;
2098 ConsumeFd(std::move(output_fd), &result);
2099
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002100 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2101 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002102 ASSERT_MATCH(result, match_str);
2103
2104 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2105
2106 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2107 ASSERT_MATCH(result, match_str);
2108}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002109
2110static constexpr uint32_t kDexData[] = {
2111 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2112 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2113 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2114 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2115 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2116 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2117 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2118 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2119 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2120 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2121 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2122 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2123 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2124 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2125 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2126 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2127 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2128};
2129
2130TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2131 StartProcess([]() {
2132 TemporaryDir td;
2133 std::string tmp_so_name;
2134 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2135 _exit(1);
2136 }
2137
2138 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2139 // move the library to which has a basename of libart.so.
2140 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2141 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2142 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2143 if (handle == nullptr) {
2144 _exit(1);
2145 }
2146
2147 void* ptr =
2148 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2149 ASSERT_TRUE(ptr != MAP_FAILED);
2150 memcpy(ptr, kDexData, sizeof(kDexData));
2151 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2152
2153 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2154 .symfile_size = sizeof(kDexData)};
2155
2156 JITDescriptor* dex_debug =
2157 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2158 ASSERT_TRUE(dex_debug != nullptr);
2159 dex_debug->version = 1;
2160 dex_debug->action_flag = 0;
2161 dex_debug->relevant_entry = 0;
2162 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2163
2164 // This sets the magic dex pc value for register 0, using the value
2165 // of register 1 + 0x102.
2166 asm(".cfi_escape "
2167 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2168 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2169 "0x13 /* DW_OP_drop */,"
2170 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2171
2172 // For each different architecture, set register one to the dex ptr mmap
2173 // created above. Then do a nullptr dereference to force a crash.
2174#if defined(__arm__)
2175 asm volatile(
2176 "mov r1, %[base]\n"
2177 "mov r2, 0\n"
2178 "str r3, [r2]\n"
2179 : [base] "+r"(ptr)
2180 :
2181 : "r1", "r2", "r3", "memory");
2182#elif defined(__aarch64__)
2183 asm volatile(
2184 "mov x1, %[base]\n"
2185 "mov x2, 0\n"
2186 "str x3, [x2]\n"
2187 : [base] "+r"(ptr)
2188 :
2189 : "x1", "x2", "x3", "memory");
2190#elif defined(__i386__)
2191 asm volatile(
2192 "mov %[base], %%ecx\n"
2193 "movl $0, %%edi\n"
2194 "movl 0(%%edi), %%edx\n"
2195 : [base] "+r"(ptr)
2196 :
2197 : "edi", "ecx", "edx", "memory");
2198#elif defined(__x86_64__)
2199 asm volatile(
2200 "mov %[base], %%rdx\n"
2201 "movq 0, %%rdi\n"
2202 "movq 0(%%rdi), %%rcx\n"
2203 : [base] "+r"(ptr)
2204 :
2205 : "rcx", "rdx", "rdi", "memory");
2206#else
2207#error "Unsupported architecture"
2208#endif
2209 _exit(0);
2210 });
2211
2212 unique_fd output_fd;
2213 StartIntercept(&output_fd);
2214 FinishCrasher();
2215 AssertDeath(SIGSEGV);
2216
2217 int intercept_result;
2218 FinishIntercept(&intercept_result);
2219 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2220
2221 std::string result;
2222 ConsumeFd(std::move(output_fd), &result);
2223
2224 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002225 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002226
2227 // Now verify that the dex_pc frame includes a proper function name.
2228 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2229}