blob: 5cc2b3aef6e0742471e82f394ae05fefd733963b [file] [log] [blame]
Josh Gaocbe70cb2016-10-18 18:17:52 -07001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Christopher Ferris35da2882021-02-17 15:39:06 -080017#include <dirent.h>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070018#include <dlfcn.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070019#include <err.h>
20#include <fcntl.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000021#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080022#include <malloc.h>
Christopher Ferrisbda10642023-04-24 18:14:53 -070023#include <pthread.h>
Josh Gaocdea7502017-11-01 15:00:40 -070024#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080025#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070026#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080027#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070028#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080029#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070030#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070031#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070032#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070033
34#include <chrono>
35#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000036#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070037#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070038#include <thread>
39
Florian Mayer920d95b2024-02-14 12:57:09 -080040#include <android/crash_detail.h>
Christopher Ferris22035cc2023-01-31 17:50:22 -080041#include <android/dlext.h>
Josh Gaobf06a402018-08-27 16:34:01 -070042#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080043#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080044#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070045#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080046#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080047
Josh Gao5f87bbd2019-01-09 17:01:49 -080048#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070049#include <android-base/file.h>
50#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070051#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#include <android-base/parseint.h>
53#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070054#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070055#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070056#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070057#include <android-base/unique_fd.h>
58#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070059#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070060#include <gtest/gtest.h>
61
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000062#include <unwindstack/Elf.h>
63#include <unwindstack/Memory.h>
64
Josh Gaoe04ca272018-01-16 15:38:17 -080065#include <libminijail.h>
66#include <scoped_minijail.h>
67
Christopher Ferris2038cc72021-09-15 03:57:10 +000068#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010069#include "debuggerd/handler.h"
Mitch Phillips18ce5422023-01-19 14:23:49 -080070#include "gtest/gtest.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070071#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010072#include "protocol.h"
73#include "tombstoned/tombstoned.h"
74#include "util.h"
75
Josh Gaocbe70cb2016-10-18 18:17:52 -070076using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080077
78using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070079using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070080using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070081
82#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070083#define ARCH_SUFFIX "64"
84#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070085#define ARCH_SUFFIX ""
86#endif
87
Elliott Hughese4781d52021-03-17 09:15:15 -070088constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070089
90#define TIMEOUT(seconds, expr) \
91 [&]() { \
92 struct sigaction old_sigaction; \
93 struct sigaction new_sigaction = {}; \
94 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080095 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070096 err(1, "sigaction failed"); \
97 } \
Mattias Simonsson38ab0452023-11-08 12:02:46 +000098 alarm(seconds * android::base::HwTimeoutMultiplier()); \
Josh Gaocbe70cb2016-10-18 18:17:52 -070099 auto value = expr; \
100 int saved_errno = errno; \
101 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
102 err(1, "sigaction failed"); \
103 } \
104 alarm(0); \
105 errno = saved_errno; \
106 return value; \
107 }()
108
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700109// Backtrace frame dump could contain:
110// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
111// or
112// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800113#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700114 ASSERT_MATCH(result, \
115 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900116
Narayan Kamatha73df602017-05-24 15:07:25 +0100117static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700118 InterceptResponse* response, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700119 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
120 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
121 if (intercept_fd->get() == -1) {
122 FAIL() << "failed to contact tombstoned: " << strerror(errno);
123 }
124
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700125 InterceptRequest req = {
126 .dump_type = intercept_type,
127 .pid = target_pid,
128 };
Josh Gao460b3362017-03-30 16:40:47 -0700129
130 unique_fd output_pipe_write;
131 if (!Pipe(output_fd, &output_pipe_write)) {
132 FAIL() << "failed to create output pipe: " << strerror(errno);
133 }
134
135 std::string pipe_size_str;
136 int pipe_buffer_size;
137 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
138 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
139 }
140
141 pipe_size_str = android::base::Trim(pipe_size_str);
142
143 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
144 FAIL() << "failed to parse pipe max size";
145 }
146
147 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
148 FAIL() << "failed to set pipe size: " << strerror(errno);
149 }
150
Josh Gao5675f3c2017-06-01 12:19:53 -0700151 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
152
Josh Gao5f87bbd2019-01-09 17:01:49 -0800153 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
154 output_pipe_write.reset();
155 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700156 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
157 }
158
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700159 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), response, sizeof(*response)));
Josh Gao460b3362017-03-30 16:40:47 -0700160 if (rc == -1) {
161 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
162 } else if (rc == 0) {
163 FAIL() << "failed to read response from tombstoned (EOF)";
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700164 } else if (rc != sizeof(*response)) {
165 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(*response)
Josh Gao460b3362017-03-30 16:40:47 -0700166 << ", received " << rc;
167 }
Josh Gao460b3362017-03-30 16:40:47 -0700168}
169
Elliott Hughesd13ea522022-01-13 09:20:26 -0800170static bool pac_supported() {
171#if defined(__aarch64__)
172 return getauxval(AT_HWCAP) & HWCAP_PACA;
173#else
174 return false;
175#endif
176}
177
Josh Gaocbe70cb2016-10-18 18:17:52 -0700178class CrasherTest : public ::testing::Test {
179 public:
180 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700181 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700182 unique_fd crasher_pipe;
183 unique_fd intercept_fd;
184
185 CrasherTest();
186 ~CrasherTest();
187
Narayan Kamatha73df602017-05-24 15:07:25 +0100188 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700189
190 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
191 void FinishIntercept(int* result);
192
Josh Gao2e7b8e22017-05-04 17:12:57 -0700193 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700194 void StartCrasher(const std::string& crash_type);
195 void FinishCrasher();
196 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700197
198 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700199};
200
201CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700202 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
203 android::base::SetProperty(kWaitForDebuggerKey, "0");
204
205 // Clear the old property too, just in case someone's been using it
206 // on this device. (We only document the new name, but we still support
207 // the old name so we don't break anyone's existing setups.)
208 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700209}
210
211CrasherTest::~CrasherTest() {
212 if (crasher_pid != -1) {
213 kill(crasher_pid, SIGKILL);
214 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700215 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700216 }
217
Elliott Hughese4781d52021-03-17 09:15:15 -0700218 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700219}
220
Narayan Kamatha73df602017-05-24 15:07:25 +0100221void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222 if (crasher_pid == -1) {
223 FAIL() << "crasher hasn't been started";
224 }
225
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700226 InterceptResponse response = {};
227 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &response, intercept_type);
228 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
229 << "Error message: " << response.error_message;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700230}
231
232void CrasherTest::FinishIntercept(int* result) {
233 InterceptResponse response;
234
Christopher Ferris11555f02019-09-20 14:18:55 -0700235 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700236 if (rc == -1) {
237 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
238 } else if (rc == 0) {
239 *result = -1;
240 } else if (rc != sizeof(response)) {
241 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
242 << ", received " << rc;
243 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700244 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700245 }
246}
247
Josh Gao2e7b8e22017-05-04 17:12:57 -0700248void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800249 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700250 unique_fd crasher_read_pipe;
251 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
252 FAIL() << "failed to create pipe: " << strerror(errno);
253 }
254
Josh Gao2e7b8e22017-05-04 17:12:57 -0700255 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700256 if (crasher_pid == -1) {
257 FAIL() << "fork failed: " << strerror(errno);
258 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800259 char dummy;
260 crasher_pipe.reset();
261 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800262 function();
263 _exit(0);
264 }
265}
266
Josh Gaocbe70cb2016-10-18 18:17:52 -0700267void CrasherTest::FinishCrasher() {
268 if (crasher_pipe == -1) {
269 FAIL() << "crasher pipe uninitialized";
270 }
271
Christopher Ferris172b0a02019-09-18 17:48:30 -0700272 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700273 if (rc == -1) {
274 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
275 } else if (rc == 0) {
276 FAIL() << "crasher pipe was closed";
277 }
278}
279
280void CrasherTest::AssertDeath(int signo) {
281 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700282 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700283 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700284 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
285 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700286 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700287 FAIL() << "failed to wait for crasher: " << strerror(errno);
288 }
289
Josh Gaoe06f2a42017-04-27 16:50:38 -0700290 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700291 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700292 ASSERT_EQ(0, WEXITSTATUS(signo));
293 } else {
294 ASSERT_FALSE(WIFEXITED(status));
295 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
296 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700297 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 crasher_pid = -1;
299}
300
301static void ConsumeFd(unique_fd fd, std::string* output) {
Kelvin Zhang786dac32023-06-15 16:23:56 -0700302 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700303}
304
Mitch Phillips78f06702021-06-01 14:35:43 -0700305class LogcatCollector {
306 public:
307 LogcatCollector() { system("logcat -c"); }
308
309 void Collect(std::string* output) {
310 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
311 ASSERT_NE(cmd_stdout, nullptr);
312 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
313 ConsumeFd(std::move(tmp_fd), output);
314 pclose(cmd_stdout);
315 }
316};
317
Josh Gaocbe70cb2016-10-18 18:17:52 -0700318TEST_F(CrasherTest, smoke) {
319 int intercept_result;
320 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800321 StartProcess([]() {
322 *reinterpret_cast<volatile char*>(0xdead) = '1';
323 });
324
Josh Gaocbe70cb2016-10-18 18:17:52 -0700325 StartIntercept(&output_fd);
326 FinishCrasher();
327 AssertDeath(SIGSEGV);
328 FinishIntercept(&intercept_result);
329
330 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
331
332 std::string result;
333 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800334#ifdef __LP64__
335 ASSERT_MATCH(result,
336 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
337#else
338 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
339#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700340
341 if (mte_supported()) {
342 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700343 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
344 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700345 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800346
347 if (pac_supported()) {
348 // Test that the default PAC_ENABLED_KEYS value is set.
349 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
350 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
351 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700352}
353
Peter Collingbournef03af882020-03-20 18:09:00 -0700354TEST_F(CrasherTest, tagged_fault_addr) {
355#if !defined(__aarch64__)
356 GTEST_SKIP() << "Requires aarch64";
357#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700358 // HWASan crashes with SIGABRT on tag mismatch.
359 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700360 int intercept_result;
361 unique_fd output_fd;
362 StartProcess([]() {
363 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
364 });
365
366 StartIntercept(&output_fd);
367 FinishCrasher();
368 AssertDeath(SIGSEGV);
369 FinishIntercept(&intercept_result);
370
371 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
372
373 std::string result;
374 ConsumeFd(std::move(output_fd), &result);
375
376 // The address can either be tagged (new kernels) or untagged (old kernels).
377 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800378 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700379}
380
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700381void CrasherTest::Trap(void* ptr) {
382 void (*volatile f)(void*) = nullptr;
383 __asm__ __volatile__("" : : "r"(f) : "memory");
384 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700385}
386
387TEST_F(CrasherTest, heap_addr_in_register) {
388#if defined(__i386__)
389 GTEST_SKIP() << "architecture does not pass arguments in registers";
390#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700391 // The memory dump in HWASan crashes sadly shows the memory near the registers
392 // in the HWASan dump function, rather the faulting context. This is a known
393 // issue.
394 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700395 int intercept_result;
396 unique_fd output_fd;
397 StartProcess([]() {
398 // Crash with a heap pointer in the first argument register.
399 Trap(malloc(1));
400 });
401
402 StartIntercept(&output_fd);
403 FinishCrasher();
404 int status;
405 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
406 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
407 // Don't test the signal number because different architectures use different signals for
408 // __builtin_trap().
409 FinishIntercept(&intercept_result);
410
411 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
412
413 std::string result;
414 ConsumeFd(std::move(output_fd), &result);
415
416#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800417 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700418#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800419 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800420#elif defined(__riscv)
421 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700422#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800423 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700424#else
425 ASSERT_TRUE(false) << "unsupported architecture";
426#endif
427}
428
Peter Collingbournecd278072020-12-21 14:08:38 -0800429#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700430static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800431 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700432 abort();
433 }
434}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800435
436static void SetTagCheckingLevelAsync() {
437 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
438 abort();
439 }
440}
Peter Collingbournef8622522020-04-07 14:07:32 -0700441#endif
442
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800443struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
444
Peter Collingbourneaa544792021-05-13 13:53:37 -0700445INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800446
447TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800448#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700449 if (!mte_supported()) {
450 GTEST_SKIP() << "Requires MTE";
451 }
452
Peter Collingbourneaa544792021-05-13 13:53:37 -0700453 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
454 if (GetParam() == 0) {
455 return;
456 }
457
Mitch Phillips78f06702021-06-01 14:35:43 -0700458 LogcatCollector logcat_collector;
459
Peter Collingbournef8622522020-04-07 14:07:32 -0700460 int intercept_result;
461 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800462 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700463 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800464 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700465 free((void *)p);
466 p[0] = 42;
467 });
468
469 StartIntercept(&output_fd);
470 FinishCrasher();
471 AssertDeath(SIGSEGV);
472 FinishIntercept(&intercept_result);
473
474 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
475
Mitch Phillips78f06702021-06-01 14:35:43 -0700476 std::vector<std::string> log_sources(2);
477 ConsumeFd(std::move(output_fd), &log_sources[0]);
478 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700479 // Tag dump only available in the tombstone, not logcat.
480 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700481
Mitch Phillips78f06702021-06-01 14:35:43 -0700482 for (const auto& result : log_sources) {
483 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
484 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
485 std::to_string(GetParam()) + R"(-byte allocation)");
486 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
487 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
488 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700489#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800490 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700491#endif
492}
493
Peter Collingbournedc476342021-05-12 15:56:43 -0700494TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
495#if defined(__aarch64__)
496 if (!mte_supported()) {
497 GTEST_SKIP() << "Requires MTE";
498 }
499
500 int intercept_result;
501 unique_fd output_fd;
502 StartProcess([&]() {
503 SetTagCheckingLevelSync();
504 volatile int* p = (volatile int*)malloc(GetParam());
505 free((void *)p);
506 p[-1] = 42;
507 });
508
509 StartIntercept(&output_fd);
510 FinishCrasher();
511 AssertDeath(SIGSEGV);
512 FinishIntercept(&intercept_result);
513
514 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
515
516 std::string result;
517 ConsumeFd(std::move(output_fd), &result);
518
519 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
520 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
521#else
522 GTEST_SKIP() << "Requires aarch64";
523#endif
524}
525
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800526TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800527#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700528 if (!mte_supported()) {
529 GTEST_SKIP() << "Requires MTE";
530 }
531
Mitch Phillips78f06702021-06-01 14:35:43 -0700532 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700533 int intercept_result;
534 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800535 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700536 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800537 volatile char* p = (volatile char*)malloc(GetParam());
538 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700539 });
540
541 StartIntercept(&output_fd);
542 FinishCrasher();
543 AssertDeath(SIGSEGV);
544 FinishIntercept(&intercept_result);
545
546 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
547
Mitch Phillips78f06702021-06-01 14:35:43 -0700548 std::vector<std::string> log_sources(2);
549 ConsumeFd(std::move(output_fd), &log_sources[0]);
550 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700551
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700552 // Tag dump only in tombstone, not logcat, and tagging is not used for
553 // overflow protection in the scudo secondary (guard pages are used instead).
554 if (GetParam() < 0x10000) {
555 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
556 }
557
Mitch Phillips78f06702021-06-01 14:35:43 -0700558 for (const auto& result : log_sources) {
559 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
560 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
561 std::to_string(GetParam()) + R"(-byte allocation)");
562 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
563 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700564#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800565 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700566#endif
567}
568
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800569TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800570#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700571 if (!mte_supported()) {
572 GTEST_SKIP() << "Requires MTE";
573 }
574
575 int intercept_result;
576 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800577 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700578 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800579 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700580 p[-1] = 42;
581 });
582
583 StartIntercept(&output_fd);
584 FinishCrasher();
585 AssertDeath(SIGSEGV);
586 FinishIntercept(&intercept_result);
587
588 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
589
590 std::string result;
591 ConsumeFd(std::move(output_fd), &result);
592
593 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800594 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800595 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700596 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700597 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700598 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700599#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800600 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700601#endif
602}
603
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800604TEST_F(CrasherTest, mte_async) {
605#if defined(__aarch64__)
606 if (!mte_supported()) {
607 GTEST_SKIP() << "Requires MTE";
608 }
609
610 int intercept_result;
611 unique_fd output_fd;
612 StartProcess([&]() {
613 SetTagCheckingLevelAsync();
614 volatile int* p = (volatile int*)malloc(16);
615 p[-1] = 42;
616 });
617
618 StartIntercept(&output_fd);
619 FinishCrasher();
620 AssertDeath(SIGSEGV);
621 FinishIntercept(&intercept_result);
622
623 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
624
625 std::string result;
626 ConsumeFd(std::move(output_fd), &result);
627
Peter Collingbourne91e816a2023-03-07 21:24:47 -0800628 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800629#else
630 GTEST_SKIP() << "Requires aarch64";
631#endif
632}
633
Peter Collingbournef8622522020-04-07 14:07:32 -0700634TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800635#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700636 if (!mte_supported()) {
637 GTEST_SKIP() << "Requires MTE";
638 }
639
Mitch Phillips78f06702021-06-01 14:35:43 -0700640 LogcatCollector logcat_collector;
641
Peter Collingbournef8622522020-04-07 14:07:32 -0700642 int intercept_result;
643 unique_fd output_fd;
644 StartProcess([]() {
645 SetTagCheckingLevelSync();
646
647 // Make two allocations with the same tag and close to one another. Check for both properties
648 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
649 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
650 // (some non-zero value << 56) apart.
651 //
652 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
653 // other.
654 std::set<uintptr_t> allocs;
655 for (int i = 0; i != 4096; ++i) {
656 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
657 auto it = allocs.insert(alloc).first;
658 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
659 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
660 }
661 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
662 *reinterpret_cast<int*>(alloc + 16) = 42;
663 }
664 }
665 });
666
667 StartIntercept(&output_fd);
668 FinishCrasher();
669 AssertDeath(SIGSEGV);
670 FinishIntercept(&intercept_result);
671
672 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
673
Mitch Phillips78f06702021-06-01 14:35:43 -0700674 std::vector<std::string> log_sources(2);
675 ConsumeFd(std::move(output_fd), &log_sources[0]);
676 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700677
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700678 // Tag dump only in the tombstone, not logcat.
679 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
680
Mitch Phillips78f06702021-06-01 14:35:43 -0700681 for (const auto& result : log_sources) {
682 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
683 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800684 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700685 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
686 // overflows), so we can't match explicitly for an underflow message.
687 ASSERT_MATCH(result,
688 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
689 // Ensure there's at least two allocation traces (one for each cause).
690 ASSERT_MATCH(
691 result,
692 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
693 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700694#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800695 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700696#endif
697}
698
Peter Collingbournecd278072020-12-21 14:08:38 -0800699#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700700static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700701 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
702 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
703 size_t page_size = getpagesize();
704 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
705 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
706 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700707 return 0;
708 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700709 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
710 PROT_READ | PROT_WRITE | PROT_MTE);
711 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
712 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
713 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
714 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
715 }
716 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700717}
718#endif
719
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700720TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800721#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700722 if (!mte_supported()) {
723 GTEST_SKIP() << "Requires MTE";
724 }
725
726 int intercept_result;
727 unique_fd output_fd;
728 StartProcess([&]() {
729 SetTagCheckingLevelSync();
730 Trap(reinterpret_cast<void *>(CreateTagMapping()));
731 });
732
733 StartIntercept(&output_fd);
734 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700735 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700736 FinishIntercept(&intercept_result);
737
738 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
739
740 std::string result;
741 ConsumeFd(std::move(output_fd), &result);
742
743 ASSERT_MATCH(result, R"(memory near x0:
744.*
745.*
746 01.............0 0000000000000000 0000000000000000 ................
747 00.............0)");
748#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800749 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700750#endif
751}
752
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700753TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
754#if defined(__aarch64__)
755 if (!mte_supported()) {
756 GTEST_SKIP() << "Requires MTE";
757 }
758
759 int intercept_result;
760 unique_fd output_fd;
761 StartProcess([&]() {
762 SetTagCheckingLevelSync();
763 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
764 p[0] = 0; // Untagged pointer, tagged memory.
765 });
766
767 StartIntercept(&output_fd);
768 FinishCrasher();
769 AssertDeath(SIGSEGV);
770 FinishIntercept(&intercept_result);
771
772 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
773
774 std::string result;
775 ConsumeFd(std::move(output_fd), &result);
776
777 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
778\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
779#else
780 GTEST_SKIP() << "Requires aarch64";
781#endif
782}
783
784TEST_F(CrasherTest, mte_fault_tag_dump) {
785#if defined(__aarch64__)
786 if (!mte_supported()) {
787 GTEST_SKIP() << "Requires MTE";
788 }
789
790 int intercept_result;
791 unique_fd output_fd;
792 StartProcess([&]() {
793 SetTagCheckingLevelSync();
794 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
795 p[320] = 0; // Untagged pointer, tagged memory.
796 });
797
798 StartIntercept(&output_fd);
799 FinishCrasher();
800 AssertDeath(SIGSEGV);
801 FinishIntercept(&intercept_result);
802
803 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
804
805 std::string result;
806 ConsumeFd(std::move(output_fd), &result);
807
808 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
809\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
810\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
811\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
812)");
813#else
814 GTEST_SKIP() << "Requires aarch64";
815#endif
816}
817
818TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
819#if defined(__aarch64__)
820 if (!mte_supported()) {
821 GTEST_SKIP() << "Requires MTE";
822 }
823
824 int intercept_result;
825 unique_fd output_fd;
826 StartProcess([&]() {
827 SetTagCheckingLevelSync();
828 size_t page_size = getpagesize();
829 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
830 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
831 });
832
833 StartIntercept(&output_fd);
834 FinishCrasher();
835 AssertDeath(SIGSEGV);
836 FinishIntercept(&intercept_result);
837
838 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
839
840 std::string result;
841 ConsumeFd(std::move(output_fd), &result);
842
843 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
844 ASSERT_MATCH(result,
845 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
846\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
847
848)"); // Ensure truncation happened and there's a newline after the tag fault.
849#else
850 GTEST_SKIP() << "Requires aarch64";
851#endif
852}
853
Josh Gaocdea7502017-11-01 15:00:40 -0700854TEST_F(CrasherTest, LD_PRELOAD) {
855 int intercept_result;
856 unique_fd output_fd;
857 StartProcess([]() {
858 setenv("LD_PRELOAD", "nonexistent.so", 1);
859 *reinterpret_cast<volatile char*>(0xdead) = '1';
860 });
861
862 StartIntercept(&output_fd);
863 FinishCrasher();
864 AssertDeath(SIGSEGV);
865 FinishIntercept(&intercept_result);
866
867 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
868
869 std::string result;
870 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800871 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700872}
873
Josh Gaocbe70cb2016-10-18 18:17:52 -0700874TEST_F(CrasherTest, abort) {
875 int intercept_result;
876 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800877 StartProcess([]() {
878 abort();
879 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700880 StartIntercept(&output_fd);
881 FinishCrasher();
882 AssertDeath(SIGABRT);
883 FinishIntercept(&intercept_result);
884
885 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
886
887 std::string result;
888 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700889 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700890}
891
892TEST_F(CrasherTest, signal) {
893 int intercept_result;
894 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800895 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700896 while (true) {
897 sleep(1);
898 }
Josh Gao502cfd22017-02-17 01:39:15 -0800899 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700900 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700901 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700902 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
903
904 AssertDeath(SIGSEGV);
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);
Elliott Hughes89722702018-05-02 10:47:00 -0700911 ASSERT_MATCH(
912 result,
913 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700914 ASSERT_MATCH(result, R"(backtrace:)");
915}
916
917TEST_F(CrasherTest, abort_message) {
918 int intercept_result;
919 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800920 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800921 // Arrived at experimentally;
922 // logd truncates at 4062.
923 // strlen("Abort message: ''") is 17.
924 // That's 4045, but we also want a NUL.
925 char buf[4045 + 1];
926 memset(buf, 'x', sizeof(buf));
927 buf[sizeof(buf) - 1] = '\0';
928 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800929 abort();
930 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700931 StartIntercept(&output_fd);
932 FinishCrasher();
933 AssertDeath(SIGABRT);
934 FinishIntercept(&intercept_result);
935
936 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
937
938 std::string result;
939 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800940 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700941}
942
Florian Mayer5fa66632024-02-07 16:42:23 -0800943static char g_crash_detail_value_changes[] = "crash_detail_value";
944static char g_crash_detail_value[] = "crash_detail_value";
945static char g_crash_detail_value2[] = "crash_detail_value2";
946
947inline crash_detail_t* _Nullable android_register_crash_detail_strs(const char* _Nonnull name,
948 const char* _Nonnull data) {
Florian Mayer920d95b2024-02-14 12:57:09 -0800949 return android_crash_detail_register(name, strlen(name), data, strlen(data));
Florian Mayer5fa66632024-02-07 16:42:23 -0800950}
951
952TEST_F(CrasherTest, crash_detail_single) {
953 int intercept_result;
954 unique_fd output_fd;
955 StartProcess([]() {
956 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
957 abort();
958 });
959 StartIntercept(&output_fd);
960 FinishCrasher();
961 AssertDeath(SIGABRT);
962 FinishIntercept(&intercept_result);
963
964 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
965
966 std::string result;
967 ConsumeFd(std::move(output_fd), &result);
968 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
969}
970
Florian Mayeraced3aa2024-02-13 13:44:50 -0800971TEST_F(CrasherTest, crash_detail_replace_data) {
972 int intercept_result;
973 unique_fd output_fd;
974 StartProcess([]() {
975 auto *cd = android_register_crash_detail_strs("CRASH_DETAIL_NAME", "original_data");
Florian Mayer920d95b2024-02-14 12:57:09 -0800976 android_crash_detail_replace_data(cd, "new_data", strlen("new_data"));
Florian Mayeraced3aa2024-02-13 13:44:50 -0800977 abort();
978 });
979 StartIntercept(&output_fd);
980 FinishCrasher();
981 AssertDeath(SIGABRT);
982 FinishIntercept(&intercept_result);
983
984 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
985
986 std::string result;
987 ConsumeFd(std::move(output_fd), &result);
988 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'new_data')");
989 // Ensure the old one no longer shows up, i.e. that we actually replaced
990 // it, not added a new one.
991 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'original_data')");
992}
993
994TEST_F(CrasherTest, crash_detail_replace_name) {
995 int intercept_result;
996 unique_fd output_fd;
997 StartProcess([]() {
998 auto *cd = android_register_crash_detail_strs("old_name", g_crash_detail_value);
Florian Mayer920d95b2024-02-14 12:57:09 -0800999 android_crash_detail_replace_name(cd, "new_name", strlen("new_name"));
Florian Mayeraced3aa2024-02-13 13:44:50 -08001000 abort();
1001 });
1002 StartIntercept(&output_fd);
1003 FinishCrasher();
1004 AssertDeath(SIGABRT);
1005 FinishIntercept(&intercept_result);
1006
1007 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1008
1009 std::string result;
1010 ConsumeFd(std::move(output_fd), &result);
1011 ASSERT_MATCH(result, R"(new_name: 'crash_detail_value')");
1012 // Ensure the old one no longer shows up, i.e. that we actually replaced
1013 // it, not added a new one.
1014 ASSERT_NOT_MATCH(result, R"(old_name: 'crash_detail_value')");
1015}
1016
Florian Mayer5fa66632024-02-07 16:42:23 -08001017TEST_F(CrasherTest, crash_detail_single_byte_name) {
1018 int intercept_result;
1019 unique_fd output_fd;
1020 StartProcess([]() {
1021 android_register_crash_detail_strs("CRASH_DETAIL_NAME\1", g_crash_detail_value);
1022 abort();
1023 });
1024 StartIntercept(&output_fd);
1025 FinishCrasher();
1026 AssertDeath(SIGABRT);
1027 FinishIntercept(&intercept_result);
1028
1029 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1030
1031 std::string result;
1032 ConsumeFd(std::move(output_fd), &result);
1033 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME\\1: 'crash_detail_value')");
1034}
1035
1036
1037TEST_F(CrasherTest, crash_detail_single_bytes) {
1038 int intercept_result;
1039 unique_fd output_fd;
1040 StartProcess([]() {
Florian Mayer920d95b2024-02-14 12:57:09 -08001041 android_crash_detail_register("CRASH_DETAIL_NAME", strlen("CRASH_DETAIL_NAME"), "\1",
Florian Mayer5fa66632024-02-07 16:42:23 -08001042 sizeof("\1"));
1043 abort();
1044 });
1045 StartIntercept(&output_fd);
1046 FinishCrasher();
1047 AssertDeath(SIGABRT);
1048 FinishIntercept(&intercept_result);
1049
1050 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1051
1052 std::string result;
1053 ConsumeFd(std::move(output_fd), &result);
1054 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: '\\1\\0')");
1055}
1056
1057TEST_F(CrasherTest, crash_detail_mixed) {
1058 int intercept_result;
1059 unique_fd output_fd;
1060 StartProcess([]() {
1061 const char data[] = "helloworld\1\255\3";
1062 android_register_crash_detail_strs("CRASH_DETAIL_NAME", data);
1063 abort();
1064 });
1065 StartIntercept(&output_fd);
1066 FinishCrasher();
1067 AssertDeath(SIGABRT);
1068 FinishIntercept(&intercept_result);
1069
1070 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1071
1072 std::string result;
1073 ConsumeFd(std::move(output_fd), &result);
1074 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'helloworld\\1\\255\\3')");
1075}
1076
1077TEST_F(CrasherTest, crash_detail_many) {
1078 int intercept_result;
1079 unique_fd output_fd;
1080 StartProcess([]() {
1081 for (int i = 0; i < 1000; ++i) {
1082 std::string name = "CRASH_DETAIL_NAME" + std::to_string(i);
1083 std::string value = "CRASH_DETAIL_VALUE" + std::to_string(i);
1084 auto* h = android_register_crash_detail_strs(name.data(), value.data());
Florian Mayer920d95b2024-02-14 12:57:09 -08001085 android_crash_detail_unregister(h);
Florian Mayer5fa66632024-02-07 16:42:23 -08001086 }
1087
1088 android_register_crash_detail_strs("FINAL_NAME", "FINAL_VALUE");
1089 android_register_crash_detail_strs("FINAL_NAME2", "FINAL_VALUE2");
1090 abort();
1091 });
1092 StartIntercept(&output_fd);
1093 FinishCrasher();
1094 AssertDeath(SIGABRT);
1095 FinishIntercept(&intercept_result);
1096
1097 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1098
1099 std::string result;
1100 ConsumeFd(std::move(output_fd), &result);
1101 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_NAME");
1102 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_VALUE");
1103 ASSERT_MATCH(result, R"(FINAL_NAME: 'FINAL_VALUE')");
1104 ASSERT_MATCH(result, R"(FINAL_NAME2: 'FINAL_VALUE2')");
1105}
1106
1107TEST_F(CrasherTest, crash_detail_single_changes) {
1108 int intercept_result;
1109 unique_fd output_fd;
1110 StartProcess([]() {
1111 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value_changes);
1112 g_crash_detail_value_changes[0] = 'C';
1113 abort();
1114 });
1115 StartIntercept(&output_fd);
1116 FinishCrasher();
1117 AssertDeath(SIGABRT);
1118 FinishIntercept(&intercept_result);
1119
1120 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1121
1122 std::string result;
1123 ConsumeFd(std::move(output_fd), &result);
1124 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'Crash_detail_value')");
1125}
1126
1127TEST_F(CrasherTest, crash_detail_multiple) {
1128 int intercept_result;
1129 unique_fd output_fd;
1130 StartProcess([]() {
1131 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1132 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1133 abort();
1134 });
1135 StartIntercept(&output_fd);
1136 FinishCrasher();
1137 AssertDeath(SIGABRT);
1138 FinishIntercept(&intercept_result);
1139
1140 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1141
1142 std::string result;
1143 ConsumeFd(std::move(output_fd), &result);
1144 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1145 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1146}
1147
1148TEST_F(CrasherTest, crash_detail_remove) {
1149 int intercept_result;
1150 unique_fd output_fd;
1151 StartProcess([]() {
1152 auto* detail1 = android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
Florian Mayer920d95b2024-02-14 12:57:09 -08001153 android_crash_detail_unregister(detail1);
Florian Mayer5fa66632024-02-07 16:42:23 -08001154 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1155 abort();
1156 });
1157 StartIntercept(&output_fd);
1158 FinishCrasher();
1159 AssertDeath(SIGABRT);
1160 FinishIntercept(&intercept_result);
1161
1162 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1163
1164 std::string result;
1165 ConsumeFd(std::move(output_fd), &result);
1166 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1167 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1168}
1169
Christopher Ferrise8891452021-08-17 17:34:53 -07001170TEST_F(CrasherTest, abort_message_newline_trimmed) {
1171 int intercept_result;
1172 unique_fd output_fd;
1173 StartProcess([]() {
1174 android_set_abort_message("Message with a newline.\n");
1175 abort();
1176 });
1177 StartIntercept(&output_fd);
1178 FinishCrasher();
1179 AssertDeath(SIGABRT);
1180 FinishIntercept(&intercept_result);
1181
1182 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1183
1184 std::string result;
1185 ConsumeFd(std::move(output_fd), &result);
1186 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1187}
1188
1189TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1190 int intercept_result;
1191 unique_fd output_fd;
1192 StartProcess([]() {
1193 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1194 abort();
1195 });
1196 StartIntercept(&output_fd);
1197 FinishCrasher();
1198 AssertDeath(SIGABRT);
1199 FinishIntercept(&intercept_result);
1200
1201 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1202
1203 std::string result;
1204 ConsumeFd(std::move(output_fd), &result);
1205 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1206}
1207
Josh Gaoe06f2a42017-04-27 16:50:38 -07001208TEST_F(CrasherTest, abort_message_backtrace) {
1209 int intercept_result;
1210 unique_fd output_fd;
1211 StartProcess([]() {
1212 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001213 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001214 exit(0);
1215 });
1216 StartIntercept(&output_fd);
1217 FinishCrasher();
1218 AssertDeath(0);
1219 FinishIntercept(&intercept_result);
1220
1221 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1222
1223 std::string result;
1224 ConsumeFd(std::move(output_fd), &result);
1225 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1226}
1227
Josh Gaocbe70cb2016-10-18 18:17:52 -07001228TEST_F(CrasherTest, intercept_timeout) {
1229 int intercept_result;
1230 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001231 StartProcess([]() {
1232 abort();
1233 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001234 StartIntercept(&output_fd);
1235
1236 // Don't let crasher finish until we timeout.
1237 FinishIntercept(&intercept_result);
1238
1239 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1240 << intercept_result << ")";
1241
1242 FinishCrasher();
1243 AssertDeath(SIGABRT);
1244}
1245
Elliott Hughese4781d52021-03-17 09:15:15 -07001246TEST_F(CrasherTest, wait_for_debugger) {
1247 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1248 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001249 }
1250 sleep(1);
1251
Josh Gao502cfd22017-02-17 01:39:15 -08001252 StartProcess([]() {
1253 abort();
1254 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001255 FinishCrasher();
1256
1257 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001258 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001259 ASSERT_TRUE(WIFSTOPPED(status));
1260 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1261
1262 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1263
1264 AssertDeath(SIGABRT);
1265}
1266
Josh Gaocbe70cb2016-10-18 18:17:52 -07001267TEST_F(CrasherTest, backtrace) {
1268 std::string result;
1269 int intercept_result;
1270 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001271
1272 StartProcess([]() {
1273 abort();
1274 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001275 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001276
1277 std::this_thread::sleep_for(500ms);
1278
1279 sigval val;
1280 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001281 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001282 FinishIntercept(&intercept_result);
1283 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1284 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001285 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001286
1287 int status;
1288 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1289
1290 StartIntercept(&output_fd);
1291 FinishCrasher();
1292 AssertDeath(SIGABRT);
1293 FinishIntercept(&intercept_result);
1294 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1295 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001296 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001297}
Josh Gaofca7ca32017-01-23 12:05:35 -08001298
1299TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001300 int intercept_result;
1301 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001302 StartProcess([]() {
1303 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001304 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001305 });
Josh Gao502cfd22017-02-17 01:39:15 -08001306
1307 StartIntercept(&output_fd);
1308 FinishCrasher();
1309 AssertDeath(SIGABRT);
1310 FinishIntercept(&intercept_result);
1311
1312 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1313
1314 std::string result;
1315 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001316 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001317}
1318
Josh Gao502cfd22017-02-17 01:39:15 -08001319TEST_F(CrasherTest, capabilities) {
1320 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1321
Josh Gaofca7ca32017-01-23 12:05:35 -08001322 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001323 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1324 err(1, "failed to set PR_SET_KEEPCAPS");
1325 }
1326
1327 if (setresuid(1, 1, 1) != 0) {
1328 err(1, "setresuid failed");
1329 }
1330
1331 __user_cap_header_struct capheader;
1332 __user_cap_data_struct capdata[2];
1333 memset(&capheader, 0, sizeof(capheader));
1334 memset(&capdata, 0, sizeof(capdata));
1335
1336 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1337 capheader.pid = 0;
1338
1339 // Turn on every third capability.
1340 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1341 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1342 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1343 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1344 }
1345
1346 // Make sure CAP_SYS_PTRACE is off.
1347 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1348 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1349
1350 if (capset(&capheader, &capdata[0]) != 0) {
1351 err(1, "capset failed");
1352 }
1353
1354 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1355 err(1, "failed to drop ambient capabilities");
1356 }
1357
Josh Gaoa5199a92017-04-03 13:18:34 -07001358 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001359 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001360 });
Josh Gao502cfd22017-02-17 01:39:15 -08001361
1362 unique_fd output_fd;
1363 StartIntercept(&output_fd);
1364 FinishCrasher();
1365 AssertDeath(SIGSYS);
1366
1367 std::string result;
1368 int intercept_result;
1369 FinishIntercept(&intercept_result);
1370 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1371 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001372 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001373 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001374}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001375
Josh Gao2e7b8e22017-05-04 17:12:57 -07001376TEST_F(CrasherTest, fake_pid) {
1377 int intercept_result;
1378 unique_fd output_fd;
1379
1380 // Prime the getpid/gettid caches.
1381 UNUSED(getpid());
1382 UNUSED(gettid());
1383
1384 std::function<pid_t()> clone_fn = []() {
1385 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1386 };
1387 StartProcess(
1388 []() {
1389 ASSERT_NE(getpid(), syscall(__NR_getpid));
1390 ASSERT_NE(gettid(), syscall(__NR_gettid));
1391 raise(SIGSEGV);
1392 },
1393 clone_fn);
1394
1395 StartIntercept(&output_fd);
1396 FinishCrasher();
1397 AssertDeath(SIGSEGV);
1398 FinishIntercept(&intercept_result);
1399
1400 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1401
1402 std::string result;
1403 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001404 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001405}
1406
Josh Gaoe04ca272018-01-16 15:38:17 -08001407static const char* const kDebuggerdSeccompPolicy =
1408 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1409
Mitch Phillips18ce5422023-01-19 14:23:49 -08001410static void setup_jail(minijail* jail) {
1411 if (!jail) {
1412 LOG(FATAL) << "failed to create minijail";
1413 }
1414
Josh Gao6f9eeec2018-09-12 13:55:47 -07001415 std::string policy;
1416 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1417 PLOG(FATAL) << "failed to read policy file";
1418 }
1419
1420 // Allow a bunch of syscalls used by the tests.
1421 policy += "\nclone: 1";
1422 policy += "\nsigaltstack: 1";
1423 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001424 policy += "\ngetrlimit: 1";
1425 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001426
1427 FILE* tmp_file = tmpfile();
1428 if (!tmp_file) {
1429 PLOG(FATAL) << "tmpfile failed";
1430 }
1431
Christopher Ferris172b0a02019-09-18 17:48:30 -07001432 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001433 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1434 PLOG(FATAL) << "failed to write policy to tmpfile";
1435 }
1436
1437 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1438 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001439 }
1440
Mitch Phillips18ce5422023-01-19 14:23:49 -08001441 minijail_no_new_privs(jail);
1442 minijail_log_seccomp_filter_failures(jail);
1443 minijail_use_seccomp_filter(jail);
1444 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1445}
Josh Gaoe04ca272018-01-16 15:38:17 -08001446
Mitch Phillips18ce5422023-01-19 14:23:49 -08001447static pid_t seccomp_fork_impl(void (*prejail)()) {
1448 ScopedMinijail jail{minijail_new()};
1449 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001450
1451 pid_t result = fork();
1452 if (result == -1) {
1453 return result;
1454 } else if (result != 0) {
1455 return result;
1456 }
1457
1458 // Spawn and detach a thread that spins forever.
1459 std::atomic<bool> thread_ready(false);
1460 std::thread thread([&jail, &thread_ready]() {
1461 minijail_enter(jail.get());
1462 thread_ready = true;
1463 for (;;)
1464 ;
1465 });
1466 thread.detach();
1467
1468 while (!thread_ready) {
1469 continue;
1470 }
1471
Josh Gao70adac62018-02-22 11:38:33 -08001472 if (prejail) {
1473 prejail();
1474 }
1475
Josh Gaoe04ca272018-01-16 15:38:17 -08001476 minijail_enter(jail.get());
1477 return result;
1478}
1479
Josh Gao70adac62018-02-22 11:38:33 -08001480static pid_t seccomp_fork() {
1481 return seccomp_fork_impl(nullptr);
1482}
1483
Josh Gaoe04ca272018-01-16 15:38:17 -08001484TEST_F(CrasherTest, seccomp_crash) {
1485 int intercept_result;
1486 unique_fd output_fd;
1487
1488 StartProcess([]() { abort(); }, &seccomp_fork);
1489
1490 StartIntercept(&output_fd);
1491 FinishCrasher();
1492 AssertDeath(SIGABRT);
1493 FinishIntercept(&intercept_result);
1494 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1495
1496 std::string result;
1497 ConsumeFd(std::move(output_fd), &result);
1498 ASSERT_BACKTRACE_FRAME(result, "abort");
1499}
1500
Josh Gao70adac62018-02-22 11:38:33 -08001501static pid_t seccomp_fork_rlimit() {
1502 return seccomp_fork_impl([]() {
1503 struct rlimit rlim = {
1504 .rlim_cur = 512 * 1024 * 1024,
1505 .rlim_max = 512 * 1024 * 1024,
1506 };
1507
1508 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1509 raise(SIGINT);
1510 }
1511 });
1512}
1513
1514TEST_F(CrasherTest, seccomp_crash_oom) {
1515 int intercept_result;
1516 unique_fd output_fd;
1517
1518 StartProcess(
1519 []() {
1520 std::vector<void*> vec;
1521 for (int i = 0; i < 512; ++i) {
1522 char* buf = static_cast<char*>(malloc(1024 * 1024));
1523 if (!buf) {
1524 abort();
1525 }
1526 memset(buf, 0xff, 1024 * 1024);
1527 vec.push_back(buf);
1528 }
1529 },
1530 &seccomp_fork_rlimit);
1531
1532 StartIntercept(&output_fd);
1533 FinishCrasher();
1534 AssertDeath(SIGABRT);
1535 FinishIntercept(&intercept_result);
1536 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1537
1538 // We can't actually generate a backtrace, just make sure that the process terminates.
1539}
1540
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001541__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001542 siginfo_t siginfo;
1543 siginfo.si_code = SI_QUEUE;
1544 siginfo.si_pid = getpid();
1545 siginfo.si_uid = getuid();
1546
1547 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1548 PLOG(FATAL) << "invalid dump type";
1549 }
1550
1551 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1552
Josh Gaoa48b41b2019-12-13 14:11:04 -08001553 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001554 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1555 return false;
1556 }
1557
1558 return true;
1559}
1560
Christopher Ferrisb999b822022-02-09 17:57:21 -08001561extern "C" void foo() {
1562 LOG(INFO) << "foo";
1563 std::this_thread::sleep_for(1s);
1564}
1565
1566extern "C" void bar() {
1567 LOG(INFO) << "bar";
1568 std::this_thread::sleep_for(1s);
1569}
1570
Josh Gaoe04ca272018-01-16 15:38:17 -08001571TEST_F(CrasherTest, seccomp_tombstone) {
1572 int intercept_result;
1573 unique_fd output_fd;
1574
1575 static const auto dump_type = kDebuggerdTombstone;
1576 StartProcess(
1577 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001578 std::thread a(foo);
1579 std::thread b(bar);
1580
1581 std::this_thread::sleep_for(100ms);
1582
Josh Gaoe04ca272018-01-16 15:38:17 -08001583 raise_debugger_signal(dump_type);
1584 _exit(0);
1585 },
1586 &seccomp_fork);
1587
1588 StartIntercept(&output_fd, dump_type);
1589 FinishCrasher();
1590 AssertDeath(0);
1591 FinishIntercept(&intercept_result);
1592 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1593
1594 std::string result;
1595 ConsumeFd(std::move(output_fd), &result);
1596 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001597 ASSERT_BACKTRACE_FRAME(result, "foo");
1598 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001599}
1600
Christopher Ferris303c6be2022-05-24 17:08:33 -07001601TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1602 int intercept_result;
1603 unique_fd output_fd;
1604
1605 static const auto dump_type = kDebuggerdTombstone;
1606 StartProcess(
1607 []() {
1608 std::thread abort_thread([] { abort(); });
1609 abort_thread.join();
1610 },
1611 &seccomp_fork);
1612
1613 StartIntercept(&output_fd, dump_type);
1614 FinishCrasher();
1615 AssertDeath(SIGABRT);
1616 FinishIntercept(&intercept_result);
1617 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1618
1619 std::string result;
1620 ConsumeFd(std::move(output_fd), &result);
1621 ASSERT_BACKTRACE_FRAME(result, "abort");
1622}
1623
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001624TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1625 int intercept_result;
1626 unique_fd output_fd;
1627
1628 static const auto dump_type = kDebuggerdTombstone;
1629 StartProcess(
1630 []() {
1631 std::thread a(foo);
1632 std::thread b(bar);
1633
1634 std::this_thread::sleep_for(100ms);
1635
1636 std::thread abort_thread([] { abort(); });
1637 abort_thread.join();
1638 },
1639 &seccomp_fork);
1640
1641 StartIntercept(&output_fd, dump_type);
1642 FinishCrasher();
1643 AssertDeath(SIGABRT);
1644 FinishIntercept(&intercept_result);
1645 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1646
1647 std::string result;
1648 ConsumeFd(std::move(output_fd), &result);
1649 ASSERT_BACKTRACE_FRAME(result, "abort");
1650 ASSERT_BACKTRACE_FRAME(result, "foo");
1651 ASSERT_BACKTRACE_FRAME(result, "bar");
1652 ASSERT_BACKTRACE_FRAME(result, "main");
1653}
1654
Josh Gaoe04ca272018-01-16 15:38:17 -08001655TEST_F(CrasherTest, seccomp_backtrace) {
1656 int intercept_result;
1657 unique_fd output_fd;
1658
1659 static const auto dump_type = kDebuggerdNativeBacktrace;
1660 StartProcess(
1661 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001662 std::thread a(foo);
1663 std::thread b(bar);
1664
1665 std::this_thread::sleep_for(100ms);
1666
Josh Gaoe04ca272018-01-16 15:38:17 -08001667 raise_debugger_signal(dump_type);
1668 _exit(0);
1669 },
1670 &seccomp_fork);
1671
1672 StartIntercept(&output_fd, dump_type);
1673 FinishCrasher();
1674 AssertDeath(0);
1675 FinishIntercept(&intercept_result);
1676 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1677
1678 std::string result;
1679 ConsumeFd(std::move(output_fd), &result);
1680 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001681 ASSERT_BACKTRACE_FRAME(result, "foo");
1682 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001683}
1684
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001685TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1686 int intercept_result;
1687 unique_fd output_fd;
1688
1689 static const auto dump_type = kDebuggerdNativeBacktrace;
1690 StartProcess(
1691 []() {
1692 std::thread a(foo);
1693 std::thread b(bar);
1694
1695 std::this_thread::sleep_for(100ms);
1696
1697 std::thread raise_thread([] {
1698 raise_debugger_signal(dump_type);
1699 _exit(0);
1700 });
1701 raise_thread.join();
1702 },
1703 &seccomp_fork);
1704
1705 StartIntercept(&output_fd, dump_type);
1706 FinishCrasher();
1707 AssertDeath(0);
1708 FinishIntercept(&intercept_result);
1709 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1710
1711 std::string result;
1712 ConsumeFd(std::move(output_fd), &result);
1713 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1714 ASSERT_BACKTRACE_FRAME(result, "foo");
1715 ASSERT_BACKTRACE_FRAME(result, "bar");
1716 ASSERT_BACKTRACE_FRAME(result, "main");
1717}
1718
Josh Gaoe04ca272018-01-16 15:38:17 -08001719TEST_F(CrasherTest, seccomp_crash_logcat) {
1720 StartProcess([]() { abort(); }, &seccomp_fork);
1721 FinishCrasher();
1722
1723 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1724 AssertDeath(SIGABRT);
1725}
1726
Josh Gaofd13bf02017-08-18 15:37:26 -07001727TEST_F(CrasherTest, competing_tracer) {
1728 int intercept_result;
1729 unique_fd output_fd;
1730 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001731 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001732 });
1733
1734 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001735
1736 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001737 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001738
1739 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001740 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001741 ASSERT_TRUE(WIFSTOPPED(status));
1742 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1743
1744 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1745 FinishIntercept(&intercept_result);
1746 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1747
1748 std::string result;
1749 ConsumeFd(std::move(output_fd), &result);
1750 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1751 regex += std::to_string(gettid());
1752 regex += R"( \(.+debuggerd_test)";
1753 ASSERT_MATCH(result, regex.c_str());
1754
Christopher Ferris172b0a02019-09-18 17:48:30 -07001755 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001756 ASSERT_TRUE(WIFSTOPPED(status));
1757 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1758
Josh Gaofd13bf02017-08-18 15:37:26 -07001759 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1760 AssertDeath(SIGABRT);
1761}
1762
Mitch Phillips18ce5422023-01-19 14:23:49 -08001763struct GwpAsanTestParameters {
1764 size_t alloc_size;
1765 bool free_before_access;
1766 int access_offset;
1767 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1768};
1769
1770struct GwpAsanCrasherTest
1771 : CrasherTest,
1772 testing::WithParamInterface<
1773 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1774
1775GwpAsanTestParameters gwp_asan_tests[] = {
1776 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1777 "Use After Free, 0 bytes into a 7-byte allocation"},
1778 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1779 "Use After Free, 1 byte into a 15-byte allocation"},
1780 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1781 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1782 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1783 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1784};
1785
1786INSTANTIATE_TEST_SUITE_P(
1787 GwpAsanTests, GwpAsanCrasherTest,
1788 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1789 /* recoverable */ testing::Bool(),
1790 /* seccomp */ testing::Bool()),
1791 [](const testing::TestParamInfo<
1792 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1793 const GwpAsanTestParameters& params = std::get<0>(info.param);
1794 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1795 name += testing::PrintToString(params.alloc_size);
1796 name += "Alloc";
1797 if (params.access_offset < 0) {
1798 name += "Left";
1799 name += testing::PrintToString(params.access_offset * -1);
1800 } else {
1801 name += "Right";
1802 name += testing::PrintToString(params.access_offset);
1803 }
1804 name += "Bytes";
1805 if (std::get<1>(info.param)) name += "Recoverable";
1806 if (std::get<2>(info.param)) name += "Seccomp";
1807 return name;
1808 });
1809
1810TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1811 if (mte_supported()) {
1812 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1813 // instead of GWP-ASan.
1814 GTEST_SKIP() << "Skipped on MTE.";
1815 }
1816 // Skip this test on HWASan, which will reliably catch test errors as well.
1817 SKIP_WITH_HWASAN;
1818
1819 GwpAsanTestParameters params = std::get<0>(GetParam());
1820 bool recoverable = std::get<1>(GetParam());
1821 LogcatCollector logcat_collector;
1822
1823 int intercept_result;
1824 unique_fd output_fd;
1825 StartProcess([&recoverable]() {
1826 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1827 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1828 if (recoverable) {
1829 env[3] = "GWP_ASAN_RECOVERABLE=true";
1830 }
1831 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1832 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1833 "DISABLED_run_gwp_asan_test");
1834 std::string test_filter = "--gtest_filter=*";
1835 test_filter += test_name;
1836 std::string this_binary = android::base::GetExecutablePath();
1837 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1838 test_filter.c_str(), nullptr};
1839 // We check the crash report from a debuggerd handler and from logcat. The
1840 // echo from stdout/stderr of the subprocess trips up atest, because it
1841 // doesn't like that two tests started in a row without the first one
1842 // finishing (even though the second one is in a subprocess).
1843 close(STDOUT_FILENO);
1844 close(STDERR_FILENO);
1845 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1846 });
1847
1848 StartIntercept(&output_fd);
1849 FinishCrasher();
1850 if (recoverable) {
1851 AssertDeath(0);
1852 } else {
1853 AssertDeath(SIGSEGV);
1854 }
1855 FinishIntercept(&intercept_result);
1856
1857 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1858
1859 std::vector<std::string> log_sources(2);
1860 ConsumeFd(std::move(output_fd), &log_sources[0]);
1861 logcat_collector.Collect(&log_sources[1]);
1862
1863 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1864 // information. Make sure the recovery still works, but the report won't be
1865 // hugely useful, it looks like a regular SEGV.
1866 bool seccomp = std::get<2>(GetParam());
1867 if (!seccomp) {
1868 for (const auto& result : log_sources) {
1869 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1870 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1871 if (params.free_before_access) {
1872 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1873 }
1874 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1875 }
1876 }
1877}
1878
1879TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1880 GwpAsanTestParameters params = std::get<0>(GetParam());
1881 bool seccomp = std::get<2>(GetParam());
1882 if (seccomp) {
1883 ScopedMinijail jail{minijail_new()};
1884 setup_jail(jail.get());
1885 minijail_enter(jail.get());
1886 }
1887
1888 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1889 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1890 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1891 p[params.access_offset] = 42;
1892 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001893
1894 bool recoverable = std::get<1>(GetParam());
1895 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1896
1897 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1898 // we end with at least one in a different slot), make sure the process still
1899 // doesn't crash.
1900 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1901 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1902 free(static_cast<void*>(const_cast<char*>(p)));
1903 free(static_cast<void*>(const_cast<char*>(p2)));
1904 *p = 42;
1905 *p2 = 42;
1906
1907 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1908 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1909 // coverage does. Thus, skip the atexit handlers.
1910 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001911}
1912
Josh Gaobf06a402018-08-27 16:34:01 -07001913TEST_F(CrasherTest, fdsan_warning_abort_message) {
1914 int intercept_result;
1915 unique_fd output_fd;
1916
1917 StartProcess([]() {
1918 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001919 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001920 if (fd == -1) {
1921 abort();
1922 }
1923 close(fd.get());
1924 _exit(0);
1925 });
1926
1927 StartIntercept(&output_fd);
1928 FinishCrasher();
1929 AssertDeath(0);
1930 FinishIntercept(&intercept_result);
1931 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1932
1933 std::string result;
1934 ConsumeFd(std::move(output_fd), &result);
1935 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1936}
1937
Josh Gaoc3c8c022017-02-13 16:36:18 -08001938TEST(crash_dump, zombie) {
1939 pid_t forkpid = fork();
1940
Josh Gaoc3c8c022017-02-13 16:36:18 -08001941 pid_t rc;
1942 int status;
1943
1944 if (forkpid == 0) {
1945 errno = 0;
1946 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1947 if (rc != -1 || errno != ECHILD) {
1948 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1949 }
1950
Josh Gaoa48b41b2019-12-13 14:11:04 -08001951 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001952
1953 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001954 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001955 if (rc != -1 || errno != ECHILD) {
1956 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1957 }
1958 _exit(0);
1959 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001960 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001961 ASSERT_EQ(forkpid, rc);
1962 ASSERT_TRUE(WIFEXITED(status));
1963 ASSERT_EQ(0, WEXITSTATUS(status));
1964 }
1965}
Josh Gao352a8452017-03-30 16:46:21 -07001966
1967TEST(tombstoned, no_notify) {
1968 // Do this a few times.
1969 for (int i = 0; i < 3; ++i) {
1970 pid_t pid = 123'456'789 + i;
1971
1972 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07001973 InterceptResponse response = {};
1974 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
1975 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
1976 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07001977
1978 {
1979 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001980 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001981 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1982 }
1983
1984 pid_t read_pid;
1985 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1986 ASSERT_EQ(read_pid, pid);
1987 }
1988}
1989
1990TEST(tombstoned, stress) {
1991 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1992 static constexpr int kDumpCount = 100;
1993
1994 std::atomic<bool> start(false);
1995 std::vector<std::thread> threads;
1996 threads.emplace_back([&start]() {
1997 while (!start) {
1998 continue;
1999 }
2000
2001 // Use a way out of range pid, to avoid stomping on an actual process.
2002 pid_t pid_base = 1'000'000;
2003
2004 for (int dump = 0; dump < kDumpCount; ++dump) {
2005 pid_t pid = pid_base + dump;
2006
2007 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002008 InterceptResponse response = {};
2009 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2010 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2011 << "Error messeage: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002012
2013 // Pretend to crash, and then immediately close the socket.
2014 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
2015 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
2016 if (sockfd == -1) {
2017 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
2018 }
2019 TombstonedCrashPacket packet = {};
2020 packet.packet_type = CrashPacketType::kDumpRequest;
2021 packet.packet.dump_request.pid = pid;
2022 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
2023 FAIL() << "failed to write to tombstoned: " << strerror(errno);
2024 }
2025
2026 continue;
2027 }
2028 });
2029
2030 threads.emplace_back([&start]() {
2031 while (!start) {
2032 continue;
2033 }
2034
2035 // Use a way out of range pid, to avoid stomping on an actual process.
2036 pid_t pid_base = 2'000'000;
2037
2038 for (int dump = 0; dump < kDumpCount; ++dump) {
2039 pid_t pid = pid_base + dump;
2040
2041 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002042 InterceptResponse response = {};
2043 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2044 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2045 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002046
2047 {
2048 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01002049 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07002050 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2051 tombstoned_notify_completion(tombstoned_socket.get());
2052 }
2053
2054 // TODO: Fix the race that requires this sleep.
2055 std::this_thread::sleep_for(50ms);
2056
2057 pid_t read_pid;
2058 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2059 ASSERT_EQ(read_pid, pid);
2060 }
2061 });
2062
2063 start = true;
2064
2065 for (std::thread& thread : threads) {
2066 thread.join();
2067 }
2068}
Narayan Kamathca5e9082017-06-02 15:42:06 +01002069
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002070TEST(tombstoned, intercept_java_trace_smoke) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002071 // Using a "real" PID is a little dangerous here - if the test fails
2072 // or crashes, we might end up getting a bogus / unreliable stack
2073 // trace.
2074 const pid_t self = getpid();
2075
2076 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002077 InterceptResponse response = {};
2078 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2079 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2080 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002081
Josh Gao76e1e302021-01-26 15:53:11 -08002082 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01002083 // should result in a "regular" FD and not the installed intercept.
2084 const char native[] = "native";
2085 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002086 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01002087 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
2088 tombstoned_notify_completion(tombstoned_socket.get());
2089
2090 // Then, connect to tombstoned asking for a java backtrace. This *should*
2091 // trigger the intercept.
2092 const char java[] = "java";
2093 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
2094 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
2095 tombstoned_notify_completion(tombstoned_socket.get());
2096
2097 char outbuf[sizeof(java)];
2098 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2099 ASSERT_STREQ("java", outbuf);
2100}
2101
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002102TEST(tombstoned, intercept_multiple_dump_types) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002103 const pid_t fake_pid = 1'234'567;
2104 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002105 InterceptResponse response = {};
2106 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2107 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2108 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002109
2110 unique_fd intercept_fd_2, output_fd_2;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002111 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
2112 kDebuggerdNativeBacktrace);
2113 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2114 << "Error message: " << response.error_message;
2115}
2116
2117TEST(tombstoned, intercept_bad_pid) {
2118 const pid_t fake_pid = -1;
2119 unique_fd intercept_fd, output_fd;
2120 InterceptResponse response = {};
2121 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2122 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2123 << "Error message: " << response.error_message;
2124 ASSERT_MATCH(response.error_message, "bad pid");
2125}
2126
2127TEST(tombstoned, intercept_bad_dump_types) {
2128 const pid_t fake_pid = 1'234'567;
2129 unique_fd intercept_fd, output_fd;
2130 InterceptResponse response = {};
2131 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
2132 static_cast<DebuggerdDumpType>(20));
2133 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2134 << "Error message: " << response.error_message;
2135 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
2136
2137 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
2138 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2139 << "Error message: " << response.error_message;
2140 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
2141
2142 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
2143 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2144 << "Error message: " << response.error_message;
2145 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
2146}
2147
2148TEST(tombstoned, intercept_already_registered) {
2149 const pid_t fake_pid = 1'234'567;
2150 unique_fd intercept_fd1, output_fd1;
2151 InterceptResponse response = {};
2152 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
2153 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2154 << "Error message: " << response.error_message;
2155
2156 unique_fd intercept_fd2, output_fd2;
2157 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
2158 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
2159 << "Error message: " << response.error_message;
2160 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
2161}
2162
2163TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
2164 const pid_t fake_pid = 1'234'567;
2165
2166 unique_fd intercept_fd, output_fd;
2167 InterceptResponse response = {};
2168 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2169 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2170 << "Error message: " << response.error_message;
2171
2172 const char data[] = "tombstone_proto";
2173 unique_fd tombstoned_socket, input_fd;
2174 ASSERT_TRUE(
2175 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
2176 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
2177 tombstoned_notify_completion(tombstoned_socket.get());
2178
2179 char outbuf[sizeof(data)];
2180 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2181 ASSERT_STREQ("tombstone_proto", outbuf);
Narayan Kamathca5e9082017-06-02 15:42:06 +01002182}
2183
2184TEST(tombstoned, intercept_any) {
2185 const pid_t fake_pid = 1'234'567;
2186
2187 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002188 InterceptResponse response = {};
2189 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2190 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2191 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002192
2193 const char any[] = "any";
2194 unique_fd tombstoned_socket, input_fd;
2195 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2196 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
2197 tombstoned_notify_completion(tombstoned_socket.get());
2198
2199 char outbuf[sizeof(any)];
2200 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2201 ASSERT_STREQ("any", outbuf);
2202}
Josh Gao2b22ae12018-09-12 14:51:03 -07002203
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002204TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
2205 const pid_t fake_pid = 1'234'567;
2206
2207 InterceptResponse response = {};
2208 unique_fd intercept_fd1, output_fd1;
2209 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2210 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2211 << "Error message: " << response.error_message;
2212
2213 unique_fd intercept_fd2, output_fd2;
2214 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2215 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2216 << "Error message: " << response.error_message;
2217
2218 unique_fd tombstoned_socket, input_fd;
2219 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2220}
2221
2222TEST(tombstoned, intercept_multiple_verify_intercept) {
2223 // Need to use our pid for java since that will verify the pid.
2224 const pid_t fake_pid = getpid();
2225
2226 InterceptResponse response = {};
2227 unique_fd intercept_fd1, output_fd1;
2228 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2229 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2230 << "Error message: " << response.error_message;
2231
2232 unique_fd intercept_fd2, output_fd2;
2233 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2234 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2235 << "Error message: " << response.error_message;
2236
2237 unique_fd intercept_fd3, output_fd3;
2238 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2239 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2240 << "Error message: " << response.error_message;
2241
2242 const char native_data[] = "native";
2243 unique_fd tombstoned_socket1, input_fd1;
2244 ASSERT_TRUE(
2245 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2246 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2247 tombstoned_notify_completion(tombstoned_socket1.get());
2248
2249 char native_outbuf[sizeof(native_data)];
2250 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2251 ASSERT_STREQ("native", native_outbuf);
2252
2253 const char java_data[] = "java";
2254 unique_fd tombstoned_socket2, input_fd2;
2255 ASSERT_TRUE(
2256 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2257 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2258 tombstoned_notify_completion(tombstoned_socket2.get());
2259
2260 char java_outbuf[sizeof(java_data)];
2261 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2262 ASSERT_STREQ("java", java_outbuf);
2263
2264 const char tomb_data[] = "tombstone";
2265 unique_fd tombstoned_socket3, input_fd3;
2266 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2267 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2268 tombstoned_notify_completion(tombstoned_socket3.get());
2269
2270 char tomb_outbuf[sizeof(tomb_data)];
2271 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2272 ASSERT_STREQ("tombstone", tomb_outbuf);
2273}
2274
Josh Gao2b22ae12018-09-12 14:51:03 -07002275TEST(tombstoned, interceptless_backtrace) {
2276 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2277 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2278 std::map<int, time_t> result;
2279 for (int i = 0; i < 99; ++i) {
2280 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2281 struct stat st;
2282 if (stat(path.c_str(), &st) == 0) {
2283 result[i] = st.st_mtim.tv_sec;
2284 }
2285 }
2286 return result;
2287 };
2288
2289 auto before = get_tombstone_timestamps();
2290 for (int i = 0; i < 50; ++i) {
2291 raise_debugger_signal(kDebuggerdNativeBacktrace);
2292 }
2293 auto after = get_tombstone_timestamps();
2294
2295 int diff = 0;
2296 for (int i = 0; i < 99; ++i) {
2297 if (after.count(i) == 0) {
2298 continue;
2299 }
2300 if (before.count(i) == 0) {
2301 ++diff;
2302 continue;
2303 }
2304 if (before[i] != after[i]) {
2305 ++diff;
2306 }
2307 }
2308
2309 // We can't be sure that nothing's crash looping in the background.
2310 // This should be good enough, though...
2311 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2312}
Christopher Ferris481e8372019-07-15 17:13:24 -07002313
2314static __attribute__((__noinline__)) void overflow_stack(void* p) {
2315 void* buf[1];
2316 buf[0] = p;
2317 static volatile void* global = buf;
2318 if (global) {
2319 global = buf;
2320 overflow_stack(&buf);
2321 }
2322}
2323
2324TEST_F(CrasherTest, stack_overflow) {
2325 int intercept_result;
2326 unique_fd output_fd;
2327 StartProcess([]() { overflow_stack(nullptr); });
2328
2329 StartIntercept(&output_fd);
2330 FinishCrasher();
2331 AssertDeath(SIGSEGV);
2332 FinishIntercept(&intercept_result);
2333
2334 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2335
2336 std::string result;
2337 ConsumeFd(std::move(output_fd), &result);
2338 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2339}
Josh Gao76e1e302021-01-26 15:53:11 -08002340
Christopher Ferris22035cc2023-01-31 17:50:22 -08002341static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002342 std::string test_lib(testing::internal::GetArgvs()[0]);
2343 auto const value = test_lib.find_last_of('/');
2344 if (value == std::string::npos) {
2345 test_lib = "./";
2346 } else {
2347 test_lib = test_lib.substr(0, value + 1) + "./";
2348 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08002349 return test_lib + "libcrash_test.so";
2350}
2351
2352static void CreateEmbeddedLibrary(int out_fd) {
2353 std::string test_lib(GetTestLibraryPath());
2354 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2355 ASSERT_NE(fd.get(), -1);
2356 off_t file_size = lseek(fd, 0, SEEK_END);
2357 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2358 std::vector<uint8_t> contents(file_size);
2359 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2360
2361 // Put the shared library data at a pagesize() offset.
2362 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2363 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2364}
2365
2366TEST_F(CrasherTest, non_zero_offset_in_library) {
2367 int intercept_result;
2368 unique_fd output_fd;
2369 TemporaryFile tf;
2370 CreateEmbeddedLibrary(tf.fd);
2371 StartProcess([&tf]() {
2372 android_dlextinfo extinfo{};
2373 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2374 extinfo.library_fd = tf.fd;
2375 extinfo.library_fd_offset = 4 * getpagesize();
2376 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2377 if (handle == nullptr) {
2378 _exit(1);
2379 }
2380 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2381 if (crash_func == nullptr) {
2382 _exit(1);
2383 }
2384 crash_func();
2385 });
2386
2387 StartIntercept(&output_fd);
2388 FinishCrasher();
2389 AssertDeath(SIGSEGV);
2390 FinishIntercept(&intercept_result);
2391
2392 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2393
2394 std::string result;
2395 ConsumeFd(std::move(output_fd), &result);
2396
2397 // Verify the crash includes an offset value in the backtrace.
2398 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2399 tf.path, 4 * getpagesize());
2400 ASSERT_MATCH(result, match_str);
2401}
2402
2403static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2404 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002405
2406 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2407 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2408
2409 // Copy the shared so to a tempory directory.
2410 return system(cp_cmd.c_str()) == 0;
2411}
2412
2413TEST_F(CrasherTest, unreadable_elf) {
2414 int intercept_result;
2415 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002416 std::string tmp_so_name;
2417 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002418 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002419 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2420 _exit(1);
2421 }
2422 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2423 if (handle == nullptr) {
2424 _exit(1);
2425 }
2426 // Delete the original shared library so that we get the warning
2427 // about unreadable elf files.
2428 if (unlink(tmp_so_name.c_str()) == -1) {
2429 _exit(1);
2430 }
2431 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2432 if (crash_func == nullptr) {
2433 _exit(1);
2434 }
2435 crash_func();
2436 });
2437
2438 StartIntercept(&output_fd);
2439 FinishCrasher();
2440 AssertDeath(SIGSEGV);
2441 FinishIntercept(&intercept_result);
2442
2443 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2444
2445 std::string result;
2446 ConsumeFd(std::move(output_fd), &result);
2447 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002448 std::string match_str = "NOTE: " + tmp_so_name;
2449 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002450}
2451
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002452void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
2453 static std::regex tombstone_re("tombstone_\\d+");
Christopher Ferris35da2882021-02-17 15:39:06 -08002454 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2455 ASSERT_TRUE(dir_h != nullptr);
Christopher Ferris35da2882021-02-17 15:39:06 -08002456 dirent* entry;
2457 while ((entry = readdir(dir_h.get())) != nullptr) {
2458 if (!std::regex_match(entry->d_name, tombstone_re)) {
2459 continue;
2460 }
2461 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002462
2463 struct stat st;
2464 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2465 continue;
2466 }
2467
2468 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002469 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002470 break;
2471 }
2472 }
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002473}
Josh Gao76e1e302021-01-26 15:53:11 -08002474
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002475TEST(tombstoned, proto) {
2476 const pid_t self = getpid();
2477 unique_fd tombstoned_socket, text_fd, proto_fd;
2478 ASSERT_TRUE(
2479 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2480
2481 tombstoned_notify_completion(tombstoned_socket.get());
2482
2483 ASSERT_NE(-1, text_fd.get());
2484 ASSERT_NE(-1, proto_fd.get());
2485
2486 struct stat text_st;
2487 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2488
2489 std::optional<std::string> tombstone_file;
2490 // Allow up to 5 seconds for the tombstone to be written to the system.
2491 const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
2492 const auto start = std::chrono::high_resolution_clock::now();
2493 while (true) {
2494 std::this_thread::sleep_for(100ms);
2495 CheckForTombstone(text_st, tombstone_file);
2496 if (tombstone_file) {
2497 break;
2498 }
2499 if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
2500 break;
2501 }
2502 }
2503
2504 ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
Christopher Ferris35da2882021-02-17 15:39:06 -08002505 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002506
2507 struct stat proto_fd_st;
2508 struct stat proto_file_st;
2509 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2510 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2511
2512 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2513 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2514}
2515
2516TEST(tombstoned, proto_intercept) {
2517 const pid_t self = getpid();
2518 unique_fd intercept_fd, output_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002519
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002520 InterceptResponse response = {};
2521 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2522 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2523 << "Error message: " << response.error_message;
Josh Gao76e1e302021-01-26 15:53:11 -08002524
2525 unique_fd tombstoned_socket, text_fd, proto_fd;
2526 ASSERT_TRUE(
2527 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2528 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2529 tombstoned_notify_completion(tombstoned_socket.get());
2530
2531 text_fd.reset();
2532
2533 std::string output;
2534 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2535 ASSERT_EQ("foo", output);
2536}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002537
2538// Verify that when an intercept is present for the main thread, and the signal
2539// is received on a different thread, the intercept still works.
2540TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2541 StartProcess([]() {
2542 std::thread thread([]() {
2543 // Raise the signal on the side thread.
2544 raise_debugger_signal(kDebuggerdNativeBacktrace);
2545 });
2546 thread.join();
2547 _exit(0);
2548 });
2549
2550 unique_fd output_fd;
2551 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2552 FinishCrasher();
2553 AssertDeath(0);
2554
2555 int intercept_result;
2556 FinishIntercept(&intercept_result);
2557 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2558
2559 std::string result;
2560 ConsumeFd(std::move(output_fd), &result);
2561 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2562}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002563
2564static std::string format_pointer(uintptr_t ptr) {
2565#if defined(__LP64__)
2566 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2567 static_cast<uint32_t>(ptr & 0xffffffff));
2568#else
2569 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2570#endif
2571}
2572
2573static std::string format_pointer(void* ptr) {
2574 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2575}
2576
2577static std::string format_full_pointer(uintptr_t ptr) {
2578#if defined(__LP64__)
2579 return android::base::StringPrintf("%016" PRIx64, ptr);
2580#else
2581 return android::base::StringPrintf("%08x", ptr);
2582#endif
2583}
2584
2585static std::string format_full_pointer(void* ptr) {
2586 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2587}
2588
2589__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2590 int* crash_ptr = reinterpret_cast<int*>(ptr);
2591 *crash_ptr = 1;
2592 return *crash_ptr;
2593}
2594
2595// Verify that a fault address before the first map is properly handled.
2596TEST_F(CrasherTest, fault_address_before_first_map) {
2597 StartProcess([]() {
2598 ASSERT_EQ(0, crash_call(0x1024));
2599 _exit(0);
2600 });
2601
2602 unique_fd output_fd;
2603 StartIntercept(&output_fd);
2604 FinishCrasher();
2605 AssertDeath(SIGSEGV);
2606
2607 int intercept_result;
2608 FinishIntercept(&intercept_result);
2609 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2610
2611 std::string result;
2612 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002613 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002614
2615 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2616
2617 std::string match_str = android::base::StringPrintf(
2618 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2619 format_pointer(0x1024).c_str());
2620 ASSERT_MATCH(result, match_str);
2621}
2622
2623// Verify that a fault address after the last map is properly handled.
2624TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002625 // This makes assumptions about the memory layout that are not true in HWASan
2626 // processes.
2627 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002628 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2629 StartProcess([crash_uptr]() {
2630 ASSERT_EQ(0, crash_call(crash_uptr));
2631 _exit(0);
2632 });
2633
2634 unique_fd output_fd;
2635 StartIntercept(&output_fd);
2636 FinishCrasher();
2637 AssertDeath(SIGSEGV);
2638
2639 int intercept_result;
2640 FinishIntercept(&intercept_result);
2641 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2642
2643 std::string result;
2644 ConsumeFd(std::move(output_fd), &result);
2645
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002646 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2647 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002648 ASSERT_MATCH(result, match_str);
2649
Ryan Prichardbc227032024-02-29 14:40:57 -08002650 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002651
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002652 // Verifies that the fault address error message is at the end of the
2653 // maps section. To do this, the check below looks for the start of the
2654 // open files section or the start of the log file section. It's possible
2655 // for either of these sections to be present after the maps section right
2656 // now.
2657 // If the sections move around, this check might need to be modified.
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002658 match_str = android::base::StringPrintf(
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002659 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002660 format_pointer(crash_uptr).c_str());
2661 ASSERT_MATCH(result, match_str);
2662}
2663
2664// Verify that a fault address between maps is properly handled.
2665TEST_F(CrasherTest, fault_address_between_maps) {
2666 // Create a map before the fork so it will be present in the child.
2667 void* start_ptr =
2668 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2669 ASSERT_NE(MAP_FAILED, start_ptr);
2670 // Unmap the page in the middle.
2671 void* middle_ptr =
2672 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2673 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2674
2675 StartProcess([middle_ptr]() {
2676 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2677 _exit(0);
2678 });
2679
2680 // Unmap the two maps.
2681 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2682 void* end_ptr =
2683 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2684 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2685
2686 unique_fd output_fd;
2687 StartIntercept(&output_fd);
2688 FinishCrasher();
2689 AssertDeath(SIGSEGV);
2690
2691 int intercept_result;
2692 FinishIntercept(&intercept_result);
2693 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2694
2695 std::string result;
2696 ConsumeFd(std::move(output_fd), &result);
2697
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002698 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2699 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002700 ASSERT_MATCH(result, match_str);
2701
Ryan Prichardbc227032024-02-29 14:40:57 -08002702 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002703
2704 match_str = android::base::StringPrintf(
2705 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2706 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2707 format_pointer(end_ptr).c_str());
2708 ASSERT_MATCH(result, match_str);
2709}
2710
2711// Verify that a fault address happens in the correct map.
2712TEST_F(CrasherTest, fault_address_in_map) {
2713 // Create a map before the fork so it will be present in the child.
2714 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2715 ASSERT_NE(MAP_FAILED, ptr);
2716
2717 StartProcess([ptr]() {
2718 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2719 _exit(0);
2720 });
2721
2722 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2723
2724 unique_fd output_fd;
2725 StartIntercept(&output_fd);
2726 FinishCrasher();
2727 AssertDeath(SIGSEGV);
2728
2729 int intercept_result;
2730 FinishIntercept(&intercept_result);
2731 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2732
2733 std::string result;
2734 ConsumeFd(std::move(output_fd), &result);
2735
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002736 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2737 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002738 ASSERT_MATCH(result, match_str);
2739
Ryan Prichardbc227032024-02-29 14:40:57 -08002740 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002741
2742 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2743 ASSERT_MATCH(result, match_str);
2744}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002745
2746static constexpr uint32_t kDexData[] = {
2747 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2748 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2749 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2750 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2751 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2752 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2753 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2754 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2755 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2756 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2757 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2758 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2759 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2760 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2761 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2762 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2763 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2764};
2765
2766TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2767 StartProcess([]() {
2768 TemporaryDir td;
2769 std::string tmp_so_name;
2770 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2771 _exit(1);
2772 }
2773
2774 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2775 // move the library to which has a basename of libart.so.
2776 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2777 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2778 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2779 if (handle == nullptr) {
2780 _exit(1);
2781 }
2782
2783 void* ptr =
2784 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2785 ASSERT_TRUE(ptr != MAP_FAILED);
2786 memcpy(ptr, kDexData, sizeof(kDexData));
2787 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2788
2789 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2790 .symfile_size = sizeof(kDexData)};
2791
2792 JITDescriptor* dex_debug =
2793 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2794 ASSERT_TRUE(dex_debug != nullptr);
2795 dex_debug->version = 1;
2796 dex_debug->action_flag = 0;
2797 dex_debug->relevant_entry = 0;
2798 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2799
2800 // This sets the magic dex pc value for register 0, using the value
2801 // of register 1 + 0x102.
2802 asm(".cfi_escape "
2803 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2804 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2805 "0x13 /* DW_OP_drop */,"
2806 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2807
2808 // For each different architecture, set register one to the dex ptr mmap
2809 // created above. Then do a nullptr dereference to force a crash.
2810#if defined(__arm__)
2811 asm volatile(
2812 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002813 "mov r2, #0\n"
2814 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002815 : [base] "+r"(ptr)
2816 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002817 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002818#elif defined(__aarch64__)
2819 asm volatile(
2820 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002821 "mov x2, #0\n"
2822 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002823 : [base] "+r"(ptr)
2824 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002825 : "x1", "x2", "memory");
2826#elif defined(__riscv)
2827 // TODO: x1 is ra (the link register) on riscv64, so this might have
2828 // unintended consequences, but we'll need to change the .cfi_escape if so.
2829 asm volatile(
2830 "mv x1, %[base]\n"
2831 "sw zero, 0(zero)\n"
2832 : [base] "+r"(ptr)
2833 :
2834 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002835#elif defined(__i386__)
2836 asm volatile(
2837 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002838 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002839 : [base] "+r"(ptr)
2840 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002841 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002842#elif defined(__x86_64__)
2843 asm volatile(
2844 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002845 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002846 : [base] "+r"(ptr)
2847 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002848 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002849#else
2850#error "Unsupported architecture"
2851#endif
2852 _exit(0);
2853 });
2854
2855 unique_fd output_fd;
2856 StartIntercept(&output_fd);
2857 FinishCrasher();
2858 AssertDeath(SIGSEGV);
2859
2860 int intercept_result;
2861 FinishIntercept(&intercept_result);
2862 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2863
2864 std::string result;
2865 ConsumeFd(std::move(output_fd), &result);
2866
2867 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002868 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002869
2870 // Now verify that the dex_pc frame includes a proper function name.
2871 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2872}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002873
2874static std::string format_map_pointer(uintptr_t ptr) {
2875#if defined(__LP64__)
2876 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2877 static_cast<uint32_t>(ptr & 0xffffffff));
2878#else
2879 return android::base::StringPrintf("%08x", ptr);
2880#endif
2881}
2882
2883// Verify that map data is properly formatted.
2884TEST_F(CrasherTest, verify_map_format) {
2885 // Create multiple maps to make sure that the map data is formatted properly.
2886 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2887 ASSERT_NE(MAP_FAILED, none_map);
2888 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2889 ASSERT_NE(MAP_FAILED, r_map);
2890 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2891 ASSERT_NE(MAP_FAILED, w_map);
2892 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2893 ASSERT_NE(MAP_FAILED, x_map);
2894
2895 TemporaryFile tf;
2896 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2897 char c = 'f';
2898 ASSERT_EQ(1, write(tf.fd, &c, 1));
2899 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2900 ASSERT_EQ(1, write(tf.fd, &c, 1));
2901 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2902 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2903 ASSERT_NE(MAP_FAILED, file_map);
2904
2905 StartProcess([]() { abort(); });
2906
2907 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2908 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2909 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2910 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2911 ASSERT_EQ(0, munmap(file_map, 0x3001));
2912
2913 unique_fd output_fd;
2914 StartIntercept(&output_fd);
2915 FinishCrasher();
2916 AssertDeath(SIGABRT);
2917 int intercept_result;
2918 FinishIntercept(&intercept_result);
2919
2920 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2921
2922 std::string result;
2923 ConsumeFd(std::move(output_fd), &result);
2924
2925 std::string match_str;
2926 // Verify none.
2927 match_str = android::base::StringPrintf(
2928 " %s-%s --- 0 1000\\n",
2929 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2930 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2931 ASSERT_MATCH(result, match_str);
2932
2933 // Verify read-only.
2934 match_str = android::base::StringPrintf(
2935 " %s-%s r-- 0 1000\\n",
2936 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2937 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2938 ASSERT_MATCH(result, match_str);
2939
2940 // Verify write-only.
2941 match_str = android::base::StringPrintf(
2942 " %s-%s -w- 0 1000\\n",
2943 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2944 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2945 ASSERT_MATCH(result, match_str);
2946
2947 // Verify exec-only.
2948 match_str = android::base::StringPrintf(
2949 " %s-%s --x 0 1000\\n",
2950 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2951 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2952 ASSERT_MATCH(result, match_str);
2953
2954 // Verify file map with non-zero offset and a name.
2955 match_str = android::base::StringPrintf(
2956 " %s-%s r-- 2000 4000 %s\\n",
2957 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2958 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2959 ASSERT_MATCH(result, match_str);
2960}
2961
2962// Verify that the tombstone map data is correct.
2963TEST_F(CrasherTest, verify_header) {
2964 StartProcess([]() { abort(); });
2965
2966 unique_fd output_fd;
2967 StartIntercept(&output_fd);
2968 FinishCrasher();
2969 AssertDeath(SIGABRT);
2970 int intercept_result;
2971 FinishIntercept(&intercept_result);
2972
2973 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2974
2975 std::string result;
2976 ConsumeFd(std::move(output_fd), &result);
2977
2978 std::string match_str = android::base::StringPrintf(
2979 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2980 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2981 android::base::GetProperty("ro.revision", "unknown").c_str());
2982 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2983 ASSERT_MATCH(result, match_str);
2984}
2985
2986// Verify that the thread header is formatted properly.
2987TEST_F(CrasherTest, verify_thread_header) {
2988 void* shared_map =
2989 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2990 ASSERT_NE(MAP_FAILED, shared_map);
2991 memset(shared_map, 0, sizeof(pid_t));
2992
2993 StartProcess([&shared_map]() {
2994 std::atomic_bool tid_written;
2995 std::thread thread([&tid_written, &shared_map]() {
2996 pid_t tid = gettid();
2997 memcpy(shared_map, &tid, sizeof(pid_t));
2998 tid_written = true;
2999 volatile bool done = false;
3000 while (!done)
3001 ;
3002 });
3003 thread.detach();
3004 while (!tid_written.load(std::memory_order_acquire))
3005 ;
3006 abort();
3007 });
3008
3009 pid_t primary_pid = crasher_pid;
3010
3011 unique_fd output_fd;
3012 StartIntercept(&output_fd);
3013 FinishCrasher();
3014 AssertDeath(SIGABRT);
3015 int intercept_result;
3016 FinishIntercept(&intercept_result);
3017 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3018
3019 // Read the tid data out.
3020 pid_t tid;
3021 memcpy(&tid, shared_map, sizeof(pid_t));
3022 ASSERT_NE(0, tid);
3023
3024 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
3025
3026 std::string result;
3027 ConsumeFd(std::move(output_fd), &result);
3028
3029 // Verify that there are two headers, one where the tid is "primary_pid"
3030 // and the other where the tid is "tid".
3031 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
3032 primary_pid, primary_pid);
3033 ASSERT_MATCH(result, match_str);
3034
3035 match_str =
3036 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
3037 ASSERT_MATCH(result, match_str);
3038}
3039
3040// Verify that there is a BuildID present in the map section and set properly.
3041TEST_F(CrasherTest, verify_build_id) {
3042 StartProcess([]() { abort(); });
3043
3044 unique_fd output_fd;
3045 StartIntercept(&output_fd);
3046 FinishCrasher();
3047 AssertDeath(SIGABRT);
3048 int intercept_result;
3049 FinishIntercept(&intercept_result);
3050 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3051
3052 std::string result;
3053 ConsumeFd(std::move(output_fd), &result);
3054
3055 // Find every /system or /apex lib and verify the BuildID is displayed
3056 // properly.
3057 bool found_valid_elf = false;
3058 std::smatch match;
3059 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
3060 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
3061 result = match.suffix()) {
3062 if (prev_file == match[1]) {
3063 // Already checked this file.
3064 continue;
3065 }
3066
3067 prev_file = match[1];
Christopher Ferris15038902023-11-10 00:05:49 -08003068 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
3069 unwindstack::Elf elf(elf_memory);
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003070 if (!elf.Init() || !elf.valid()) {
3071 // Skipping invalid elf files.
3072 continue;
3073 }
3074 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
3075
3076 found_valid_elf = true;
3077 }
3078 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
3079}
Christopher Ferrisbda10642023-04-24 18:14:53 -07003080
3081const char kLogMessage[] = "Should not see this log message.";
3082
3083// Verify that the logd process does not read the log.
3084TEST_F(CrasherTest, logd_skips_reading_logs) {
3085 StartProcess([]() {
3086 pthread_setname_np(pthread_self(), "logd");
3087 LOG(INFO) << kLogMessage;
3088 abort();
3089 });
3090
3091 unique_fd output_fd;
3092 StartIntercept(&output_fd);
3093 FinishCrasher();
3094 AssertDeath(SIGABRT);
3095 int intercept_result;
3096 FinishIntercept(&intercept_result);
3097 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3098
3099 std::string result;
3100 ConsumeFd(std::move(output_fd), &result);
3101 // logd should not contain our log message.
3102 ASSERT_NOT_MATCH(result, kLogMessage);
3103}
3104
3105// Verify that the logd process does not read the log when the non-main
3106// thread crashes.
3107TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
3108 StartProcess([]() {
3109 pthread_setname_np(pthread_self(), "logd");
3110 LOG(INFO) << kLogMessage;
3111
3112 std::thread thread([]() {
3113 pthread_setname_np(pthread_self(), "not_logd_thread");
3114 // Raise the signal on the side thread.
3115 raise_debugger_signal(kDebuggerdTombstone);
3116 });
3117 thread.join();
3118 _exit(0);
3119 });
3120
3121 unique_fd output_fd;
3122 StartIntercept(&output_fd, kDebuggerdTombstone);
3123 FinishCrasher();
3124 AssertDeath(0);
3125
3126 int intercept_result;
3127 FinishIntercept(&intercept_result);
3128 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3129
3130 std::string result;
3131 ConsumeFd(std::move(output_fd), &result);
3132 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
3133 ASSERT_NOT_MATCH(result, kLogMessage);
3134}
Christopher Ferris98d62422023-05-24 20:01:10 +00003135
3136// Disable this test since there is a high liklihood that this would
3137// be flaky since it requires 500 messages being in the log.
3138TEST_F(CrasherTest, DISABLED_max_log_messages) {
3139 StartProcess([]() {
3140 for (size_t i = 0; i < 600; i++) {
3141 LOG(INFO) << "Message number " << i;
3142 }
3143 abort();
3144 });
3145
3146 unique_fd output_fd;
3147 StartIntercept(&output_fd);
3148 FinishCrasher();
3149 AssertDeath(SIGABRT);
3150 int intercept_result;
3151 FinishIntercept(&intercept_result);
3152 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3153
3154 std::string result;
3155 ConsumeFd(std::move(output_fd), &result);
3156 ASSERT_NOT_MATCH(result, "Message number 99");
3157 ASSERT_MATCH(result, "Message number 100");
3158 ASSERT_MATCH(result, "Message number 599");
3159}
3160
3161TEST_F(CrasherTest, log_with_newline) {
3162 StartProcess([]() {
3163 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
3164 abort();
3165 });
3166
3167 unique_fd output_fd;
3168 StartIntercept(&output_fd);
3169 FinishCrasher();
3170 AssertDeath(SIGABRT);
3171 int intercept_result;
3172 FinishIntercept(&intercept_result);
3173 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3174
3175 std::string result;
3176 ConsumeFd(std::move(output_fd), &result);
3177 ASSERT_MATCH(result, ":\\s*This line has a newline.");
3178 ASSERT_MATCH(result, ":\\s*This is on the next line.");
3179}