blob: a4bb8b5bdc2e5bd6fc3b9a086041f7966c58f33e [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 Collingbourne939d0742021-02-02 19:00:45 -0800352 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700353 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700354}
355
Peter Collingbournef03af882020-03-20 18:09:00 -0700356TEST_F(CrasherTest, tagged_fault_addr) {
357#if !defined(__aarch64__)
358 GTEST_SKIP() << "Requires aarch64";
359#endif
360 int intercept_result;
361 unique_fd output_fd;
362 StartProcess([]() {
363 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
364 });
365
366 StartIntercept(&output_fd);
367 FinishCrasher();
368 AssertDeath(SIGSEGV);
369 FinishIntercept(&intercept_result);
370
371 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
372
373 std::string result;
374 ConsumeFd(std::move(output_fd), &result);
375
376 // The address can either be tagged (new kernels) or untagged (old kernels).
377 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800378 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700379}
380
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700381// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
382// compiler could still clobber the argument register before trapping, but that's unlikely.
383__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
384 __builtin_trap();
385}
386
387TEST_F(CrasherTest, heap_addr_in_register) {
388#if defined(__i386__)
389 GTEST_SKIP() << "architecture does not pass arguments in registers";
390#endif
391 int intercept_result;
392 unique_fd output_fd;
393 StartProcess([]() {
394 // Crash with a heap pointer in the first argument register.
395 Trap(malloc(1));
396 });
397
398 StartIntercept(&output_fd);
399 FinishCrasher();
400 int status;
401 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
402 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
403 // Don't test the signal number because different architectures use different signals for
404 // __builtin_trap().
405 FinishIntercept(&intercept_result);
406
407 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
408
409 std::string result;
410 ConsumeFd(std::move(output_fd), &result);
411
412#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800413 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700414#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800415 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700416#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800417 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700418#else
419 ASSERT_TRUE(false) << "unsupported architecture";
420#endif
421}
422
Peter Collingbournecd278072020-12-21 14:08:38 -0800423#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700424static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800425 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700426 abort();
427 }
428}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800429
430static void SetTagCheckingLevelAsync() {
431 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
432 abort();
433 }
434}
Peter Collingbournef8622522020-04-07 14:07:32 -0700435#endif
436
Mitch Phillips7168a212021-03-09 16:53:23 -0800437// Number of iterations required to reliably guarantee a GWP-ASan crash.
438// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
439// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
440// the counter reaches zero, we provide a sampled allocation. Then, double that
441// figure to allow for left/right allocation alignment, as this is done randomly
442// without bias.
443#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
444
445struct GwpAsanTestParameters {
446 size_t alloc_size;
447 bool free_before_access;
448 int access_offset;
449 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
450};
451
452struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
453
454GwpAsanTestParameters gwp_asan_tests[] = {
455 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
456 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
457 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
458 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
459};
460
461INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
462
463TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
464 if (mte_supported()) {
465 // Skip this test on MTE hardware, as MTE will reliably catch these errors
466 // instead of GWP-ASan.
467 GTEST_SKIP() << "Skipped on MTE.";
468 }
469
470 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700471 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800472
473 int intercept_result;
474 unique_fd output_fd;
475 StartProcess([&params]() {
476 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
477 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
478 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
479 p[params.access_offset] = 42;
480 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
481 }
482 });
483
484 StartIntercept(&output_fd);
485 FinishCrasher();
486 AssertDeath(SIGSEGV);
487 FinishIntercept(&intercept_result);
488
489 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
490
Mitch Phillips78f06702021-06-01 14:35:43 -0700491 std::vector<std::string> log_sources(2);
492 ConsumeFd(std::move(output_fd), &log_sources[0]);
493 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800494
Mitch Phillips78f06702021-06-01 14:35:43 -0700495 for (const auto& result : log_sources) {
496 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
497 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
498 if (params.free_before_access) {
499 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
500 }
501 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800502 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800503}
504
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800505struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
506
Peter Collingbourneaa544792021-05-13 13:53:37 -0700507INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800508
509TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800510#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700511 if (!mte_supported()) {
512 GTEST_SKIP() << "Requires MTE";
513 }
514
Peter Collingbourneaa544792021-05-13 13:53:37 -0700515 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
516 if (GetParam() == 0) {
517 return;
518 }
519
Mitch Phillips78f06702021-06-01 14:35:43 -0700520 LogcatCollector logcat_collector;
521
Peter Collingbournef8622522020-04-07 14:07:32 -0700522 int intercept_result;
523 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800524 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700525 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800526 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700527 free((void *)p);
528 p[0] = 42;
529 });
530
531 StartIntercept(&output_fd);
532 FinishCrasher();
533 AssertDeath(SIGSEGV);
534 FinishIntercept(&intercept_result);
535
536 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
537
Mitch Phillips78f06702021-06-01 14:35:43 -0700538 std::vector<std::string> log_sources(2);
539 ConsumeFd(std::move(output_fd), &log_sources[0]);
540 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700541 // Tag dump only available in the tombstone, not logcat.
542 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700543
Mitch Phillips78f06702021-06-01 14:35:43 -0700544 for (const auto& result : log_sources) {
545 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
546 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
547 std::to_string(GetParam()) + R"(-byte allocation)");
548 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
549 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
550 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700551#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800552 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700553#endif
554}
555
Peter Collingbournedc476342021-05-12 15:56:43 -0700556TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
557#if defined(__aarch64__)
558 if (!mte_supported()) {
559 GTEST_SKIP() << "Requires MTE";
560 }
561
562 int intercept_result;
563 unique_fd output_fd;
564 StartProcess([&]() {
565 SetTagCheckingLevelSync();
566 volatile int* p = (volatile int*)malloc(GetParam());
567 free((void *)p);
568 p[-1] = 42;
569 });
570
571 StartIntercept(&output_fd);
572 FinishCrasher();
573 AssertDeath(SIGSEGV);
574 FinishIntercept(&intercept_result);
575
576 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
577
578 std::string result;
579 ConsumeFd(std::move(output_fd), &result);
580
581 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
582 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
583#else
584 GTEST_SKIP() << "Requires aarch64";
585#endif
586}
587
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800588TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800589#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700590 if (!mte_supported()) {
591 GTEST_SKIP() << "Requires MTE";
592 }
593
Mitch Phillips78f06702021-06-01 14:35:43 -0700594 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700595 int intercept_result;
596 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800597 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700598 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800599 volatile char* p = (volatile char*)malloc(GetParam());
600 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700601 });
602
603 StartIntercept(&output_fd);
604 FinishCrasher();
605 AssertDeath(SIGSEGV);
606 FinishIntercept(&intercept_result);
607
608 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
609
Mitch Phillips78f06702021-06-01 14:35:43 -0700610 std::vector<std::string> log_sources(2);
611 ConsumeFd(std::move(output_fd), &log_sources[0]);
612 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700613
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700614 // Tag dump only in tombstone, not logcat, and tagging is not used for
615 // overflow protection in the scudo secondary (guard pages are used instead).
616 if (GetParam() < 0x10000) {
617 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
618 }
619
Mitch Phillips78f06702021-06-01 14:35:43 -0700620 for (const auto& result : log_sources) {
621 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
622 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
623 std::to_string(GetParam()) + R"(-byte allocation)");
624 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
625 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700626#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800627 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700628#endif
629}
630
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800631TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800632#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700633 if (!mte_supported()) {
634 GTEST_SKIP() << "Requires MTE";
635 }
636
637 int intercept_result;
638 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800639 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700640 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800641 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700642 p[-1] = 42;
643 });
644
645 StartIntercept(&output_fd);
646 FinishCrasher();
647 AssertDeath(SIGSEGV);
648 FinishIntercept(&intercept_result);
649
650 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
651
652 std::string result;
653 ConsumeFd(std::move(output_fd), &result);
654
655 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800656 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800657 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700658 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700659 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700660 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700661#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800662 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700663#endif
664}
665
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800666TEST_F(CrasherTest, mte_async) {
667#if defined(__aarch64__)
668 if (!mte_supported()) {
669 GTEST_SKIP() << "Requires MTE";
670 }
671
672 int intercept_result;
673 unique_fd output_fd;
674 StartProcess([&]() {
675 SetTagCheckingLevelAsync();
676 volatile int* p = (volatile int*)malloc(16);
677 p[-1] = 42;
678 });
679
680 StartIntercept(&output_fd);
681 FinishCrasher();
682 AssertDeath(SIGSEGV);
683 FinishIntercept(&intercept_result);
684
685 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
686
687 std::string result;
688 ConsumeFd(std::move(output_fd), &result);
689
690 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
691#else
692 GTEST_SKIP() << "Requires aarch64";
693#endif
694}
695
Peter Collingbournef8622522020-04-07 14:07:32 -0700696TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800697#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700698 if (!mte_supported()) {
699 GTEST_SKIP() << "Requires MTE";
700 }
701
Mitch Phillips78f06702021-06-01 14:35:43 -0700702 LogcatCollector logcat_collector;
703
Peter Collingbournef8622522020-04-07 14:07:32 -0700704 int intercept_result;
705 unique_fd output_fd;
706 StartProcess([]() {
707 SetTagCheckingLevelSync();
708
709 // Make two allocations with the same tag and close to one another. Check for both properties
710 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
711 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
712 // (some non-zero value << 56) apart.
713 //
714 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
715 // other.
716 std::set<uintptr_t> allocs;
717 for (int i = 0; i != 4096; ++i) {
718 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
719 auto it = allocs.insert(alloc).first;
720 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
721 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
722 }
723 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
724 *reinterpret_cast<int*>(alloc + 16) = 42;
725 }
726 }
727 });
728
729 StartIntercept(&output_fd);
730 FinishCrasher();
731 AssertDeath(SIGSEGV);
732 FinishIntercept(&intercept_result);
733
734 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
735
Mitch Phillips78f06702021-06-01 14:35:43 -0700736 std::vector<std::string> log_sources(2);
737 ConsumeFd(std::move(output_fd), &log_sources[0]);
738 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700739
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700740 // Tag dump only in the tombstone, not logcat.
741 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
742
Mitch Phillips78f06702021-06-01 14:35:43 -0700743 for (const auto& result : log_sources) {
744 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
745 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800746 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700747 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
748 // overflows), so we can't match explicitly for an underflow message.
749 ASSERT_MATCH(result,
750 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
751 // Ensure there's at least two allocation traces (one for each cause).
752 ASSERT_MATCH(
753 result,
754 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
755 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700756#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800757 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700758#endif
759}
760
Peter Collingbournecd278072020-12-21 14:08:38 -0800761#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700762static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700763 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
764 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
765 size_t page_size = getpagesize();
766 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
767 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
768 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700769 return 0;
770 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700771 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
772 PROT_READ | PROT_WRITE | PROT_MTE);
773 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
774 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
775 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
776 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
777 }
778 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700779}
780#endif
781
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700782TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800783#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700784 if (!mte_supported()) {
785 GTEST_SKIP() << "Requires MTE";
786 }
787
788 int intercept_result;
789 unique_fd output_fd;
790 StartProcess([&]() {
791 SetTagCheckingLevelSync();
792 Trap(reinterpret_cast<void *>(CreateTagMapping()));
793 });
794
795 StartIntercept(&output_fd);
796 FinishCrasher();
797 AssertDeath(SIGTRAP);
798 FinishIntercept(&intercept_result);
799
800 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
801
802 std::string result;
803 ConsumeFd(std::move(output_fd), &result);
804
805 ASSERT_MATCH(result, R"(memory near x0:
806.*
807.*
808 01.............0 0000000000000000 0000000000000000 ................
809 00.............0)");
810#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800811 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700812#endif
813}
814
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700815TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
816#if defined(__aarch64__)
817 if (!mte_supported()) {
818 GTEST_SKIP() << "Requires MTE";
819 }
820
821 int intercept_result;
822 unique_fd output_fd;
823 StartProcess([&]() {
824 SetTagCheckingLevelSync();
825 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
826 p[0] = 0; // Untagged pointer, tagged memory.
827 });
828
829 StartIntercept(&output_fd);
830 FinishCrasher();
831 AssertDeath(SIGSEGV);
832 FinishIntercept(&intercept_result);
833
834 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
835
836 std::string result;
837 ConsumeFd(std::move(output_fd), &result);
838
839 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
840\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
841#else
842 GTEST_SKIP() << "Requires aarch64";
843#endif
844}
845
846TEST_F(CrasherTest, mte_fault_tag_dump) {
847#if defined(__aarch64__)
848 if (!mte_supported()) {
849 GTEST_SKIP() << "Requires MTE";
850 }
851
852 int intercept_result;
853 unique_fd output_fd;
854 StartProcess([&]() {
855 SetTagCheckingLevelSync();
856 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
857 p[320] = 0; // Untagged pointer, tagged memory.
858 });
859
860 StartIntercept(&output_fd);
861 FinishCrasher();
862 AssertDeath(SIGSEGV);
863 FinishIntercept(&intercept_result);
864
865 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
866
867 std::string result;
868 ConsumeFd(std::move(output_fd), &result);
869
870 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
871\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
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)");
875#else
876 GTEST_SKIP() << "Requires aarch64";
877#endif
878}
879
880TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
881#if defined(__aarch64__)
882 if (!mte_supported()) {
883 GTEST_SKIP() << "Requires MTE";
884 }
885
886 int intercept_result;
887 unique_fd output_fd;
888 StartProcess([&]() {
889 SetTagCheckingLevelSync();
890 size_t page_size = getpagesize();
891 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
892 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
893 });
894
895 StartIntercept(&output_fd);
896 FinishCrasher();
897 AssertDeath(SIGSEGV);
898 FinishIntercept(&intercept_result);
899
900 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
901
902 std::string result;
903 ConsumeFd(std::move(output_fd), &result);
904
905 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
906 ASSERT_MATCH(result,
907 R"(\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
910)"); // Ensure truncation happened and there's a newline after the tag fault.
911#else
912 GTEST_SKIP() << "Requires aarch64";
913#endif
914}
915
Josh Gaocdea7502017-11-01 15:00:40 -0700916TEST_F(CrasherTest, LD_PRELOAD) {
917 int intercept_result;
918 unique_fd output_fd;
919 StartProcess([]() {
920 setenv("LD_PRELOAD", "nonexistent.so", 1);
921 *reinterpret_cast<volatile char*>(0xdead) = '1';
922 });
923
924 StartIntercept(&output_fd);
925 FinishCrasher();
926 AssertDeath(SIGSEGV);
927 FinishIntercept(&intercept_result);
928
929 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
930
931 std::string result;
932 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800933 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700934}
935
Josh Gaocbe70cb2016-10-18 18:17:52 -0700936TEST_F(CrasherTest, abort) {
937 int intercept_result;
938 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800939 StartProcess([]() {
940 abort();
941 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700942 StartIntercept(&output_fd);
943 FinishCrasher();
944 AssertDeath(SIGABRT);
945 FinishIntercept(&intercept_result);
946
947 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
948
949 std::string result;
950 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700951 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700952}
953
954TEST_F(CrasherTest, signal) {
955 int intercept_result;
956 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800957 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700958 while (true) {
959 sleep(1);
960 }
Josh Gao502cfd22017-02-17 01:39:15 -0800961 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700962 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700963 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700964 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
965
966 AssertDeath(SIGSEGV);
967 FinishIntercept(&intercept_result);
968
969 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
970
971 std::string result;
972 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700973 ASSERT_MATCH(
974 result,
975 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700976 ASSERT_MATCH(result, R"(backtrace:)");
977}
978
979TEST_F(CrasherTest, abort_message) {
980 int intercept_result;
981 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800982 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800983 // Arrived at experimentally;
984 // logd truncates at 4062.
985 // strlen("Abort message: ''") is 17.
986 // That's 4045, but we also want a NUL.
987 char buf[4045 + 1];
988 memset(buf, 'x', sizeof(buf));
989 buf[sizeof(buf) - 1] = '\0';
990 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800991 abort();
992 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700993 StartIntercept(&output_fd);
994 FinishCrasher();
995 AssertDeath(SIGABRT);
996 FinishIntercept(&intercept_result);
997
998 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
999
1000 std::string result;
1001 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001002 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001003}
1004
Christopher Ferrise8891452021-08-17 17:34:53 -07001005TEST_F(CrasherTest, abort_message_newline_trimmed) {
1006 int intercept_result;
1007 unique_fd output_fd;
1008 StartProcess([]() {
1009 android_set_abort_message("Message with a newline.\n");
1010 abort();
1011 });
1012 StartIntercept(&output_fd);
1013 FinishCrasher();
1014 AssertDeath(SIGABRT);
1015 FinishIntercept(&intercept_result);
1016
1017 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1018
1019 std::string result;
1020 ConsumeFd(std::move(output_fd), &result);
1021 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1022}
1023
1024TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1025 int intercept_result;
1026 unique_fd output_fd;
1027 StartProcess([]() {
1028 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1029 abort();
1030 });
1031 StartIntercept(&output_fd);
1032 FinishCrasher();
1033 AssertDeath(SIGABRT);
1034 FinishIntercept(&intercept_result);
1035
1036 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1037
1038 std::string result;
1039 ConsumeFd(std::move(output_fd), &result);
1040 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1041}
1042
Josh Gaoe06f2a42017-04-27 16:50:38 -07001043TEST_F(CrasherTest, abort_message_backtrace) {
1044 int intercept_result;
1045 unique_fd output_fd;
1046 StartProcess([]() {
1047 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001048 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001049 exit(0);
1050 });
1051 StartIntercept(&output_fd);
1052 FinishCrasher();
1053 AssertDeath(0);
1054 FinishIntercept(&intercept_result);
1055
1056 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1057
1058 std::string result;
1059 ConsumeFd(std::move(output_fd), &result);
1060 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1061}
1062
Josh Gaocbe70cb2016-10-18 18:17:52 -07001063TEST_F(CrasherTest, intercept_timeout) {
1064 int intercept_result;
1065 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001066 StartProcess([]() {
1067 abort();
1068 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001069 StartIntercept(&output_fd);
1070
1071 // Don't let crasher finish until we timeout.
1072 FinishIntercept(&intercept_result);
1073
1074 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1075 << intercept_result << ")";
1076
1077 FinishCrasher();
1078 AssertDeath(SIGABRT);
1079}
1080
Elliott Hughese4781d52021-03-17 09:15:15 -07001081TEST_F(CrasherTest, wait_for_debugger) {
1082 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1083 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001084 }
1085 sleep(1);
1086
Josh Gao502cfd22017-02-17 01:39:15 -08001087 StartProcess([]() {
1088 abort();
1089 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001090 FinishCrasher();
1091
1092 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001093 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001094 ASSERT_TRUE(WIFSTOPPED(status));
1095 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1096
1097 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1098
1099 AssertDeath(SIGABRT);
1100}
1101
Josh Gaocbe70cb2016-10-18 18:17:52 -07001102TEST_F(CrasherTest, backtrace) {
1103 std::string result;
1104 int intercept_result;
1105 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001106
1107 StartProcess([]() {
1108 abort();
1109 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001110 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001111
1112 std::this_thread::sleep_for(500ms);
1113
1114 sigval val;
1115 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001116 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001117 FinishIntercept(&intercept_result);
1118 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1119 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001120 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001121
1122 int status;
1123 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1124
1125 StartIntercept(&output_fd);
1126 FinishCrasher();
1127 AssertDeath(SIGABRT);
1128 FinishIntercept(&intercept_result);
1129 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1130 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001131 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001132}
Josh Gaofca7ca32017-01-23 12:05:35 -08001133
1134TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001135 int intercept_result;
1136 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001137 StartProcess([]() {
1138 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001139 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001140 });
Josh Gao502cfd22017-02-17 01:39:15 -08001141
1142 StartIntercept(&output_fd);
1143 FinishCrasher();
1144 AssertDeath(SIGABRT);
1145 FinishIntercept(&intercept_result);
1146
1147 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1148
1149 std::string result;
1150 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001151 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001152}
1153
Josh Gao502cfd22017-02-17 01:39:15 -08001154TEST_F(CrasherTest, capabilities) {
1155 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1156
Josh Gaofca7ca32017-01-23 12:05:35 -08001157 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001158 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1159 err(1, "failed to set PR_SET_KEEPCAPS");
1160 }
1161
1162 if (setresuid(1, 1, 1) != 0) {
1163 err(1, "setresuid failed");
1164 }
1165
1166 __user_cap_header_struct capheader;
1167 __user_cap_data_struct capdata[2];
1168 memset(&capheader, 0, sizeof(capheader));
1169 memset(&capdata, 0, sizeof(capdata));
1170
1171 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1172 capheader.pid = 0;
1173
1174 // Turn on every third capability.
1175 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1176 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1177 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1178 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1179 }
1180
1181 // Make sure CAP_SYS_PTRACE is off.
1182 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1183 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1184
1185 if (capset(&capheader, &capdata[0]) != 0) {
1186 err(1, "capset failed");
1187 }
1188
1189 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1190 err(1, "failed to drop ambient capabilities");
1191 }
1192
Josh Gaoa5199a92017-04-03 13:18:34 -07001193 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001194 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001195 });
Josh Gao502cfd22017-02-17 01:39:15 -08001196
1197 unique_fd output_fd;
1198 StartIntercept(&output_fd);
1199 FinishCrasher();
1200 AssertDeath(SIGSYS);
1201
1202 std::string result;
1203 int intercept_result;
1204 FinishIntercept(&intercept_result);
1205 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1206 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001207 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001208 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001209}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001210
Josh Gao2e7b8e22017-05-04 17:12:57 -07001211TEST_F(CrasherTest, fake_pid) {
1212 int intercept_result;
1213 unique_fd output_fd;
1214
1215 // Prime the getpid/gettid caches.
1216 UNUSED(getpid());
1217 UNUSED(gettid());
1218
1219 std::function<pid_t()> clone_fn = []() {
1220 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1221 };
1222 StartProcess(
1223 []() {
1224 ASSERT_NE(getpid(), syscall(__NR_getpid));
1225 ASSERT_NE(gettid(), syscall(__NR_gettid));
1226 raise(SIGSEGV);
1227 },
1228 clone_fn);
1229
1230 StartIntercept(&output_fd);
1231 FinishCrasher();
1232 AssertDeath(SIGSEGV);
1233 FinishIntercept(&intercept_result);
1234
1235 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1236
1237 std::string result;
1238 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001239 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001240}
1241
Josh Gaoe04ca272018-01-16 15:38:17 -08001242static const char* const kDebuggerdSeccompPolicy =
1243 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1244
Josh Gao70adac62018-02-22 11:38:33 -08001245static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001246 std::string policy;
1247 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1248 PLOG(FATAL) << "failed to read policy file";
1249 }
1250
1251 // Allow a bunch of syscalls used by the tests.
1252 policy += "\nclone: 1";
1253 policy += "\nsigaltstack: 1";
1254 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001255 policy += "\ngetrlimit: 1";
1256 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001257
1258 FILE* tmp_file = tmpfile();
1259 if (!tmp_file) {
1260 PLOG(FATAL) << "tmpfile failed";
1261 }
1262
Christopher Ferris172b0a02019-09-18 17:48:30 -07001263 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001264 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1265 PLOG(FATAL) << "failed to write policy to tmpfile";
1266 }
1267
1268 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1269 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001270 }
1271
1272 ScopedMinijail jail{minijail_new()};
1273 if (!jail) {
1274 LOG(FATAL) << "failed to create minijail";
1275 }
1276
1277 minijail_no_new_privs(jail.get());
1278 minijail_log_seccomp_filter_failures(jail.get());
1279 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001280 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001281
1282 pid_t result = fork();
1283 if (result == -1) {
1284 return result;
1285 } else if (result != 0) {
1286 return result;
1287 }
1288
1289 // Spawn and detach a thread that spins forever.
1290 std::atomic<bool> thread_ready(false);
1291 std::thread thread([&jail, &thread_ready]() {
1292 minijail_enter(jail.get());
1293 thread_ready = true;
1294 for (;;)
1295 ;
1296 });
1297 thread.detach();
1298
1299 while (!thread_ready) {
1300 continue;
1301 }
1302
Josh Gao70adac62018-02-22 11:38:33 -08001303 if (prejail) {
1304 prejail();
1305 }
1306
Josh Gaoe04ca272018-01-16 15:38:17 -08001307 minijail_enter(jail.get());
1308 return result;
1309}
1310
Josh Gao70adac62018-02-22 11:38:33 -08001311static pid_t seccomp_fork() {
1312 return seccomp_fork_impl(nullptr);
1313}
1314
Josh Gaoe04ca272018-01-16 15:38:17 -08001315TEST_F(CrasherTest, seccomp_crash) {
1316 int intercept_result;
1317 unique_fd output_fd;
1318
1319 StartProcess([]() { abort(); }, &seccomp_fork);
1320
1321 StartIntercept(&output_fd);
1322 FinishCrasher();
1323 AssertDeath(SIGABRT);
1324 FinishIntercept(&intercept_result);
1325 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1326
1327 std::string result;
1328 ConsumeFd(std::move(output_fd), &result);
1329 ASSERT_BACKTRACE_FRAME(result, "abort");
1330}
1331
Josh Gao70adac62018-02-22 11:38:33 -08001332static pid_t seccomp_fork_rlimit() {
1333 return seccomp_fork_impl([]() {
1334 struct rlimit rlim = {
1335 .rlim_cur = 512 * 1024 * 1024,
1336 .rlim_max = 512 * 1024 * 1024,
1337 };
1338
1339 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1340 raise(SIGINT);
1341 }
1342 });
1343}
1344
1345TEST_F(CrasherTest, seccomp_crash_oom) {
1346 int intercept_result;
1347 unique_fd output_fd;
1348
1349 StartProcess(
1350 []() {
1351 std::vector<void*> vec;
1352 for (int i = 0; i < 512; ++i) {
1353 char* buf = static_cast<char*>(malloc(1024 * 1024));
1354 if (!buf) {
1355 abort();
1356 }
1357 memset(buf, 0xff, 1024 * 1024);
1358 vec.push_back(buf);
1359 }
1360 },
1361 &seccomp_fork_rlimit);
1362
1363 StartIntercept(&output_fd);
1364 FinishCrasher();
1365 AssertDeath(SIGABRT);
1366 FinishIntercept(&intercept_result);
1367 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1368
1369 // We can't actually generate a backtrace, just make sure that the process terminates.
1370}
1371
Josh Gaoe04ca272018-01-16 15:38:17 -08001372__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1373 siginfo_t siginfo;
1374 siginfo.si_code = SI_QUEUE;
1375 siginfo.si_pid = getpid();
1376 siginfo.si_uid = getuid();
1377
1378 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1379 PLOG(FATAL) << "invalid dump type";
1380 }
1381
1382 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1383
Josh Gaoa48b41b2019-12-13 14:11:04 -08001384 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001385 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1386 return false;
1387 }
1388
1389 return true;
1390}
1391
1392TEST_F(CrasherTest, seccomp_tombstone) {
1393 int intercept_result;
1394 unique_fd output_fd;
1395
1396 static const auto dump_type = kDebuggerdTombstone;
1397 StartProcess(
1398 []() {
1399 raise_debugger_signal(dump_type);
1400 _exit(0);
1401 },
1402 &seccomp_fork);
1403
1404 StartIntercept(&output_fd, dump_type);
1405 FinishCrasher();
1406 AssertDeath(0);
1407 FinishIntercept(&intercept_result);
1408 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1409
1410 std::string result;
1411 ConsumeFd(std::move(output_fd), &result);
1412 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1413}
1414
Josh Gao6f9eeec2018-09-12 13:55:47 -07001415extern "C" void foo() {
1416 LOG(INFO) << "foo";
1417 std::this_thread::sleep_for(1s);
1418}
1419
1420extern "C" void bar() {
1421 LOG(INFO) << "bar";
1422 std::this_thread::sleep_for(1s);
1423}
1424
Josh Gaoe04ca272018-01-16 15:38:17 -08001425TEST_F(CrasherTest, seccomp_backtrace) {
1426 int intercept_result;
1427 unique_fd output_fd;
1428
1429 static const auto dump_type = kDebuggerdNativeBacktrace;
1430 StartProcess(
1431 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001432 std::thread a(foo);
1433 std::thread b(bar);
1434
1435 std::this_thread::sleep_for(100ms);
1436
Josh Gaoe04ca272018-01-16 15:38:17 -08001437 raise_debugger_signal(dump_type);
1438 _exit(0);
1439 },
1440 &seccomp_fork);
1441
1442 StartIntercept(&output_fd, dump_type);
1443 FinishCrasher();
1444 AssertDeath(0);
1445 FinishIntercept(&intercept_result);
1446 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1447
1448 std::string result;
1449 ConsumeFd(std::move(output_fd), &result);
1450 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001451 ASSERT_BACKTRACE_FRAME(result, "foo");
1452 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001453}
1454
1455TEST_F(CrasherTest, seccomp_crash_logcat) {
1456 StartProcess([]() { abort(); }, &seccomp_fork);
1457 FinishCrasher();
1458
1459 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1460 AssertDeath(SIGABRT);
1461}
1462
Josh Gaofd13bf02017-08-18 15:37:26 -07001463TEST_F(CrasherTest, competing_tracer) {
1464 int intercept_result;
1465 unique_fd output_fd;
1466 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001467 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001468 });
1469
1470 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001471
1472 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001473 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001474
1475 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001476 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001477 ASSERT_TRUE(WIFSTOPPED(status));
1478 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1479
1480 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1481 FinishIntercept(&intercept_result);
1482 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1483
1484 std::string result;
1485 ConsumeFd(std::move(output_fd), &result);
1486 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1487 regex += std::to_string(gettid());
1488 regex += R"( \(.+debuggerd_test)";
1489 ASSERT_MATCH(result, regex.c_str());
1490
Christopher Ferris172b0a02019-09-18 17:48:30 -07001491 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001492 ASSERT_TRUE(WIFSTOPPED(status));
1493 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1494
Josh Gaofd13bf02017-08-18 15:37:26 -07001495 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1496 AssertDeath(SIGABRT);
1497}
1498
Josh Gaobf06a402018-08-27 16:34:01 -07001499TEST_F(CrasherTest, fdsan_warning_abort_message) {
1500 int intercept_result;
1501 unique_fd output_fd;
1502
1503 StartProcess([]() {
1504 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001505 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001506 if (fd == -1) {
1507 abort();
1508 }
1509 close(fd.get());
1510 _exit(0);
1511 });
1512
1513 StartIntercept(&output_fd);
1514 FinishCrasher();
1515 AssertDeath(0);
1516 FinishIntercept(&intercept_result);
1517 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1518
1519 std::string result;
1520 ConsumeFd(std::move(output_fd), &result);
1521 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1522}
1523
Josh Gaoc3c8c022017-02-13 16:36:18 -08001524TEST(crash_dump, zombie) {
1525 pid_t forkpid = fork();
1526
Josh Gaoc3c8c022017-02-13 16:36:18 -08001527 pid_t rc;
1528 int status;
1529
1530 if (forkpid == 0) {
1531 errno = 0;
1532 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1533 if (rc != -1 || errno != ECHILD) {
1534 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1535 }
1536
Josh Gaoa48b41b2019-12-13 14:11:04 -08001537 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001538
1539 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001540 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001541 if (rc != -1 || errno != ECHILD) {
1542 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1543 }
1544 _exit(0);
1545 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001546 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001547 ASSERT_EQ(forkpid, rc);
1548 ASSERT_TRUE(WIFEXITED(status));
1549 ASSERT_EQ(0, WEXITSTATUS(status));
1550 }
1551}
Josh Gao352a8452017-03-30 16:46:21 -07001552
1553TEST(tombstoned, no_notify) {
1554 // Do this a few times.
1555 for (int i = 0; i < 3; ++i) {
1556 pid_t pid = 123'456'789 + i;
1557
1558 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001559 InterceptStatus status;
1560 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1561 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001562
1563 {
1564 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001565 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001566 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1567 }
1568
1569 pid_t read_pid;
1570 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1571 ASSERT_EQ(read_pid, pid);
1572 }
1573}
1574
1575TEST(tombstoned, stress) {
1576 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1577 static constexpr int kDumpCount = 100;
1578
1579 std::atomic<bool> start(false);
1580 std::vector<std::thread> threads;
1581 threads.emplace_back([&start]() {
1582 while (!start) {
1583 continue;
1584 }
1585
1586 // Use a way out of range pid, to avoid stomping on an actual process.
1587 pid_t pid_base = 1'000'000;
1588
1589 for (int dump = 0; dump < kDumpCount; ++dump) {
1590 pid_t pid = pid_base + dump;
1591
1592 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001593 InterceptStatus status;
1594 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1595 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001596
1597 // Pretend to crash, and then immediately close the socket.
1598 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1599 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1600 if (sockfd == -1) {
1601 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1602 }
1603 TombstonedCrashPacket packet = {};
1604 packet.packet_type = CrashPacketType::kDumpRequest;
1605 packet.packet.dump_request.pid = pid;
1606 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1607 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1608 }
1609
1610 continue;
1611 }
1612 });
1613
1614 threads.emplace_back([&start]() {
1615 while (!start) {
1616 continue;
1617 }
1618
1619 // Use a way out of range pid, to avoid stomping on an actual process.
1620 pid_t pid_base = 2'000'000;
1621
1622 for (int dump = 0; dump < kDumpCount; ++dump) {
1623 pid_t pid = pid_base + dump;
1624
1625 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001626 InterceptStatus status;
1627 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1628 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001629
1630 {
1631 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001632 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001633 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1634 tombstoned_notify_completion(tombstoned_socket.get());
1635 }
1636
1637 // TODO: Fix the race that requires this sleep.
1638 std::this_thread::sleep_for(50ms);
1639
1640 pid_t read_pid;
1641 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1642 ASSERT_EQ(read_pid, pid);
1643 }
1644 });
1645
1646 start = true;
1647
1648 for (std::thread& thread : threads) {
1649 thread.join();
1650 }
1651}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001652
1653TEST(tombstoned, java_trace_intercept_smoke) {
1654 // Using a "real" PID is a little dangerous here - if the test fails
1655 // or crashes, we might end up getting a bogus / unreliable stack
1656 // trace.
1657 const pid_t self = getpid();
1658
1659 unique_fd intercept_fd, output_fd;
1660 InterceptStatus status;
1661 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1662 ASSERT_EQ(InterceptStatus::kRegistered, status);
1663
Josh Gao76e1e302021-01-26 15:53:11 -08001664 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001665 // should result in a "regular" FD and not the installed intercept.
1666 const char native[] = "native";
1667 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001668 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001669 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1670 tombstoned_notify_completion(tombstoned_socket.get());
1671
1672 // Then, connect to tombstoned asking for a java backtrace. This *should*
1673 // trigger the intercept.
1674 const char java[] = "java";
1675 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1676 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1677 tombstoned_notify_completion(tombstoned_socket.get());
1678
1679 char outbuf[sizeof(java)];
1680 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1681 ASSERT_STREQ("java", outbuf);
1682}
1683
1684TEST(tombstoned, multiple_intercepts) {
1685 const pid_t fake_pid = 1'234'567;
1686 unique_fd intercept_fd, output_fd;
1687 InterceptStatus status;
1688 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1689 ASSERT_EQ(InterceptStatus::kRegistered, status);
1690
1691 unique_fd intercept_fd_2, output_fd_2;
1692 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1693 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1694}
1695
1696TEST(tombstoned, intercept_any) {
1697 const pid_t fake_pid = 1'234'567;
1698
1699 unique_fd intercept_fd, output_fd;
1700 InterceptStatus status;
1701 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1702 ASSERT_EQ(InterceptStatus::kRegistered, status);
1703
1704 const char any[] = "any";
1705 unique_fd tombstoned_socket, input_fd;
1706 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1707 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1708 tombstoned_notify_completion(tombstoned_socket.get());
1709
1710 char outbuf[sizeof(any)];
1711 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1712 ASSERT_STREQ("any", outbuf);
1713}
Josh Gao2b22ae12018-09-12 14:51:03 -07001714
1715TEST(tombstoned, interceptless_backtrace) {
1716 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1717 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1718 std::map<int, time_t> result;
1719 for (int i = 0; i < 99; ++i) {
1720 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1721 struct stat st;
1722 if (stat(path.c_str(), &st) == 0) {
1723 result[i] = st.st_mtim.tv_sec;
1724 }
1725 }
1726 return result;
1727 };
1728
1729 auto before = get_tombstone_timestamps();
1730 for (int i = 0; i < 50; ++i) {
1731 raise_debugger_signal(kDebuggerdNativeBacktrace);
1732 }
1733 auto after = get_tombstone_timestamps();
1734
1735 int diff = 0;
1736 for (int i = 0; i < 99; ++i) {
1737 if (after.count(i) == 0) {
1738 continue;
1739 }
1740 if (before.count(i) == 0) {
1741 ++diff;
1742 continue;
1743 }
1744 if (before[i] != after[i]) {
1745 ++diff;
1746 }
1747 }
1748
1749 // We can't be sure that nothing's crash looping in the background.
1750 // This should be good enough, though...
1751 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1752}
Christopher Ferris481e8372019-07-15 17:13:24 -07001753
1754static __attribute__((__noinline__)) void overflow_stack(void* p) {
1755 void* buf[1];
1756 buf[0] = p;
1757 static volatile void* global = buf;
1758 if (global) {
1759 global = buf;
1760 overflow_stack(&buf);
1761 }
1762}
1763
1764TEST_F(CrasherTest, stack_overflow) {
1765 int intercept_result;
1766 unique_fd output_fd;
1767 StartProcess([]() { overflow_stack(nullptr); });
1768
1769 StartIntercept(&output_fd);
1770 FinishCrasher();
1771 AssertDeath(SIGSEGV);
1772 FinishIntercept(&intercept_result);
1773
1774 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1775
1776 std::string result;
1777 ConsumeFd(std::move(output_fd), &result);
1778 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1779}
Josh Gao76e1e302021-01-26 15:53:11 -08001780
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001781static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1782 std::string test_lib(testing::internal::GetArgvs()[0]);
1783 auto const value = test_lib.find_last_of('/');
1784 if (value == std::string::npos) {
1785 test_lib = "./";
1786 } else {
1787 test_lib = test_lib.substr(0, value + 1) + "./";
1788 }
1789 test_lib += "libcrash_test.so";
1790
1791 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1792 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1793
1794 // Copy the shared so to a tempory directory.
1795 return system(cp_cmd.c_str()) == 0;
1796}
1797
1798TEST_F(CrasherTest, unreadable_elf) {
1799 int intercept_result;
1800 unique_fd output_fd;
1801 StartProcess([]() {
1802 TemporaryDir td;
1803 std::string tmp_so_name;
1804 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1805 _exit(1);
1806 }
1807 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1808 if (handle == nullptr) {
1809 _exit(1);
1810 }
1811 // Delete the original shared library so that we get the warning
1812 // about unreadable elf files.
1813 if (unlink(tmp_so_name.c_str()) == -1) {
1814 _exit(1);
1815 }
1816 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1817 if (crash_func == nullptr) {
1818 _exit(1);
1819 }
1820 crash_func();
1821 });
1822
1823 StartIntercept(&output_fd);
1824 FinishCrasher();
1825 AssertDeath(SIGSEGV);
1826 FinishIntercept(&intercept_result);
1827
1828 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1829
1830 std::string result;
1831 ConsumeFd(std::move(output_fd), &result);
1832 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
1833}
1834
Josh Gao76e1e302021-01-26 15:53:11 -08001835TEST(tombstoned, proto) {
1836 const pid_t self = getpid();
1837 unique_fd tombstoned_socket, text_fd, proto_fd;
1838 ASSERT_TRUE(
1839 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1840
1841 tombstoned_notify_completion(tombstoned_socket.get());
1842
1843 ASSERT_NE(-1, text_fd.get());
1844 ASSERT_NE(-1, proto_fd.get());
1845
1846 struct stat text_st;
1847 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1848
1849 // Give tombstoned some time to link the files into place.
1850 std::this_thread::sleep_for(100ms);
1851
1852 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001853 std::optional<std::string> tombstone_file;
1854 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1855 ASSERT_TRUE(dir_h != nullptr);
1856 std::regex tombstone_re("tombstone_\\d+");
1857 dirent* entry;
1858 while ((entry = readdir(dir_h.get())) != nullptr) {
1859 if (!std::regex_match(entry->d_name, tombstone_re)) {
1860 continue;
1861 }
1862 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001863
1864 struct stat st;
1865 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1866 continue;
1867 }
1868
1869 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001870 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001871 break;
1872 }
1873 }
1874
Christopher Ferris35da2882021-02-17 15:39:06 -08001875 ASSERT_TRUE(tombstone_file);
1876 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001877
1878 struct stat proto_fd_st;
1879 struct stat proto_file_st;
1880 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1881 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1882
1883 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1884 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1885}
1886
1887TEST(tombstoned, proto_intercept) {
1888 const pid_t self = getpid();
1889 unique_fd intercept_fd, output_fd;
1890 InterceptStatus status;
1891
1892 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1893 ASSERT_EQ(InterceptStatus::kRegistered, status);
1894
1895 unique_fd tombstoned_socket, text_fd, proto_fd;
1896 ASSERT_TRUE(
1897 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1898 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1899 tombstoned_notify_completion(tombstoned_socket.get());
1900
1901 text_fd.reset();
1902
1903 std::string output;
1904 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1905 ASSERT_EQ("foo", output);
1906}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001907
1908// Verify that when an intercept is present for the main thread, and the signal
1909// is received on a different thread, the intercept still works.
1910TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1911 StartProcess([]() {
1912 std::thread thread([]() {
1913 // Raise the signal on the side thread.
1914 raise_debugger_signal(kDebuggerdNativeBacktrace);
1915 });
1916 thread.join();
1917 _exit(0);
1918 });
1919
1920 unique_fd output_fd;
1921 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1922 FinishCrasher();
1923 AssertDeath(0);
1924
1925 int intercept_result;
1926 FinishIntercept(&intercept_result);
1927 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1928
1929 std::string result;
1930 ConsumeFd(std::move(output_fd), &result);
1931 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1932}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001933
1934static std::string format_pointer(uintptr_t ptr) {
1935#if defined(__LP64__)
1936 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1937 static_cast<uint32_t>(ptr & 0xffffffff));
1938#else
1939 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1940#endif
1941}
1942
1943static std::string format_pointer(void* ptr) {
1944 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1945}
1946
1947static std::string format_full_pointer(uintptr_t ptr) {
1948#if defined(__LP64__)
1949 return android::base::StringPrintf("%016" PRIx64, ptr);
1950#else
1951 return android::base::StringPrintf("%08x", ptr);
1952#endif
1953}
1954
1955static std::string format_full_pointer(void* ptr) {
1956 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1957}
1958
1959__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1960 int* crash_ptr = reinterpret_cast<int*>(ptr);
1961 *crash_ptr = 1;
1962 return *crash_ptr;
1963}
1964
1965// Verify that a fault address before the first map is properly handled.
1966TEST_F(CrasherTest, fault_address_before_first_map) {
1967 StartProcess([]() {
1968 ASSERT_EQ(0, crash_call(0x1024));
1969 _exit(0);
1970 });
1971
1972 unique_fd output_fd;
1973 StartIntercept(&output_fd);
1974 FinishCrasher();
1975 AssertDeath(SIGSEGV);
1976
1977 int intercept_result;
1978 FinishIntercept(&intercept_result);
1979 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1980
1981 std::string result;
1982 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08001983 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001984
1985 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
1986
1987 std::string match_str = android::base::StringPrintf(
1988 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
1989 format_pointer(0x1024).c_str());
1990 ASSERT_MATCH(result, match_str);
1991}
1992
1993// Verify that a fault address after the last map is properly handled.
1994TEST_F(CrasherTest, fault_address_after_last_map) {
1995 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
1996 StartProcess([crash_uptr]() {
1997 ASSERT_EQ(0, crash_call(crash_uptr));
1998 _exit(0);
1999 });
2000
2001 unique_fd output_fd;
2002 StartIntercept(&output_fd);
2003 FinishCrasher();
2004 AssertDeath(SIGSEGV);
2005
2006 int intercept_result;
2007 FinishIntercept(&intercept_result);
2008 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2009
2010 std::string result;
2011 ConsumeFd(std::move(output_fd), &result);
2012
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002013 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2014 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002015 ASSERT_MATCH(result, match_str);
2016
2017 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2018
2019 // Assumes that the open files section comes after the map section.
2020 // If that assumption changes, the regex below needs to change.
2021 match_str = android::base::StringPrintf(
2022 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2023 format_pointer(crash_uptr).c_str());
2024 ASSERT_MATCH(result, match_str);
2025}
2026
2027// Verify that a fault address between maps is properly handled.
2028TEST_F(CrasherTest, fault_address_between_maps) {
2029 // Create a map before the fork so it will be present in the child.
2030 void* start_ptr =
2031 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2032 ASSERT_NE(MAP_FAILED, start_ptr);
2033 // Unmap the page in the middle.
2034 void* middle_ptr =
2035 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2036 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2037
2038 StartProcess([middle_ptr]() {
2039 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2040 _exit(0);
2041 });
2042
2043 // Unmap the two maps.
2044 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2045 void* end_ptr =
2046 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2047 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2048
2049 unique_fd output_fd;
2050 StartIntercept(&output_fd);
2051 FinishCrasher();
2052 AssertDeath(SIGSEGV);
2053
2054 int intercept_result;
2055 FinishIntercept(&intercept_result);
2056 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2057
2058 std::string result;
2059 ConsumeFd(std::move(output_fd), &result);
2060
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002061 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2062 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002063 ASSERT_MATCH(result, match_str);
2064
2065 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2066
2067 match_str = android::base::StringPrintf(
2068 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2069 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2070 format_pointer(end_ptr).c_str());
2071 ASSERT_MATCH(result, match_str);
2072}
2073
2074// Verify that a fault address happens in the correct map.
2075TEST_F(CrasherTest, fault_address_in_map) {
2076 // Create a map before the fork so it will be present in the child.
2077 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2078 ASSERT_NE(MAP_FAILED, ptr);
2079
2080 StartProcess([ptr]() {
2081 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2082 _exit(0);
2083 });
2084
2085 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2086
2087 unique_fd output_fd;
2088 StartIntercept(&output_fd);
2089 FinishCrasher();
2090 AssertDeath(SIGSEGV);
2091
2092 int intercept_result;
2093 FinishIntercept(&intercept_result);
2094 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2095
2096 std::string result;
2097 ConsumeFd(std::move(output_fd), &result);
2098
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002099 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2100 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002101 ASSERT_MATCH(result, match_str);
2102
2103 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2104
2105 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2106 ASSERT_MATCH(result, match_str);
2107}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002108
2109static constexpr uint32_t kDexData[] = {
2110 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2111 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2112 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2113 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2114 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2115 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2116 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2117 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2118 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2119 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2120 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2121 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2122 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2123 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2124 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2125 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2126 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2127};
2128
2129TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2130 StartProcess([]() {
2131 TemporaryDir td;
2132 std::string tmp_so_name;
2133 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2134 _exit(1);
2135 }
2136
2137 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2138 // move the library to which has a basename of libart.so.
2139 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2140 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2141 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2142 if (handle == nullptr) {
2143 _exit(1);
2144 }
2145
2146 void* ptr =
2147 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2148 ASSERT_TRUE(ptr != MAP_FAILED);
2149 memcpy(ptr, kDexData, sizeof(kDexData));
2150 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2151
2152 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2153 .symfile_size = sizeof(kDexData)};
2154
2155 JITDescriptor* dex_debug =
2156 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2157 ASSERT_TRUE(dex_debug != nullptr);
2158 dex_debug->version = 1;
2159 dex_debug->action_flag = 0;
2160 dex_debug->relevant_entry = 0;
2161 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2162
2163 // This sets the magic dex pc value for register 0, using the value
2164 // of register 1 + 0x102.
2165 asm(".cfi_escape "
2166 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2167 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2168 "0x13 /* DW_OP_drop */,"
2169 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2170
2171 // For each different architecture, set register one to the dex ptr mmap
2172 // created above. Then do a nullptr dereference to force a crash.
2173#if defined(__arm__)
2174 asm volatile(
2175 "mov r1, %[base]\n"
2176 "mov r2, 0\n"
2177 "str r3, [r2]\n"
2178 : [base] "+r"(ptr)
2179 :
2180 : "r1", "r2", "r3", "memory");
2181#elif defined(__aarch64__)
2182 asm volatile(
2183 "mov x1, %[base]\n"
2184 "mov x2, 0\n"
2185 "str x3, [x2]\n"
2186 : [base] "+r"(ptr)
2187 :
2188 : "x1", "x2", "x3", "memory");
2189#elif defined(__i386__)
2190 asm volatile(
2191 "mov %[base], %%ecx\n"
2192 "movl $0, %%edi\n"
2193 "movl 0(%%edi), %%edx\n"
2194 : [base] "+r"(ptr)
2195 :
2196 : "edi", "ecx", "edx", "memory");
2197#elif defined(__x86_64__)
2198 asm volatile(
2199 "mov %[base], %%rdx\n"
2200 "movq 0, %%rdi\n"
2201 "movq 0(%%rdi), %%rcx\n"
2202 : [base] "+r"(ptr)
2203 :
2204 : "rcx", "rdx", "rdi", "memory");
2205#else
2206#error "Unsupported architecture"
2207#endif
2208 _exit(0);
2209 });
2210
2211 unique_fd output_fd;
2212 StartIntercept(&output_fd);
2213 FinishCrasher();
2214 AssertDeath(SIGSEGV);
2215
2216 int intercept_result;
2217 FinishIntercept(&intercept_result);
2218 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2219
2220 std::string result;
2221 ConsumeFd(std::move(output_fd), &result);
2222
2223 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002224 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002225
2226 // Now verify that the dex_pc frame includes a proper function name.
2227 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2228}