blob: 43942742e37f15655defc1dcb6545fa95fb4cc2f [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 Collingbourne939d0742021-02-02 19:00:45 -0800347 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700348 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700349}
350
Peter Collingbournef03af882020-03-20 18:09:00 -0700351TEST_F(CrasherTest, tagged_fault_addr) {
352#if !defined(__aarch64__)
353 GTEST_SKIP() << "Requires aarch64";
354#endif
355 int intercept_result;
356 unique_fd output_fd;
357 StartProcess([]() {
358 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
359 });
360
361 StartIntercept(&output_fd);
362 FinishCrasher();
363 AssertDeath(SIGSEGV);
364 FinishIntercept(&intercept_result);
365
366 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
367
368 std::string result;
369 ConsumeFd(std::move(output_fd), &result);
370
371 // The address can either be tagged (new kernels) or untagged (old kernels).
372 ASSERT_MATCH(
373 result,
374 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
375}
376
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700377// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
378// compiler could still clobber the argument register before trapping, but that's unlikely.
379__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
380 __builtin_trap();
381}
382
383TEST_F(CrasherTest, heap_addr_in_register) {
384#if defined(__i386__)
385 GTEST_SKIP() << "architecture does not pass arguments in registers";
386#endif
387 int intercept_result;
388 unique_fd output_fd;
389 StartProcess([]() {
390 // Crash with a heap pointer in the first argument register.
391 Trap(malloc(1));
392 });
393
394 StartIntercept(&output_fd);
395 FinishCrasher();
396 int status;
397 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
398 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
399 // Don't test the signal number because different architectures use different signals for
400 // __builtin_trap().
401 FinishIntercept(&intercept_result);
402
403 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
404
405 std::string result;
406 ConsumeFd(std::move(output_fd), &result);
407
408#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800409 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700410#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800411 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700412#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800413 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700414#else
415 ASSERT_TRUE(false) << "unsupported architecture";
416#endif
417}
418
Peter Collingbournecd278072020-12-21 14:08:38 -0800419#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700420static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800421 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700422 abort();
423 }
424}
425#endif
426
Mitch Phillips7168a212021-03-09 16:53:23 -0800427// Number of iterations required to reliably guarantee a GWP-ASan crash.
428// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
429// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
430// the counter reaches zero, we provide a sampled allocation. Then, double that
431// figure to allow for left/right allocation alignment, as this is done randomly
432// without bias.
433#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
434
435struct GwpAsanTestParameters {
436 size_t alloc_size;
437 bool free_before_access;
438 int access_offset;
439 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
440};
441
442struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
443
444GwpAsanTestParameters gwp_asan_tests[] = {
445 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
446 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
447 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
448 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
449};
450
451INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
452
453TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
454 if (mte_supported()) {
455 // Skip this test on MTE hardware, as MTE will reliably catch these errors
456 // instead of GWP-ASan.
457 GTEST_SKIP() << "Skipped on MTE.";
458 }
459
460 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700461 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800462
463 int intercept_result;
464 unique_fd output_fd;
465 StartProcess([&params]() {
466 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
467 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
468 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
469 p[params.access_offset] = 42;
470 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
471 }
472 });
473
474 StartIntercept(&output_fd);
475 FinishCrasher();
476 AssertDeath(SIGSEGV);
477 FinishIntercept(&intercept_result);
478
479 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
480
Mitch Phillips78f06702021-06-01 14:35:43 -0700481 std::vector<std::string> log_sources(2);
482 ConsumeFd(std::move(output_fd), &log_sources[0]);
483 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800484
Mitch Phillips78f06702021-06-01 14:35:43 -0700485 for (const auto& result : log_sources) {
486 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
487 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
488 if (params.free_before_access) {
489 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
490 }
491 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800492 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800493}
494
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800495struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
496
Peter Collingbourneaa544792021-05-13 13:53:37 -0700497INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800498
499TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800500#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700501 if (!mte_supported()) {
502 GTEST_SKIP() << "Requires MTE";
503 }
504
Peter Collingbourneaa544792021-05-13 13:53:37 -0700505 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
506 if (GetParam() == 0) {
507 return;
508 }
509
Mitch Phillips78f06702021-06-01 14:35:43 -0700510 LogcatCollector logcat_collector;
511
Peter Collingbournef8622522020-04-07 14:07:32 -0700512 int intercept_result;
513 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800514 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700515 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800516 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700517 free((void *)p);
518 p[0] = 42;
519 });
520
521 StartIntercept(&output_fd);
522 FinishCrasher();
523 AssertDeath(SIGSEGV);
524 FinishIntercept(&intercept_result);
525
526 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
527
Mitch Phillips78f06702021-06-01 14:35:43 -0700528 std::vector<std::string> log_sources(2);
529 ConsumeFd(std::move(output_fd), &log_sources[0]);
530 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700531 // Tag dump only available in the tombstone, not logcat.
532 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700533
Mitch Phillips78f06702021-06-01 14:35:43 -0700534 for (const auto& result : log_sources) {
535 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
536 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
537 std::to_string(GetParam()) + R"(-byte allocation)");
538 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
539 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
540 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700541#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800542 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700543#endif
544}
545
Peter Collingbournedc476342021-05-12 15:56:43 -0700546TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
547#if defined(__aarch64__)
548 if (!mte_supported()) {
549 GTEST_SKIP() << "Requires MTE";
550 }
551
552 int intercept_result;
553 unique_fd output_fd;
554 StartProcess([&]() {
555 SetTagCheckingLevelSync();
556 volatile int* p = (volatile int*)malloc(GetParam());
557 free((void *)p);
558 p[-1] = 42;
559 });
560
561 StartIntercept(&output_fd);
562 FinishCrasher();
563 AssertDeath(SIGSEGV);
564 FinishIntercept(&intercept_result);
565
566 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
567
568 std::string result;
569 ConsumeFd(std::move(output_fd), &result);
570
571 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
572 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
573#else
574 GTEST_SKIP() << "Requires aarch64";
575#endif
576}
577
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800578TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800579#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700580 if (!mte_supported()) {
581 GTEST_SKIP() << "Requires MTE";
582 }
583
Mitch Phillips78f06702021-06-01 14:35:43 -0700584 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700585 int intercept_result;
586 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800587 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700588 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800589 volatile char* p = (volatile char*)malloc(GetParam());
590 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700591 });
592
593 StartIntercept(&output_fd);
594 FinishCrasher();
595 AssertDeath(SIGSEGV);
596 FinishIntercept(&intercept_result);
597
598 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
599
Mitch Phillips78f06702021-06-01 14:35:43 -0700600 std::vector<std::string> log_sources(2);
601 ConsumeFd(std::move(output_fd), &log_sources[0]);
602 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700603
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700604 // Tag dump only in tombstone, not logcat, and tagging is not used for
605 // overflow protection in the scudo secondary (guard pages are used instead).
606 if (GetParam() < 0x10000) {
607 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
608 }
609
Mitch Phillips78f06702021-06-01 14:35:43 -0700610 for (const auto& result : log_sources) {
611 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
612 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
613 std::to_string(GetParam()) + R"(-byte allocation)");
614 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
615 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700616#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800617 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700618#endif
619}
620
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800621TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800622#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700623 if (!mte_supported()) {
624 GTEST_SKIP() << "Requires MTE";
625 }
626
627 int intercept_result;
628 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800629 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700630 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800631 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700632 p[-1] = 42;
633 });
634
635 StartIntercept(&output_fd);
636 FinishCrasher();
637 AssertDeath(SIGSEGV);
638 FinishIntercept(&intercept_result);
639
640 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
641
642 std::string result;
643 ConsumeFd(std::move(output_fd), &result);
644
645 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800646 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800647 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700648 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700649 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700650 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700651#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800652 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700653#endif
654}
655
656TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800657#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700658 if (!mte_supported()) {
659 GTEST_SKIP() << "Requires MTE";
660 }
661
Mitch Phillips78f06702021-06-01 14:35:43 -0700662 LogcatCollector logcat_collector;
663
Peter Collingbournef8622522020-04-07 14:07:32 -0700664 int intercept_result;
665 unique_fd output_fd;
666 StartProcess([]() {
667 SetTagCheckingLevelSync();
668
669 // Make two allocations with the same tag and close to one another. Check for both properties
670 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
671 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
672 // (some non-zero value << 56) apart.
673 //
674 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
675 // other.
676 std::set<uintptr_t> allocs;
677 for (int i = 0; i != 4096; ++i) {
678 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
679 auto it = allocs.insert(alloc).first;
680 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
681 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
682 }
683 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
684 *reinterpret_cast<int*>(alloc + 16) = 42;
685 }
686 }
687 });
688
689 StartIntercept(&output_fd);
690 FinishCrasher();
691 AssertDeath(SIGSEGV);
692 FinishIntercept(&intercept_result);
693
694 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
695
Mitch Phillips78f06702021-06-01 14:35:43 -0700696 std::vector<std::string> log_sources(2);
697 ConsumeFd(std::move(output_fd), &log_sources[0]);
698 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700699
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700700 // Tag dump only in the tombstone, not logcat.
701 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
702
Mitch Phillips78f06702021-06-01 14:35:43 -0700703 for (const auto& result : log_sources) {
704 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
705 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
706 "listing them in decreasing order of probability."));
707 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
708 // overflows), so we can't match explicitly for an underflow message.
709 ASSERT_MATCH(result,
710 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
711 // Ensure there's at least two allocation traces (one for each cause).
712 ASSERT_MATCH(
713 result,
714 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
715 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700716#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800717 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700718#endif
719}
720
Peter Collingbournecd278072020-12-21 14:08:38 -0800721#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700722static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700723 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
724 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
725 size_t page_size = getpagesize();
726 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
727 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
728 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700729 return 0;
730 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700731 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
732 PROT_READ | PROT_WRITE | PROT_MTE);
733 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
734 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
735 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
736 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
737 }
738 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700739}
740#endif
741
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700742TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800743#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700744 if (!mte_supported()) {
745 GTEST_SKIP() << "Requires MTE";
746 }
747
748 int intercept_result;
749 unique_fd output_fd;
750 StartProcess([&]() {
751 SetTagCheckingLevelSync();
752 Trap(reinterpret_cast<void *>(CreateTagMapping()));
753 });
754
755 StartIntercept(&output_fd);
756 FinishCrasher();
757 AssertDeath(SIGTRAP);
758 FinishIntercept(&intercept_result);
759
760 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
761
762 std::string result;
763 ConsumeFd(std::move(output_fd), &result);
764
765 ASSERT_MATCH(result, R"(memory near x0:
766.*
767.*
768 01.............0 0000000000000000 0000000000000000 ................
769 00.............0)");
770#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800771 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700772#endif
773}
774
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700775TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
776#if defined(__aarch64__)
777 if (!mte_supported()) {
778 GTEST_SKIP() << "Requires MTE";
779 }
780
781 int intercept_result;
782 unique_fd output_fd;
783 StartProcess([&]() {
784 SetTagCheckingLevelSync();
785 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
786 p[0] = 0; // Untagged pointer, tagged memory.
787 });
788
789 StartIntercept(&output_fd);
790 FinishCrasher();
791 AssertDeath(SIGSEGV);
792 FinishIntercept(&intercept_result);
793
794 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
795
796 std::string result;
797 ConsumeFd(std::move(output_fd), &result);
798
799 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
800\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
801#else
802 GTEST_SKIP() << "Requires aarch64";
803#endif
804}
805
806TEST_F(CrasherTest, mte_fault_tag_dump) {
807#if defined(__aarch64__)
808 if (!mte_supported()) {
809 GTEST_SKIP() << "Requires MTE";
810 }
811
812 int intercept_result;
813 unique_fd output_fd;
814 StartProcess([&]() {
815 SetTagCheckingLevelSync();
816 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
817 p[320] = 0; // Untagged pointer, tagged memory.
818 });
819
820 StartIntercept(&output_fd);
821 FinishCrasher();
822 AssertDeath(SIGSEGV);
823 FinishIntercept(&intercept_result);
824
825 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
826
827 std::string result;
828 ConsumeFd(std::move(output_fd), &result);
829
830 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
831\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
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)");
835#else
836 GTEST_SKIP() << "Requires aarch64";
837#endif
838}
839
840TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
841#if defined(__aarch64__)
842 if (!mte_supported()) {
843 GTEST_SKIP() << "Requires MTE";
844 }
845
846 int intercept_result;
847 unique_fd output_fd;
848 StartProcess([&]() {
849 SetTagCheckingLevelSync();
850 size_t page_size = getpagesize();
851 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
852 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
853 });
854
855 StartIntercept(&output_fd);
856 FinishCrasher();
857 AssertDeath(SIGSEGV);
858 FinishIntercept(&intercept_result);
859
860 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
861
862 std::string result;
863 ConsumeFd(std::move(output_fd), &result);
864
865 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
866 ASSERT_MATCH(result,
867 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
868\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
869
870)"); // Ensure truncation happened and there's a newline after the tag fault.
871#else
872 GTEST_SKIP() << "Requires aarch64";
873#endif
874}
875
Josh Gaocdea7502017-11-01 15:00:40 -0700876TEST_F(CrasherTest, LD_PRELOAD) {
877 int intercept_result;
878 unique_fd output_fd;
879 StartProcess([]() {
880 setenv("LD_PRELOAD", "nonexistent.so", 1);
881 *reinterpret_cast<volatile char*>(0xdead) = '1';
882 });
883
884 StartIntercept(&output_fd);
885 FinishCrasher();
886 AssertDeath(SIGSEGV);
887 FinishIntercept(&intercept_result);
888
889 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
890
891 std::string result;
892 ConsumeFd(std::move(output_fd), &result);
893 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
894}
895
Josh Gaocbe70cb2016-10-18 18:17:52 -0700896TEST_F(CrasherTest, abort) {
897 int intercept_result;
898 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800899 StartProcess([]() {
900 abort();
901 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700902 StartIntercept(&output_fd);
903 FinishCrasher();
904 AssertDeath(SIGABRT);
905 FinishIntercept(&intercept_result);
906
907 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
908
909 std::string result;
910 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700911 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700912}
913
914TEST_F(CrasherTest, signal) {
915 int intercept_result;
916 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800917 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700918 while (true) {
919 sleep(1);
920 }
Josh Gao502cfd22017-02-17 01:39:15 -0800921 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700922 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700923 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700924 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
925
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);
Elliott Hughes89722702018-05-02 10:47:00 -0700933 ASSERT_MATCH(
934 result,
935 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700936 ASSERT_MATCH(result, R"(backtrace:)");
937}
938
939TEST_F(CrasherTest, abort_message) {
940 int intercept_result;
941 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800942 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800943 // Arrived at experimentally;
944 // logd truncates at 4062.
945 // strlen("Abort message: ''") is 17.
946 // That's 4045, but we also want a NUL.
947 char buf[4045 + 1];
948 memset(buf, 'x', sizeof(buf));
949 buf[sizeof(buf) - 1] = '\0';
950 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800951 abort();
952 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700953 StartIntercept(&output_fd);
954 FinishCrasher();
955 AssertDeath(SIGABRT);
956 FinishIntercept(&intercept_result);
957
958 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
959
960 std::string result;
961 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800962 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700963}
964
Christopher Ferrise8891452021-08-17 17:34:53 -0700965TEST_F(CrasherTest, abort_message_newline_trimmed) {
966 int intercept_result;
967 unique_fd output_fd;
968 StartProcess([]() {
969 android_set_abort_message("Message with a newline.\n");
970 abort();
971 });
972 StartIntercept(&output_fd);
973 FinishCrasher();
974 AssertDeath(SIGABRT);
975 FinishIntercept(&intercept_result);
976
977 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
978
979 std::string result;
980 ConsumeFd(std::move(output_fd), &result);
981 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
982}
983
984TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
985 int intercept_result;
986 unique_fd output_fd;
987 StartProcess([]() {
988 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
989 abort();
990 });
991 StartIntercept(&output_fd);
992 FinishCrasher();
993 AssertDeath(SIGABRT);
994 FinishIntercept(&intercept_result);
995
996 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
997
998 std::string result;
999 ConsumeFd(std::move(output_fd), &result);
1000 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1001}
1002
Josh Gaoe06f2a42017-04-27 16:50:38 -07001003TEST_F(CrasherTest, abort_message_backtrace) {
1004 int intercept_result;
1005 unique_fd output_fd;
1006 StartProcess([]() {
1007 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001008 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001009 exit(0);
1010 });
1011 StartIntercept(&output_fd);
1012 FinishCrasher();
1013 AssertDeath(0);
1014 FinishIntercept(&intercept_result);
1015
1016 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1017
1018 std::string result;
1019 ConsumeFd(std::move(output_fd), &result);
1020 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1021}
1022
Josh Gaocbe70cb2016-10-18 18:17:52 -07001023TEST_F(CrasherTest, intercept_timeout) {
1024 int intercept_result;
1025 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001026 StartProcess([]() {
1027 abort();
1028 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001029 StartIntercept(&output_fd);
1030
1031 // Don't let crasher finish until we timeout.
1032 FinishIntercept(&intercept_result);
1033
1034 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1035 << intercept_result << ")";
1036
1037 FinishCrasher();
1038 AssertDeath(SIGABRT);
1039}
1040
Elliott Hughese4781d52021-03-17 09:15:15 -07001041TEST_F(CrasherTest, wait_for_debugger) {
1042 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1043 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001044 }
1045 sleep(1);
1046
Josh Gao502cfd22017-02-17 01:39:15 -08001047 StartProcess([]() {
1048 abort();
1049 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001050 FinishCrasher();
1051
1052 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001053 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001054 ASSERT_TRUE(WIFSTOPPED(status));
1055 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1056
1057 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1058
1059 AssertDeath(SIGABRT);
1060}
1061
Josh Gaocbe70cb2016-10-18 18:17:52 -07001062TEST_F(CrasherTest, backtrace) {
1063 std::string result;
1064 int intercept_result;
1065 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001066
1067 StartProcess([]() {
1068 abort();
1069 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001070 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001071
1072 std::this_thread::sleep_for(500ms);
1073
1074 sigval val;
1075 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001076 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001077 FinishIntercept(&intercept_result);
1078 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1079 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001080 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001081
1082 int status;
1083 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1084
1085 StartIntercept(&output_fd);
1086 FinishCrasher();
1087 AssertDeath(SIGABRT);
1088 FinishIntercept(&intercept_result);
1089 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1090 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001091 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001092}
Josh Gaofca7ca32017-01-23 12:05:35 -08001093
1094TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001095 int intercept_result;
1096 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001097 StartProcess([]() {
1098 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001099 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001100 });
Josh Gao502cfd22017-02-17 01:39:15 -08001101
1102 StartIntercept(&output_fd);
1103 FinishCrasher();
1104 AssertDeath(SIGABRT);
1105 FinishIntercept(&intercept_result);
1106
1107 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1108
1109 std::string result;
1110 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001111 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001112}
1113
Josh Gao502cfd22017-02-17 01:39:15 -08001114TEST_F(CrasherTest, capabilities) {
1115 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1116
Josh Gaofca7ca32017-01-23 12:05:35 -08001117 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001118 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1119 err(1, "failed to set PR_SET_KEEPCAPS");
1120 }
1121
1122 if (setresuid(1, 1, 1) != 0) {
1123 err(1, "setresuid failed");
1124 }
1125
1126 __user_cap_header_struct capheader;
1127 __user_cap_data_struct capdata[2];
1128 memset(&capheader, 0, sizeof(capheader));
1129 memset(&capdata, 0, sizeof(capdata));
1130
1131 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1132 capheader.pid = 0;
1133
1134 // Turn on every third capability.
1135 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1136 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1137 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1138 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1139 }
1140
1141 // Make sure CAP_SYS_PTRACE is off.
1142 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1143 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1144
1145 if (capset(&capheader, &capdata[0]) != 0) {
1146 err(1, "capset failed");
1147 }
1148
1149 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1150 err(1, "failed to drop ambient capabilities");
1151 }
1152
Josh Gaoa5199a92017-04-03 13:18:34 -07001153 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001154 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001155 });
Josh Gao502cfd22017-02-17 01:39:15 -08001156
1157 unique_fd output_fd;
1158 StartIntercept(&output_fd);
1159 FinishCrasher();
1160 AssertDeath(SIGSYS);
1161
1162 std::string result;
1163 int intercept_result;
1164 FinishIntercept(&intercept_result);
1165 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1166 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001167 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001168 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001169}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001170
Josh Gao2e7b8e22017-05-04 17:12:57 -07001171TEST_F(CrasherTest, fake_pid) {
1172 int intercept_result;
1173 unique_fd output_fd;
1174
1175 // Prime the getpid/gettid caches.
1176 UNUSED(getpid());
1177 UNUSED(gettid());
1178
1179 std::function<pid_t()> clone_fn = []() {
1180 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1181 };
1182 StartProcess(
1183 []() {
1184 ASSERT_NE(getpid(), syscall(__NR_getpid));
1185 ASSERT_NE(gettid(), syscall(__NR_gettid));
1186 raise(SIGSEGV);
1187 },
1188 clone_fn);
1189
1190 StartIntercept(&output_fd);
1191 FinishCrasher();
1192 AssertDeath(SIGSEGV);
1193 FinishIntercept(&intercept_result);
1194
1195 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1196
1197 std::string result;
1198 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001199 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001200}
1201
Josh Gaoe04ca272018-01-16 15:38:17 -08001202static const char* const kDebuggerdSeccompPolicy =
1203 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1204
Josh Gao70adac62018-02-22 11:38:33 -08001205static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001206 std::string policy;
1207 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1208 PLOG(FATAL) << "failed to read policy file";
1209 }
1210
1211 // Allow a bunch of syscalls used by the tests.
1212 policy += "\nclone: 1";
1213 policy += "\nsigaltstack: 1";
1214 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001215 policy += "\ngetrlimit: 1";
1216 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001217
1218 FILE* tmp_file = tmpfile();
1219 if (!tmp_file) {
1220 PLOG(FATAL) << "tmpfile failed";
1221 }
1222
Christopher Ferris172b0a02019-09-18 17:48:30 -07001223 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001224 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1225 PLOG(FATAL) << "failed to write policy to tmpfile";
1226 }
1227
1228 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1229 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001230 }
1231
1232 ScopedMinijail jail{minijail_new()};
1233 if (!jail) {
1234 LOG(FATAL) << "failed to create minijail";
1235 }
1236
1237 minijail_no_new_privs(jail.get());
1238 minijail_log_seccomp_filter_failures(jail.get());
1239 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001240 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001241
1242 pid_t result = fork();
1243 if (result == -1) {
1244 return result;
1245 } else if (result != 0) {
1246 return result;
1247 }
1248
1249 // Spawn and detach a thread that spins forever.
1250 std::atomic<bool> thread_ready(false);
1251 std::thread thread([&jail, &thread_ready]() {
1252 minijail_enter(jail.get());
1253 thread_ready = true;
1254 for (;;)
1255 ;
1256 });
1257 thread.detach();
1258
1259 while (!thread_ready) {
1260 continue;
1261 }
1262
Josh Gao70adac62018-02-22 11:38:33 -08001263 if (prejail) {
1264 prejail();
1265 }
1266
Josh Gaoe04ca272018-01-16 15:38:17 -08001267 minijail_enter(jail.get());
1268 return result;
1269}
1270
Josh Gao70adac62018-02-22 11:38:33 -08001271static pid_t seccomp_fork() {
1272 return seccomp_fork_impl(nullptr);
1273}
1274
Josh Gaoe04ca272018-01-16 15:38:17 -08001275TEST_F(CrasherTest, seccomp_crash) {
1276 int intercept_result;
1277 unique_fd output_fd;
1278
1279 StartProcess([]() { abort(); }, &seccomp_fork);
1280
1281 StartIntercept(&output_fd);
1282 FinishCrasher();
1283 AssertDeath(SIGABRT);
1284 FinishIntercept(&intercept_result);
1285 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1286
1287 std::string result;
1288 ConsumeFd(std::move(output_fd), &result);
1289 ASSERT_BACKTRACE_FRAME(result, "abort");
1290}
1291
Josh Gao70adac62018-02-22 11:38:33 -08001292static pid_t seccomp_fork_rlimit() {
1293 return seccomp_fork_impl([]() {
1294 struct rlimit rlim = {
1295 .rlim_cur = 512 * 1024 * 1024,
1296 .rlim_max = 512 * 1024 * 1024,
1297 };
1298
1299 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1300 raise(SIGINT);
1301 }
1302 });
1303}
1304
1305TEST_F(CrasherTest, seccomp_crash_oom) {
1306 int intercept_result;
1307 unique_fd output_fd;
1308
1309 StartProcess(
1310 []() {
1311 std::vector<void*> vec;
1312 for (int i = 0; i < 512; ++i) {
1313 char* buf = static_cast<char*>(malloc(1024 * 1024));
1314 if (!buf) {
1315 abort();
1316 }
1317 memset(buf, 0xff, 1024 * 1024);
1318 vec.push_back(buf);
1319 }
1320 },
1321 &seccomp_fork_rlimit);
1322
1323 StartIntercept(&output_fd);
1324 FinishCrasher();
1325 AssertDeath(SIGABRT);
1326 FinishIntercept(&intercept_result);
1327 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1328
1329 // We can't actually generate a backtrace, just make sure that the process terminates.
1330}
1331
Josh Gaoe04ca272018-01-16 15:38:17 -08001332__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1333 siginfo_t siginfo;
1334 siginfo.si_code = SI_QUEUE;
1335 siginfo.si_pid = getpid();
1336 siginfo.si_uid = getuid();
1337
1338 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1339 PLOG(FATAL) << "invalid dump type";
1340 }
1341
1342 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1343
Josh Gaoa48b41b2019-12-13 14:11:04 -08001344 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001345 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1346 return false;
1347 }
1348
1349 return true;
1350}
1351
1352TEST_F(CrasherTest, seccomp_tombstone) {
1353 int intercept_result;
1354 unique_fd output_fd;
1355
1356 static const auto dump_type = kDebuggerdTombstone;
1357 StartProcess(
1358 []() {
1359 raise_debugger_signal(dump_type);
1360 _exit(0);
1361 },
1362 &seccomp_fork);
1363
1364 StartIntercept(&output_fd, dump_type);
1365 FinishCrasher();
1366 AssertDeath(0);
1367 FinishIntercept(&intercept_result);
1368 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1369
1370 std::string result;
1371 ConsumeFd(std::move(output_fd), &result);
1372 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1373}
1374
Josh Gao6f9eeec2018-09-12 13:55:47 -07001375extern "C" void foo() {
1376 LOG(INFO) << "foo";
1377 std::this_thread::sleep_for(1s);
1378}
1379
1380extern "C" void bar() {
1381 LOG(INFO) << "bar";
1382 std::this_thread::sleep_for(1s);
1383}
1384
Josh Gaoe04ca272018-01-16 15:38:17 -08001385TEST_F(CrasherTest, seccomp_backtrace) {
1386 int intercept_result;
1387 unique_fd output_fd;
1388
1389 static const auto dump_type = kDebuggerdNativeBacktrace;
1390 StartProcess(
1391 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001392 std::thread a(foo);
1393 std::thread b(bar);
1394
1395 std::this_thread::sleep_for(100ms);
1396
Josh Gaoe04ca272018-01-16 15:38:17 -08001397 raise_debugger_signal(dump_type);
1398 _exit(0);
1399 },
1400 &seccomp_fork);
1401
1402 StartIntercept(&output_fd, dump_type);
1403 FinishCrasher();
1404 AssertDeath(0);
1405 FinishIntercept(&intercept_result);
1406 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1407
1408 std::string result;
1409 ConsumeFd(std::move(output_fd), &result);
1410 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001411 ASSERT_BACKTRACE_FRAME(result, "foo");
1412 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001413}
1414
1415TEST_F(CrasherTest, seccomp_crash_logcat) {
1416 StartProcess([]() { abort(); }, &seccomp_fork);
1417 FinishCrasher();
1418
1419 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1420 AssertDeath(SIGABRT);
1421}
1422
Josh Gaofd13bf02017-08-18 15:37:26 -07001423TEST_F(CrasherTest, competing_tracer) {
1424 int intercept_result;
1425 unique_fd output_fd;
1426 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001427 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001428 });
1429
1430 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001431
1432 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001433 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001434
1435 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001436 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001437 ASSERT_TRUE(WIFSTOPPED(status));
1438 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1439
1440 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1441 FinishIntercept(&intercept_result);
1442 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1443
1444 std::string result;
1445 ConsumeFd(std::move(output_fd), &result);
1446 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1447 regex += std::to_string(gettid());
1448 regex += R"( \(.+debuggerd_test)";
1449 ASSERT_MATCH(result, regex.c_str());
1450
Christopher Ferris172b0a02019-09-18 17:48:30 -07001451 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001452 ASSERT_TRUE(WIFSTOPPED(status));
1453 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1454
Josh Gaofd13bf02017-08-18 15:37:26 -07001455 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1456 AssertDeath(SIGABRT);
1457}
1458
Josh Gaobf06a402018-08-27 16:34:01 -07001459TEST_F(CrasherTest, fdsan_warning_abort_message) {
1460 int intercept_result;
1461 unique_fd output_fd;
1462
1463 StartProcess([]() {
1464 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001465 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001466 if (fd == -1) {
1467 abort();
1468 }
1469 close(fd.get());
1470 _exit(0);
1471 });
1472
1473 StartIntercept(&output_fd);
1474 FinishCrasher();
1475 AssertDeath(0);
1476 FinishIntercept(&intercept_result);
1477 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1478
1479 std::string result;
1480 ConsumeFd(std::move(output_fd), &result);
1481 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1482}
1483
Josh Gaoc3c8c022017-02-13 16:36:18 -08001484TEST(crash_dump, zombie) {
1485 pid_t forkpid = fork();
1486
Josh Gaoc3c8c022017-02-13 16:36:18 -08001487 pid_t rc;
1488 int status;
1489
1490 if (forkpid == 0) {
1491 errno = 0;
1492 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1493 if (rc != -1 || errno != ECHILD) {
1494 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1495 }
1496
Josh Gaoa48b41b2019-12-13 14:11:04 -08001497 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001498
1499 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001500 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001501 if (rc != -1 || errno != ECHILD) {
1502 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1503 }
1504 _exit(0);
1505 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001506 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001507 ASSERT_EQ(forkpid, rc);
1508 ASSERT_TRUE(WIFEXITED(status));
1509 ASSERT_EQ(0, WEXITSTATUS(status));
1510 }
1511}
Josh Gao352a8452017-03-30 16:46:21 -07001512
1513TEST(tombstoned, no_notify) {
1514 // Do this a few times.
1515 for (int i = 0; i < 3; ++i) {
1516 pid_t pid = 123'456'789 + i;
1517
1518 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001519 InterceptStatus status;
1520 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1521 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001522
1523 {
1524 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001525 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001526 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1527 }
1528
1529 pid_t read_pid;
1530 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1531 ASSERT_EQ(read_pid, pid);
1532 }
1533}
1534
1535TEST(tombstoned, stress) {
1536 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1537 static constexpr int kDumpCount = 100;
1538
1539 std::atomic<bool> start(false);
1540 std::vector<std::thread> threads;
1541 threads.emplace_back([&start]() {
1542 while (!start) {
1543 continue;
1544 }
1545
1546 // Use a way out of range pid, to avoid stomping on an actual process.
1547 pid_t pid_base = 1'000'000;
1548
1549 for (int dump = 0; dump < kDumpCount; ++dump) {
1550 pid_t pid = pid_base + dump;
1551
1552 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001553 InterceptStatus status;
1554 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1555 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001556
1557 // Pretend to crash, and then immediately close the socket.
1558 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1559 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1560 if (sockfd == -1) {
1561 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1562 }
1563 TombstonedCrashPacket packet = {};
1564 packet.packet_type = CrashPacketType::kDumpRequest;
1565 packet.packet.dump_request.pid = pid;
1566 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1567 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1568 }
1569
1570 continue;
1571 }
1572 });
1573
1574 threads.emplace_back([&start]() {
1575 while (!start) {
1576 continue;
1577 }
1578
1579 // Use a way out of range pid, to avoid stomping on an actual process.
1580 pid_t pid_base = 2'000'000;
1581
1582 for (int dump = 0; dump < kDumpCount; ++dump) {
1583 pid_t pid = pid_base + dump;
1584
1585 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001586 InterceptStatus status;
1587 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1588 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001589
1590 {
1591 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001592 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001593 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1594 tombstoned_notify_completion(tombstoned_socket.get());
1595 }
1596
1597 // TODO: Fix the race that requires this sleep.
1598 std::this_thread::sleep_for(50ms);
1599
1600 pid_t read_pid;
1601 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1602 ASSERT_EQ(read_pid, pid);
1603 }
1604 });
1605
1606 start = true;
1607
1608 for (std::thread& thread : threads) {
1609 thread.join();
1610 }
1611}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001612
1613TEST(tombstoned, java_trace_intercept_smoke) {
1614 // Using a "real" PID is a little dangerous here - if the test fails
1615 // or crashes, we might end up getting a bogus / unreliable stack
1616 // trace.
1617 const pid_t self = getpid();
1618
1619 unique_fd intercept_fd, output_fd;
1620 InterceptStatus status;
1621 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1622 ASSERT_EQ(InterceptStatus::kRegistered, status);
1623
Josh Gao76e1e302021-01-26 15:53:11 -08001624 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001625 // should result in a "regular" FD and not the installed intercept.
1626 const char native[] = "native";
1627 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001628 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001629 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1630 tombstoned_notify_completion(tombstoned_socket.get());
1631
1632 // Then, connect to tombstoned asking for a java backtrace. This *should*
1633 // trigger the intercept.
1634 const char java[] = "java";
1635 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1636 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1637 tombstoned_notify_completion(tombstoned_socket.get());
1638
1639 char outbuf[sizeof(java)];
1640 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1641 ASSERT_STREQ("java", outbuf);
1642}
1643
1644TEST(tombstoned, multiple_intercepts) {
1645 const pid_t fake_pid = 1'234'567;
1646 unique_fd intercept_fd, output_fd;
1647 InterceptStatus status;
1648 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1649 ASSERT_EQ(InterceptStatus::kRegistered, status);
1650
1651 unique_fd intercept_fd_2, output_fd_2;
1652 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1653 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1654}
1655
1656TEST(tombstoned, intercept_any) {
1657 const pid_t fake_pid = 1'234'567;
1658
1659 unique_fd intercept_fd, output_fd;
1660 InterceptStatus status;
1661 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1662 ASSERT_EQ(InterceptStatus::kRegistered, status);
1663
1664 const char any[] = "any";
1665 unique_fd tombstoned_socket, input_fd;
1666 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1667 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1668 tombstoned_notify_completion(tombstoned_socket.get());
1669
1670 char outbuf[sizeof(any)];
1671 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1672 ASSERT_STREQ("any", outbuf);
1673}
Josh Gao2b22ae12018-09-12 14:51:03 -07001674
1675TEST(tombstoned, interceptless_backtrace) {
1676 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1677 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1678 std::map<int, time_t> result;
1679 for (int i = 0; i < 99; ++i) {
1680 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1681 struct stat st;
1682 if (stat(path.c_str(), &st) == 0) {
1683 result[i] = st.st_mtim.tv_sec;
1684 }
1685 }
1686 return result;
1687 };
1688
1689 auto before = get_tombstone_timestamps();
1690 for (int i = 0; i < 50; ++i) {
1691 raise_debugger_signal(kDebuggerdNativeBacktrace);
1692 }
1693 auto after = get_tombstone_timestamps();
1694
1695 int diff = 0;
1696 for (int i = 0; i < 99; ++i) {
1697 if (after.count(i) == 0) {
1698 continue;
1699 }
1700 if (before.count(i) == 0) {
1701 ++diff;
1702 continue;
1703 }
1704 if (before[i] != after[i]) {
1705 ++diff;
1706 }
1707 }
1708
1709 // We can't be sure that nothing's crash looping in the background.
1710 // This should be good enough, though...
1711 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1712}
Christopher Ferris481e8372019-07-15 17:13:24 -07001713
1714static __attribute__((__noinline__)) void overflow_stack(void* p) {
1715 void* buf[1];
1716 buf[0] = p;
1717 static volatile void* global = buf;
1718 if (global) {
1719 global = buf;
1720 overflow_stack(&buf);
1721 }
1722}
1723
1724TEST_F(CrasherTest, stack_overflow) {
1725 int intercept_result;
1726 unique_fd output_fd;
1727 StartProcess([]() { overflow_stack(nullptr); });
1728
1729 StartIntercept(&output_fd);
1730 FinishCrasher();
1731 AssertDeath(SIGSEGV);
1732 FinishIntercept(&intercept_result);
1733
1734 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1735
1736 std::string result;
1737 ConsumeFd(std::move(output_fd), &result);
1738 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1739}
Josh Gao76e1e302021-01-26 15:53:11 -08001740
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001741static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1742 std::string test_lib(testing::internal::GetArgvs()[0]);
1743 auto const value = test_lib.find_last_of('/');
1744 if (value == std::string::npos) {
1745 test_lib = "./";
1746 } else {
1747 test_lib = test_lib.substr(0, value + 1) + "./";
1748 }
1749 test_lib += "libcrash_test.so";
1750
1751 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1752 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1753
1754 // Copy the shared so to a tempory directory.
1755 return system(cp_cmd.c_str()) == 0;
1756}
1757
1758TEST_F(CrasherTest, unreadable_elf) {
1759 int intercept_result;
1760 unique_fd output_fd;
1761 StartProcess([]() {
1762 TemporaryDir td;
1763 std::string tmp_so_name;
1764 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1765 _exit(1);
1766 }
1767 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1768 if (handle == nullptr) {
1769 _exit(1);
1770 }
1771 // Delete the original shared library so that we get the warning
1772 // about unreadable elf files.
1773 if (unlink(tmp_so_name.c_str()) == -1) {
1774 _exit(1);
1775 }
1776 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1777 if (crash_func == nullptr) {
1778 _exit(1);
1779 }
1780 crash_func();
1781 });
1782
1783 StartIntercept(&output_fd);
1784 FinishCrasher();
1785 AssertDeath(SIGSEGV);
1786 FinishIntercept(&intercept_result);
1787
1788 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1789
1790 std::string result;
1791 ConsumeFd(std::move(output_fd), &result);
1792 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
1793}
1794
Josh Gao76e1e302021-01-26 15:53:11 -08001795TEST(tombstoned, proto) {
1796 const pid_t self = getpid();
1797 unique_fd tombstoned_socket, text_fd, proto_fd;
1798 ASSERT_TRUE(
1799 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1800
1801 tombstoned_notify_completion(tombstoned_socket.get());
1802
1803 ASSERT_NE(-1, text_fd.get());
1804 ASSERT_NE(-1, proto_fd.get());
1805
1806 struct stat text_st;
1807 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1808
1809 // Give tombstoned some time to link the files into place.
1810 std::this_thread::sleep_for(100ms);
1811
1812 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001813 std::optional<std::string> tombstone_file;
1814 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1815 ASSERT_TRUE(dir_h != nullptr);
1816 std::regex tombstone_re("tombstone_\\d+");
1817 dirent* entry;
1818 while ((entry = readdir(dir_h.get())) != nullptr) {
1819 if (!std::regex_match(entry->d_name, tombstone_re)) {
1820 continue;
1821 }
1822 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001823
1824 struct stat st;
1825 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1826 continue;
1827 }
1828
1829 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001830 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001831 break;
1832 }
1833 }
1834
Christopher Ferris35da2882021-02-17 15:39:06 -08001835 ASSERT_TRUE(tombstone_file);
1836 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001837
1838 struct stat proto_fd_st;
1839 struct stat proto_file_st;
1840 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1841 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1842
1843 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1844 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1845}
1846
1847TEST(tombstoned, proto_intercept) {
1848 const pid_t self = getpid();
1849 unique_fd intercept_fd, output_fd;
1850 InterceptStatus status;
1851
1852 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1853 ASSERT_EQ(InterceptStatus::kRegistered, status);
1854
1855 unique_fd tombstoned_socket, text_fd, proto_fd;
1856 ASSERT_TRUE(
1857 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1858 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1859 tombstoned_notify_completion(tombstoned_socket.get());
1860
1861 text_fd.reset();
1862
1863 std::string output;
1864 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1865 ASSERT_EQ("foo", output);
1866}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001867
1868// Verify that when an intercept is present for the main thread, and the signal
1869// is received on a different thread, the intercept still works.
1870TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1871 StartProcess([]() {
1872 std::thread thread([]() {
1873 // Raise the signal on the side thread.
1874 raise_debugger_signal(kDebuggerdNativeBacktrace);
1875 });
1876 thread.join();
1877 _exit(0);
1878 });
1879
1880 unique_fd output_fd;
1881 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1882 FinishCrasher();
1883 AssertDeath(0);
1884
1885 int intercept_result;
1886 FinishIntercept(&intercept_result);
1887 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1888
1889 std::string result;
1890 ConsumeFd(std::move(output_fd), &result);
1891 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1892}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001893
1894static std::string format_pointer(uintptr_t ptr) {
1895#if defined(__LP64__)
1896 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1897 static_cast<uint32_t>(ptr & 0xffffffff));
1898#else
1899 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1900#endif
1901}
1902
1903static std::string format_pointer(void* ptr) {
1904 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1905}
1906
1907static std::string format_full_pointer(uintptr_t ptr) {
1908#if defined(__LP64__)
1909 return android::base::StringPrintf("%016" PRIx64, ptr);
1910#else
1911 return android::base::StringPrintf("%08x", ptr);
1912#endif
1913}
1914
1915static std::string format_full_pointer(void* ptr) {
1916 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1917}
1918
1919__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1920 int* crash_ptr = reinterpret_cast<int*>(ptr);
1921 *crash_ptr = 1;
1922 return *crash_ptr;
1923}
1924
1925// Verify that a fault address before the first map is properly handled.
1926TEST_F(CrasherTest, fault_address_before_first_map) {
1927 StartProcess([]() {
1928 ASSERT_EQ(0, crash_call(0x1024));
1929 _exit(0);
1930 });
1931
1932 unique_fd output_fd;
1933 StartIntercept(&output_fd);
1934 FinishCrasher();
1935 AssertDeath(SIGSEGV);
1936
1937 int intercept_result;
1938 FinishIntercept(&intercept_result);
1939 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1940
1941 std::string result;
1942 ConsumeFd(std::move(output_fd), &result);
1943 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x1024)");
1944
1945 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
1946
1947 std::string match_str = android::base::StringPrintf(
1948 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
1949 format_pointer(0x1024).c_str());
1950 ASSERT_MATCH(result, match_str);
1951}
1952
1953// Verify that a fault address after the last map is properly handled.
1954TEST_F(CrasherTest, fault_address_after_last_map) {
1955 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
1956 StartProcess([crash_uptr]() {
1957 ASSERT_EQ(0, crash_call(crash_uptr));
1958 _exit(0);
1959 });
1960
1961 unique_fd output_fd;
1962 StartIntercept(&output_fd);
1963 FinishCrasher();
1964 AssertDeath(SIGSEGV);
1965
1966 int intercept_result;
1967 FinishIntercept(&intercept_result);
1968 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1969
1970 std::string result;
1971 ConsumeFd(std::move(output_fd), &result);
1972
1973 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
1974 match_str += android::base::StringPrintf("0x%" PRIxPTR, crash_uptr);
1975 ASSERT_MATCH(result, match_str);
1976
1977 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
1978
1979 // Assumes that the open files section comes after the map section.
1980 // If that assumption changes, the regex below needs to change.
1981 match_str = android::base::StringPrintf(
1982 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
1983 format_pointer(crash_uptr).c_str());
1984 ASSERT_MATCH(result, match_str);
1985}
1986
1987// Verify that a fault address between maps is properly handled.
1988TEST_F(CrasherTest, fault_address_between_maps) {
1989 // Create a map before the fork so it will be present in the child.
1990 void* start_ptr =
1991 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
1992 ASSERT_NE(MAP_FAILED, start_ptr);
1993 // Unmap the page in the middle.
1994 void* middle_ptr =
1995 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
1996 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
1997
1998 StartProcess([middle_ptr]() {
1999 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2000 _exit(0);
2001 });
2002
2003 // Unmap the two maps.
2004 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2005 void* end_ptr =
2006 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2007 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2008
2009 unique_fd output_fd;
2010 StartIntercept(&output_fd);
2011 FinishCrasher();
2012 AssertDeath(SIGSEGV);
2013
2014 int intercept_result;
2015 FinishIntercept(&intercept_result);
2016 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2017
2018 std::string result;
2019 ConsumeFd(std::move(output_fd), &result);
2020
2021 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
2022 match_str += android::base::StringPrintf("%p", middle_ptr);
2023 ASSERT_MATCH(result, match_str);
2024
2025 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2026
2027 match_str = android::base::StringPrintf(
2028 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2029 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2030 format_pointer(end_ptr).c_str());
2031 ASSERT_MATCH(result, match_str);
2032}
2033
2034// Verify that a fault address happens in the correct map.
2035TEST_F(CrasherTest, fault_address_in_map) {
2036 // Create a map before the fork so it will be present in the child.
2037 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2038 ASSERT_NE(MAP_FAILED, ptr);
2039
2040 StartProcess([ptr]() {
2041 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2042 _exit(0);
2043 });
2044
2045 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2046
2047 unique_fd output_fd;
2048 StartIntercept(&output_fd);
2049 FinishCrasher();
2050 AssertDeath(SIGSEGV);
2051
2052 int intercept_result;
2053 FinishIntercept(&intercept_result);
2054 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2055
2056 std::string result;
2057 ConsumeFd(std::move(output_fd), &result);
2058
2059 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr )";
2060 match_str += android::base::StringPrintf("%p", ptr);
2061 ASSERT_MATCH(result, match_str);
2062
2063 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2064
2065 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2066 ASSERT_MATCH(result, match_str);
2067}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002068
2069static constexpr uint32_t kDexData[] = {
2070 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2071 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2072 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2073 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2074 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2075 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2076 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2077 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2078 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2079 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2080 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2081 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2082 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2083 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2084 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2085 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2086 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2087};
2088
2089TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2090 StartProcess([]() {
2091 TemporaryDir td;
2092 std::string tmp_so_name;
2093 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2094 _exit(1);
2095 }
2096
2097 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2098 // move the library to which has a basename of libart.so.
2099 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2100 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2101 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2102 if (handle == nullptr) {
2103 _exit(1);
2104 }
2105
2106 void* ptr =
2107 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2108 ASSERT_TRUE(ptr != MAP_FAILED);
2109 memcpy(ptr, kDexData, sizeof(kDexData));
2110 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2111
2112 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2113 .symfile_size = sizeof(kDexData)};
2114
2115 JITDescriptor* dex_debug =
2116 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2117 ASSERT_TRUE(dex_debug != nullptr);
2118 dex_debug->version = 1;
2119 dex_debug->action_flag = 0;
2120 dex_debug->relevant_entry = 0;
2121 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2122
2123 // This sets the magic dex pc value for register 0, using the value
2124 // of register 1 + 0x102.
2125 asm(".cfi_escape "
2126 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2127 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2128 "0x13 /* DW_OP_drop */,"
2129 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2130
2131 // For each different architecture, set register one to the dex ptr mmap
2132 // created above. Then do a nullptr dereference to force a crash.
2133#if defined(__arm__)
2134 asm volatile(
2135 "mov r1, %[base]\n"
2136 "mov r2, 0\n"
2137 "str r3, [r2]\n"
2138 : [base] "+r"(ptr)
2139 :
2140 : "r1", "r2", "r3", "memory");
2141#elif defined(__aarch64__)
2142 asm volatile(
2143 "mov x1, %[base]\n"
2144 "mov x2, 0\n"
2145 "str x3, [x2]\n"
2146 : [base] "+r"(ptr)
2147 :
2148 : "x1", "x2", "x3", "memory");
2149#elif defined(__i386__)
2150 asm volatile(
2151 "mov %[base], %%ecx\n"
2152 "movl $0, %%edi\n"
2153 "movl 0(%%edi), %%edx\n"
2154 : [base] "+r"(ptr)
2155 :
2156 : "edi", "ecx", "edx", "memory");
2157#elif defined(__x86_64__)
2158 asm volatile(
2159 "mov %[base], %%rdx\n"
2160 "movq 0, %%rdi\n"
2161 "movq 0(%%rdi), %%rcx\n"
2162 : [base] "+r"(ptr)
2163 :
2164 : "rcx", "rdx", "rdi", "memory");
2165#else
2166#error "Unsupported architecture"
2167#endif
2168 _exit(0);
2169 });
2170
2171 unique_fd output_fd;
2172 StartIntercept(&output_fd);
2173 FinishCrasher();
2174 AssertDeath(SIGSEGV);
2175
2176 int intercept_result;
2177 FinishIntercept(&intercept_result);
2178 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2179
2180 std::string result;
2181 ConsumeFd(std::move(output_fd), &result);
2182
2183 // Verify the process crashed properly.
2184 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0)");
2185
2186 // Now verify that the dex_pc frame includes a proper function name.
2187 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2188}