blob: e555793cf2b590bdc56f97edfa159e948885d4c8 [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);
343 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700344
345 if (mte_supported()) {
346 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700347 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
348 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700349 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700350}
351
Peter Collingbournef03af882020-03-20 18:09:00 -0700352TEST_F(CrasherTest, tagged_fault_addr) {
353#if !defined(__aarch64__)
354 GTEST_SKIP() << "Requires aarch64";
355#endif
356 int intercept_result;
357 unique_fd output_fd;
358 StartProcess([]() {
359 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
360 });
361
362 StartIntercept(&output_fd);
363 FinishCrasher();
364 AssertDeath(SIGSEGV);
365 FinishIntercept(&intercept_result);
366
367 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
368
369 std::string result;
370 ConsumeFd(std::move(output_fd), &result);
371
372 // The address can either be tagged (new kernels) or untagged (old kernels).
373 ASSERT_MATCH(
374 result,
375 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
376}
377
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700378// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
379// compiler could still clobber the argument register before trapping, but that's unlikely.
380__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
381 __builtin_trap();
382}
383
384TEST_F(CrasherTest, heap_addr_in_register) {
385#if defined(__i386__)
386 GTEST_SKIP() << "architecture does not pass arguments in registers";
387#endif
388 int intercept_result;
389 unique_fd output_fd;
390 StartProcess([]() {
391 // Crash with a heap pointer in the first argument register.
392 Trap(malloc(1));
393 });
394
395 StartIntercept(&output_fd);
396 FinishCrasher();
397 int status;
398 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
399 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
400 // Don't test the signal number because different architectures use different signals for
401 // __builtin_trap().
402 FinishIntercept(&intercept_result);
403
404 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
405
406 std::string result;
407 ConsumeFd(std::move(output_fd), &result);
408
409#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800410 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700411#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800412 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700413#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800414 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700415#else
416 ASSERT_TRUE(false) << "unsupported architecture";
417#endif
418}
419
Peter Collingbournecd278072020-12-21 14:08:38 -0800420#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700421static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800422 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700423 abort();
424 }
425}
426#endif
427
Mitch Phillips7168a212021-03-09 16:53:23 -0800428// Number of iterations required to reliably guarantee a GWP-ASan crash.
429// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
430// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
431// the counter reaches zero, we provide a sampled allocation. Then, double that
432// figure to allow for left/right allocation alignment, as this is done randomly
433// without bias.
434#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
435
436struct GwpAsanTestParameters {
437 size_t alloc_size;
438 bool free_before_access;
439 int access_offset;
440 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
441};
442
443struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
444
445GwpAsanTestParameters gwp_asan_tests[] = {
446 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
447 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
448 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
449 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
450};
451
452INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
453
454TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
455 if (mte_supported()) {
456 // Skip this test on MTE hardware, as MTE will reliably catch these errors
457 // instead of GWP-ASan.
458 GTEST_SKIP() << "Skipped on MTE.";
459 }
460
461 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700462 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800463
464 int intercept_result;
465 unique_fd output_fd;
466 StartProcess([&params]() {
467 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
468 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
469 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
470 p[params.access_offset] = 42;
471 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
472 }
473 });
474
475 StartIntercept(&output_fd);
476 FinishCrasher();
477 AssertDeath(SIGSEGV);
478 FinishIntercept(&intercept_result);
479
480 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
481
Mitch Phillips78f06702021-06-01 14:35:43 -0700482 std::vector<std::string> log_sources(2);
483 ConsumeFd(std::move(output_fd), &log_sources[0]);
484 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800485
Mitch Phillips78f06702021-06-01 14:35:43 -0700486 for (const auto& result : log_sources) {
487 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
488 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
489 if (params.free_before_access) {
490 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
491 }
492 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800493 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800494}
495
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800496struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
497
Peter Collingbourneaa544792021-05-13 13:53:37 -0700498INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800499
500TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800501#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700502 if (!mte_supported()) {
503 GTEST_SKIP() << "Requires MTE";
504 }
505
Peter Collingbourneaa544792021-05-13 13:53:37 -0700506 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
507 if (GetParam() == 0) {
508 return;
509 }
510
Mitch Phillips78f06702021-06-01 14:35:43 -0700511 LogcatCollector logcat_collector;
512
Peter Collingbournef8622522020-04-07 14:07:32 -0700513 int intercept_result;
514 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800515 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700516 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800517 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700518 free((void *)p);
519 p[0] = 42;
520 });
521
522 StartIntercept(&output_fd);
523 FinishCrasher();
524 AssertDeath(SIGSEGV);
525 FinishIntercept(&intercept_result);
526
527 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
528
Mitch Phillips78f06702021-06-01 14:35:43 -0700529 std::vector<std::string> log_sources(2);
530 ConsumeFd(std::move(output_fd), &log_sources[0]);
531 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700532 // Tag dump only available in the tombstone, not logcat.
533 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700534
Mitch Phillips78f06702021-06-01 14:35:43 -0700535 for (const auto& result : log_sources) {
536 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
537 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
538 std::to_string(GetParam()) + R"(-byte allocation)");
539 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
540 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
541 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700542#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800543 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700544#endif
545}
546
Peter Collingbournedc476342021-05-12 15:56:43 -0700547TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
548#if defined(__aarch64__)
549 if (!mte_supported()) {
550 GTEST_SKIP() << "Requires MTE";
551 }
552
553 int intercept_result;
554 unique_fd output_fd;
555 StartProcess([&]() {
556 SetTagCheckingLevelSync();
557 volatile int* p = (volatile int*)malloc(GetParam());
558 free((void *)p);
559 p[-1] = 42;
560 });
561
562 StartIntercept(&output_fd);
563 FinishCrasher();
564 AssertDeath(SIGSEGV);
565 FinishIntercept(&intercept_result);
566
567 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
568
569 std::string result;
570 ConsumeFd(std::move(output_fd), &result);
571
572 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
573 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
574#else
575 GTEST_SKIP() << "Requires aarch64";
576#endif
577}
578
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800579TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800580#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700581 if (!mte_supported()) {
582 GTEST_SKIP() << "Requires MTE";
583 }
584
Mitch Phillips78f06702021-06-01 14:35:43 -0700585 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700586 int intercept_result;
587 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800588 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700589 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800590 volatile char* p = (volatile char*)malloc(GetParam());
591 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700592 });
593
594 StartIntercept(&output_fd);
595 FinishCrasher();
596 AssertDeath(SIGSEGV);
597 FinishIntercept(&intercept_result);
598
599 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
600
Mitch Phillips78f06702021-06-01 14:35:43 -0700601 std::vector<std::string> log_sources(2);
602 ConsumeFd(std::move(output_fd), &log_sources[0]);
603 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700604
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700605 // Tag dump only in tombstone, not logcat, and tagging is not used for
606 // overflow protection in the scudo secondary (guard pages are used instead).
607 if (GetParam() < 0x10000) {
608 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
609 }
610
Mitch Phillips78f06702021-06-01 14:35:43 -0700611 for (const auto& result : log_sources) {
612 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
613 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
614 std::to_string(GetParam()) + R"(-byte allocation)");
615 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
616 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700617#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800618 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700619#endif
620}
621
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800622TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800623#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700624 if (!mte_supported()) {
625 GTEST_SKIP() << "Requires MTE";
626 }
627
628 int intercept_result;
629 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800630 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700631 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800632 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700633 p[-1] = 42;
634 });
635
636 StartIntercept(&output_fd);
637 FinishCrasher();
638 AssertDeath(SIGSEGV);
639 FinishIntercept(&intercept_result);
640
641 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
642
643 std::string result;
644 ConsumeFd(std::move(output_fd), &result);
645
646 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800647 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800648 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700649 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700650 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700651 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700652#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800653 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700654#endif
655}
656
657TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800658#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700659 if (!mte_supported()) {
660 GTEST_SKIP() << "Requires MTE";
661 }
662
Mitch Phillips78f06702021-06-01 14:35:43 -0700663 LogcatCollector logcat_collector;
664
Peter Collingbournef8622522020-04-07 14:07:32 -0700665 int intercept_result;
666 unique_fd output_fd;
667 StartProcess([]() {
668 SetTagCheckingLevelSync();
669
670 // Make two allocations with the same tag and close to one another. Check for both properties
671 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
672 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
673 // (some non-zero value << 56) apart.
674 //
675 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
676 // other.
677 std::set<uintptr_t> allocs;
678 for (int i = 0; i != 4096; ++i) {
679 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
680 auto it = allocs.insert(alloc).first;
681 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
682 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
683 }
684 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
685 *reinterpret_cast<int*>(alloc + 16) = 42;
686 }
687 }
688 });
689
690 StartIntercept(&output_fd);
691 FinishCrasher();
692 AssertDeath(SIGSEGV);
693 FinishIntercept(&intercept_result);
694
695 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
696
Mitch Phillips78f06702021-06-01 14:35:43 -0700697 std::vector<std::string> log_sources(2);
698 ConsumeFd(std::move(output_fd), &log_sources[0]);
699 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700700
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700701 // Tag dump only in the tombstone, not logcat.
702 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
703
Mitch Phillips78f06702021-06-01 14:35:43 -0700704 for (const auto& result : log_sources) {
705 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
706 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
707 "listing them in decreasing order of probability."));
708 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
709 // overflows), so we can't match explicitly for an underflow message.
710 ASSERT_MATCH(result,
711 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
712 // Ensure there's at least two allocation traces (one for each cause).
713 ASSERT_MATCH(
714 result,
715 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
716 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700717#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800718 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700719#endif
720}
721
Peter Collingbournecd278072020-12-21 14:08:38 -0800722#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700723static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700724 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
725 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
726 size_t page_size = getpagesize();
727 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
728 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
729 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700730 return 0;
731 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700732 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
733 PROT_READ | PROT_WRITE | PROT_MTE);
734 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
735 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
736 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
737 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
738 }
739 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700740}
741#endif
742
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700743TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800744#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700745 if (!mte_supported()) {
746 GTEST_SKIP() << "Requires MTE";
747 }
748
749 int intercept_result;
750 unique_fd output_fd;
751 StartProcess([&]() {
752 SetTagCheckingLevelSync();
753 Trap(reinterpret_cast<void *>(CreateTagMapping()));
754 });
755
756 StartIntercept(&output_fd);
757 FinishCrasher();
758 AssertDeath(SIGTRAP);
759 FinishIntercept(&intercept_result);
760
761 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
762
763 std::string result;
764 ConsumeFd(std::move(output_fd), &result);
765
766 ASSERT_MATCH(result, R"(memory near x0:
767.*
768.*
769 01.............0 0000000000000000 0000000000000000 ................
770 00.............0)");
771#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800772 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700773#endif
774}
775
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700776TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
777#if defined(__aarch64__)
778 if (!mte_supported()) {
779 GTEST_SKIP() << "Requires MTE";
780 }
781
782 int intercept_result;
783 unique_fd output_fd;
784 StartProcess([&]() {
785 SetTagCheckingLevelSync();
786 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
787 p[0] = 0; // Untagged pointer, tagged memory.
788 });
789
790 StartIntercept(&output_fd);
791 FinishCrasher();
792 AssertDeath(SIGSEGV);
793 FinishIntercept(&intercept_result);
794
795 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
796
797 std::string result;
798 ConsumeFd(std::move(output_fd), &result);
799
800 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
801\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
802#else
803 GTEST_SKIP() << "Requires aarch64";
804#endif
805}
806
807TEST_F(CrasherTest, mte_fault_tag_dump) {
808#if defined(__aarch64__)
809 if (!mte_supported()) {
810 GTEST_SKIP() << "Requires MTE";
811 }
812
813 int intercept_result;
814 unique_fd output_fd;
815 StartProcess([&]() {
816 SetTagCheckingLevelSync();
817 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
818 p[320] = 0; // Untagged pointer, tagged memory.
819 });
820
821 StartIntercept(&output_fd);
822 FinishCrasher();
823 AssertDeath(SIGSEGV);
824 FinishIntercept(&intercept_result);
825
826 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
827
828 std::string result;
829 ConsumeFd(std::move(output_fd), &result);
830
831 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
832\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
833\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
834\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
835)");
836#else
837 GTEST_SKIP() << "Requires aarch64";
838#endif
839}
840
841TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
842#if defined(__aarch64__)
843 if (!mte_supported()) {
844 GTEST_SKIP() << "Requires MTE";
845 }
846
847 int intercept_result;
848 unique_fd output_fd;
849 StartProcess([&]() {
850 SetTagCheckingLevelSync();
851 size_t page_size = getpagesize();
852 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
853 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
854 });
855
856 StartIntercept(&output_fd);
857 FinishCrasher();
858 AssertDeath(SIGSEGV);
859 FinishIntercept(&intercept_result);
860
861 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
862
863 std::string result;
864 ConsumeFd(std::move(output_fd), &result);
865
866 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
867 ASSERT_MATCH(result,
868 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
869\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
870
871)"); // Ensure truncation happened and there's a newline after the tag fault.
872#else
873 GTEST_SKIP() << "Requires aarch64";
874#endif
875}
876
Josh Gaocdea7502017-11-01 15:00:40 -0700877TEST_F(CrasherTest, LD_PRELOAD) {
878 int intercept_result;
879 unique_fd output_fd;
880 StartProcess([]() {
881 setenv("LD_PRELOAD", "nonexistent.so", 1);
882 *reinterpret_cast<volatile char*>(0xdead) = '1';
883 });
884
885 StartIntercept(&output_fd);
886 FinishCrasher();
887 AssertDeath(SIGSEGV);
888 FinishIntercept(&intercept_result);
889
890 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
891
892 std::string result;
893 ConsumeFd(std::move(output_fd), &result);
894 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
895}
896
Josh Gaocbe70cb2016-10-18 18:17:52 -0700897TEST_F(CrasherTest, abort) {
898 int intercept_result;
899 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800900 StartProcess([]() {
901 abort();
902 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700903 StartIntercept(&output_fd);
904 FinishCrasher();
905 AssertDeath(SIGABRT);
906 FinishIntercept(&intercept_result);
907
908 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
909
910 std::string result;
911 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700912 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700913}
914
915TEST_F(CrasherTest, signal) {
916 int intercept_result;
917 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800918 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700919 while (true) {
920 sleep(1);
921 }
Josh Gao502cfd22017-02-17 01:39:15 -0800922 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700923 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700924 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700925 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
926
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);
Elliott Hughes89722702018-05-02 10:47:00 -0700934 ASSERT_MATCH(
935 result,
936 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700937 ASSERT_MATCH(result, R"(backtrace:)");
938}
939
940TEST_F(CrasherTest, abort_message) {
941 int intercept_result;
942 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800943 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800944 // Arrived at experimentally;
945 // logd truncates at 4062.
946 // strlen("Abort message: ''") is 17.
947 // That's 4045, but we also want a NUL.
948 char buf[4045 + 1];
949 memset(buf, 'x', sizeof(buf));
950 buf[sizeof(buf) - 1] = '\0';
951 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800952 abort();
953 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700954 StartIntercept(&output_fd);
955 FinishCrasher();
956 AssertDeath(SIGABRT);
957 FinishIntercept(&intercept_result);
958
959 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
960
961 std::string result;
962 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800963 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700964}
965
Christopher Ferrise8891452021-08-17 17:34:53 -0700966TEST_F(CrasherTest, abort_message_newline_trimmed) {
967 int intercept_result;
968 unique_fd output_fd;
969 StartProcess([]() {
970 android_set_abort_message("Message with a newline.\n");
971 abort();
972 });
973 StartIntercept(&output_fd);
974 FinishCrasher();
975 AssertDeath(SIGABRT);
976 FinishIntercept(&intercept_result);
977
978 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
979
980 std::string result;
981 ConsumeFd(std::move(output_fd), &result);
982 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
983}
984
985TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
986 int intercept_result;
987 unique_fd output_fd;
988 StartProcess([]() {
989 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
990 abort();
991 });
992 StartIntercept(&output_fd);
993 FinishCrasher();
994 AssertDeath(SIGABRT);
995 FinishIntercept(&intercept_result);
996
997 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
998
999 std::string result;
1000 ConsumeFd(std::move(output_fd), &result);
1001 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1002}
1003
Josh Gaoe06f2a42017-04-27 16:50:38 -07001004TEST_F(CrasherTest, abort_message_backtrace) {
1005 int intercept_result;
1006 unique_fd output_fd;
1007 StartProcess([]() {
1008 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001009 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001010 exit(0);
1011 });
1012 StartIntercept(&output_fd);
1013 FinishCrasher();
1014 AssertDeath(0);
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_NOT_MATCH(result, R"(Abort message:)");
1022}
1023
Josh Gaocbe70cb2016-10-18 18:17:52 -07001024TEST_F(CrasherTest, intercept_timeout) {
1025 int intercept_result;
1026 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001027 StartProcess([]() {
1028 abort();
1029 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001030 StartIntercept(&output_fd);
1031
1032 // Don't let crasher finish until we timeout.
1033 FinishIntercept(&intercept_result);
1034
1035 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1036 << intercept_result << ")";
1037
1038 FinishCrasher();
1039 AssertDeath(SIGABRT);
1040}
1041
Elliott Hughese4781d52021-03-17 09:15:15 -07001042TEST_F(CrasherTest, wait_for_debugger) {
1043 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1044 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001045 }
1046 sleep(1);
1047
Josh Gao502cfd22017-02-17 01:39:15 -08001048 StartProcess([]() {
1049 abort();
1050 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001051 FinishCrasher();
1052
1053 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001054 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001055 ASSERT_TRUE(WIFSTOPPED(status));
1056 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1057
1058 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1059
1060 AssertDeath(SIGABRT);
1061}
1062
Josh Gaocbe70cb2016-10-18 18:17:52 -07001063TEST_F(CrasherTest, backtrace) {
1064 std::string result;
1065 int intercept_result;
1066 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001067
1068 StartProcess([]() {
1069 abort();
1070 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001071 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001072
1073 std::this_thread::sleep_for(500ms);
1074
1075 sigval val;
1076 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001077 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001078 FinishIntercept(&intercept_result);
1079 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1080 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001081 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001082
1083 int status;
1084 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1085
1086 StartIntercept(&output_fd);
1087 FinishCrasher();
1088 AssertDeath(SIGABRT);
1089 FinishIntercept(&intercept_result);
1090 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1091 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001092 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001093}
Josh Gaofca7ca32017-01-23 12:05:35 -08001094
1095TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001096 int intercept_result;
1097 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001098 StartProcess([]() {
1099 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001100 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001101 });
Josh Gao502cfd22017-02-17 01:39:15 -08001102
1103 StartIntercept(&output_fd);
1104 FinishCrasher();
1105 AssertDeath(SIGABRT);
1106 FinishIntercept(&intercept_result);
1107
1108 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1109
1110 std::string result;
1111 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001112 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001113}
1114
Josh Gao502cfd22017-02-17 01:39:15 -08001115TEST_F(CrasherTest, capabilities) {
1116 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1117
Josh Gaofca7ca32017-01-23 12:05:35 -08001118 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001119 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1120 err(1, "failed to set PR_SET_KEEPCAPS");
1121 }
1122
1123 if (setresuid(1, 1, 1) != 0) {
1124 err(1, "setresuid failed");
1125 }
1126
1127 __user_cap_header_struct capheader;
1128 __user_cap_data_struct capdata[2];
1129 memset(&capheader, 0, sizeof(capheader));
1130 memset(&capdata, 0, sizeof(capdata));
1131
1132 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1133 capheader.pid = 0;
1134
1135 // Turn on every third capability.
1136 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1137 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1138 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1139 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1140 }
1141
1142 // Make sure CAP_SYS_PTRACE is off.
1143 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1144 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1145
1146 if (capset(&capheader, &capdata[0]) != 0) {
1147 err(1, "capset failed");
1148 }
1149
1150 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1151 err(1, "failed to drop ambient capabilities");
1152 }
1153
Josh Gaoa5199a92017-04-03 13:18:34 -07001154 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001155 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001156 });
Josh Gao502cfd22017-02-17 01:39:15 -08001157
1158 unique_fd output_fd;
1159 StartIntercept(&output_fd);
1160 FinishCrasher();
1161 AssertDeath(SIGSYS);
1162
1163 std::string result;
1164 int intercept_result;
1165 FinishIntercept(&intercept_result);
1166 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1167 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001168 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001169 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001170}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001171
Josh Gao2e7b8e22017-05-04 17:12:57 -07001172TEST_F(CrasherTest, fake_pid) {
1173 int intercept_result;
1174 unique_fd output_fd;
1175
1176 // Prime the getpid/gettid caches.
1177 UNUSED(getpid());
1178 UNUSED(gettid());
1179
1180 std::function<pid_t()> clone_fn = []() {
1181 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1182 };
1183 StartProcess(
1184 []() {
1185 ASSERT_NE(getpid(), syscall(__NR_getpid));
1186 ASSERT_NE(gettid(), syscall(__NR_gettid));
1187 raise(SIGSEGV);
1188 },
1189 clone_fn);
1190
1191 StartIntercept(&output_fd);
1192 FinishCrasher();
1193 AssertDeath(SIGSEGV);
1194 FinishIntercept(&intercept_result);
1195
1196 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1197
1198 std::string result;
1199 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001200 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001201}
1202
Josh Gaoe04ca272018-01-16 15:38:17 -08001203static const char* const kDebuggerdSeccompPolicy =
1204 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1205
Josh Gao70adac62018-02-22 11:38:33 -08001206static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001207 std::string policy;
1208 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1209 PLOG(FATAL) << "failed to read policy file";
1210 }
1211
1212 // Allow a bunch of syscalls used by the tests.
1213 policy += "\nclone: 1";
1214 policy += "\nsigaltstack: 1";
1215 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001216 policy += "\ngetrlimit: 1";
1217 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001218
1219 FILE* tmp_file = tmpfile();
1220 if (!tmp_file) {
1221 PLOG(FATAL) << "tmpfile failed";
1222 }
1223
Christopher Ferris172b0a02019-09-18 17:48:30 -07001224 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001225 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1226 PLOG(FATAL) << "failed to write policy to tmpfile";
1227 }
1228
1229 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1230 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001231 }
1232
1233 ScopedMinijail jail{minijail_new()};
1234 if (!jail) {
1235 LOG(FATAL) << "failed to create minijail";
1236 }
1237
1238 minijail_no_new_privs(jail.get());
1239 minijail_log_seccomp_filter_failures(jail.get());
1240 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001241 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001242
1243 pid_t result = fork();
1244 if (result == -1) {
1245 return result;
1246 } else if (result != 0) {
1247 return result;
1248 }
1249
1250 // Spawn and detach a thread that spins forever.
1251 std::atomic<bool> thread_ready(false);
1252 std::thread thread([&jail, &thread_ready]() {
1253 minijail_enter(jail.get());
1254 thread_ready = true;
1255 for (;;)
1256 ;
1257 });
1258 thread.detach();
1259
1260 while (!thread_ready) {
1261 continue;
1262 }
1263
Josh Gao70adac62018-02-22 11:38:33 -08001264 if (prejail) {
1265 prejail();
1266 }
1267
Josh Gaoe04ca272018-01-16 15:38:17 -08001268 minijail_enter(jail.get());
1269 return result;
1270}
1271
Josh Gao70adac62018-02-22 11:38:33 -08001272static pid_t seccomp_fork() {
1273 return seccomp_fork_impl(nullptr);
1274}
1275
Josh Gaoe04ca272018-01-16 15:38:17 -08001276TEST_F(CrasherTest, seccomp_crash) {
1277 int intercept_result;
1278 unique_fd output_fd;
1279
1280 StartProcess([]() { abort(); }, &seccomp_fork);
1281
1282 StartIntercept(&output_fd);
1283 FinishCrasher();
1284 AssertDeath(SIGABRT);
1285 FinishIntercept(&intercept_result);
1286 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1287
1288 std::string result;
1289 ConsumeFd(std::move(output_fd), &result);
1290 ASSERT_BACKTRACE_FRAME(result, "abort");
1291}
1292
Josh Gao70adac62018-02-22 11:38:33 -08001293static pid_t seccomp_fork_rlimit() {
1294 return seccomp_fork_impl([]() {
1295 struct rlimit rlim = {
1296 .rlim_cur = 512 * 1024 * 1024,
1297 .rlim_max = 512 * 1024 * 1024,
1298 };
1299
1300 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1301 raise(SIGINT);
1302 }
1303 });
1304}
1305
1306TEST_F(CrasherTest, seccomp_crash_oom) {
1307 int intercept_result;
1308 unique_fd output_fd;
1309
1310 StartProcess(
1311 []() {
1312 std::vector<void*> vec;
1313 for (int i = 0; i < 512; ++i) {
1314 char* buf = static_cast<char*>(malloc(1024 * 1024));
1315 if (!buf) {
1316 abort();
1317 }
1318 memset(buf, 0xff, 1024 * 1024);
1319 vec.push_back(buf);
1320 }
1321 },
1322 &seccomp_fork_rlimit);
1323
1324 StartIntercept(&output_fd);
1325 FinishCrasher();
1326 AssertDeath(SIGABRT);
1327 FinishIntercept(&intercept_result);
1328 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1329
1330 // We can't actually generate a backtrace, just make sure that the process terminates.
1331}
1332
Josh Gaoe04ca272018-01-16 15:38:17 -08001333__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1334 siginfo_t siginfo;
1335 siginfo.si_code = SI_QUEUE;
1336 siginfo.si_pid = getpid();
1337 siginfo.si_uid = getuid();
1338
1339 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1340 PLOG(FATAL) << "invalid dump type";
1341 }
1342
1343 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1344
Josh Gaoa48b41b2019-12-13 14:11:04 -08001345 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001346 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1347 return false;
1348 }
1349
1350 return true;
1351}
1352
1353TEST_F(CrasherTest, seccomp_tombstone) {
1354 int intercept_result;
1355 unique_fd output_fd;
1356
1357 static const auto dump_type = kDebuggerdTombstone;
1358 StartProcess(
1359 []() {
1360 raise_debugger_signal(dump_type);
1361 _exit(0);
1362 },
1363 &seccomp_fork);
1364
1365 StartIntercept(&output_fd, dump_type);
1366 FinishCrasher();
1367 AssertDeath(0);
1368 FinishIntercept(&intercept_result);
1369 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1370
1371 std::string result;
1372 ConsumeFd(std::move(output_fd), &result);
1373 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1374}
1375
Josh Gao6f9eeec2018-09-12 13:55:47 -07001376extern "C" void foo() {
1377 LOG(INFO) << "foo";
1378 std::this_thread::sleep_for(1s);
1379}
1380
1381extern "C" void bar() {
1382 LOG(INFO) << "bar";
1383 std::this_thread::sleep_for(1s);
1384}
1385
Josh Gaoe04ca272018-01-16 15:38:17 -08001386TEST_F(CrasherTest, seccomp_backtrace) {
1387 int intercept_result;
1388 unique_fd output_fd;
1389
1390 static const auto dump_type = kDebuggerdNativeBacktrace;
1391 StartProcess(
1392 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001393 std::thread a(foo);
1394 std::thread b(bar);
1395
1396 std::this_thread::sleep_for(100ms);
1397
Josh Gaoe04ca272018-01-16 15:38:17 -08001398 raise_debugger_signal(dump_type);
1399 _exit(0);
1400 },
1401 &seccomp_fork);
1402
1403 StartIntercept(&output_fd, dump_type);
1404 FinishCrasher();
1405 AssertDeath(0);
1406 FinishIntercept(&intercept_result);
1407 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1408
1409 std::string result;
1410 ConsumeFd(std::move(output_fd), &result);
1411 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001412 ASSERT_BACKTRACE_FRAME(result, "foo");
1413 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001414}
1415
1416TEST_F(CrasherTest, seccomp_crash_logcat) {
1417 StartProcess([]() { abort(); }, &seccomp_fork);
1418 FinishCrasher();
1419
1420 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1421 AssertDeath(SIGABRT);
1422}
1423
Josh Gaofd13bf02017-08-18 15:37:26 -07001424TEST_F(CrasherTest, competing_tracer) {
1425 int intercept_result;
1426 unique_fd output_fd;
1427 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001428 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001429 });
1430
1431 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001432
1433 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001434 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001435
1436 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001437 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001438 ASSERT_TRUE(WIFSTOPPED(status));
1439 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1440
1441 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1442 FinishIntercept(&intercept_result);
1443 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1444
1445 std::string result;
1446 ConsumeFd(std::move(output_fd), &result);
1447 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1448 regex += std::to_string(gettid());
1449 regex += R"( \(.+debuggerd_test)";
1450 ASSERT_MATCH(result, regex.c_str());
1451
Christopher Ferris172b0a02019-09-18 17:48:30 -07001452 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001453 ASSERT_TRUE(WIFSTOPPED(status));
1454 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1455
Josh Gaofd13bf02017-08-18 15:37:26 -07001456 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1457 AssertDeath(SIGABRT);
1458}
1459
Josh Gaobf06a402018-08-27 16:34:01 -07001460TEST_F(CrasherTest, fdsan_warning_abort_message) {
1461 int intercept_result;
1462 unique_fd output_fd;
1463
1464 StartProcess([]() {
1465 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001466 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001467 if (fd == -1) {
1468 abort();
1469 }
1470 close(fd.get());
1471 _exit(0);
1472 });
1473
1474 StartIntercept(&output_fd);
1475 FinishCrasher();
1476 AssertDeath(0);
1477 FinishIntercept(&intercept_result);
1478 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1479
1480 std::string result;
1481 ConsumeFd(std::move(output_fd), &result);
1482 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1483}
1484
Josh Gaoc3c8c022017-02-13 16:36:18 -08001485TEST(crash_dump, zombie) {
1486 pid_t forkpid = fork();
1487
Josh Gaoc3c8c022017-02-13 16:36:18 -08001488 pid_t rc;
1489 int status;
1490
1491 if (forkpid == 0) {
1492 errno = 0;
1493 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1494 if (rc != -1 || errno != ECHILD) {
1495 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1496 }
1497
Josh Gaoa48b41b2019-12-13 14:11:04 -08001498 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001499
1500 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001501 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001502 if (rc != -1 || errno != ECHILD) {
1503 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1504 }
1505 _exit(0);
1506 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001507 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001508 ASSERT_EQ(forkpid, rc);
1509 ASSERT_TRUE(WIFEXITED(status));
1510 ASSERT_EQ(0, WEXITSTATUS(status));
1511 }
1512}
Josh Gao352a8452017-03-30 16:46:21 -07001513
1514TEST(tombstoned, no_notify) {
1515 // Do this a few times.
1516 for (int i = 0; i < 3; ++i) {
1517 pid_t pid = 123'456'789 + i;
1518
1519 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001520 InterceptStatus status;
1521 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1522 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001523
1524 {
1525 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001526 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001527 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1528 }
1529
1530 pid_t read_pid;
1531 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1532 ASSERT_EQ(read_pid, pid);
1533 }
1534}
1535
1536TEST(tombstoned, stress) {
1537 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1538 static constexpr int kDumpCount = 100;
1539
1540 std::atomic<bool> start(false);
1541 std::vector<std::thread> threads;
1542 threads.emplace_back([&start]() {
1543 while (!start) {
1544 continue;
1545 }
1546
1547 // Use a way out of range pid, to avoid stomping on an actual process.
1548 pid_t pid_base = 1'000'000;
1549
1550 for (int dump = 0; dump < kDumpCount; ++dump) {
1551 pid_t pid = pid_base + dump;
1552
1553 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001554 InterceptStatus status;
1555 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1556 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001557
1558 // Pretend to crash, and then immediately close the socket.
1559 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1560 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1561 if (sockfd == -1) {
1562 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1563 }
1564 TombstonedCrashPacket packet = {};
1565 packet.packet_type = CrashPacketType::kDumpRequest;
1566 packet.packet.dump_request.pid = pid;
1567 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1568 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1569 }
1570
1571 continue;
1572 }
1573 });
1574
1575 threads.emplace_back([&start]() {
1576 while (!start) {
1577 continue;
1578 }
1579
1580 // Use a way out of range pid, to avoid stomping on an actual process.
1581 pid_t pid_base = 2'000'000;
1582
1583 for (int dump = 0; dump < kDumpCount; ++dump) {
1584 pid_t pid = pid_base + dump;
1585
1586 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001587 InterceptStatus status;
1588 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1589 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001590
1591 {
1592 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001593 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001594 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1595 tombstoned_notify_completion(tombstoned_socket.get());
1596 }
1597
1598 // TODO: Fix the race that requires this sleep.
1599 std::this_thread::sleep_for(50ms);
1600
1601 pid_t read_pid;
1602 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1603 ASSERT_EQ(read_pid, pid);
1604 }
1605 });
1606
1607 start = true;
1608
1609 for (std::thread& thread : threads) {
1610 thread.join();
1611 }
1612}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001613
1614TEST(tombstoned, java_trace_intercept_smoke) {
1615 // Using a "real" PID is a little dangerous here - if the test fails
1616 // or crashes, we might end up getting a bogus / unreliable stack
1617 // trace.
1618 const pid_t self = getpid();
1619
1620 unique_fd intercept_fd, output_fd;
1621 InterceptStatus status;
1622 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1623 ASSERT_EQ(InterceptStatus::kRegistered, status);
1624
Josh Gao76e1e302021-01-26 15:53:11 -08001625 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001626 // should result in a "regular" FD and not the installed intercept.
1627 const char native[] = "native";
1628 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001629 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001630 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1631 tombstoned_notify_completion(tombstoned_socket.get());
1632
1633 // Then, connect to tombstoned asking for a java backtrace. This *should*
1634 // trigger the intercept.
1635 const char java[] = "java";
1636 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1637 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1638 tombstoned_notify_completion(tombstoned_socket.get());
1639
1640 char outbuf[sizeof(java)];
1641 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1642 ASSERT_STREQ("java", outbuf);
1643}
1644
1645TEST(tombstoned, multiple_intercepts) {
1646 const pid_t fake_pid = 1'234'567;
1647 unique_fd intercept_fd, output_fd;
1648 InterceptStatus status;
1649 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1650 ASSERT_EQ(InterceptStatus::kRegistered, status);
1651
1652 unique_fd intercept_fd_2, output_fd_2;
1653 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1654 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1655}
1656
1657TEST(tombstoned, intercept_any) {
1658 const pid_t fake_pid = 1'234'567;
1659
1660 unique_fd intercept_fd, output_fd;
1661 InterceptStatus status;
1662 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1663 ASSERT_EQ(InterceptStatus::kRegistered, status);
1664
1665 const char any[] = "any";
1666 unique_fd tombstoned_socket, input_fd;
1667 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1668 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1669 tombstoned_notify_completion(tombstoned_socket.get());
1670
1671 char outbuf[sizeof(any)];
1672 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1673 ASSERT_STREQ("any", outbuf);
1674}
Josh Gao2b22ae12018-09-12 14:51:03 -07001675
1676TEST(tombstoned, interceptless_backtrace) {
1677 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1678 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1679 std::map<int, time_t> result;
1680 for (int i = 0; i < 99; ++i) {
1681 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1682 struct stat st;
1683 if (stat(path.c_str(), &st) == 0) {
1684 result[i] = st.st_mtim.tv_sec;
1685 }
1686 }
1687 return result;
1688 };
1689
1690 auto before = get_tombstone_timestamps();
1691 for (int i = 0; i < 50; ++i) {
1692 raise_debugger_signal(kDebuggerdNativeBacktrace);
1693 }
1694 auto after = get_tombstone_timestamps();
1695
1696 int diff = 0;
1697 for (int i = 0; i < 99; ++i) {
1698 if (after.count(i) == 0) {
1699 continue;
1700 }
1701 if (before.count(i) == 0) {
1702 ++diff;
1703 continue;
1704 }
1705 if (before[i] != after[i]) {
1706 ++diff;
1707 }
1708 }
1709
1710 // We can't be sure that nothing's crash looping in the background.
1711 // This should be good enough, though...
1712 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1713}
Christopher Ferris481e8372019-07-15 17:13:24 -07001714
1715static __attribute__((__noinline__)) void overflow_stack(void* p) {
1716 void* buf[1];
1717 buf[0] = p;
1718 static volatile void* global = buf;
1719 if (global) {
1720 global = buf;
1721 overflow_stack(&buf);
1722 }
1723}
1724
1725TEST_F(CrasherTest, stack_overflow) {
1726 int intercept_result;
1727 unique_fd output_fd;
1728 StartProcess([]() { overflow_stack(nullptr); });
1729
1730 StartIntercept(&output_fd);
1731 FinishCrasher();
1732 AssertDeath(SIGSEGV);
1733 FinishIntercept(&intercept_result);
1734
1735 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1736
1737 std::string result;
1738 ConsumeFd(std::move(output_fd), &result);
1739 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1740}
Josh Gao76e1e302021-01-26 15:53:11 -08001741
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001742static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1743 std::string test_lib(testing::internal::GetArgvs()[0]);
1744 auto const value = test_lib.find_last_of('/');
1745 if (value == std::string::npos) {
1746 test_lib = "./";
1747 } else {
1748 test_lib = test_lib.substr(0, value + 1) + "./";
1749 }
1750 test_lib += "libcrash_test.so";
1751
1752 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1753 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1754
1755 // Copy the shared so to a tempory directory.
1756 return system(cp_cmd.c_str()) == 0;
1757}
1758
1759TEST_F(CrasherTest, unreadable_elf) {
1760 int intercept_result;
1761 unique_fd output_fd;
1762 StartProcess([]() {
1763 TemporaryDir td;
1764 std::string tmp_so_name;
1765 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1766 _exit(1);
1767 }
1768 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1769 if (handle == nullptr) {
1770 _exit(1);
1771 }
1772 // Delete the original shared library so that we get the warning
1773 // about unreadable elf files.
1774 if (unlink(tmp_so_name.c_str()) == -1) {
1775 _exit(1);
1776 }
1777 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1778 if (crash_func == nullptr) {
1779 _exit(1);
1780 }
1781 crash_func();
1782 });
1783
1784 StartIntercept(&output_fd);
1785 FinishCrasher();
1786 AssertDeath(SIGSEGV);
1787 FinishIntercept(&intercept_result);
1788
1789 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1790
1791 std::string result;
1792 ConsumeFd(std::move(output_fd), &result);
1793 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
1794}
1795
Josh Gao76e1e302021-01-26 15:53:11 -08001796TEST(tombstoned, proto) {
1797 const pid_t self = getpid();
1798 unique_fd tombstoned_socket, text_fd, proto_fd;
1799 ASSERT_TRUE(
1800 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1801
1802 tombstoned_notify_completion(tombstoned_socket.get());
1803
1804 ASSERT_NE(-1, text_fd.get());
1805 ASSERT_NE(-1, proto_fd.get());
1806
1807 struct stat text_st;
1808 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1809
1810 // Give tombstoned some time to link the files into place.
1811 std::this_thread::sleep_for(100ms);
1812
1813 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001814 std::optional<std::string> tombstone_file;
1815 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1816 ASSERT_TRUE(dir_h != nullptr);
1817 std::regex tombstone_re("tombstone_\\d+");
1818 dirent* entry;
1819 while ((entry = readdir(dir_h.get())) != nullptr) {
1820 if (!std::regex_match(entry->d_name, tombstone_re)) {
1821 continue;
1822 }
1823 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001824
1825 struct stat st;
1826 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1827 continue;
1828 }
1829
1830 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001831 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001832 break;
1833 }
1834 }
1835
Christopher Ferris35da2882021-02-17 15:39:06 -08001836 ASSERT_TRUE(tombstone_file);
1837 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001838
1839 struct stat proto_fd_st;
1840 struct stat proto_file_st;
1841 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1842 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1843
1844 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1845 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1846}
1847
1848TEST(tombstoned, proto_intercept) {
1849 const pid_t self = getpid();
1850 unique_fd intercept_fd, output_fd;
1851 InterceptStatus status;
1852
1853 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1854 ASSERT_EQ(InterceptStatus::kRegistered, status);
1855
1856 unique_fd tombstoned_socket, text_fd, proto_fd;
1857 ASSERT_TRUE(
1858 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1859 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1860 tombstoned_notify_completion(tombstoned_socket.get());
1861
1862 text_fd.reset();
1863
1864 std::string output;
1865 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1866 ASSERT_EQ("foo", output);
1867}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001868
1869// Verify that when an intercept is present for the main thread, and the signal
1870// is received on a different thread, the intercept still works.
1871TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1872 StartProcess([]() {
1873 std::thread thread([]() {
1874 // Raise the signal on the side thread.
1875 raise_debugger_signal(kDebuggerdNativeBacktrace);
1876 });
1877 thread.join();
1878 _exit(0);
1879 });
1880
1881 unique_fd output_fd;
1882 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1883 FinishCrasher();
1884 AssertDeath(0);
1885
1886 int intercept_result;
1887 FinishIntercept(&intercept_result);
1888 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1889
1890 std::string result;
1891 ConsumeFd(std::move(output_fd), &result);
1892 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1893}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001894
1895static std::string format_pointer(uintptr_t ptr) {
1896#if defined(__LP64__)
1897 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1898 static_cast<uint32_t>(ptr & 0xffffffff));
1899#else
1900 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1901#endif
1902}
1903
1904static std::string format_pointer(void* ptr) {
1905 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1906}
1907
1908static std::string format_full_pointer(uintptr_t ptr) {
1909#if defined(__LP64__)
1910 return android::base::StringPrintf("%016" PRIx64, ptr);
1911#else
1912 return android::base::StringPrintf("%08x", ptr);
1913#endif
1914}
1915
1916static std::string format_full_pointer(void* ptr) {
1917 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1918}
1919
1920__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1921 int* crash_ptr = reinterpret_cast<int*>(ptr);
1922 *crash_ptr = 1;
1923 return *crash_ptr;
1924}
1925
1926// Verify that a fault address before the first map is properly handled.
1927TEST_F(CrasherTest, fault_address_before_first_map) {
1928 StartProcess([]() {
1929 ASSERT_EQ(0, crash_call(0x1024));
1930 _exit(0);
1931 });
1932
1933 unique_fd output_fd;
1934 StartIntercept(&output_fd);
1935 FinishCrasher();
1936 AssertDeath(SIGSEGV);
1937
1938 int intercept_result;
1939 FinishIntercept(&intercept_result);
1940 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1941
1942 std::string result;
1943 ConsumeFd(std::move(output_fd), &result);
1944 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x1024)");
1945
1946 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
1947
1948 std::string match_str = android::base::StringPrintf(
1949 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
1950 format_pointer(0x1024).c_str());
1951 ASSERT_MATCH(result, match_str);
1952}
1953
1954// Verify that a fault address after the last map is properly handled.
1955TEST_F(CrasherTest, fault_address_after_last_map) {
1956 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
1957 StartProcess([crash_uptr]() {
1958 ASSERT_EQ(0, crash_call(crash_uptr));
1959 _exit(0);
1960 });
1961
1962 unique_fd output_fd;
1963 StartIntercept(&output_fd);
1964 FinishCrasher();
1965 AssertDeath(SIGSEGV);
1966
1967 int intercept_result;
1968 FinishIntercept(&intercept_result);
1969 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1970
1971 std::string result;
1972 ConsumeFd(std::move(output_fd), &result);
1973
1974 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
1975 match_str += android::base::StringPrintf("0x%" PRIxPTR, crash_uptr);
1976 ASSERT_MATCH(result, match_str);
1977
1978 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
1979
1980 // Assumes that the open files section comes after the map section.
1981 // If that assumption changes, the regex below needs to change.
1982 match_str = android::base::StringPrintf(
1983 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
1984 format_pointer(crash_uptr).c_str());
1985 ASSERT_MATCH(result, match_str);
1986}
1987
1988// Verify that a fault address between maps is properly handled.
1989TEST_F(CrasherTest, fault_address_between_maps) {
1990 // Create a map before the fork so it will be present in the child.
1991 void* start_ptr =
1992 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
1993 ASSERT_NE(MAP_FAILED, start_ptr);
1994 // Unmap the page in the middle.
1995 void* middle_ptr =
1996 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
1997 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
1998
1999 StartProcess([middle_ptr]() {
2000 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2001 _exit(0);
2002 });
2003
2004 // Unmap the two maps.
2005 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2006 void* end_ptr =
2007 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2008 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2009
2010 unique_fd output_fd;
2011 StartIntercept(&output_fd);
2012 FinishCrasher();
2013 AssertDeath(SIGSEGV);
2014
2015 int intercept_result;
2016 FinishIntercept(&intercept_result);
2017 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2018
2019 std::string result;
2020 ConsumeFd(std::move(output_fd), &result);
2021
2022 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
2023 match_str += android::base::StringPrintf("%p", middle_ptr);
2024 ASSERT_MATCH(result, match_str);
2025
2026 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2027
2028 match_str = android::base::StringPrintf(
2029 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2030 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2031 format_pointer(end_ptr).c_str());
2032 ASSERT_MATCH(result, match_str);
2033}
2034
2035// Verify that a fault address happens in the correct map.
2036TEST_F(CrasherTest, fault_address_in_map) {
2037 // Create a map before the fork so it will be present in the child.
2038 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2039 ASSERT_NE(MAP_FAILED, ptr);
2040
2041 StartProcess([ptr]() {
2042 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2043 _exit(0);
2044 });
2045
2046 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2047
2048 unique_fd output_fd;
2049 StartIntercept(&output_fd);
2050 FinishCrasher();
2051 AssertDeath(SIGSEGV);
2052
2053 int intercept_result;
2054 FinishIntercept(&intercept_result);
2055 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2056
2057 std::string result;
2058 ConsumeFd(std::move(output_fd), &result);
2059
2060 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr )";
2061 match_str += android::base::StringPrintf("%p", ptr);
2062 ASSERT_MATCH(result, match_str);
2063
2064 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2065
2066 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2067 ASSERT_MATCH(result, match_str);
2068}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002069
2070static constexpr uint32_t kDexData[] = {
2071 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2072 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2073 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2074 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2075 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2076 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2077 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2078 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2079 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2080 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2081 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2082 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2083 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2084 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2085 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2086 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2087 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2088};
2089
2090TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2091 StartProcess([]() {
2092 TemporaryDir td;
2093 std::string tmp_so_name;
2094 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2095 _exit(1);
2096 }
2097
2098 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2099 // move the library to which has a basename of libart.so.
2100 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2101 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2102 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2103 if (handle == nullptr) {
2104 _exit(1);
2105 }
2106
2107 void* ptr =
2108 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2109 ASSERT_TRUE(ptr != MAP_FAILED);
2110 memcpy(ptr, kDexData, sizeof(kDexData));
2111 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2112
2113 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2114 .symfile_size = sizeof(kDexData)};
2115
2116 JITDescriptor* dex_debug =
2117 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2118 ASSERT_TRUE(dex_debug != nullptr);
2119 dex_debug->version = 1;
2120 dex_debug->action_flag = 0;
2121 dex_debug->relevant_entry = 0;
2122 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2123
2124 // This sets the magic dex pc value for register 0, using the value
2125 // of register 1 + 0x102.
2126 asm(".cfi_escape "
2127 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2128 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2129 "0x13 /* DW_OP_drop */,"
2130 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2131
2132 // For each different architecture, set register one to the dex ptr mmap
2133 // created above. Then do a nullptr dereference to force a crash.
2134#if defined(__arm__)
2135 asm volatile(
2136 "mov r1, %[base]\n"
2137 "mov r2, 0\n"
2138 "str r3, [r2]\n"
2139 : [base] "+r"(ptr)
2140 :
2141 : "r1", "r2", "r3", "memory");
2142#elif defined(__aarch64__)
2143 asm volatile(
2144 "mov x1, %[base]\n"
2145 "mov x2, 0\n"
2146 "str x3, [x2]\n"
2147 : [base] "+r"(ptr)
2148 :
2149 : "x1", "x2", "x3", "memory");
2150#elif defined(__i386__)
2151 asm volatile(
2152 "mov %[base], %%ecx\n"
2153 "movl $0, %%edi\n"
2154 "movl 0(%%edi), %%edx\n"
2155 : [base] "+r"(ptr)
2156 :
2157 : "edi", "ecx", "edx", "memory");
2158#elif defined(__x86_64__)
2159 asm volatile(
2160 "mov %[base], %%rdx\n"
2161 "movq 0, %%rdi\n"
2162 "movq 0(%%rdi), %%rcx\n"
2163 : [base] "+r"(ptr)
2164 :
2165 : "rcx", "rdx", "rdi", "memory");
2166#else
2167#error "Unsupported architecture"
2168#endif
2169 _exit(0);
2170 });
2171
2172 unique_fd output_fd;
2173 StartIntercept(&output_fd);
2174 FinishCrasher();
2175 AssertDeath(SIGSEGV);
2176
2177 int intercept_result;
2178 FinishIntercept(&intercept_result);
2179 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2180
2181 std::string result;
2182 ConsumeFd(std::move(output_fd), &result);
2183
2184 // Verify the process crashed properly.
2185 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0)");
2186
2187 // Now verify that the dex_pc frame includes a proper function name.
2188 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2189}