blob: 962097e65d1693f814446446bc0f238e908a8f55 [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 Ferrisdf5ae062024-08-07 20:31:50 +000021#include <inttypes.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000022#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080023#include <malloc.h>
Christopher Ferrisbda10642023-04-24 18:14:53 -070024#include <pthread.h>
Florian Mayere6462f92024-02-28 11:12:11 -080025#include <setjmp.h>
Josh Gaocdea7502017-11-01 15:00:40 -070026#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080027#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070028#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080029#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070030#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080031#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070032#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070033#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070034#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070035
36#include <chrono>
37#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000038#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070039#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070040#include <thread>
41
Florian Mayer920d95b2024-02-14 12:57:09 -080042#include <android/crash_detail.h>
Christopher Ferris22035cc2023-01-31 17:50:22 -080043#include <android/dlext.h>
Josh Gaobf06a402018-08-27 16:34:01 -070044#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080045#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080046#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070047#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080048#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080049
Josh Gao5f87bbd2019-01-09 17:01:49 -080050#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070051#include <android-base/file.h>
52#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070053#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/parseint.h>
55#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070056#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070057#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070058#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070059#include <android-base/unique_fd.h>
60#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070061#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070062#include <gtest/gtest.h>
63
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000064#include <unwindstack/Elf.h>
65#include <unwindstack/Memory.h>
66
Josh Gaoe04ca272018-01-16 15:38:17 -080067#include <libminijail.h>
68#include <scoped_minijail.h>
69
Christopher Ferris2038cc72021-09-15 03:57:10 +000070#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010071#include "debuggerd/handler.h"
Mitch Phillips18ce5422023-01-19 14:23:49 -080072#include "gtest/gtest.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010073#include "protocol.h"
74#include "tombstoned/tombstoned.h"
75#include "util.h"
76
Josh Gaocbe70cb2016-10-18 18:17:52 -070077using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080078
79using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070080using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070081using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070082
83#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070084#define ARCH_SUFFIX "64"
85#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070086#define ARCH_SUFFIX ""
87#endif
88
Elliott Hughese4781d52021-03-17 09:15:15 -070089constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070090
91#define TIMEOUT(seconds, expr) \
92 [&]() { \
93 struct sigaction old_sigaction; \
94 struct sigaction new_sigaction = {}; \
95 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080096 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070097 err(1, "sigaction failed"); \
98 } \
Mattias Simonsson38ab0452023-11-08 12:02:46 +000099 alarm(seconds * android::base::HwTimeoutMultiplier()); \
Josh Gaocbe70cb2016-10-18 18:17:52 -0700100 auto value = expr; \
101 int saved_errno = errno; \
102 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
103 err(1, "sigaction failed"); \
104 } \
105 alarm(0); \
106 errno = saved_errno; \
107 return value; \
108 }()
109
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700110// Backtrace frame dump could contain:
111// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
112// or
113// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800114#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700115 ASSERT_MATCH(result, \
116 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900117
Narayan Kamatha73df602017-05-24 15:07:25 +0100118static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700119 InterceptResponse* response, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700120 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
121 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
122 if (intercept_fd->get() == -1) {
123 FAIL() << "failed to contact tombstoned: " << strerror(errno);
124 }
125
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700126 InterceptRequest req = {
127 .dump_type = intercept_type,
128 .pid = target_pid,
129 };
Josh Gao460b3362017-03-30 16:40:47 -0700130
131 unique_fd output_pipe_write;
132 if (!Pipe(output_fd, &output_pipe_write)) {
133 FAIL() << "failed to create output pipe: " << strerror(errno);
134 }
135
136 std::string pipe_size_str;
137 int pipe_buffer_size;
138 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
139 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
140 }
141
142 pipe_size_str = android::base::Trim(pipe_size_str);
143
144 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
145 FAIL() << "failed to parse pipe max size";
146 }
147
148 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
149 FAIL() << "failed to set pipe size: " << strerror(errno);
150 }
151
Josh Gao5675f3c2017-06-01 12:19:53 -0700152 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
153
Josh Gao5f87bbd2019-01-09 17:01:49 -0800154 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
155 output_pipe_write.reset();
156 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700157 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
158 }
159
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700160 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), response, sizeof(*response)));
Josh Gao460b3362017-03-30 16:40:47 -0700161 if (rc == -1) {
162 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
163 } else if (rc == 0) {
164 FAIL() << "failed to read response from tombstoned (EOF)";
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700165 } else if (rc != sizeof(*response)) {
166 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(*response)
Josh Gao460b3362017-03-30 16:40:47 -0700167 << ", received " << rc;
168 }
Josh Gao460b3362017-03-30 16:40:47 -0700169}
170
Elliott Hughesd13ea522022-01-13 09:20:26 -0800171static bool pac_supported() {
172#if defined(__aarch64__)
173 return getauxval(AT_HWCAP) & HWCAP_PACA;
174#else
175 return false;
176#endif
177}
178
Josh Gaocbe70cb2016-10-18 18:17:52 -0700179class CrasherTest : public ::testing::Test {
180 public:
181 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700182 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700183 unique_fd crasher_pipe;
184 unique_fd intercept_fd;
185
186 CrasherTest();
187 ~CrasherTest();
188
Narayan Kamatha73df602017-05-24 15:07:25 +0100189 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700190
191 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
192 void FinishIntercept(int* result);
193
Josh Gao2e7b8e22017-05-04 17:12:57 -0700194 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700195 void StartCrasher(const std::string& crash_type);
196 void FinishCrasher();
197 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700198
199 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700200};
201
202CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700203 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
204 android::base::SetProperty(kWaitForDebuggerKey, "0");
205
206 // Clear the old property too, just in case someone's been using it
207 // on this device. (We only document the new name, but we still support
208 // the old name so we don't break anyone's existing setups.)
209 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700210}
211
212CrasherTest::~CrasherTest() {
213 if (crasher_pid != -1) {
214 kill(crasher_pid, SIGKILL);
215 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700216 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700217 }
218
Elliott Hughese4781d52021-03-17 09:15:15 -0700219 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700220}
221
Narayan Kamatha73df602017-05-24 15:07:25 +0100222void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700223 if (crasher_pid == -1) {
224 FAIL() << "crasher hasn't been started";
225 }
226
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700227 InterceptResponse response = {};
228 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &response, intercept_type);
229 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
230 << "Error message: " << response.error_message;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700231}
232
233void CrasherTest::FinishIntercept(int* result) {
234 InterceptResponse response;
235
Christopher Ferris11555f02019-09-20 14:18:55 -0700236 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700237 if (rc == -1) {
238 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
239 } else if (rc == 0) {
240 *result = -1;
241 } else if (rc != sizeof(response)) {
242 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
243 << ", received " << rc;
244 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700245 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700246 }
247}
248
Josh Gao2e7b8e22017-05-04 17:12:57 -0700249void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800250 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700251 unique_fd crasher_read_pipe;
252 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
253 FAIL() << "failed to create pipe: " << strerror(errno);
254 }
255
Josh Gao2e7b8e22017-05-04 17:12:57 -0700256 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700257 if (crasher_pid == -1) {
258 FAIL() << "fork failed: " << strerror(errno);
259 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800260 char dummy;
261 crasher_pipe.reset();
262 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800263 function();
264 _exit(0);
265 }
266}
267
Josh Gaocbe70cb2016-10-18 18:17:52 -0700268void CrasherTest::FinishCrasher() {
269 if (crasher_pipe == -1) {
270 FAIL() << "crasher pipe uninitialized";
271 }
272
Christopher Ferris172b0a02019-09-18 17:48:30 -0700273 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700274 if (rc == -1) {
275 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
276 } else if (rc == 0) {
277 FAIL() << "crasher pipe was closed";
278 }
279}
280
281void CrasherTest::AssertDeath(int signo) {
282 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700283 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700284 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700285 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
286 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700287 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700288 FAIL() << "failed to wait for crasher: " << strerror(errno);
289 }
290
Josh Gaoe06f2a42017-04-27 16:50:38 -0700291 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700292 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700293 ASSERT_EQ(0, WEXITSTATUS(signo));
294 } else {
295 ASSERT_FALSE(WIFEXITED(status));
296 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
297 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700299 crasher_pid = -1;
300}
301
302static void ConsumeFd(unique_fd fd, std::string* output) {
Kelvin Zhang786dac32023-06-15 16:23:56 -0700303 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700304}
305
Mitch Phillips78f06702021-06-01 14:35:43 -0700306class LogcatCollector {
307 public:
308 LogcatCollector() { system("logcat -c"); }
309
310 void Collect(std::string* output) {
311 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
312 ASSERT_NE(cmd_stdout, nullptr);
313 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
314 ConsumeFd(std::move(tmp_fd), output);
315 pclose(cmd_stdout);
316 }
317};
318
Josh Gaocbe70cb2016-10-18 18:17:52 -0700319TEST_F(CrasherTest, smoke) {
320 int intercept_result;
321 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800322 StartProcess([]() {
323 *reinterpret_cast<volatile char*>(0xdead) = '1';
324 });
325
Josh Gaocbe70cb2016-10-18 18:17:52 -0700326 StartIntercept(&output_fd);
327 FinishCrasher();
328 AssertDeath(SIGSEGV);
329 FinishIntercept(&intercept_result);
330
331 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
332
333 std::string result;
334 ConsumeFd(std::move(output_fd), &result);
Christopher Ferris2f77c2a2024-05-07 12:25:31 -0700335 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700336
337 if (mte_supported()) {
338 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700339 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
340 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700341 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800342
343 if (pac_supported()) {
344 // Test that the default PAC_ENABLED_KEYS value is set.
345 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
346 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
347 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700348}
349
Peter Collingbournef03af882020-03-20 18:09:00 -0700350TEST_F(CrasherTest, tagged_fault_addr) {
351#if !defined(__aarch64__)
352 GTEST_SKIP() << "Requires aarch64";
353#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700354 // HWASan crashes with SIGABRT on tag mismatch.
355 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700356 int intercept_result;
357 unique_fd output_fd;
358 StartProcess([]() {
359 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
360 });
361
362 StartIntercept(&output_fd);
363 FinishCrasher();
364 AssertDeath(SIGSEGV);
365 FinishIntercept(&intercept_result);
366
367 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
368
369 std::string result;
370 ConsumeFd(std::move(output_fd), &result);
371
372 // The address can either be tagged (new kernels) or untagged (old kernels).
373 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800374 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700375}
376
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700377void CrasherTest::Trap(void* ptr) {
378 void (*volatile f)(void*) = nullptr;
379 __asm__ __volatile__("" : : "r"(f) : "memory");
380 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700381}
382
383TEST_F(CrasherTest, heap_addr_in_register) {
384#if defined(__i386__)
385 GTEST_SKIP() << "architecture does not pass arguments in registers";
386#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700387 // The memory dump in HWASan crashes sadly shows the memory near the registers
388 // in the HWASan dump function, rather the faulting context. This is a known
389 // issue.
390 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700391 int intercept_result;
392 unique_fd output_fd;
393 StartProcess([]() {
394 // Crash with a heap pointer in the first argument register.
395 Trap(malloc(1));
396 });
397
398 StartIntercept(&output_fd);
399 FinishCrasher();
400 int status;
401 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
402 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
403 // Don't test the signal number because different architectures use different signals for
404 // __builtin_trap().
405 FinishIntercept(&intercept_result);
406
407 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
408
409 std::string result;
410 ConsumeFd(std::move(output_fd), &result);
411
412#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800413 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700414#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800415 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800416#elif defined(__riscv)
417 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700418#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800419 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700420#else
421 ASSERT_TRUE(false) << "unsupported architecture";
422#endif
423}
424
Peter Collingbournecd278072020-12-21 14:08:38 -0800425#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700426static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800427 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700428 abort();
429 }
430}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800431
432static void SetTagCheckingLevelAsync() {
433 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
434 abort();
435 }
436}
Peter Collingbournef8622522020-04-07 14:07:32 -0700437#endif
438
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800439struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
440
Peter Collingbourneaa544792021-05-13 13:53:37 -0700441INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800442
443TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800444#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700445 if (!mte_supported()) {
446 GTEST_SKIP() << "Requires MTE";
447 }
448
Peter Collingbourneaa544792021-05-13 13:53:37 -0700449 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
450 if (GetParam() == 0) {
451 return;
452 }
453
Mitch Phillips78f06702021-06-01 14:35:43 -0700454 LogcatCollector logcat_collector;
455
Peter Collingbournef8622522020-04-07 14:07:32 -0700456 int intercept_result;
457 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800458 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700459 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800460 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700461 free((void *)p);
462 p[0] = 42;
463 });
464
465 StartIntercept(&output_fd);
466 FinishCrasher();
467 AssertDeath(SIGSEGV);
468 FinishIntercept(&intercept_result);
469
470 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
471
Mitch Phillips78f06702021-06-01 14:35:43 -0700472 std::vector<std::string> log_sources(2);
473 ConsumeFd(std::move(output_fd), &log_sources[0]);
474 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700475 // Tag dump only available in the tombstone, not logcat.
476 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700477
Mitch Phillips78f06702021-06-01 14:35:43 -0700478 for (const auto& result : log_sources) {
479 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
480 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
481 std::to_string(GetParam()) + R"(-byte allocation)");
482 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
483 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
484 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700485#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800486 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700487#endif
488}
489
Peter Collingbournedc476342021-05-12 15:56:43 -0700490TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
491#if defined(__aarch64__)
492 if (!mte_supported()) {
493 GTEST_SKIP() << "Requires MTE";
494 }
495
496 int intercept_result;
497 unique_fd output_fd;
498 StartProcess([&]() {
499 SetTagCheckingLevelSync();
500 volatile int* p = (volatile int*)malloc(GetParam());
501 free((void *)p);
502 p[-1] = 42;
503 });
504
505 StartIntercept(&output_fd);
506 FinishCrasher();
507 AssertDeath(SIGSEGV);
508 FinishIntercept(&intercept_result);
509
510 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
511
512 std::string result;
513 ConsumeFd(std::move(output_fd), &result);
514
515 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
516 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
517#else
518 GTEST_SKIP() << "Requires aarch64";
519#endif
520}
521
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800522TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800523#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700524 if (!mte_supported()) {
525 GTEST_SKIP() << "Requires MTE";
526 }
527
Mitch Phillips78f06702021-06-01 14:35:43 -0700528 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700529 int intercept_result;
530 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800531 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700532 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800533 volatile char* p = (volatile char*)malloc(GetParam());
534 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700535 });
536
537 StartIntercept(&output_fd);
538 FinishCrasher();
539 AssertDeath(SIGSEGV);
540 FinishIntercept(&intercept_result);
541
542 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
543
Mitch Phillips78f06702021-06-01 14:35:43 -0700544 std::vector<std::string> log_sources(2);
545 ConsumeFd(std::move(output_fd), &log_sources[0]);
546 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700547
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700548 // Tag dump only in tombstone, not logcat, and tagging is not used for
549 // overflow protection in the scudo secondary (guard pages are used instead).
550 if (GetParam() < 0x10000) {
551 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
552 }
553
Mitch Phillips78f06702021-06-01 14:35:43 -0700554 for (const auto& result : log_sources) {
555 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
556 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
557 std::to_string(GetParam()) + R"(-byte allocation)");
558 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
559 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700560#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800561 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700562#endif
563}
564
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800565TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800566#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700567 if (!mte_supported()) {
568 GTEST_SKIP() << "Requires MTE";
569 }
570
571 int intercept_result;
572 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800573 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700574 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800575 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700576 p[-1] = 42;
577 });
578
579 StartIntercept(&output_fd);
580 FinishCrasher();
581 AssertDeath(SIGSEGV);
582 FinishIntercept(&intercept_result);
583
584 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
585
586 std::string result;
587 ConsumeFd(std::move(output_fd), &result);
588
589 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800590 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800591 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700592 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700593 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700594 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700595#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800596 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700597#endif
598}
599
Florian Mayere6462f92024-02-28 11:12:11 -0800600__attribute__((noinline)) void mte_illegal_setjmp_helper(jmp_buf& jump_buf) {
Florian Mayer1fef1b12024-03-06 16:53:30 -0800601 // This frame is at least 8 bytes for storing and restoring the LR before the
602 // setjmp below. So this can never get an empty stack frame, even if we omit
603 // the frame pointer. So, the SP of this is always less (numerically) than the
604 // calling function frame.
Florian Mayere6462f92024-02-28 11:12:11 -0800605 setjmp(jump_buf);
606}
607
Florian Mayer92164902024-04-10 20:24:56 +0000608TEST_F(CrasherTest, DISABLED_mte_illegal_setjmp) {
Florian Mayere6462f92024-02-28 11:12:11 -0800609 // This setjmp is illegal because it jumps back into a function that already returned.
610 // Quoting man 3 setjmp:
611 // If the function which called setjmp() returns before longjmp() is
612 // called, the behavior is undefined. Some kind of subtle or
613 // unsubtle chaos is sure to result.
614 // https://man7.org/linux/man-pages/man3/longjmp.3.html
615#if defined(__aarch64__)
616 if (!mte_supported()) {
617 GTEST_SKIP() << "Requires MTE";
618 }
619
620 int intercept_result;
621 unique_fd output_fd;
622 StartProcess([&]() {
623 SetTagCheckingLevelSync();
624 jmp_buf jump_buf;
625 mte_illegal_setjmp_helper(jump_buf);
626 longjmp(jump_buf, 1);
627 });
628
629 StartIntercept(&output_fd);
630 FinishCrasher();
631 AssertDeath(SIGABRT);
632 FinishIntercept(&intercept_result);
633
634 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
635
636 std::string result;
637 ConsumeFd(std::move(output_fd), &result);
638
639 // In our test-case, we have a NEGATIVE stack adjustment, which is being
640 // interpreted as unsigned integer, and thus is "too large".
641 // TODO(fmayer): fix the error message for this
642 ASSERT_MATCH(result, R"(memtag_handle_longjmp: stack adjustment too large)");
643#else
644 GTEST_SKIP() << "Requires aarch64";
645#endif
646}
647
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800648TEST_F(CrasherTest, mte_async) {
649#if defined(__aarch64__)
650 if (!mte_supported()) {
651 GTEST_SKIP() << "Requires MTE";
652 }
653
654 int intercept_result;
655 unique_fd output_fd;
656 StartProcess([&]() {
657 SetTagCheckingLevelAsync();
658 volatile int* p = (volatile int*)malloc(16);
659 p[-1] = 42;
660 });
661
662 StartIntercept(&output_fd);
663 FinishCrasher();
664 AssertDeath(SIGSEGV);
665 FinishIntercept(&intercept_result);
666
667 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
668
669 std::string result;
670 ConsumeFd(std::move(output_fd), &result);
671
Peter Collingbourne91e816a2023-03-07 21:24:47 -0800672 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800673#else
674 GTEST_SKIP() << "Requires aarch64";
675#endif
676}
677
Peter Collingbournef8622522020-04-07 14:07:32 -0700678TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800679#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700680 if (!mte_supported()) {
681 GTEST_SKIP() << "Requires MTE";
682 }
683
Mitch Phillips78f06702021-06-01 14:35:43 -0700684 LogcatCollector logcat_collector;
685
Peter Collingbournef8622522020-04-07 14:07:32 -0700686 int intercept_result;
687 unique_fd output_fd;
688 StartProcess([]() {
689 SetTagCheckingLevelSync();
690
691 // Make two allocations with the same tag and close to one another. Check for both properties
692 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
693 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
694 // (some non-zero value << 56) apart.
695 //
696 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
697 // other.
698 std::set<uintptr_t> allocs;
699 for (int i = 0; i != 4096; ++i) {
700 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
701 auto it = allocs.insert(alloc).first;
702 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
703 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
704 }
705 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
706 *reinterpret_cast<int*>(alloc + 16) = 42;
707 }
708 }
709 });
710
711 StartIntercept(&output_fd);
712 FinishCrasher();
713 AssertDeath(SIGSEGV);
714 FinishIntercept(&intercept_result);
715
716 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
717
Mitch Phillips78f06702021-06-01 14:35:43 -0700718 std::vector<std::string> log_sources(2);
719 ConsumeFd(std::move(output_fd), &log_sources[0]);
720 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700721
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700722 // Tag dump only in the tombstone, not logcat.
723 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
724
Mitch Phillips78f06702021-06-01 14:35:43 -0700725 for (const auto& result : log_sources) {
726 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
727 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800728 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700729 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
730 // overflows), so we can't match explicitly for an underflow message.
731 ASSERT_MATCH(result,
732 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
733 // Ensure there's at least two allocation traces (one for each cause).
734 ASSERT_MATCH(
735 result,
736 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
737 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700738#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800739 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700740#endif
741}
742
Peter Collingbournecd278072020-12-21 14:08:38 -0800743#if defined(__aarch64__)
Christopher Ferris1e7b7cb2024-08-26 15:30:32 -0700744constexpr size_t kTagGranuleSize = 16;
745
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700746static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700747 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
748 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
749 size_t page_size = getpagesize();
750 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
751 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
752 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700753 return 0;
754 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700755 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
756 PROT_READ | PROT_WRITE | PROT_MTE);
757 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
758 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
759 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
760 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
761 }
762 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700763}
764#endif
765
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700766TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800767#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700768 if (!mte_supported()) {
769 GTEST_SKIP() << "Requires MTE";
770 }
771
772 int intercept_result;
773 unique_fd output_fd;
774 StartProcess([&]() {
775 SetTagCheckingLevelSync();
776 Trap(reinterpret_cast<void *>(CreateTagMapping()));
777 });
778
779 StartIntercept(&output_fd);
780 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700781 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700782 FinishIntercept(&intercept_result);
783
784 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
785
786 std::string result;
787 ConsumeFd(std::move(output_fd), &result);
788
789 ASSERT_MATCH(result, R"(memory near x0:
790.*
791.*
792 01.............0 0000000000000000 0000000000000000 ................
793 00.............0)");
794#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800795 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700796#endif
797}
798
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700799TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
800#if defined(__aarch64__)
801 if (!mte_supported()) {
802 GTEST_SKIP() << "Requires MTE";
803 }
804
805 int intercept_result;
806 unique_fd output_fd;
807 StartProcess([&]() {
808 SetTagCheckingLevelSync();
809 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
810 p[0] = 0; // Untagged pointer, tagged memory.
811 });
812
813 StartIntercept(&output_fd);
814 FinishCrasher();
815 AssertDeath(SIGSEGV);
816 FinishIntercept(&intercept_result);
817
818 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
819
820 std::string result;
821 ConsumeFd(std::move(output_fd), &result);
822
823 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
824\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
825#else
826 GTEST_SKIP() << "Requires aarch64";
827#endif
828}
829
830TEST_F(CrasherTest, mte_fault_tag_dump) {
831#if defined(__aarch64__)
832 if (!mte_supported()) {
833 GTEST_SKIP() << "Requires MTE";
834 }
835
836 int intercept_result;
837 unique_fd output_fd;
838 StartProcess([&]() {
839 SetTagCheckingLevelSync();
840 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
841 p[320] = 0; // Untagged pointer, tagged memory.
842 });
843
844 StartIntercept(&output_fd);
845 FinishCrasher();
846 AssertDeath(SIGSEGV);
847 FinishIntercept(&intercept_result);
848
849 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
850
851 std::string result;
852 ConsumeFd(std::move(output_fd), &result);
853
854 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
855\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
856\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
857\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
858)");
859#else
860 GTEST_SKIP() << "Requires aarch64";
861#endif
862}
863
864TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
865#if defined(__aarch64__)
866 if (!mte_supported()) {
867 GTEST_SKIP() << "Requires MTE";
868 }
869
870 int intercept_result;
871 unique_fd output_fd;
872 StartProcess([&]() {
873 SetTagCheckingLevelSync();
874 size_t page_size = getpagesize();
875 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
876 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
877 });
878
879 StartIntercept(&output_fd);
880 FinishCrasher();
881 AssertDeath(SIGSEGV);
882 FinishIntercept(&intercept_result);
883
884 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
885
886 std::string result;
887 ConsumeFd(std::move(output_fd), &result);
888
889 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
890 ASSERT_MATCH(result,
891 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
892\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
893
894)"); // Ensure truncation happened and there's a newline after the tag fault.
895#else
896 GTEST_SKIP() << "Requires aarch64";
897#endif
898}
899
Josh Gaocdea7502017-11-01 15:00:40 -0700900TEST_F(CrasherTest, LD_PRELOAD) {
901 int intercept_result;
902 unique_fd output_fd;
903 StartProcess([]() {
904 setenv("LD_PRELOAD", "nonexistent.so", 1);
905 *reinterpret_cast<volatile char*>(0xdead) = '1';
906 });
907
908 StartIntercept(&output_fd);
909 FinishCrasher();
910 AssertDeath(SIGSEGV);
911 FinishIntercept(&intercept_result);
912
913 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
914
915 std::string result;
916 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800917 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700918}
919
Josh Gaocbe70cb2016-10-18 18:17:52 -0700920TEST_F(CrasherTest, abort) {
921 int intercept_result;
922 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800923 StartProcess([]() {
924 abort();
925 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700926 StartIntercept(&output_fd);
927 FinishCrasher();
928 AssertDeath(SIGABRT);
929 FinishIntercept(&intercept_result);
930
931 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
932
933 std::string result;
934 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700935 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700936}
937
938TEST_F(CrasherTest, signal) {
939 int intercept_result;
940 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800941 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700942 while (true) {
943 sleep(1);
944 }
Josh Gao502cfd22017-02-17 01:39:15 -0800945 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700946 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700947 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700948 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
949
950 AssertDeath(SIGSEGV);
951 FinishIntercept(&intercept_result);
952
953 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
954
955 std::string result;
956 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700957 ASSERT_MATCH(
958 result,
959 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700960 ASSERT_MATCH(result, R"(backtrace:)");
961}
962
963TEST_F(CrasherTest, abort_message) {
964 int intercept_result;
965 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800966 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800967 // Arrived at experimentally;
968 // logd truncates at 4062.
969 // strlen("Abort message: ''") is 17.
970 // That's 4045, but we also want a NUL.
971 char buf[4045 + 1];
972 memset(buf, 'x', sizeof(buf));
973 buf[sizeof(buf) - 1] = '\0';
974 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800975 abort();
976 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700977 StartIntercept(&output_fd);
978 FinishCrasher();
979 AssertDeath(SIGABRT);
980 FinishIntercept(&intercept_result);
981
982 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
983
984 std::string result;
985 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800986 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700987}
988
Florian Mayer5fa66632024-02-07 16:42:23 -0800989static char g_crash_detail_value_changes[] = "crash_detail_value";
990static char g_crash_detail_value[] = "crash_detail_value";
991static char g_crash_detail_value2[] = "crash_detail_value2";
992
993inline crash_detail_t* _Nullable android_register_crash_detail_strs(const char* _Nonnull name,
994 const char* _Nonnull data) {
Florian Mayer920d95b2024-02-14 12:57:09 -0800995 return android_crash_detail_register(name, strlen(name), data, strlen(data));
Florian Mayer5fa66632024-02-07 16:42:23 -0800996}
997
998TEST_F(CrasherTest, crash_detail_single) {
999 int intercept_result;
1000 unique_fd output_fd;
1001 StartProcess([]() {
1002 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1003 abort();
1004 });
1005 StartIntercept(&output_fd);
1006 FinishCrasher();
1007 AssertDeath(SIGABRT);
1008 FinishIntercept(&intercept_result);
1009
1010 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1011
1012 std::string result;
1013 ConsumeFd(std::move(output_fd), &result);
1014 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1015}
1016
Florian Mayeraced3aa2024-02-13 13:44:50 -08001017TEST_F(CrasherTest, crash_detail_replace_data) {
1018 int intercept_result;
1019 unique_fd output_fd;
1020 StartProcess([]() {
1021 auto *cd = android_register_crash_detail_strs("CRASH_DETAIL_NAME", "original_data");
Florian Mayer920d95b2024-02-14 12:57:09 -08001022 android_crash_detail_replace_data(cd, "new_data", strlen("new_data"));
Florian Mayeraced3aa2024-02-13 13:44:50 -08001023 abort();
1024 });
1025 StartIntercept(&output_fd);
1026 FinishCrasher();
1027 AssertDeath(SIGABRT);
1028 FinishIntercept(&intercept_result);
1029
1030 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1031
1032 std::string result;
1033 ConsumeFd(std::move(output_fd), &result);
1034 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'new_data')");
1035 // Ensure the old one no longer shows up, i.e. that we actually replaced
1036 // it, not added a new one.
1037 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'original_data')");
1038}
1039
1040TEST_F(CrasherTest, crash_detail_replace_name) {
1041 int intercept_result;
1042 unique_fd output_fd;
1043 StartProcess([]() {
1044 auto *cd = android_register_crash_detail_strs("old_name", g_crash_detail_value);
Florian Mayer920d95b2024-02-14 12:57:09 -08001045 android_crash_detail_replace_name(cd, "new_name", strlen("new_name"));
Florian Mayeraced3aa2024-02-13 13:44:50 -08001046 abort();
1047 });
1048 StartIntercept(&output_fd);
1049 FinishCrasher();
1050 AssertDeath(SIGABRT);
1051 FinishIntercept(&intercept_result);
1052
1053 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1054
1055 std::string result;
1056 ConsumeFd(std::move(output_fd), &result);
1057 ASSERT_MATCH(result, R"(new_name: 'crash_detail_value')");
1058 // Ensure the old one no longer shows up, i.e. that we actually replaced
1059 // it, not added a new one.
1060 ASSERT_NOT_MATCH(result, R"(old_name: 'crash_detail_value')");
1061}
1062
Florian Mayer5fa66632024-02-07 16:42:23 -08001063TEST_F(CrasherTest, crash_detail_single_byte_name) {
1064 int intercept_result;
1065 unique_fd output_fd;
1066 StartProcess([]() {
1067 android_register_crash_detail_strs("CRASH_DETAIL_NAME\1", g_crash_detail_value);
1068 abort();
1069 });
1070 StartIntercept(&output_fd);
1071 FinishCrasher();
1072 AssertDeath(SIGABRT);
1073 FinishIntercept(&intercept_result);
1074
1075 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1076
1077 std::string result;
1078 ConsumeFd(std::move(output_fd), &result);
1079 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME\\1: 'crash_detail_value')");
1080}
1081
1082
1083TEST_F(CrasherTest, crash_detail_single_bytes) {
1084 int intercept_result;
1085 unique_fd output_fd;
1086 StartProcess([]() {
Florian Mayer920d95b2024-02-14 12:57:09 -08001087 android_crash_detail_register("CRASH_DETAIL_NAME", strlen("CRASH_DETAIL_NAME"), "\1",
Florian Mayer5fa66632024-02-07 16:42:23 -08001088 sizeof("\1"));
1089 abort();
1090 });
1091 StartIntercept(&output_fd);
1092 FinishCrasher();
1093 AssertDeath(SIGABRT);
1094 FinishIntercept(&intercept_result);
1095
1096 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1097
1098 std::string result;
1099 ConsumeFd(std::move(output_fd), &result);
1100 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: '\\1\\0')");
1101}
1102
1103TEST_F(CrasherTest, crash_detail_mixed) {
1104 int intercept_result;
1105 unique_fd output_fd;
1106 StartProcess([]() {
1107 const char data[] = "helloworld\1\255\3";
1108 android_register_crash_detail_strs("CRASH_DETAIL_NAME", data);
1109 abort();
1110 });
1111 StartIntercept(&output_fd);
1112 FinishCrasher();
1113 AssertDeath(SIGABRT);
1114 FinishIntercept(&intercept_result);
1115
1116 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1117
1118 std::string result;
1119 ConsumeFd(std::move(output_fd), &result);
1120 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'helloworld\\1\\255\\3')");
1121}
1122
1123TEST_F(CrasherTest, crash_detail_many) {
1124 int intercept_result;
1125 unique_fd output_fd;
1126 StartProcess([]() {
1127 for (int i = 0; i < 1000; ++i) {
1128 std::string name = "CRASH_DETAIL_NAME" + std::to_string(i);
1129 std::string value = "CRASH_DETAIL_VALUE" + std::to_string(i);
1130 auto* h = android_register_crash_detail_strs(name.data(), value.data());
Florian Mayer920d95b2024-02-14 12:57:09 -08001131 android_crash_detail_unregister(h);
Florian Mayer5fa66632024-02-07 16:42:23 -08001132 }
1133
1134 android_register_crash_detail_strs("FINAL_NAME", "FINAL_VALUE");
1135 android_register_crash_detail_strs("FINAL_NAME2", "FINAL_VALUE2");
1136 abort();
1137 });
1138 StartIntercept(&output_fd);
1139 FinishCrasher();
1140 AssertDeath(SIGABRT);
1141 FinishIntercept(&intercept_result);
1142
1143 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1144
1145 std::string result;
1146 ConsumeFd(std::move(output_fd), &result);
1147 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_NAME");
1148 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_VALUE");
1149 ASSERT_MATCH(result, R"(FINAL_NAME: 'FINAL_VALUE')");
1150 ASSERT_MATCH(result, R"(FINAL_NAME2: 'FINAL_VALUE2')");
1151}
1152
1153TEST_F(CrasherTest, crash_detail_single_changes) {
1154 int intercept_result;
1155 unique_fd output_fd;
1156 StartProcess([]() {
1157 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value_changes);
1158 g_crash_detail_value_changes[0] = 'C';
1159 abort();
1160 });
1161 StartIntercept(&output_fd);
1162 FinishCrasher();
1163 AssertDeath(SIGABRT);
1164 FinishIntercept(&intercept_result);
1165
1166 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1167
1168 std::string result;
1169 ConsumeFd(std::move(output_fd), &result);
1170 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'Crash_detail_value')");
1171}
1172
1173TEST_F(CrasherTest, crash_detail_multiple) {
1174 int intercept_result;
1175 unique_fd output_fd;
1176 StartProcess([]() {
1177 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1178 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1179 abort();
1180 });
1181 StartIntercept(&output_fd);
1182 FinishCrasher();
1183 AssertDeath(SIGABRT);
1184 FinishIntercept(&intercept_result);
1185
1186 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1187
1188 std::string result;
1189 ConsumeFd(std::move(output_fd), &result);
1190 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1191 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1192}
1193
1194TEST_F(CrasherTest, crash_detail_remove) {
1195 int intercept_result;
1196 unique_fd output_fd;
1197 StartProcess([]() {
1198 auto* detail1 = android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
Florian Mayer920d95b2024-02-14 12:57:09 -08001199 android_crash_detail_unregister(detail1);
Florian Mayer5fa66632024-02-07 16:42:23 -08001200 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1201 abort();
1202 });
1203 StartIntercept(&output_fd);
1204 FinishCrasher();
1205 AssertDeath(SIGABRT);
1206 FinishIntercept(&intercept_result);
1207
1208 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1209
1210 std::string result;
1211 ConsumeFd(std::move(output_fd), &result);
1212 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1213 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1214}
1215
Christopher Ferrise8891452021-08-17 17:34:53 -07001216TEST_F(CrasherTest, abort_message_newline_trimmed) {
1217 int intercept_result;
1218 unique_fd output_fd;
1219 StartProcess([]() {
1220 android_set_abort_message("Message with a newline.\n");
1221 abort();
1222 });
1223 StartIntercept(&output_fd);
1224 FinishCrasher();
1225 AssertDeath(SIGABRT);
1226 FinishIntercept(&intercept_result);
1227
1228 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1229
1230 std::string result;
1231 ConsumeFd(std::move(output_fd), &result);
1232 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1233}
1234
1235TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1236 int intercept_result;
1237 unique_fd output_fd;
1238 StartProcess([]() {
1239 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1240 abort();
1241 });
1242 StartIntercept(&output_fd);
1243 FinishCrasher();
1244 AssertDeath(SIGABRT);
1245 FinishIntercept(&intercept_result);
1246
1247 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1248
1249 std::string result;
1250 ConsumeFd(std::move(output_fd), &result);
1251 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1252}
1253
Josh Gaoe06f2a42017-04-27 16:50:38 -07001254TEST_F(CrasherTest, abort_message_backtrace) {
1255 int intercept_result;
1256 unique_fd output_fd;
1257 StartProcess([]() {
1258 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001259 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001260 exit(0);
1261 });
1262 StartIntercept(&output_fd);
1263 FinishCrasher();
1264 AssertDeath(0);
1265 FinishIntercept(&intercept_result);
1266
1267 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1268
1269 std::string result;
1270 ConsumeFd(std::move(output_fd), &result);
1271 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1272}
1273
Josh Gaocbe70cb2016-10-18 18:17:52 -07001274TEST_F(CrasherTest, intercept_timeout) {
1275 int intercept_result;
1276 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001277 StartProcess([]() {
1278 abort();
1279 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001280 StartIntercept(&output_fd);
1281
1282 // Don't let crasher finish until we timeout.
1283 FinishIntercept(&intercept_result);
1284
1285 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1286 << intercept_result << ")";
1287
1288 FinishCrasher();
1289 AssertDeath(SIGABRT);
1290}
1291
Elliott Hughese4781d52021-03-17 09:15:15 -07001292TEST_F(CrasherTest, wait_for_debugger) {
1293 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1294 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001295 }
1296 sleep(1);
1297
Josh Gao502cfd22017-02-17 01:39:15 -08001298 StartProcess([]() {
1299 abort();
1300 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001301 FinishCrasher();
1302
1303 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001304 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001305 ASSERT_TRUE(WIFSTOPPED(status));
1306 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1307
1308 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1309
1310 AssertDeath(SIGABRT);
1311}
1312
Josh Gaocbe70cb2016-10-18 18:17:52 -07001313TEST_F(CrasherTest, backtrace) {
1314 std::string result;
1315 int intercept_result;
1316 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001317
1318 StartProcess([]() {
1319 abort();
1320 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001321 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001322
1323 std::this_thread::sleep_for(500ms);
1324
1325 sigval val;
1326 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001327 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001328 FinishIntercept(&intercept_result);
1329 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1330 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001331 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001332
1333 int status;
1334 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1335
1336 StartIntercept(&output_fd);
1337 FinishCrasher();
1338 AssertDeath(SIGABRT);
1339 FinishIntercept(&intercept_result);
1340 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1341 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001342 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001343}
Josh Gaofca7ca32017-01-23 12:05:35 -08001344
1345TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001346 int intercept_result;
1347 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001348 StartProcess([]() {
1349 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001350 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001351 });
Josh Gao502cfd22017-02-17 01:39:15 -08001352
1353 StartIntercept(&output_fd);
1354 FinishCrasher();
1355 AssertDeath(SIGABRT);
1356 FinishIntercept(&intercept_result);
1357
1358 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1359
1360 std::string result;
1361 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001362 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001363}
1364
Josh Gao502cfd22017-02-17 01:39:15 -08001365TEST_F(CrasherTest, capabilities) {
1366 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1367
Josh Gaofca7ca32017-01-23 12:05:35 -08001368 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001369 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1370 err(1, "failed to set PR_SET_KEEPCAPS");
1371 }
1372
1373 if (setresuid(1, 1, 1) != 0) {
1374 err(1, "setresuid failed");
1375 }
1376
1377 __user_cap_header_struct capheader;
1378 __user_cap_data_struct capdata[2];
1379 memset(&capheader, 0, sizeof(capheader));
1380 memset(&capdata, 0, sizeof(capdata));
1381
1382 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1383 capheader.pid = 0;
1384
1385 // Turn on every third capability.
1386 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1387 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1388 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1389 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1390 }
1391
1392 // Make sure CAP_SYS_PTRACE is off.
1393 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1394 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1395
1396 if (capset(&capheader, &capdata[0]) != 0) {
1397 err(1, "capset failed");
1398 }
1399
1400 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1401 err(1, "failed to drop ambient capabilities");
1402 }
1403
Josh Gaoa5199a92017-04-03 13:18:34 -07001404 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001405 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001406 });
Josh Gao502cfd22017-02-17 01:39:15 -08001407
1408 unique_fd output_fd;
1409 StartIntercept(&output_fd);
1410 FinishCrasher();
1411 AssertDeath(SIGSYS);
1412
1413 std::string result;
1414 int intercept_result;
1415 FinishIntercept(&intercept_result);
1416 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1417 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001418 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001419 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001420}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001421
Josh Gao2e7b8e22017-05-04 17:12:57 -07001422TEST_F(CrasherTest, fake_pid) {
1423 int intercept_result;
1424 unique_fd output_fd;
1425
1426 // Prime the getpid/gettid caches.
1427 UNUSED(getpid());
1428 UNUSED(gettid());
1429
1430 std::function<pid_t()> clone_fn = []() {
1431 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1432 };
1433 StartProcess(
1434 []() {
1435 ASSERT_NE(getpid(), syscall(__NR_getpid));
1436 ASSERT_NE(gettid(), syscall(__NR_gettid));
1437 raise(SIGSEGV);
1438 },
1439 clone_fn);
1440
1441 StartIntercept(&output_fd);
1442 FinishCrasher();
1443 AssertDeath(SIGSEGV);
1444 FinishIntercept(&intercept_result);
1445
1446 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1447
1448 std::string result;
1449 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001450 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001451}
1452
Josh Gaoe04ca272018-01-16 15:38:17 -08001453static const char* const kDebuggerdSeccompPolicy =
1454 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1455
Mitch Phillips18ce5422023-01-19 14:23:49 -08001456static void setup_jail(minijail* jail) {
1457 if (!jail) {
1458 LOG(FATAL) << "failed to create minijail";
1459 }
1460
Josh Gao6f9eeec2018-09-12 13:55:47 -07001461 std::string policy;
1462 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1463 PLOG(FATAL) << "failed to read policy file";
1464 }
1465
1466 // Allow a bunch of syscalls used by the tests.
1467 policy += "\nclone: 1";
1468 policy += "\nsigaltstack: 1";
1469 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001470 policy += "\ngetrlimit: 1";
1471 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001472
1473 FILE* tmp_file = tmpfile();
1474 if (!tmp_file) {
1475 PLOG(FATAL) << "tmpfile failed";
1476 }
1477
Christopher Ferris172b0a02019-09-18 17:48:30 -07001478 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001479 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1480 PLOG(FATAL) << "failed to write policy to tmpfile";
1481 }
1482
1483 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1484 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001485 }
1486
Mitch Phillips18ce5422023-01-19 14:23:49 -08001487 minijail_no_new_privs(jail);
1488 minijail_log_seccomp_filter_failures(jail);
1489 minijail_use_seccomp_filter(jail);
1490 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1491}
Josh Gaoe04ca272018-01-16 15:38:17 -08001492
Mitch Phillips18ce5422023-01-19 14:23:49 -08001493static pid_t seccomp_fork_impl(void (*prejail)()) {
1494 ScopedMinijail jail{minijail_new()};
1495 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001496
1497 pid_t result = fork();
1498 if (result == -1) {
1499 return result;
1500 } else if (result != 0) {
1501 return result;
1502 }
1503
1504 // Spawn and detach a thread that spins forever.
1505 std::atomic<bool> thread_ready(false);
1506 std::thread thread([&jail, &thread_ready]() {
1507 minijail_enter(jail.get());
1508 thread_ready = true;
1509 for (;;)
1510 ;
1511 });
1512 thread.detach();
1513
1514 while (!thread_ready) {
1515 continue;
1516 }
1517
Josh Gao70adac62018-02-22 11:38:33 -08001518 if (prejail) {
1519 prejail();
1520 }
1521
Josh Gaoe04ca272018-01-16 15:38:17 -08001522 minijail_enter(jail.get());
1523 return result;
1524}
1525
Josh Gao70adac62018-02-22 11:38:33 -08001526static pid_t seccomp_fork() {
1527 return seccomp_fork_impl(nullptr);
1528}
1529
Josh Gaoe04ca272018-01-16 15:38:17 -08001530TEST_F(CrasherTest, seccomp_crash) {
1531 int intercept_result;
1532 unique_fd output_fd;
1533
1534 StartProcess([]() { abort(); }, &seccomp_fork);
1535
1536 StartIntercept(&output_fd);
1537 FinishCrasher();
1538 AssertDeath(SIGABRT);
1539 FinishIntercept(&intercept_result);
1540 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1541
1542 std::string result;
1543 ConsumeFd(std::move(output_fd), &result);
1544 ASSERT_BACKTRACE_FRAME(result, "abort");
1545}
1546
Josh Gao70adac62018-02-22 11:38:33 -08001547static pid_t seccomp_fork_rlimit() {
1548 return seccomp_fork_impl([]() {
1549 struct rlimit rlim = {
1550 .rlim_cur = 512 * 1024 * 1024,
1551 .rlim_max = 512 * 1024 * 1024,
1552 };
1553
1554 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1555 raise(SIGINT);
1556 }
1557 });
1558}
1559
1560TEST_F(CrasherTest, seccomp_crash_oom) {
1561 int intercept_result;
1562 unique_fd output_fd;
1563
1564 StartProcess(
1565 []() {
1566 std::vector<void*> vec;
1567 for (int i = 0; i < 512; ++i) {
1568 char* buf = static_cast<char*>(malloc(1024 * 1024));
1569 if (!buf) {
1570 abort();
1571 }
1572 memset(buf, 0xff, 1024 * 1024);
1573 vec.push_back(buf);
1574 }
1575 },
1576 &seccomp_fork_rlimit);
1577
1578 StartIntercept(&output_fd);
1579 FinishCrasher();
1580 AssertDeath(SIGABRT);
1581 FinishIntercept(&intercept_result);
1582 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1583
1584 // We can't actually generate a backtrace, just make sure that the process terminates.
1585}
1586
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001587__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001588 siginfo_t siginfo;
1589 siginfo.si_code = SI_QUEUE;
1590 siginfo.si_pid = getpid();
1591 siginfo.si_uid = getuid();
1592
1593 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1594 PLOG(FATAL) << "invalid dump type";
1595 }
1596
1597 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1598
Josh Gaoa48b41b2019-12-13 14:11:04 -08001599 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001600 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1601 return false;
1602 }
1603
1604 return true;
1605}
1606
Christopher Ferrisb999b822022-02-09 17:57:21 -08001607extern "C" void foo() {
1608 LOG(INFO) << "foo";
1609 std::this_thread::sleep_for(1s);
1610}
1611
1612extern "C" void bar() {
1613 LOG(INFO) << "bar";
1614 std::this_thread::sleep_for(1s);
1615}
1616
Josh Gaoe04ca272018-01-16 15:38:17 -08001617TEST_F(CrasherTest, seccomp_tombstone) {
1618 int intercept_result;
1619 unique_fd output_fd;
1620
1621 static const auto dump_type = kDebuggerdTombstone;
1622 StartProcess(
1623 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001624 std::thread a(foo);
1625 std::thread b(bar);
1626
1627 std::this_thread::sleep_for(100ms);
1628
Josh Gaoe04ca272018-01-16 15:38:17 -08001629 raise_debugger_signal(dump_type);
1630 _exit(0);
1631 },
1632 &seccomp_fork);
1633
1634 StartIntercept(&output_fd, dump_type);
1635 FinishCrasher();
1636 AssertDeath(0);
1637 FinishIntercept(&intercept_result);
1638 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1639
1640 std::string result;
1641 ConsumeFd(std::move(output_fd), &result);
1642 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001643 ASSERT_BACKTRACE_FRAME(result, "foo");
1644 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001645}
1646
Christopher Ferris303c6be2022-05-24 17:08:33 -07001647TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1648 int intercept_result;
1649 unique_fd output_fd;
1650
1651 static const auto dump_type = kDebuggerdTombstone;
1652 StartProcess(
1653 []() {
1654 std::thread abort_thread([] { abort(); });
1655 abort_thread.join();
1656 },
1657 &seccomp_fork);
1658
1659 StartIntercept(&output_fd, dump_type);
1660 FinishCrasher();
1661 AssertDeath(SIGABRT);
1662 FinishIntercept(&intercept_result);
1663 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1664
1665 std::string result;
1666 ConsumeFd(std::move(output_fd), &result);
Xiaohui Niu7bfbe412024-04-26 11:08:15 +08001667 ASSERT_MATCH(
1668 result,
1669 R"(signal 6 \(SIGABRT\))");
Christopher Ferris303c6be2022-05-24 17:08:33 -07001670 ASSERT_BACKTRACE_FRAME(result, "abort");
1671}
1672
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001673TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1674 int intercept_result;
1675 unique_fd output_fd;
1676
1677 static const auto dump_type = kDebuggerdTombstone;
1678 StartProcess(
1679 []() {
1680 std::thread a(foo);
1681 std::thread b(bar);
1682
1683 std::this_thread::sleep_for(100ms);
1684
1685 std::thread abort_thread([] { abort(); });
1686 abort_thread.join();
1687 },
1688 &seccomp_fork);
1689
1690 StartIntercept(&output_fd, dump_type);
1691 FinishCrasher();
1692 AssertDeath(SIGABRT);
1693 FinishIntercept(&intercept_result);
1694 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1695
1696 std::string result;
1697 ConsumeFd(std::move(output_fd), &result);
1698 ASSERT_BACKTRACE_FRAME(result, "abort");
1699 ASSERT_BACKTRACE_FRAME(result, "foo");
1700 ASSERT_BACKTRACE_FRAME(result, "bar");
1701 ASSERT_BACKTRACE_FRAME(result, "main");
1702}
1703
Josh Gaoe04ca272018-01-16 15:38:17 -08001704TEST_F(CrasherTest, seccomp_backtrace) {
1705 int intercept_result;
1706 unique_fd output_fd;
1707
1708 static const auto dump_type = kDebuggerdNativeBacktrace;
1709 StartProcess(
1710 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001711 std::thread a(foo);
1712 std::thread b(bar);
1713
1714 std::this_thread::sleep_for(100ms);
1715
Josh Gaoe04ca272018-01-16 15:38:17 -08001716 raise_debugger_signal(dump_type);
1717 _exit(0);
1718 },
1719 &seccomp_fork);
1720
1721 StartIntercept(&output_fd, dump_type);
1722 FinishCrasher();
1723 AssertDeath(0);
1724 FinishIntercept(&intercept_result);
1725 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1726
1727 std::string result;
1728 ConsumeFd(std::move(output_fd), &result);
1729 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001730 ASSERT_BACKTRACE_FRAME(result, "foo");
1731 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001732}
1733
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001734TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1735 int intercept_result;
1736 unique_fd output_fd;
1737
1738 static const auto dump_type = kDebuggerdNativeBacktrace;
1739 StartProcess(
1740 []() {
1741 std::thread a(foo);
1742 std::thread b(bar);
1743
1744 std::this_thread::sleep_for(100ms);
1745
1746 std::thread raise_thread([] {
1747 raise_debugger_signal(dump_type);
1748 _exit(0);
1749 });
1750 raise_thread.join();
1751 },
1752 &seccomp_fork);
1753
1754 StartIntercept(&output_fd, dump_type);
1755 FinishCrasher();
1756 AssertDeath(0);
1757 FinishIntercept(&intercept_result);
1758 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1759
1760 std::string result;
1761 ConsumeFd(std::move(output_fd), &result);
1762 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1763 ASSERT_BACKTRACE_FRAME(result, "foo");
1764 ASSERT_BACKTRACE_FRAME(result, "bar");
1765 ASSERT_BACKTRACE_FRAME(result, "main");
1766}
1767
Josh Gaoe04ca272018-01-16 15:38:17 -08001768TEST_F(CrasherTest, seccomp_crash_logcat) {
1769 StartProcess([]() { abort(); }, &seccomp_fork);
1770 FinishCrasher();
1771
1772 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1773 AssertDeath(SIGABRT);
1774}
1775
Josh Gaofd13bf02017-08-18 15:37:26 -07001776TEST_F(CrasherTest, competing_tracer) {
1777 int intercept_result;
1778 unique_fd output_fd;
1779 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001780 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001781 });
1782
1783 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001784
1785 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001786 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001787
1788 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001789 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001790 ASSERT_TRUE(WIFSTOPPED(status));
1791 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1792
1793 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1794 FinishIntercept(&intercept_result);
1795 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1796
1797 std::string result;
1798 ConsumeFd(std::move(output_fd), &result);
1799 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1800 regex += std::to_string(gettid());
1801 regex += R"( \(.+debuggerd_test)";
1802 ASSERT_MATCH(result, regex.c_str());
1803
Christopher Ferris172b0a02019-09-18 17:48:30 -07001804 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001805 ASSERT_TRUE(WIFSTOPPED(status));
1806 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1807
Josh Gaofd13bf02017-08-18 15:37:26 -07001808 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1809 AssertDeath(SIGABRT);
1810}
1811
Mitch Phillips18ce5422023-01-19 14:23:49 -08001812struct GwpAsanTestParameters {
1813 size_t alloc_size;
1814 bool free_before_access;
1815 int access_offset;
1816 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1817};
1818
1819struct GwpAsanCrasherTest
1820 : CrasherTest,
1821 testing::WithParamInterface<
1822 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1823
1824GwpAsanTestParameters gwp_asan_tests[] = {
1825 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1826 "Use After Free, 0 bytes into a 7-byte allocation"},
1827 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1828 "Use After Free, 1 byte into a 15-byte allocation"},
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07001829 {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
1830 /* access_offset */ getpagesize() + 2,
1831 android::base::StringPrintf("Buffer Overflow, 2 bytes right of a %d-byte allocation",
1832 getpagesize())},
1833 {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
1834 /* access_offset */ -1,
1835 android::base::StringPrintf("Buffer Underflow, 1 byte left of a %d-byte allocation",
1836 getpagesize())},
Mitch Phillips18ce5422023-01-19 14:23:49 -08001837};
1838
1839INSTANTIATE_TEST_SUITE_P(
1840 GwpAsanTests, GwpAsanCrasherTest,
1841 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1842 /* recoverable */ testing::Bool(),
1843 /* seccomp */ testing::Bool()),
1844 [](const testing::TestParamInfo<
1845 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1846 const GwpAsanTestParameters& params = std::get<0>(info.param);
1847 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1848 name += testing::PrintToString(params.alloc_size);
1849 name += "Alloc";
1850 if (params.access_offset < 0) {
1851 name += "Left";
1852 name += testing::PrintToString(params.access_offset * -1);
1853 } else {
1854 name += "Right";
1855 name += testing::PrintToString(params.access_offset);
1856 }
1857 name += "Bytes";
1858 if (std::get<1>(info.param)) name += "Recoverable";
1859 if (std::get<2>(info.param)) name += "Seccomp";
1860 return name;
1861 });
1862
1863TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1864 if (mte_supported()) {
1865 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1866 // instead of GWP-ASan.
1867 GTEST_SKIP() << "Skipped on MTE.";
1868 }
1869 // Skip this test on HWASan, which will reliably catch test errors as well.
1870 SKIP_WITH_HWASAN;
1871
1872 GwpAsanTestParameters params = std::get<0>(GetParam());
1873 bool recoverable = std::get<1>(GetParam());
1874 LogcatCollector logcat_collector;
1875
1876 int intercept_result;
1877 unique_fd output_fd;
1878 StartProcess([&recoverable]() {
1879 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1880 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
Mitch Phillipsa2f53352024-04-09 15:59:12 +02001881 if (!recoverable) {
1882 env[3] = "GWP_ASAN_RECOVERABLE=false";
Mitch Phillips18ce5422023-01-19 14:23:49 -08001883 }
1884 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1885 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1886 "DISABLED_run_gwp_asan_test");
1887 std::string test_filter = "--gtest_filter=*";
1888 test_filter += test_name;
1889 std::string this_binary = android::base::GetExecutablePath();
1890 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1891 test_filter.c_str(), nullptr};
1892 // We check the crash report from a debuggerd handler and from logcat. The
1893 // echo from stdout/stderr of the subprocess trips up atest, because it
1894 // doesn't like that two tests started in a row without the first one
1895 // finishing (even though the second one is in a subprocess).
1896 close(STDOUT_FILENO);
1897 close(STDERR_FILENO);
1898 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1899 });
1900
1901 StartIntercept(&output_fd);
1902 FinishCrasher();
1903 if (recoverable) {
1904 AssertDeath(0);
1905 } else {
1906 AssertDeath(SIGSEGV);
1907 }
1908 FinishIntercept(&intercept_result);
1909
1910 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1911
1912 std::vector<std::string> log_sources(2);
1913 ConsumeFd(std::move(output_fd), &log_sources[0]);
1914 logcat_collector.Collect(&log_sources[1]);
1915
1916 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1917 // information. Make sure the recovery still works, but the report won't be
1918 // hugely useful, it looks like a regular SEGV.
1919 bool seccomp = std::get<2>(GetParam());
1920 if (!seccomp) {
1921 for (const auto& result : log_sources) {
1922 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1923 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1924 if (params.free_before_access) {
1925 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1926 }
1927 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1928 }
1929 }
1930}
1931
1932TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1933 GwpAsanTestParameters params = std::get<0>(GetParam());
1934 bool seccomp = std::get<2>(GetParam());
1935 if (seccomp) {
1936 ScopedMinijail jail{minijail_new()};
1937 setup_jail(jail.get());
1938 minijail_enter(jail.get());
1939 }
1940
1941 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1942 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1943 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1944 p[params.access_offset] = 42;
1945 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001946
1947 bool recoverable = std::get<1>(GetParam());
1948 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1949
1950 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1951 // we end with at least one in a different slot), make sure the process still
1952 // doesn't crash.
1953 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1954 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1955 free(static_cast<void*>(const_cast<char*>(p)));
1956 free(static_cast<void*>(const_cast<char*>(p2)));
1957 *p = 42;
1958 *p2 = 42;
1959
1960 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1961 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1962 // coverage does. Thus, skip the atexit handlers.
1963 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001964}
1965
Josh Gaobf06a402018-08-27 16:34:01 -07001966TEST_F(CrasherTest, fdsan_warning_abort_message) {
1967 int intercept_result;
1968 unique_fd output_fd;
1969
1970 StartProcess([]() {
1971 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001972 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001973 if (fd == -1) {
1974 abort();
1975 }
1976 close(fd.get());
1977 _exit(0);
1978 });
1979
1980 StartIntercept(&output_fd);
1981 FinishCrasher();
1982 AssertDeath(0);
1983 FinishIntercept(&intercept_result);
1984 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1985
1986 std::string result;
1987 ConsumeFd(std::move(output_fd), &result);
1988 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1989}
1990
Josh Gaoc3c8c022017-02-13 16:36:18 -08001991TEST(crash_dump, zombie) {
1992 pid_t forkpid = fork();
1993
Josh Gaoc3c8c022017-02-13 16:36:18 -08001994 pid_t rc;
1995 int status;
1996
1997 if (forkpid == 0) {
1998 errno = 0;
1999 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
2000 if (rc != -1 || errno != ECHILD) {
2001 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
2002 }
2003
Josh Gaoa48b41b2019-12-13 14:11:04 -08002004 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08002005
2006 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07002007 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08002008 if (rc != -1 || errno != ECHILD) {
2009 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
2010 }
2011 _exit(0);
2012 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07002013 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08002014 ASSERT_EQ(forkpid, rc);
2015 ASSERT_TRUE(WIFEXITED(status));
2016 ASSERT_EQ(0, WEXITSTATUS(status));
2017 }
2018}
Josh Gao352a8452017-03-30 16:46:21 -07002019
2020TEST(tombstoned, no_notify) {
2021 // Do this a few times.
2022 for (int i = 0; i < 3; ++i) {
2023 pid_t pid = 123'456'789 + i;
2024
2025 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002026 InterceptResponse response = {};
2027 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2028 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2029 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002030
2031 {
2032 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01002033 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07002034 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2035 }
2036
2037 pid_t read_pid;
2038 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2039 ASSERT_EQ(read_pid, pid);
2040 }
2041}
2042
2043TEST(tombstoned, stress) {
2044 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
2045 static constexpr int kDumpCount = 100;
2046
2047 std::atomic<bool> start(false);
2048 std::vector<std::thread> threads;
2049 threads.emplace_back([&start]() {
2050 while (!start) {
2051 continue;
2052 }
2053
2054 // Use a way out of range pid, to avoid stomping on an actual process.
2055 pid_t pid_base = 1'000'000;
2056
2057 for (int dump = 0; dump < kDumpCount; ++dump) {
2058 pid_t pid = pid_base + dump;
2059
2060 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002061 InterceptResponse response = {};
2062 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2063 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2064 << "Error messeage: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002065
2066 // Pretend to crash, and then immediately close the socket.
2067 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
2068 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
2069 if (sockfd == -1) {
2070 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
2071 }
2072 TombstonedCrashPacket packet = {};
2073 packet.packet_type = CrashPacketType::kDumpRequest;
2074 packet.packet.dump_request.pid = pid;
2075 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
2076 FAIL() << "failed to write to tombstoned: " << strerror(errno);
2077 }
2078
2079 continue;
2080 }
2081 });
2082
2083 threads.emplace_back([&start]() {
2084 while (!start) {
2085 continue;
2086 }
2087
2088 // Use a way out of range pid, to avoid stomping on an actual process.
2089 pid_t pid_base = 2'000'000;
2090
2091 for (int dump = 0; dump < kDumpCount; ++dump) {
2092 pid_t pid = pid_base + dump;
2093
2094 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002095 InterceptResponse response = {};
2096 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2097 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2098 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002099
2100 {
2101 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01002102 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07002103 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2104 tombstoned_notify_completion(tombstoned_socket.get());
2105 }
2106
2107 // TODO: Fix the race that requires this sleep.
2108 std::this_thread::sleep_for(50ms);
2109
2110 pid_t read_pid;
2111 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2112 ASSERT_EQ(read_pid, pid);
2113 }
2114 });
2115
2116 start = true;
2117
2118 for (std::thread& thread : threads) {
2119 thread.join();
2120 }
2121}
Narayan Kamathca5e9082017-06-02 15:42:06 +01002122
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002123TEST(tombstoned, intercept_java_trace_smoke) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002124 // Using a "real" PID is a little dangerous here - if the test fails
2125 // or crashes, we might end up getting a bogus / unreliable stack
2126 // trace.
2127 const pid_t self = getpid();
2128
2129 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002130 InterceptResponse response = {};
2131 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2132 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2133 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002134
Josh Gao76e1e302021-01-26 15:53:11 -08002135 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01002136 // should result in a "regular" FD and not the installed intercept.
2137 const char native[] = "native";
2138 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002139 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01002140 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
2141 tombstoned_notify_completion(tombstoned_socket.get());
2142
2143 // Then, connect to tombstoned asking for a java backtrace. This *should*
2144 // trigger the intercept.
2145 const char java[] = "java";
2146 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
2147 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
2148 tombstoned_notify_completion(tombstoned_socket.get());
2149
2150 char outbuf[sizeof(java)];
2151 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2152 ASSERT_STREQ("java", outbuf);
2153}
2154
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002155TEST(tombstoned, intercept_multiple_dump_types) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002156 const pid_t fake_pid = 1'234'567;
2157 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002158 InterceptResponse response = {};
2159 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2160 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2161 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002162
2163 unique_fd intercept_fd_2, output_fd_2;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002164 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
2165 kDebuggerdNativeBacktrace);
2166 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2167 << "Error message: " << response.error_message;
2168}
2169
2170TEST(tombstoned, intercept_bad_pid) {
2171 const pid_t fake_pid = -1;
2172 unique_fd intercept_fd, output_fd;
2173 InterceptResponse response = {};
2174 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2175 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2176 << "Error message: " << response.error_message;
2177 ASSERT_MATCH(response.error_message, "bad pid");
2178}
2179
2180TEST(tombstoned, intercept_bad_dump_types) {
2181 const pid_t fake_pid = 1'234'567;
2182 unique_fd intercept_fd, output_fd;
2183 InterceptResponse response = {};
2184 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
2185 static_cast<DebuggerdDumpType>(20));
2186 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2187 << "Error message: " << response.error_message;
2188 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
2189
2190 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
2191 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2192 << "Error message: " << response.error_message;
2193 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
2194
2195 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
2196 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2197 << "Error message: " << response.error_message;
2198 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
2199}
2200
2201TEST(tombstoned, intercept_already_registered) {
2202 const pid_t fake_pid = 1'234'567;
2203 unique_fd intercept_fd1, output_fd1;
2204 InterceptResponse response = {};
2205 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
2206 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2207 << "Error message: " << response.error_message;
2208
2209 unique_fd intercept_fd2, output_fd2;
2210 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
2211 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
2212 << "Error message: " << response.error_message;
2213 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
2214}
2215
2216TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
2217 const pid_t fake_pid = 1'234'567;
2218
2219 unique_fd intercept_fd, output_fd;
2220 InterceptResponse response = {};
2221 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2222 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2223 << "Error message: " << response.error_message;
2224
2225 const char data[] = "tombstone_proto";
2226 unique_fd tombstoned_socket, input_fd;
2227 ASSERT_TRUE(
2228 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
2229 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
2230 tombstoned_notify_completion(tombstoned_socket.get());
2231
2232 char outbuf[sizeof(data)];
2233 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2234 ASSERT_STREQ("tombstone_proto", outbuf);
Narayan Kamathca5e9082017-06-02 15:42:06 +01002235}
2236
2237TEST(tombstoned, intercept_any) {
2238 const pid_t fake_pid = 1'234'567;
2239
2240 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002241 InterceptResponse response = {};
2242 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2243 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2244 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002245
2246 const char any[] = "any";
2247 unique_fd tombstoned_socket, input_fd;
2248 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2249 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
2250 tombstoned_notify_completion(tombstoned_socket.get());
2251
2252 char outbuf[sizeof(any)];
2253 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2254 ASSERT_STREQ("any", outbuf);
2255}
Josh Gao2b22ae12018-09-12 14:51:03 -07002256
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002257TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
2258 const pid_t fake_pid = 1'234'567;
2259
2260 InterceptResponse response = {};
2261 unique_fd intercept_fd1, output_fd1;
2262 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2263 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2264 << "Error message: " << response.error_message;
2265
2266 unique_fd intercept_fd2, output_fd2;
2267 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2268 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2269 << "Error message: " << response.error_message;
2270
2271 unique_fd tombstoned_socket, input_fd;
2272 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2273}
2274
2275TEST(tombstoned, intercept_multiple_verify_intercept) {
2276 // Need to use our pid for java since that will verify the pid.
2277 const pid_t fake_pid = getpid();
2278
2279 InterceptResponse response = {};
2280 unique_fd intercept_fd1, output_fd1;
2281 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2282 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2283 << "Error message: " << response.error_message;
2284
2285 unique_fd intercept_fd2, output_fd2;
2286 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2287 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2288 << "Error message: " << response.error_message;
2289
2290 unique_fd intercept_fd3, output_fd3;
2291 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2292 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2293 << "Error message: " << response.error_message;
2294
2295 const char native_data[] = "native";
2296 unique_fd tombstoned_socket1, input_fd1;
2297 ASSERT_TRUE(
2298 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2299 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2300 tombstoned_notify_completion(tombstoned_socket1.get());
2301
2302 char native_outbuf[sizeof(native_data)];
2303 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2304 ASSERT_STREQ("native", native_outbuf);
2305
2306 const char java_data[] = "java";
2307 unique_fd tombstoned_socket2, input_fd2;
2308 ASSERT_TRUE(
2309 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2310 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2311 tombstoned_notify_completion(tombstoned_socket2.get());
2312
2313 char java_outbuf[sizeof(java_data)];
2314 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2315 ASSERT_STREQ("java", java_outbuf);
2316
2317 const char tomb_data[] = "tombstone";
2318 unique_fd tombstoned_socket3, input_fd3;
2319 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2320 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2321 tombstoned_notify_completion(tombstoned_socket3.get());
2322
2323 char tomb_outbuf[sizeof(tomb_data)];
2324 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2325 ASSERT_STREQ("tombstone", tomb_outbuf);
2326}
2327
Josh Gao2b22ae12018-09-12 14:51:03 -07002328TEST(tombstoned, interceptless_backtrace) {
2329 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2330 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2331 std::map<int, time_t> result;
2332 for (int i = 0; i < 99; ++i) {
2333 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2334 struct stat st;
2335 if (stat(path.c_str(), &st) == 0) {
2336 result[i] = st.st_mtim.tv_sec;
2337 }
2338 }
2339 return result;
2340 };
2341
2342 auto before = get_tombstone_timestamps();
2343 for (int i = 0; i < 50; ++i) {
2344 raise_debugger_signal(kDebuggerdNativeBacktrace);
2345 }
2346 auto after = get_tombstone_timestamps();
2347
2348 int diff = 0;
2349 for (int i = 0; i < 99; ++i) {
2350 if (after.count(i) == 0) {
2351 continue;
2352 }
2353 if (before.count(i) == 0) {
2354 ++diff;
2355 continue;
2356 }
2357 if (before[i] != after[i]) {
2358 ++diff;
2359 }
2360 }
2361
2362 // We can't be sure that nothing's crash looping in the background.
2363 // This should be good enough, though...
2364 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2365}
Christopher Ferris481e8372019-07-15 17:13:24 -07002366
2367static __attribute__((__noinline__)) void overflow_stack(void* p) {
2368 void* buf[1];
2369 buf[0] = p;
2370 static volatile void* global = buf;
2371 if (global) {
2372 global = buf;
2373 overflow_stack(&buf);
2374 }
2375}
2376
2377TEST_F(CrasherTest, stack_overflow) {
2378 int intercept_result;
2379 unique_fd output_fd;
2380 StartProcess([]() { overflow_stack(nullptr); });
2381
2382 StartIntercept(&output_fd);
2383 FinishCrasher();
2384 AssertDeath(SIGSEGV);
2385 FinishIntercept(&intercept_result);
2386
2387 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2388
2389 std::string result;
2390 ConsumeFd(std::move(output_fd), &result);
2391 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2392}
Josh Gao76e1e302021-01-26 15:53:11 -08002393
Christopher Ferris22035cc2023-01-31 17:50:22 -08002394static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002395 std::string test_lib(testing::internal::GetArgvs()[0]);
2396 auto const value = test_lib.find_last_of('/');
2397 if (value == std::string::npos) {
2398 test_lib = "./";
2399 } else {
2400 test_lib = test_lib.substr(0, value + 1) + "./";
2401 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08002402 return test_lib + "libcrash_test.so";
2403}
2404
2405static void CreateEmbeddedLibrary(int out_fd) {
2406 std::string test_lib(GetTestLibraryPath());
2407 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2408 ASSERT_NE(fd.get(), -1);
2409 off_t file_size = lseek(fd, 0, SEEK_END);
2410 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2411 std::vector<uint8_t> contents(file_size);
2412 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2413
2414 // Put the shared library data at a pagesize() offset.
2415 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2416 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2417}
2418
2419TEST_F(CrasherTest, non_zero_offset_in_library) {
2420 int intercept_result;
2421 unique_fd output_fd;
2422 TemporaryFile tf;
2423 CreateEmbeddedLibrary(tf.fd);
2424 StartProcess([&tf]() {
2425 android_dlextinfo extinfo{};
2426 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2427 extinfo.library_fd = tf.fd;
2428 extinfo.library_fd_offset = 4 * getpagesize();
2429 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2430 if (handle == nullptr) {
2431 _exit(1);
2432 }
2433 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2434 if (crash_func == nullptr) {
2435 _exit(1);
2436 }
2437 crash_func();
2438 });
2439
2440 StartIntercept(&output_fd);
2441 FinishCrasher();
2442 AssertDeath(SIGSEGV);
2443 FinishIntercept(&intercept_result);
2444
2445 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2446
2447 std::string result;
2448 ConsumeFd(std::move(output_fd), &result);
2449
2450 // Verify the crash includes an offset value in the backtrace.
2451 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2452 tf.path, 4 * getpagesize());
2453 ASSERT_MATCH(result, match_str);
2454}
2455
2456static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2457 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002458
2459 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2460 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2461
2462 // Copy the shared so to a tempory directory.
2463 return system(cp_cmd.c_str()) == 0;
2464}
2465
2466TEST_F(CrasherTest, unreadable_elf) {
2467 int intercept_result;
2468 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002469 std::string tmp_so_name;
2470 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002471 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002472 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2473 _exit(1);
2474 }
2475 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2476 if (handle == nullptr) {
2477 _exit(1);
2478 }
2479 // Delete the original shared library so that we get the warning
2480 // about unreadable elf files.
2481 if (unlink(tmp_so_name.c_str()) == -1) {
2482 _exit(1);
2483 }
2484 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2485 if (crash_func == nullptr) {
2486 _exit(1);
2487 }
2488 crash_func();
2489 });
2490
2491 StartIntercept(&output_fd);
2492 FinishCrasher();
2493 AssertDeath(SIGSEGV);
2494 FinishIntercept(&intercept_result);
2495
2496 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2497
2498 std::string result;
2499 ConsumeFd(std::move(output_fd), &result);
2500 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002501 std::string match_str = "NOTE: " + tmp_so_name;
2502 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002503}
2504
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002505void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
2506 static std::regex tombstone_re("tombstone_\\d+");
Christopher Ferris35da2882021-02-17 15:39:06 -08002507 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2508 ASSERT_TRUE(dir_h != nullptr);
Christopher Ferris35da2882021-02-17 15:39:06 -08002509 dirent* entry;
2510 while ((entry = readdir(dir_h.get())) != nullptr) {
2511 if (!std::regex_match(entry->d_name, tombstone_re)) {
2512 continue;
2513 }
2514 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002515
2516 struct stat st;
2517 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2518 continue;
2519 }
2520
2521 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002522 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002523 break;
2524 }
2525 }
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002526}
Josh Gao76e1e302021-01-26 15:53:11 -08002527
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002528TEST(tombstoned, proto) {
2529 const pid_t self = getpid();
2530 unique_fd tombstoned_socket, text_fd, proto_fd;
2531 ASSERT_TRUE(
2532 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2533
2534 tombstoned_notify_completion(tombstoned_socket.get());
2535
2536 ASSERT_NE(-1, text_fd.get());
2537 ASSERT_NE(-1, proto_fd.get());
2538
2539 struct stat text_st;
2540 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2541
2542 std::optional<std::string> tombstone_file;
2543 // Allow up to 5 seconds for the tombstone to be written to the system.
2544 const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
2545 const auto start = std::chrono::high_resolution_clock::now();
2546 while (true) {
2547 std::this_thread::sleep_for(100ms);
2548 CheckForTombstone(text_st, tombstone_file);
2549 if (tombstone_file) {
2550 break;
2551 }
2552 if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
2553 break;
2554 }
2555 }
2556
2557 ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
Christopher Ferris35da2882021-02-17 15:39:06 -08002558 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002559
2560 struct stat proto_fd_st;
2561 struct stat proto_file_st;
2562 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2563 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2564
2565 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2566 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2567}
2568
2569TEST(tombstoned, proto_intercept) {
2570 const pid_t self = getpid();
2571 unique_fd intercept_fd, output_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002572
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002573 InterceptResponse response = {};
2574 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2575 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2576 << "Error message: " << response.error_message;
Josh Gao76e1e302021-01-26 15:53:11 -08002577
2578 unique_fd tombstoned_socket, text_fd, proto_fd;
2579 ASSERT_TRUE(
2580 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2581 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2582 tombstoned_notify_completion(tombstoned_socket.get());
2583
2584 text_fd.reset();
2585
2586 std::string output;
2587 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2588 ASSERT_EQ("foo", output);
2589}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002590
2591// Verify that when an intercept is present for the main thread, and the signal
2592// is received on a different thread, the intercept still works.
2593TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2594 StartProcess([]() {
2595 std::thread thread([]() {
2596 // Raise the signal on the side thread.
2597 raise_debugger_signal(kDebuggerdNativeBacktrace);
2598 });
2599 thread.join();
2600 _exit(0);
2601 });
2602
2603 unique_fd output_fd;
2604 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2605 FinishCrasher();
2606 AssertDeath(0);
2607
2608 int intercept_result;
2609 FinishIntercept(&intercept_result);
2610 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2611
2612 std::string result;
2613 ConsumeFd(std::move(output_fd), &result);
2614 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2615}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002616
2617static std::string format_pointer(uintptr_t ptr) {
2618#if defined(__LP64__)
2619 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2620 static_cast<uint32_t>(ptr & 0xffffffff));
2621#else
2622 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2623#endif
2624}
2625
2626static std::string format_pointer(void* ptr) {
2627 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2628}
2629
2630static std::string format_full_pointer(uintptr_t ptr) {
2631#if defined(__LP64__)
2632 return android::base::StringPrintf("%016" PRIx64, ptr);
2633#else
2634 return android::base::StringPrintf("%08x", ptr);
2635#endif
2636}
2637
2638static std::string format_full_pointer(void* ptr) {
2639 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2640}
2641
2642__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2643 int* crash_ptr = reinterpret_cast<int*>(ptr);
2644 *crash_ptr = 1;
2645 return *crash_ptr;
2646}
2647
2648// Verify that a fault address before the first map is properly handled.
2649TEST_F(CrasherTest, fault_address_before_first_map) {
2650 StartProcess([]() {
2651 ASSERT_EQ(0, crash_call(0x1024));
2652 _exit(0);
2653 });
2654
2655 unique_fd output_fd;
2656 StartIntercept(&output_fd);
2657 FinishCrasher();
2658 AssertDeath(SIGSEGV);
2659
2660 int intercept_result;
2661 FinishIntercept(&intercept_result);
2662 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2663
2664 std::string result;
2665 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002666 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002667
2668 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2669
2670 std::string match_str = android::base::StringPrintf(
2671 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2672 format_pointer(0x1024).c_str());
2673 ASSERT_MATCH(result, match_str);
2674}
2675
2676// Verify that a fault address after the last map is properly handled.
2677TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002678 // This makes assumptions about the memory layout that are not true in HWASan
2679 // processes.
2680 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002681 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2682 StartProcess([crash_uptr]() {
2683 ASSERT_EQ(0, crash_call(crash_uptr));
2684 _exit(0);
2685 });
2686
2687 unique_fd output_fd;
2688 StartIntercept(&output_fd);
2689 FinishCrasher();
2690 AssertDeath(SIGSEGV);
2691
2692 int intercept_result;
2693 FinishIntercept(&intercept_result);
2694 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2695
2696 std::string result;
2697 ConsumeFd(std::move(output_fd), &result);
2698
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002699 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2700 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002701 ASSERT_MATCH(result, match_str);
2702
Ryan Prichardbc227032024-02-29 14:40:57 -08002703 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002704
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002705 // Verifies that the fault address error message is at the end of the
2706 // maps section. To do this, the check below looks for the start of the
2707 // open files section or the start of the log file section. It's possible
2708 // for either of these sections to be present after the maps section right
2709 // now.
2710 // If the sections move around, this check might need to be modified.
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002711 match_str = android::base::StringPrintf(
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002712 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002713 format_pointer(crash_uptr).c_str());
2714 ASSERT_MATCH(result, match_str);
2715}
2716
2717// Verify that a fault address between maps is properly handled.
2718TEST_F(CrasherTest, fault_address_between_maps) {
2719 // Create a map before the fork so it will be present in the child.
2720 void* start_ptr =
2721 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2722 ASSERT_NE(MAP_FAILED, start_ptr);
2723 // Unmap the page in the middle.
2724 void* middle_ptr =
2725 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2726 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2727
2728 StartProcess([middle_ptr]() {
2729 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2730 _exit(0);
2731 });
2732
2733 // Unmap the two maps.
2734 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2735 void* end_ptr =
2736 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2737 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2738
2739 unique_fd output_fd;
2740 StartIntercept(&output_fd);
2741 FinishCrasher();
2742 AssertDeath(SIGSEGV);
2743
2744 int intercept_result;
2745 FinishIntercept(&intercept_result);
2746 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2747
2748 std::string result;
2749 ConsumeFd(std::move(output_fd), &result);
2750
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002751 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2752 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002753 ASSERT_MATCH(result, match_str);
2754
Ryan Prichardbc227032024-02-29 14:40:57 -08002755 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002756
2757 match_str = android::base::StringPrintf(
2758 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2759 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2760 format_pointer(end_ptr).c_str());
2761 ASSERT_MATCH(result, match_str);
2762}
2763
2764// Verify that a fault address happens in the correct map.
2765TEST_F(CrasherTest, fault_address_in_map) {
2766 // Create a map before the fork so it will be present in the child.
2767 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2768 ASSERT_NE(MAP_FAILED, ptr);
2769
2770 StartProcess([ptr]() {
2771 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2772 _exit(0);
2773 });
2774
2775 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2776
2777 unique_fd output_fd;
2778 StartIntercept(&output_fd);
2779 FinishCrasher();
2780 AssertDeath(SIGSEGV);
2781
2782 int intercept_result;
2783 FinishIntercept(&intercept_result);
2784 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2785
2786 std::string result;
2787 ConsumeFd(std::move(output_fd), &result);
2788
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002789 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2790 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002791 ASSERT_MATCH(result, match_str);
2792
Ryan Prichardbc227032024-02-29 14:40:57 -08002793 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002794
2795 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2796 ASSERT_MATCH(result, match_str);
2797}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002798
2799static constexpr uint32_t kDexData[] = {
2800 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2801 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2802 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2803 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2804 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2805 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2806 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2807 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2808 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2809 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2810 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2811 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2812 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2813 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2814 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2815 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2816 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2817};
2818
2819TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2820 StartProcess([]() {
2821 TemporaryDir td;
2822 std::string tmp_so_name;
2823 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2824 _exit(1);
2825 }
2826
2827 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2828 // move the library to which has a basename of libart.so.
2829 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2830 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2831 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2832 if (handle == nullptr) {
2833 _exit(1);
2834 }
2835
2836 void* ptr =
2837 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2838 ASSERT_TRUE(ptr != MAP_FAILED);
2839 memcpy(ptr, kDexData, sizeof(kDexData));
2840 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2841
2842 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2843 .symfile_size = sizeof(kDexData)};
2844
2845 JITDescriptor* dex_debug =
2846 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2847 ASSERT_TRUE(dex_debug != nullptr);
2848 dex_debug->version = 1;
2849 dex_debug->action_flag = 0;
2850 dex_debug->relevant_entry = 0;
2851 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2852
2853 // This sets the magic dex pc value for register 0, using the value
2854 // of register 1 + 0x102.
2855 asm(".cfi_escape "
2856 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2857 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2858 "0x13 /* DW_OP_drop */,"
2859 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2860
2861 // For each different architecture, set register one to the dex ptr mmap
2862 // created above. Then do a nullptr dereference to force a crash.
2863#if defined(__arm__)
2864 asm volatile(
2865 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002866 "mov r2, #0\n"
2867 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002868 : [base] "+r"(ptr)
2869 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002870 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002871#elif defined(__aarch64__)
2872 asm volatile(
2873 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002874 "mov x2, #0\n"
2875 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002876 : [base] "+r"(ptr)
2877 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002878 : "x1", "x2", "memory");
2879#elif defined(__riscv)
2880 // TODO: x1 is ra (the link register) on riscv64, so this might have
2881 // unintended consequences, but we'll need to change the .cfi_escape if so.
2882 asm volatile(
2883 "mv x1, %[base]\n"
2884 "sw zero, 0(zero)\n"
2885 : [base] "+r"(ptr)
2886 :
2887 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002888#elif defined(__i386__)
2889 asm volatile(
2890 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002891 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002892 : [base] "+r"(ptr)
2893 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002894 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002895#elif defined(__x86_64__)
2896 asm volatile(
2897 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002898 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002899 : [base] "+r"(ptr)
2900 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002901 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002902#else
2903#error "Unsupported architecture"
2904#endif
2905 _exit(0);
2906 });
2907
2908 unique_fd output_fd;
2909 StartIntercept(&output_fd);
2910 FinishCrasher();
2911 AssertDeath(SIGSEGV);
2912
2913 int intercept_result;
2914 FinishIntercept(&intercept_result);
2915 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2916
2917 std::string result;
2918 ConsumeFd(std::move(output_fd), &result);
2919
2920 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002921 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002922
2923 // Now verify that the dex_pc frame includes a proper function name.
2924 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2925}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002926
2927static std::string format_map_pointer(uintptr_t ptr) {
2928#if defined(__LP64__)
2929 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2930 static_cast<uint32_t>(ptr & 0xffffffff));
2931#else
2932 return android::base::StringPrintf("%08x", ptr);
2933#endif
2934}
2935
2936// Verify that map data is properly formatted.
2937TEST_F(CrasherTest, verify_map_format) {
2938 // Create multiple maps to make sure that the map data is formatted properly.
2939 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2940 ASSERT_NE(MAP_FAILED, none_map);
2941 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2942 ASSERT_NE(MAP_FAILED, r_map);
2943 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2944 ASSERT_NE(MAP_FAILED, w_map);
2945 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2946 ASSERT_NE(MAP_FAILED, x_map);
2947
2948 TemporaryFile tf;
2949 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2950 char c = 'f';
2951 ASSERT_EQ(1, write(tf.fd, &c, 1));
2952 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2953 ASSERT_EQ(1, write(tf.fd, &c, 1));
2954 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2955 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2956 ASSERT_NE(MAP_FAILED, file_map);
2957
2958 StartProcess([]() { abort(); });
2959
2960 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2961 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2962 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2963 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2964 ASSERT_EQ(0, munmap(file_map, 0x3001));
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;
2979 // Verify none.
2980 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07002981 " %s-%s --- 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002982 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07002983 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str(),
2984 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002985 ASSERT_MATCH(result, match_str);
2986
2987 // Verify read-only.
2988 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07002989 " %s-%s r-- 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002990 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07002991 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str(),
2992 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002993 ASSERT_MATCH(result, match_str);
2994
2995 // Verify write-only.
2996 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07002997 " %s-%s -w- 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002998 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07002999 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str(),
3000 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003001 ASSERT_MATCH(result, match_str);
3002
3003 // Verify exec-only.
3004 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003005 " %s-%s --x 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003006 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003007 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str(),
3008 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003009 ASSERT_MATCH(result, match_str);
3010
3011 // Verify file map with non-zero offset and a name.
3012 match_str = android::base::StringPrintf(
3013 " %s-%s r-- 2000 4000 %s\\n",
3014 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
3015 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
3016 ASSERT_MATCH(result, match_str);
3017}
3018
3019// Verify that the tombstone map data is correct.
3020TEST_F(CrasherTest, verify_header) {
3021 StartProcess([]() { abort(); });
3022
3023 unique_fd output_fd;
3024 StartIntercept(&output_fd);
3025 FinishCrasher();
3026 AssertDeath(SIGABRT);
3027 int intercept_result;
3028 FinishIntercept(&intercept_result);
3029
3030 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3031
3032 std::string result;
3033 ConsumeFd(std::move(output_fd), &result);
3034
3035 std::string match_str = android::base::StringPrintf(
3036 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
3037 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
3038 android::base::GetProperty("ro.revision", "unknown").c_str());
3039 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
3040 ASSERT_MATCH(result, match_str);
3041}
3042
3043// Verify that the thread header is formatted properly.
3044TEST_F(CrasherTest, verify_thread_header) {
3045 void* shared_map =
3046 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
3047 ASSERT_NE(MAP_FAILED, shared_map);
3048 memset(shared_map, 0, sizeof(pid_t));
3049
3050 StartProcess([&shared_map]() {
3051 std::atomic_bool tid_written;
3052 std::thread thread([&tid_written, &shared_map]() {
3053 pid_t tid = gettid();
3054 memcpy(shared_map, &tid, sizeof(pid_t));
3055 tid_written = true;
3056 volatile bool done = false;
3057 while (!done)
3058 ;
3059 });
3060 thread.detach();
3061 while (!tid_written.load(std::memory_order_acquire))
3062 ;
3063 abort();
3064 });
3065
3066 pid_t primary_pid = crasher_pid;
3067
3068 unique_fd output_fd;
3069 StartIntercept(&output_fd);
3070 FinishCrasher();
3071 AssertDeath(SIGABRT);
3072 int intercept_result;
3073 FinishIntercept(&intercept_result);
3074 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3075
3076 // Read the tid data out.
3077 pid_t tid;
3078 memcpy(&tid, shared_map, sizeof(pid_t));
3079 ASSERT_NE(0, tid);
3080
3081 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
3082
3083 std::string result;
3084 ConsumeFd(std::move(output_fd), &result);
3085
3086 // Verify that there are two headers, one where the tid is "primary_pid"
3087 // and the other where the tid is "tid".
3088 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
3089 primary_pid, primary_pid);
3090 ASSERT_MATCH(result, match_str);
3091
3092 match_str =
3093 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
3094 ASSERT_MATCH(result, match_str);
3095}
3096
3097// Verify that there is a BuildID present in the map section and set properly.
3098TEST_F(CrasherTest, verify_build_id) {
3099 StartProcess([]() { abort(); });
3100
3101 unique_fd output_fd;
3102 StartIntercept(&output_fd);
3103 FinishCrasher();
3104 AssertDeath(SIGABRT);
3105 int intercept_result;
3106 FinishIntercept(&intercept_result);
3107 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3108
3109 std::string result;
3110 ConsumeFd(std::move(output_fd), &result);
3111
3112 // Find every /system or /apex lib and verify the BuildID is displayed
3113 // properly.
3114 bool found_valid_elf = false;
3115 std::smatch match;
3116 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
3117 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
3118 result = match.suffix()) {
3119 if (prev_file == match[1]) {
3120 // Already checked this file.
3121 continue;
3122 }
3123
3124 prev_file = match[1];
Christopher Ferris15038902023-11-10 00:05:49 -08003125 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
3126 unwindstack::Elf elf(elf_memory);
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003127 if (!elf.Init() || !elf.valid()) {
3128 // Skipping invalid elf files.
3129 continue;
3130 }
3131 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
3132
3133 found_valid_elf = true;
3134 }
3135 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
3136}
Christopher Ferrisbda10642023-04-24 18:14:53 -07003137
3138const char kLogMessage[] = "Should not see this log message.";
3139
3140// Verify that the logd process does not read the log.
3141TEST_F(CrasherTest, logd_skips_reading_logs) {
3142 StartProcess([]() {
3143 pthread_setname_np(pthread_self(), "logd");
3144 LOG(INFO) << kLogMessage;
3145 abort();
3146 });
3147
3148 unique_fd output_fd;
3149 StartIntercept(&output_fd);
3150 FinishCrasher();
3151 AssertDeath(SIGABRT);
3152 int intercept_result;
3153 FinishIntercept(&intercept_result);
3154 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3155
3156 std::string result;
3157 ConsumeFd(std::move(output_fd), &result);
3158 // logd should not contain our log message.
3159 ASSERT_NOT_MATCH(result, kLogMessage);
3160}
3161
3162// Verify that the logd process does not read the log when the non-main
3163// thread crashes.
3164TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
3165 StartProcess([]() {
3166 pthread_setname_np(pthread_self(), "logd");
3167 LOG(INFO) << kLogMessage;
3168
3169 std::thread thread([]() {
3170 pthread_setname_np(pthread_self(), "not_logd_thread");
3171 // Raise the signal on the side thread.
3172 raise_debugger_signal(kDebuggerdTombstone);
3173 });
3174 thread.join();
3175 _exit(0);
3176 });
3177
3178 unique_fd output_fd;
3179 StartIntercept(&output_fd, kDebuggerdTombstone);
3180 FinishCrasher();
3181 AssertDeath(0);
3182
3183 int intercept_result;
3184 FinishIntercept(&intercept_result);
3185 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3186
3187 std::string result;
3188 ConsumeFd(std::move(output_fd), &result);
3189 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
3190 ASSERT_NOT_MATCH(result, kLogMessage);
3191}
Christopher Ferris98d62422023-05-24 20:01:10 +00003192
3193// Disable this test since there is a high liklihood that this would
3194// be flaky since it requires 500 messages being in the log.
3195TEST_F(CrasherTest, DISABLED_max_log_messages) {
3196 StartProcess([]() {
3197 for (size_t i = 0; i < 600; i++) {
3198 LOG(INFO) << "Message number " << i;
3199 }
3200 abort();
3201 });
3202
3203 unique_fd output_fd;
3204 StartIntercept(&output_fd);
3205 FinishCrasher();
3206 AssertDeath(SIGABRT);
3207 int intercept_result;
3208 FinishIntercept(&intercept_result);
3209 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3210
3211 std::string result;
3212 ConsumeFd(std::move(output_fd), &result);
3213 ASSERT_NOT_MATCH(result, "Message number 99");
3214 ASSERT_MATCH(result, "Message number 100");
3215 ASSERT_MATCH(result, "Message number 599");
3216}
3217
3218TEST_F(CrasherTest, log_with_newline) {
3219 StartProcess([]() {
3220 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
3221 abort();
3222 });
3223
3224 unique_fd output_fd;
3225 StartIntercept(&output_fd);
3226 FinishCrasher();
3227 AssertDeath(SIGABRT);
3228 int intercept_result;
3229 FinishIntercept(&intercept_result);
3230 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3231
3232 std::string result;
3233 ConsumeFd(std::move(output_fd), &result);
3234 ASSERT_MATCH(result, ":\\s*This line has a newline.");
3235 ASSERT_MATCH(result, ":\\s*This is on the next line.");
3236}