blob: 13c8d70b50410a642f4dd5d6c05a28505fec5314 [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"
Peter Collingbourne39a17302024-03-07 17:50:10 -080073#include "libdebuggerd/utility_host.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010074#include "protocol.h"
75#include "tombstoned/tombstoned.h"
76#include "util.h"
77
Josh Gaocbe70cb2016-10-18 18:17:52 -070078using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080079
80using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070081using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070082using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070083
84#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070085#define ARCH_SUFFIX "64"
86#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070087#define ARCH_SUFFIX ""
88#endif
89
Elliott Hughese4781d52021-03-17 09:15:15 -070090constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070091
92#define TIMEOUT(seconds, expr) \
93 [&]() { \
94 struct sigaction old_sigaction; \
95 struct sigaction new_sigaction = {}; \
96 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080097 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070098 err(1, "sigaction failed"); \
99 } \
Mattias Simonsson38ab0452023-11-08 12:02:46 +0000100 alarm(seconds * android::base::HwTimeoutMultiplier()); \
Josh Gaocbe70cb2016-10-18 18:17:52 -0700101 auto value = expr; \
102 int saved_errno = errno; \
103 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
104 err(1, "sigaction failed"); \
105 } \
106 alarm(0); \
107 errno = saved_errno; \
108 return value; \
109 }()
110
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700111// Backtrace frame dump could contain:
112// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
113// or
114// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800115#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700116 ASSERT_MATCH(result, \
117 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900118
Narayan Kamatha73df602017-05-24 15:07:25 +0100119static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700120 InterceptResponse* response, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700121 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
122 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
123 if (intercept_fd->get() == -1) {
124 FAIL() << "failed to contact tombstoned: " << strerror(errno);
125 }
126
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700127 InterceptRequest req = {
128 .dump_type = intercept_type,
129 .pid = target_pid,
130 };
Josh Gao460b3362017-03-30 16:40:47 -0700131
132 unique_fd output_pipe_write;
133 if (!Pipe(output_fd, &output_pipe_write)) {
134 FAIL() << "failed to create output pipe: " << strerror(errno);
135 }
136
137 std::string pipe_size_str;
138 int pipe_buffer_size;
139 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
140 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
141 }
142
143 pipe_size_str = android::base::Trim(pipe_size_str);
144
145 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
146 FAIL() << "failed to parse pipe max size";
147 }
148
149 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
150 FAIL() << "failed to set pipe size: " << strerror(errno);
151 }
152
Josh Gao5675f3c2017-06-01 12:19:53 -0700153 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
154
Josh Gao5f87bbd2019-01-09 17:01:49 -0800155 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
156 output_pipe_write.reset();
157 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700158 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
159 }
160
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700161 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), response, sizeof(*response)));
Josh Gao460b3362017-03-30 16:40:47 -0700162 if (rc == -1) {
163 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
164 } else if (rc == 0) {
165 FAIL() << "failed to read response from tombstoned (EOF)";
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700166 } else if (rc != sizeof(*response)) {
167 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(*response)
Josh Gao460b3362017-03-30 16:40:47 -0700168 << ", received " << rc;
169 }
Josh Gao460b3362017-03-30 16:40:47 -0700170}
171
Elliott Hughesd13ea522022-01-13 09:20:26 -0800172static bool pac_supported() {
173#if defined(__aarch64__)
174 return getauxval(AT_HWCAP) & HWCAP_PACA;
175#else
176 return false;
177#endif
178}
179
Josh Gaocbe70cb2016-10-18 18:17:52 -0700180class CrasherTest : public ::testing::Test {
181 public:
182 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700183 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700184 unique_fd crasher_pipe;
185 unique_fd intercept_fd;
186
187 CrasherTest();
188 ~CrasherTest();
189
Narayan Kamatha73df602017-05-24 15:07:25 +0100190 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700191
192 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
193 void FinishIntercept(int* result);
194
Josh Gao2e7b8e22017-05-04 17:12:57 -0700195 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700196 void StartCrasher(const std::string& crash_type);
197 void FinishCrasher();
198 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700199
200 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700201};
202
203CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700204 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
205 android::base::SetProperty(kWaitForDebuggerKey, "0");
206
207 // Clear the old property too, just in case someone's been using it
208 // on this device. (We only document the new name, but we still support
209 // the old name so we don't break anyone's existing setups.)
210 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700211}
212
213CrasherTest::~CrasherTest() {
214 if (crasher_pid != -1) {
215 kill(crasher_pid, SIGKILL);
216 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700217 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700218 }
219
Elliott Hughese4781d52021-03-17 09:15:15 -0700220 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221}
222
Narayan Kamatha73df602017-05-24 15:07:25 +0100223void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700224 if (crasher_pid == -1) {
225 FAIL() << "crasher hasn't been started";
226 }
227
Christopher Ferrisb92b52c2023-10-16 19:14:28 -0700228 InterceptResponse response = {};
229 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &response, intercept_type);
230 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
231 << "Error message: " << response.error_message;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700232}
233
234void CrasherTest::FinishIntercept(int* result) {
235 InterceptResponse response;
236
Christopher Ferris11555f02019-09-20 14:18:55 -0700237 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700238 if (rc == -1) {
239 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
240 } else if (rc == 0) {
241 *result = -1;
242 } else if (rc != sizeof(response)) {
243 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
244 << ", received " << rc;
245 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700246 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700247 }
248}
249
Josh Gao2e7b8e22017-05-04 17:12:57 -0700250void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800251 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700252 unique_fd crasher_read_pipe;
253 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
254 FAIL() << "failed to create pipe: " << strerror(errno);
255 }
256
Josh Gao2e7b8e22017-05-04 17:12:57 -0700257 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700258 if (crasher_pid == -1) {
259 FAIL() << "fork failed: " << strerror(errno);
260 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800261 char dummy;
262 crasher_pipe.reset();
263 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800264 function();
265 _exit(0);
266 }
267}
268
Josh Gaocbe70cb2016-10-18 18:17:52 -0700269void CrasherTest::FinishCrasher() {
270 if (crasher_pipe == -1) {
271 FAIL() << "crasher pipe uninitialized";
272 }
273
Christopher Ferris172b0a02019-09-18 17:48:30 -0700274 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700275 if (rc == -1) {
276 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
277 } else if (rc == 0) {
278 FAIL() << "crasher pipe was closed";
279 }
280}
281
282void CrasherTest::AssertDeath(int signo) {
283 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700284 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700285 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700286 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
287 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700288 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700289 FAIL() << "failed to wait for crasher: " << strerror(errno);
290 }
291
Josh Gaoe06f2a42017-04-27 16:50:38 -0700292 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700293 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700294 ASSERT_EQ(0, WEXITSTATUS(signo));
295 } else {
296 ASSERT_FALSE(WIFEXITED(status));
297 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
298 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700299 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700300 crasher_pid = -1;
301}
302
303static void ConsumeFd(unique_fd fd, std::string* output) {
Kelvin Zhang786dac32023-06-15 16:23:56 -0700304 ASSERT_TRUE(android::base::ReadFdToString(fd, output));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700305}
306
Mitch Phillips78f06702021-06-01 14:35:43 -0700307class LogcatCollector {
308 public:
309 LogcatCollector() { system("logcat -c"); }
310
311 void Collect(std::string* output) {
312 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
313 ASSERT_NE(cmd_stdout, nullptr);
314 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
315 ConsumeFd(std::move(tmp_fd), output);
316 pclose(cmd_stdout);
317 }
318};
319
Josh Gaocbe70cb2016-10-18 18:17:52 -0700320TEST_F(CrasherTest, smoke) {
321 int intercept_result;
322 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800323 StartProcess([]() {
324 *reinterpret_cast<volatile char*>(0xdead) = '1';
325 });
326
Josh Gaocbe70cb2016-10-18 18:17:52 -0700327 StartIntercept(&output_fd);
328 FinishCrasher();
329 AssertDeath(SIGSEGV);
330 FinishIntercept(&intercept_result);
331
332 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
333
334 std::string result;
335 ConsumeFd(std::move(output_fd), &result);
Christopher Ferris2f77c2a2024-05-07 12:25:31 -0700336 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700337
338 if (mte_supported()) {
339 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700340 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
341 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700342 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800343
344 if (pac_supported()) {
345 // Test that the default PAC_ENABLED_KEYS value is set.
346 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
347 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
348 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700349}
350
Peter Collingbournef03af882020-03-20 18:09:00 -0700351TEST_F(CrasherTest, tagged_fault_addr) {
352#if !defined(__aarch64__)
353 GTEST_SKIP() << "Requires aarch64";
354#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700355 // HWASan crashes with SIGABRT on tag mismatch.
356 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700357 int intercept_result;
358 unique_fd output_fd;
359 StartProcess([]() {
360 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
361 });
362
363 StartIntercept(&output_fd);
364 FinishCrasher();
365 AssertDeath(SIGSEGV);
366 FinishIntercept(&intercept_result);
367
368 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
369
370 std::string result;
371 ConsumeFd(std::move(output_fd), &result);
372
373 // The address can either be tagged (new kernels) or untagged (old kernels).
374 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800375 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700376}
377
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700378void CrasherTest::Trap(void* ptr) {
379 void (*volatile f)(void*) = nullptr;
380 __asm__ __volatile__("" : : "r"(f) : "memory");
381 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700382}
383
384TEST_F(CrasherTest, heap_addr_in_register) {
385#if defined(__i386__)
386 GTEST_SKIP() << "architecture does not pass arguments in registers";
387#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700388 // The memory dump in HWASan crashes sadly shows the memory near the registers
389 // in the HWASan dump function, rather the faulting context. This is a known
390 // issue.
391 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700392 int intercept_result;
393 unique_fd output_fd;
394 StartProcess([]() {
395 // Crash with a heap pointer in the first argument register.
396 Trap(malloc(1));
397 });
398
399 StartIntercept(&output_fd);
400 FinishCrasher();
401 int status;
402 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
403 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
404 // Don't test the signal number because different architectures use different signals for
405 // __builtin_trap().
406 FinishIntercept(&intercept_result);
407
408 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
409
410 std::string result;
411 ConsumeFd(std::move(output_fd), &result);
412
413#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800414 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700415#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800416 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800417#elif defined(__riscv)
418 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700419#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800420 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700421#else
422 ASSERT_TRUE(false) << "unsupported architecture";
423#endif
424}
425
Peter Collingbournecd278072020-12-21 14:08:38 -0800426#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700427static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800428 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700429 abort();
430 }
431}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800432
433static void SetTagCheckingLevelAsync() {
434 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
435 abort();
436 }
437}
Peter Collingbournef8622522020-04-07 14:07:32 -0700438#endif
439
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800440struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
441
Peter Collingbourneaa544792021-05-13 13:53:37 -0700442INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800443
444TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800445#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700446 if (!mte_supported()) {
447 GTEST_SKIP() << "Requires MTE";
448 }
449
Peter Collingbourneaa544792021-05-13 13:53:37 -0700450 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
451 if (GetParam() == 0) {
452 return;
453 }
454
Mitch Phillips78f06702021-06-01 14:35:43 -0700455 LogcatCollector logcat_collector;
456
Peter Collingbournef8622522020-04-07 14:07:32 -0700457 int intercept_result;
458 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800459 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700460 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800461 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700462 free((void *)p);
463 p[0] = 42;
464 });
465
466 StartIntercept(&output_fd);
467 FinishCrasher();
468 AssertDeath(SIGSEGV);
469 FinishIntercept(&intercept_result);
470
471 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
472
Mitch Phillips78f06702021-06-01 14:35:43 -0700473 std::vector<std::string> log_sources(2);
474 ConsumeFd(std::move(output_fd), &log_sources[0]);
475 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700476 // Tag dump only available in the tombstone, not logcat.
477 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700478
Mitch Phillips78f06702021-06-01 14:35:43 -0700479 for (const auto& result : log_sources) {
480 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
481 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
482 std::to_string(GetParam()) + R"(-byte allocation)");
483 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
484 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
485 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700486#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800487 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700488#endif
489}
490
Peter Collingbournedc476342021-05-12 15:56:43 -0700491TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
492#if defined(__aarch64__)
493 if (!mte_supported()) {
494 GTEST_SKIP() << "Requires MTE";
495 }
496
497 int intercept_result;
498 unique_fd output_fd;
499 StartProcess([&]() {
500 SetTagCheckingLevelSync();
501 volatile int* p = (volatile int*)malloc(GetParam());
502 free((void *)p);
503 p[-1] = 42;
504 });
505
506 StartIntercept(&output_fd);
507 FinishCrasher();
508 AssertDeath(SIGSEGV);
509 FinishIntercept(&intercept_result);
510
511 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
512
513 std::string result;
514 ConsumeFd(std::move(output_fd), &result);
515
516 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
517 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
518#else
519 GTEST_SKIP() << "Requires aarch64";
520#endif
521}
522
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800523TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800524#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700525 if (!mte_supported()) {
526 GTEST_SKIP() << "Requires MTE";
527 }
528
Mitch Phillips78f06702021-06-01 14:35:43 -0700529 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700530 int intercept_result;
531 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800532 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700533 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800534 volatile char* p = (volatile char*)malloc(GetParam());
535 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700536 });
537
538 StartIntercept(&output_fd);
539 FinishCrasher();
540 AssertDeath(SIGSEGV);
541 FinishIntercept(&intercept_result);
542
543 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
544
Mitch Phillips78f06702021-06-01 14:35:43 -0700545 std::vector<std::string> log_sources(2);
546 ConsumeFd(std::move(output_fd), &log_sources[0]);
547 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700548
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700549 // Tag dump only in tombstone, not logcat, and tagging is not used for
550 // overflow protection in the scudo secondary (guard pages are used instead).
551 if (GetParam() < 0x10000) {
552 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
553 }
554
Mitch Phillips78f06702021-06-01 14:35:43 -0700555 for (const auto& result : log_sources) {
556 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
557 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
558 std::to_string(GetParam()) + R"(-byte allocation)");
559 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
560 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700561#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800562 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700563#endif
564}
565
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800566TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800567#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700568 if (!mte_supported()) {
569 GTEST_SKIP() << "Requires MTE";
570 }
571
572 int intercept_result;
573 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800574 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700575 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800576 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700577 p[-1] = 42;
578 });
579
580 StartIntercept(&output_fd);
581 FinishCrasher();
582 AssertDeath(SIGSEGV);
583 FinishIntercept(&intercept_result);
584
585 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
586
587 std::string result;
588 ConsumeFd(std::move(output_fd), &result);
589
590 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800591 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800592 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700593 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700594 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700595 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700596#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800597 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700598#endif
599}
600
Florian Mayere6462f92024-02-28 11:12:11 -0800601__attribute__((noinline)) void mte_illegal_setjmp_helper(jmp_buf& jump_buf) {
Florian Mayer1fef1b12024-03-06 16:53:30 -0800602 // This frame is at least 8 bytes for storing and restoring the LR before the
603 // setjmp below. So this can never get an empty stack frame, even if we omit
604 // the frame pointer. So, the SP of this is always less (numerically) than the
605 // calling function frame.
Florian Mayere6462f92024-02-28 11:12:11 -0800606 setjmp(jump_buf);
607}
608
Florian Mayer92164902024-04-10 20:24:56 +0000609TEST_F(CrasherTest, DISABLED_mte_illegal_setjmp) {
Florian Mayere6462f92024-02-28 11:12:11 -0800610 // This setjmp is illegal because it jumps back into a function that already returned.
611 // Quoting man 3 setjmp:
612 // If the function which called setjmp() returns before longjmp() is
613 // called, the behavior is undefined. Some kind of subtle or
614 // unsubtle chaos is sure to result.
615 // https://man7.org/linux/man-pages/man3/longjmp.3.html
616#if defined(__aarch64__)
617 if (!mte_supported()) {
618 GTEST_SKIP() << "Requires MTE";
619 }
620
621 int intercept_result;
622 unique_fd output_fd;
623 StartProcess([&]() {
624 SetTagCheckingLevelSync();
625 jmp_buf jump_buf;
626 mte_illegal_setjmp_helper(jump_buf);
627 longjmp(jump_buf, 1);
628 });
629
630 StartIntercept(&output_fd);
631 FinishCrasher();
632 AssertDeath(SIGABRT);
633 FinishIntercept(&intercept_result);
634
635 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
636
637 std::string result;
638 ConsumeFd(std::move(output_fd), &result);
639
640 // In our test-case, we have a NEGATIVE stack adjustment, which is being
641 // interpreted as unsigned integer, and thus is "too large".
642 // TODO(fmayer): fix the error message for this
643 ASSERT_MATCH(result, R"(memtag_handle_longjmp: stack adjustment too large)");
644#else
645 GTEST_SKIP() << "Requires aarch64";
646#endif
647}
648
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800649TEST_F(CrasherTest, mte_async) {
650#if defined(__aarch64__)
651 if (!mte_supported()) {
652 GTEST_SKIP() << "Requires MTE";
653 }
654
655 int intercept_result;
656 unique_fd output_fd;
657 StartProcess([&]() {
658 SetTagCheckingLevelAsync();
659 volatile int* p = (volatile int*)malloc(16);
660 p[-1] = 42;
661 });
662
663 StartIntercept(&output_fd);
664 FinishCrasher();
665 AssertDeath(SIGSEGV);
666 FinishIntercept(&intercept_result);
667
668 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
669
670 std::string result;
671 ConsumeFd(std::move(output_fd), &result);
672
Peter Collingbourne91e816a2023-03-07 21:24:47 -0800673 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800674#else
675 GTEST_SKIP() << "Requires aarch64";
676#endif
677}
678
Peter Collingbournef8622522020-04-07 14:07:32 -0700679TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800680#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700681 if (!mte_supported()) {
682 GTEST_SKIP() << "Requires MTE";
683 }
684
Mitch Phillips78f06702021-06-01 14:35:43 -0700685 LogcatCollector logcat_collector;
686
Peter Collingbournef8622522020-04-07 14:07:32 -0700687 int intercept_result;
688 unique_fd output_fd;
689 StartProcess([]() {
690 SetTagCheckingLevelSync();
691
692 // Make two allocations with the same tag and close to one another. Check for both properties
693 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
694 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
695 // (some non-zero value << 56) apart.
696 //
697 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
698 // other.
699 std::set<uintptr_t> allocs;
700 for (int i = 0; i != 4096; ++i) {
701 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
702 auto it = allocs.insert(alloc).first;
703 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
704 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
705 }
706 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
707 *reinterpret_cast<int*>(alloc + 16) = 42;
708 }
709 }
710 });
711
712 StartIntercept(&output_fd);
713 FinishCrasher();
714 AssertDeath(SIGSEGV);
715 FinishIntercept(&intercept_result);
716
717 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
718
Mitch Phillips78f06702021-06-01 14:35:43 -0700719 std::vector<std::string> log_sources(2);
720 ConsumeFd(std::move(output_fd), &log_sources[0]);
721 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700722
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700723 // Tag dump only in the tombstone, not logcat.
724 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
725
Mitch Phillips78f06702021-06-01 14:35:43 -0700726 for (const auto& result : log_sources) {
727 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
728 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800729 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700730 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
731 // overflows), so we can't match explicitly for an underflow message.
732 ASSERT_MATCH(result,
733 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
734 // Ensure there's at least two allocation traces (one for each cause).
735 ASSERT_MATCH(
736 result,
737 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
738 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700739#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800740 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700741#endif
742}
743
Peter Collingbournecd278072020-12-21 14:08:38 -0800744#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700745static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700746 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
747 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
748 size_t page_size = getpagesize();
749 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
750 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
751 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700752 return 0;
753 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700754 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
755 PROT_READ | PROT_WRITE | PROT_MTE);
756 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
757 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
758 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
759 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
760 }
761 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700762}
763#endif
764
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700765TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800766#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700767 if (!mte_supported()) {
768 GTEST_SKIP() << "Requires MTE";
769 }
770
771 int intercept_result;
772 unique_fd output_fd;
773 StartProcess([&]() {
774 SetTagCheckingLevelSync();
775 Trap(reinterpret_cast<void *>(CreateTagMapping()));
776 });
777
778 StartIntercept(&output_fd);
779 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700780 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700781 FinishIntercept(&intercept_result);
782
783 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
784
785 std::string result;
786 ConsumeFd(std::move(output_fd), &result);
787
788 ASSERT_MATCH(result, R"(memory near x0:
789.*
790.*
791 01.............0 0000000000000000 0000000000000000 ................
792 00.............0)");
793#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800794 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700795#endif
796}
797
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700798TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
799#if defined(__aarch64__)
800 if (!mte_supported()) {
801 GTEST_SKIP() << "Requires MTE";
802 }
803
804 int intercept_result;
805 unique_fd output_fd;
806 StartProcess([&]() {
807 SetTagCheckingLevelSync();
808 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
809 p[0] = 0; // Untagged pointer, tagged memory.
810 });
811
812 StartIntercept(&output_fd);
813 FinishCrasher();
814 AssertDeath(SIGSEGV);
815 FinishIntercept(&intercept_result);
816
817 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
818
819 std::string result;
820 ConsumeFd(std::move(output_fd), &result);
821
822 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
823\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
824#else
825 GTEST_SKIP() << "Requires aarch64";
826#endif
827}
828
829TEST_F(CrasherTest, mte_fault_tag_dump) {
830#if defined(__aarch64__)
831 if (!mte_supported()) {
832 GTEST_SKIP() << "Requires MTE";
833 }
834
835 int intercept_result;
836 unique_fd output_fd;
837 StartProcess([&]() {
838 SetTagCheckingLevelSync();
839 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
840 p[320] = 0; // Untagged pointer, tagged memory.
841 });
842
843 StartIntercept(&output_fd);
844 FinishCrasher();
845 AssertDeath(SIGSEGV);
846 FinishIntercept(&intercept_result);
847
848 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
849
850 std::string result;
851 ConsumeFd(std::move(output_fd), &result);
852
853 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
854\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
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)");
858#else
859 GTEST_SKIP() << "Requires aarch64";
860#endif
861}
862
863TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
864#if defined(__aarch64__)
865 if (!mte_supported()) {
866 GTEST_SKIP() << "Requires MTE";
867 }
868
869 int intercept_result;
870 unique_fd output_fd;
871 StartProcess([&]() {
872 SetTagCheckingLevelSync();
873 size_t page_size = getpagesize();
874 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
875 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
876 });
877
878 StartIntercept(&output_fd);
879 FinishCrasher();
880 AssertDeath(SIGSEGV);
881 FinishIntercept(&intercept_result);
882
883 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
884
885 std::string result;
886 ConsumeFd(std::move(output_fd), &result);
887
888 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
889 ASSERT_MATCH(result,
890 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
891\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
892
893)"); // Ensure truncation happened and there's a newline after the tag fault.
894#else
895 GTEST_SKIP() << "Requires aarch64";
896#endif
897}
898
Josh Gaocdea7502017-11-01 15:00:40 -0700899TEST_F(CrasherTest, LD_PRELOAD) {
900 int intercept_result;
901 unique_fd output_fd;
902 StartProcess([]() {
903 setenv("LD_PRELOAD", "nonexistent.so", 1);
904 *reinterpret_cast<volatile char*>(0xdead) = '1';
905 });
906
907 StartIntercept(&output_fd);
908 FinishCrasher();
909 AssertDeath(SIGSEGV);
910 FinishIntercept(&intercept_result);
911
912 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
913
914 std::string result;
915 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800916 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700917}
918
Josh Gaocbe70cb2016-10-18 18:17:52 -0700919TEST_F(CrasherTest, abort) {
920 int intercept_result;
921 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800922 StartProcess([]() {
923 abort();
924 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700925 StartIntercept(&output_fd);
926 FinishCrasher();
927 AssertDeath(SIGABRT);
928 FinishIntercept(&intercept_result);
929
930 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
931
932 std::string result;
933 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700934 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700935}
936
937TEST_F(CrasherTest, signal) {
938 int intercept_result;
939 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800940 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700941 while (true) {
942 sleep(1);
943 }
Josh Gao502cfd22017-02-17 01:39:15 -0800944 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700945 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700946 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700947 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
948
949 AssertDeath(SIGSEGV);
950 FinishIntercept(&intercept_result);
951
952 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
953
954 std::string result;
955 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700956 ASSERT_MATCH(
957 result,
958 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700959 ASSERT_MATCH(result, R"(backtrace:)");
960}
961
962TEST_F(CrasherTest, abort_message) {
963 int intercept_result;
964 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800965 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800966 // Arrived at experimentally;
967 // logd truncates at 4062.
968 // strlen("Abort message: ''") is 17.
969 // That's 4045, but we also want a NUL.
970 char buf[4045 + 1];
971 memset(buf, 'x', sizeof(buf));
972 buf[sizeof(buf) - 1] = '\0';
973 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800974 abort();
975 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700976 StartIntercept(&output_fd);
977 FinishCrasher();
978 AssertDeath(SIGABRT);
979 FinishIntercept(&intercept_result);
980
981 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
982
983 std::string result;
984 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800985 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700986}
987
Florian Mayer5fa66632024-02-07 16:42:23 -0800988static char g_crash_detail_value_changes[] = "crash_detail_value";
989static char g_crash_detail_value[] = "crash_detail_value";
990static char g_crash_detail_value2[] = "crash_detail_value2";
991
992inline crash_detail_t* _Nullable android_register_crash_detail_strs(const char* _Nonnull name,
993 const char* _Nonnull data) {
Florian Mayer920d95b2024-02-14 12:57:09 -0800994 return android_crash_detail_register(name, strlen(name), data, strlen(data));
Florian Mayer5fa66632024-02-07 16:42:23 -0800995}
996
997TEST_F(CrasherTest, crash_detail_single) {
998 int intercept_result;
999 unique_fd output_fd;
1000 StartProcess([]() {
1001 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1002 abort();
1003 });
1004 StartIntercept(&output_fd);
1005 FinishCrasher();
1006 AssertDeath(SIGABRT);
1007 FinishIntercept(&intercept_result);
1008
1009 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1010
1011 std::string result;
1012 ConsumeFd(std::move(output_fd), &result);
1013 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1014}
1015
Florian Mayeraced3aa2024-02-13 13:44:50 -08001016TEST_F(CrasherTest, crash_detail_replace_data) {
1017 int intercept_result;
1018 unique_fd output_fd;
1019 StartProcess([]() {
1020 auto *cd = android_register_crash_detail_strs("CRASH_DETAIL_NAME", "original_data");
Florian Mayer920d95b2024-02-14 12:57:09 -08001021 android_crash_detail_replace_data(cd, "new_data", strlen("new_data"));
Florian Mayeraced3aa2024-02-13 13:44:50 -08001022 abort();
1023 });
1024 StartIntercept(&output_fd);
1025 FinishCrasher();
1026 AssertDeath(SIGABRT);
1027 FinishIntercept(&intercept_result);
1028
1029 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1030
1031 std::string result;
1032 ConsumeFd(std::move(output_fd), &result);
1033 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'new_data')");
1034 // Ensure the old one no longer shows up, i.e. that we actually replaced
1035 // it, not added a new one.
1036 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'original_data')");
1037}
1038
1039TEST_F(CrasherTest, crash_detail_replace_name) {
1040 int intercept_result;
1041 unique_fd output_fd;
1042 StartProcess([]() {
1043 auto *cd = android_register_crash_detail_strs("old_name", g_crash_detail_value);
Florian Mayer920d95b2024-02-14 12:57:09 -08001044 android_crash_detail_replace_name(cd, "new_name", strlen("new_name"));
Florian Mayeraced3aa2024-02-13 13:44:50 -08001045 abort();
1046 });
1047 StartIntercept(&output_fd);
1048 FinishCrasher();
1049 AssertDeath(SIGABRT);
1050 FinishIntercept(&intercept_result);
1051
1052 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1053
1054 std::string result;
1055 ConsumeFd(std::move(output_fd), &result);
1056 ASSERT_MATCH(result, R"(new_name: 'crash_detail_value')");
1057 // Ensure the old one no longer shows up, i.e. that we actually replaced
1058 // it, not added a new one.
1059 ASSERT_NOT_MATCH(result, R"(old_name: 'crash_detail_value')");
1060}
1061
Florian Mayer5fa66632024-02-07 16:42:23 -08001062TEST_F(CrasherTest, crash_detail_single_byte_name) {
1063 int intercept_result;
1064 unique_fd output_fd;
1065 StartProcess([]() {
1066 android_register_crash_detail_strs("CRASH_DETAIL_NAME\1", g_crash_detail_value);
1067 abort();
1068 });
1069 StartIntercept(&output_fd);
1070 FinishCrasher();
1071 AssertDeath(SIGABRT);
1072 FinishIntercept(&intercept_result);
1073
1074 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1075
1076 std::string result;
1077 ConsumeFd(std::move(output_fd), &result);
1078 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME\\1: 'crash_detail_value')");
1079}
1080
1081
1082TEST_F(CrasherTest, crash_detail_single_bytes) {
1083 int intercept_result;
1084 unique_fd output_fd;
1085 StartProcess([]() {
Florian Mayer920d95b2024-02-14 12:57:09 -08001086 android_crash_detail_register("CRASH_DETAIL_NAME", strlen("CRASH_DETAIL_NAME"), "\1",
Florian Mayer5fa66632024-02-07 16:42:23 -08001087 sizeof("\1"));
1088 abort();
1089 });
1090 StartIntercept(&output_fd);
1091 FinishCrasher();
1092 AssertDeath(SIGABRT);
1093 FinishIntercept(&intercept_result);
1094
1095 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1096
1097 std::string result;
1098 ConsumeFd(std::move(output_fd), &result);
1099 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: '\\1\\0')");
1100}
1101
1102TEST_F(CrasherTest, crash_detail_mixed) {
1103 int intercept_result;
1104 unique_fd output_fd;
1105 StartProcess([]() {
1106 const char data[] = "helloworld\1\255\3";
1107 android_register_crash_detail_strs("CRASH_DETAIL_NAME", data);
1108 abort();
1109 });
1110 StartIntercept(&output_fd);
1111 FinishCrasher();
1112 AssertDeath(SIGABRT);
1113 FinishIntercept(&intercept_result);
1114
1115 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1116
1117 std::string result;
1118 ConsumeFd(std::move(output_fd), &result);
1119 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'helloworld\\1\\255\\3')");
1120}
1121
1122TEST_F(CrasherTest, crash_detail_many) {
1123 int intercept_result;
1124 unique_fd output_fd;
1125 StartProcess([]() {
1126 for (int i = 0; i < 1000; ++i) {
1127 std::string name = "CRASH_DETAIL_NAME" + std::to_string(i);
1128 std::string value = "CRASH_DETAIL_VALUE" + std::to_string(i);
1129 auto* h = android_register_crash_detail_strs(name.data(), value.data());
Florian Mayer920d95b2024-02-14 12:57:09 -08001130 android_crash_detail_unregister(h);
Florian Mayer5fa66632024-02-07 16:42:23 -08001131 }
1132
1133 android_register_crash_detail_strs("FINAL_NAME", "FINAL_VALUE");
1134 android_register_crash_detail_strs("FINAL_NAME2", "FINAL_VALUE2");
1135 abort();
1136 });
1137 StartIntercept(&output_fd);
1138 FinishCrasher();
1139 AssertDeath(SIGABRT);
1140 FinishIntercept(&intercept_result);
1141
1142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1143
1144 std::string result;
1145 ConsumeFd(std::move(output_fd), &result);
1146 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_NAME");
1147 ASSERT_NOT_MATCH(result, "CRASH_DETAIL_VALUE");
1148 ASSERT_MATCH(result, R"(FINAL_NAME: 'FINAL_VALUE')");
1149 ASSERT_MATCH(result, R"(FINAL_NAME2: 'FINAL_VALUE2')");
1150}
1151
1152TEST_F(CrasherTest, crash_detail_single_changes) {
1153 int intercept_result;
1154 unique_fd output_fd;
1155 StartProcess([]() {
1156 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value_changes);
1157 g_crash_detail_value_changes[0] = 'C';
1158 abort();
1159 });
1160 StartIntercept(&output_fd);
1161 FinishCrasher();
1162 AssertDeath(SIGABRT);
1163 FinishIntercept(&intercept_result);
1164
1165 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1166
1167 std::string result;
1168 ConsumeFd(std::move(output_fd), &result);
1169 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'Crash_detail_value')");
1170}
1171
1172TEST_F(CrasherTest, crash_detail_multiple) {
1173 int intercept_result;
1174 unique_fd output_fd;
1175 StartProcess([]() {
1176 android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
1177 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1178 abort();
1179 });
1180 StartIntercept(&output_fd);
1181 FinishCrasher();
1182 AssertDeath(SIGABRT);
1183 FinishIntercept(&intercept_result);
1184
1185 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1186
1187 std::string result;
1188 ConsumeFd(std::move(output_fd), &result);
1189 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1190 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1191}
1192
1193TEST_F(CrasherTest, crash_detail_remove) {
1194 int intercept_result;
1195 unique_fd output_fd;
1196 StartProcess([]() {
1197 auto* detail1 = android_register_crash_detail_strs("CRASH_DETAIL_NAME", g_crash_detail_value);
Florian Mayer920d95b2024-02-14 12:57:09 -08001198 android_crash_detail_unregister(detail1);
Florian Mayer5fa66632024-02-07 16:42:23 -08001199 android_register_crash_detail_strs("CRASH_DETAIL_NAME2", g_crash_detail_value2);
1200 abort();
1201 });
1202 StartIntercept(&output_fd);
1203 FinishCrasher();
1204 AssertDeath(SIGABRT);
1205 FinishIntercept(&intercept_result);
1206
1207 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1208
1209 std::string result;
1210 ConsumeFd(std::move(output_fd), &result);
1211 ASSERT_NOT_MATCH(result, R"(CRASH_DETAIL_NAME: 'crash_detail_value')");
1212 ASSERT_MATCH(result, R"(CRASH_DETAIL_NAME2: 'crash_detail_value2')");
1213}
1214
Christopher Ferrise8891452021-08-17 17:34:53 -07001215TEST_F(CrasherTest, abort_message_newline_trimmed) {
1216 int intercept_result;
1217 unique_fd output_fd;
1218 StartProcess([]() {
1219 android_set_abort_message("Message with a newline.\n");
1220 abort();
1221 });
1222 StartIntercept(&output_fd);
1223 FinishCrasher();
1224 AssertDeath(SIGABRT);
1225 FinishIntercept(&intercept_result);
1226
1227 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1228
1229 std::string result;
1230 ConsumeFd(std::move(output_fd), &result);
1231 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1232}
1233
1234TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1235 int intercept_result;
1236 unique_fd output_fd;
1237 StartProcess([]() {
1238 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1239 abort();
1240 });
1241 StartIntercept(&output_fd);
1242 FinishCrasher();
1243 AssertDeath(SIGABRT);
1244 FinishIntercept(&intercept_result);
1245
1246 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1247
1248 std::string result;
1249 ConsumeFd(std::move(output_fd), &result);
1250 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1251}
1252
Josh Gaoe06f2a42017-04-27 16:50:38 -07001253TEST_F(CrasherTest, abort_message_backtrace) {
1254 int intercept_result;
1255 unique_fd output_fd;
1256 StartProcess([]() {
1257 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001258 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001259 exit(0);
1260 });
1261 StartIntercept(&output_fd);
1262 FinishCrasher();
1263 AssertDeath(0);
1264 FinishIntercept(&intercept_result);
1265
1266 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1267
1268 std::string result;
1269 ConsumeFd(std::move(output_fd), &result);
1270 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1271}
1272
Josh Gaocbe70cb2016-10-18 18:17:52 -07001273TEST_F(CrasherTest, intercept_timeout) {
1274 int intercept_result;
1275 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001276 StartProcess([]() {
1277 abort();
1278 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001279 StartIntercept(&output_fd);
1280
1281 // Don't let crasher finish until we timeout.
1282 FinishIntercept(&intercept_result);
1283
1284 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1285 << intercept_result << ")";
1286
1287 FinishCrasher();
1288 AssertDeath(SIGABRT);
1289}
1290
Elliott Hughese4781d52021-03-17 09:15:15 -07001291TEST_F(CrasherTest, wait_for_debugger) {
1292 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1293 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001294 }
1295 sleep(1);
1296
Josh Gao502cfd22017-02-17 01:39:15 -08001297 StartProcess([]() {
1298 abort();
1299 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001300 FinishCrasher();
1301
1302 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001303 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001304 ASSERT_TRUE(WIFSTOPPED(status));
1305 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1306
1307 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1308
1309 AssertDeath(SIGABRT);
1310}
1311
Josh Gaocbe70cb2016-10-18 18:17:52 -07001312TEST_F(CrasherTest, backtrace) {
1313 std::string result;
1314 int intercept_result;
1315 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001316
1317 StartProcess([]() {
1318 abort();
1319 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001320 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001321
1322 std::this_thread::sleep_for(500ms);
1323
1324 sigval val;
1325 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001326 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001327 FinishIntercept(&intercept_result);
1328 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1329 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001330 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001331
1332 int status;
1333 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1334
1335 StartIntercept(&output_fd);
1336 FinishCrasher();
1337 AssertDeath(SIGABRT);
1338 FinishIntercept(&intercept_result);
1339 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1340 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001341 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001342}
Josh Gaofca7ca32017-01-23 12:05:35 -08001343
1344TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001345 int intercept_result;
1346 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001347 StartProcess([]() {
1348 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001349 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001350 });
Josh Gao502cfd22017-02-17 01:39:15 -08001351
1352 StartIntercept(&output_fd);
1353 FinishCrasher();
1354 AssertDeath(SIGABRT);
1355 FinishIntercept(&intercept_result);
1356
1357 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1358
1359 std::string result;
1360 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001361 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001362}
1363
Josh Gao502cfd22017-02-17 01:39:15 -08001364TEST_F(CrasherTest, capabilities) {
1365 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1366
Josh Gaofca7ca32017-01-23 12:05:35 -08001367 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001368 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1369 err(1, "failed to set PR_SET_KEEPCAPS");
1370 }
1371
1372 if (setresuid(1, 1, 1) != 0) {
1373 err(1, "setresuid failed");
1374 }
1375
1376 __user_cap_header_struct capheader;
1377 __user_cap_data_struct capdata[2];
1378 memset(&capheader, 0, sizeof(capheader));
1379 memset(&capdata, 0, sizeof(capdata));
1380
1381 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1382 capheader.pid = 0;
1383
1384 // Turn on every third capability.
1385 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1386 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1387 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1388 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1389 }
1390
1391 // Make sure CAP_SYS_PTRACE is off.
1392 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1393 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1394
1395 if (capset(&capheader, &capdata[0]) != 0) {
1396 err(1, "capset failed");
1397 }
1398
1399 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1400 err(1, "failed to drop ambient capabilities");
1401 }
1402
Josh Gaoa5199a92017-04-03 13:18:34 -07001403 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001404 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001405 });
Josh Gao502cfd22017-02-17 01:39:15 -08001406
1407 unique_fd output_fd;
1408 StartIntercept(&output_fd);
1409 FinishCrasher();
1410 AssertDeath(SIGSYS);
1411
1412 std::string result;
1413 int intercept_result;
1414 FinishIntercept(&intercept_result);
1415 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1416 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001417 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001418 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001419}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001420
Josh Gao2e7b8e22017-05-04 17:12:57 -07001421TEST_F(CrasherTest, fake_pid) {
1422 int intercept_result;
1423 unique_fd output_fd;
1424
1425 // Prime the getpid/gettid caches.
1426 UNUSED(getpid());
1427 UNUSED(gettid());
1428
1429 std::function<pid_t()> clone_fn = []() {
1430 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1431 };
1432 StartProcess(
1433 []() {
1434 ASSERT_NE(getpid(), syscall(__NR_getpid));
1435 ASSERT_NE(gettid(), syscall(__NR_gettid));
1436 raise(SIGSEGV);
1437 },
1438 clone_fn);
1439
1440 StartIntercept(&output_fd);
1441 FinishCrasher();
1442 AssertDeath(SIGSEGV);
1443 FinishIntercept(&intercept_result);
1444
1445 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1446
1447 std::string result;
1448 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001449 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001450}
1451
Josh Gaoe04ca272018-01-16 15:38:17 -08001452static const char* const kDebuggerdSeccompPolicy =
1453 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1454
Mitch Phillips18ce5422023-01-19 14:23:49 -08001455static void setup_jail(minijail* jail) {
1456 if (!jail) {
1457 LOG(FATAL) << "failed to create minijail";
1458 }
1459
Josh Gao6f9eeec2018-09-12 13:55:47 -07001460 std::string policy;
1461 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1462 PLOG(FATAL) << "failed to read policy file";
1463 }
1464
1465 // Allow a bunch of syscalls used by the tests.
1466 policy += "\nclone: 1";
1467 policy += "\nsigaltstack: 1";
1468 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001469 policy += "\ngetrlimit: 1";
1470 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001471
1472 FILE* tmp_file = tmpfile();
1473 if (!tmp_file) {
1474 PLOG(FATAL) << "tmpfile failed";
1475 }
1476
Christopher Ferris172b0a02019-09-18 17:48:30 -07001477 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001478 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1479 PLOG(FATAL) << "failed to write policy to tmpfile";
1480 }
1481
1482 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1483 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001484 }
1485
Mitch Phillips18ce5422023-01-19 14:23:49 -08001486 minijail_no_new_privs(jail);
1487 minijail_log_seccomp_filter_failures(jail);
1488 minijail_use_seccomp_filter(jail);
1489 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1490}
Josh Gaoe04ca272018-01-16 15:38:17 -08001491
Mitch Phillips18ce5422023-01-19 14:23:49 -08001492static pid_t seccomp_fork_impl(void (*prejail)()) {
1493 ScopedMinijail jail{minijail_new()};
1494 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001495
1496 pid_t result = fork();
1497 if (result == -1) {
1498 return result;
1499 } else if (result != 0) {
1500 return result;
1501 }
1502
1503 // Spawn and detach a thread that spins forever.
1504 std::atomic<bool> thread_ready(false);
1505 std::thread thread([&jail, &thread_ready]() {
1506 minijail_enter(jail.get());
1507 thread_ready = true;
1508 for (;;)
1509 ;
1510 });
1511 thread.detach();
1512
1513 while (!thread_ready) {
1514 continue;
1515 }
1516
Josh Gao70adac62018-02-22 11:38:33 -08001517 if (prejail) {
1518 prejail();
1519 }
1520
Josh Gaoe04ca272018-01-16 15:38:17 -08001521 minijail_enter(jail.get());
1522 return result;
1523}
1524
Josh Gao70adac62018-02-22 11:38:33 -08001525static pid_t seccomp_fork() {
1526 return seccomp_fork_impl(nullptr);
1527}
1528
Josh Gaoe04ca272018-01-16 15:38:17 -08001529TEST_F(CrasherTest, seccomp_crash) {
1530 int intercept_result;
1531 unique_fd output_fd;
1532
1533 StartProcess([]() { abort(); }, &seccomp_fork);
1534
1535 StartIntercept(&output_fd);
1536 FinishCrasher();
1537 AssertDeath(SIGABRT);
1538 FinishIntercept(&intercept_result);
1539 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1540
1541 std::string result;
1542 ConsumeFd(std::move(output_fd), &result);
1543 ASSERT_BACKTRACE_FRAME(result, "abort");
1544}
1545
Josh Gao70adac62018-02-22 11:38:33 -08001546static pid_t seccomp_fork_rlimit() {
1547 return seccomp_fork_impl([]() {
1548 struct rlimit rlim = {
1549 .rlim_cur = 512 * 1024 * 1024,
1550 .rlim_max = 512 * 1024 * 1024,
1551 };
1552
1553 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1554 raise(SIGINT);
1555 }
1556 });
1557}
1558
1559TEST_F(CrasherTest, seccomp_crash_oom) {
1560 int intercept_result;
1561 unique_fd output_fd;
1562
1563 StartProcess(
1564 []() {
1565 std::vector<void*> vec;
1566 for (int i = 0; i < 512; ++i) {
1567 char* buf = static_cast<char*>(malloc(1024 * 1024));
1568 if (!buf) {
1569 abort();
1570 }
1571 memset(buf, 0xff, 1024 * 1024);
1572 vec.push_back(buf);
1573 }
1574 },
1575 &seccomp_fork_rlimit);
1576
1577 StartIntercept(&output_fd);
1578 FinishCrasher();
1579 AssertDeath(SIGABRT);
1580 FinishIntercept(&intercept_result);
1581 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1582
1583 // We can't actually generate a backtrace, just make sure that the process terminates.
1584}
1585
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001586__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001587 siginfo_t siginfo;
1588 siginfo.si_code = SI_QUEUE;
1589 siginfo.si_pid = getpid();
1590 siginfo.si_uid = getuid();
1591
1592 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1593 PLOG(FATAL) << "invalid dump type";
1594 }
1595
1596 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1597
Josh Gaoa48b41b2019-12-13 14:11:04 -08001598 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001599 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1600 return false;
1601 }
1602
1603 return true;
1604}
1605
Christopher Ferrisb999b822022-02-09 17:57:21 -08001606extern "C" void foo() {
1607 LOG(INFO) << "foo";
1608 std::this_thread::sleep_for(1s);
1609}
1610
1611extern "C" void bar() {
1612 LOG(INFO) << "bar";
1613 std::this_thread::sleep_for(1s);
1614}
1615
Josh Gaoe04ca272018-01-16 15:38:17 -08001616TEST_F(CrasherTest, seccomp_tombstone) {
1617 int intercept_result;
1618 unique_fd output_fd;
1619
1620 static const auto dump_type = kDebuggerdTombstone;
1621 StartProcess(
1622 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001623 std::thread a(foo);
1624 std::thread b(bar);
1625
1626 std::this_thread::sleep_for(100ms);
1627
Josh Gaoe04ca272018-01-16 15:38:17 -08001628 raise_debugger_signal(dump_type);
1629 _exit(0);
1630 },
1631 &seccomp_fork);
1632
1633 StartIntercept(&output_fd, dump_type);
1634 FinishCrasher();
1635 AssertDeath(0);
1636 FinishIntercept(&intercept_result);
1637 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1638
1639 std::string result;
1640 ConsumeFd(std::move(output_fd), &result);
1641 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001642 ASSERT_BACKTRACE_FRAME(result, "foo");
1643 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001644}
1645
Christopher Ferris303c6be2022-05-24 17:08:33 -07001646TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1647 int intercept_result;
1648 unique_fd output_fd;
1649
1650 static const auto dump_type = kDebuggerdTombstone;
1651 StartProcess(
1652 []() {
1653 std::thread abort_thread([] { abort(); });
1654 abort_thread.join();
1655 },
1656 &seccomp_fork);
1657
1658 StartIntercept(&output_fd, dump_type);
1659 FinishCrasher();
1660 AssertDeath(SIGABRT);
1661 FinishIntercept(&intercept_result);
1662 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1663
1664 std::string result;
1665 ConsumeFd(std::move(output_fd), &result);
Xiaohui Niu7bfbe412024-04-26 11:08:15 +08001666 ASSERT_MATCH(
1667 result,
1668 R"(signal 6 \(SIGABRT\))");
Christopher Ferris303c6be2022-05-24 17:08:33 -07001669 ASSERT_BACKTRACE_FRAME(result, "abort");
1670}
1671
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001672TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1673 int intercept_result;
1674 unique_fd output_fd;
1675
1676 static const auto dump_type = kDebuggerdTombstone;
1677 StartProcess(
1678 []() {
1679 std::thread a(foo);
1680 std::thread b(bar);
1681
1682 std::this_thread::sleep_for(100ms);
1683
1684 std::thread abort_thread([] { abort(); });
1685 abort_thread.join();
1686 },
1687 &seccomp_fork);
1688
1689 StartIntercept(&output_fd, dump_type);
1690 FinishCrasher();
1691 AssertDeath(SIGABRT);
1692 FinishIntercept(&intercept_result);
1693 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1694
1695 std::string result;
1696 ConsumeFd(std::move(output_fd), &result);
1697 ASSERT_BACKTRACE_FRAME(result, "abort");
1698 ASSERT_BACKTRACE_FRAME(result, "foo");
1699 ASSERT_BACKTRACE_FRAME(result, "bar");
1700 ASSERT_BACKTRACE_FRAME(result, "main");
1701}
1702
Josh Gaoe04ca272018-01-16 15:38:17 -08001703TEST_F(CrasherTest, seccomp_backtrace) {
1704 int intercept_result;
1705 unique_fd output_fd;
1706
1707 static const auto dump_type = kDebuggerdNativeBacktrace;
1708 StartProcess(
1709 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001710 std::thread a(foo);
1711 std::thread b(bar);
1712
1713 std::this_thread::sleep_for(100ms);
1714
Josh Gaoe04ca272018-01-16 15:38:17 -08001715 raise_debugger_signal(dump_type);
1716 _exit(0);
1717 },
1718 &seccomp_fork);
1719
1720 StartIntercept(&output_fd, dump_type);
1721 FinishCrasher();
1722 AssertDeath(0);
1723 FinishIntercept(&intercept_result);
1724 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1725
1726 std::string result;
1727 ConsumeFd(std::move(output_fd), &result);
1728 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001729 ASSERT_BACKTRACE_FRAME(result, "foo");
1730 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001731}
1732
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001733TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1734 int intercept_result;
1735 unique_fd output_fd;
1736
1737 static const auto dump_type = kDebuggerdNativeBacktrace;
1738 StartProcess(
1739 []() {
1740 std::thread a(foo);
1741 std::thread b(bar);
1742
1743 std::this_thread::sleep_for(100ms);
1744
1745 std::thread raise_thread([] {
1746 raise_debugger_signal(dump_type);
1747 _exit(0);
1748 });
1749 raise_thread.join();
1750 },
1751 &seccomp_fork);
1752
1753 StartIntercept(&output_fd, dump_type);
1754 FinishCrasher();
1755 AssertDeath(0);
1756 FinishIntercept(&intercept_result);
1757 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1758
1759 std::string result;
1760 ConsumeFd(std::move(output_fd), &result);
1761 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1762 ASSERT_BACKTRACE_FRAME(result, "foo");
1763 ASSERT_BACKTRACE_FRAME(result, "bar");
1764 ASSERT_BACKTRACE_FRAME(result, "main");
1765}
1766
Josh Gaoe04ca272018-01-16 15:38:17 -08001767TEST_F(CrasherTest, seccomp_crash_logcat) {
1768 StartProcess([]() { abort(); }, &seccomp_fork);
1769 FinishCrasher();
1770
1771 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1772 AssertDeath(SIGABRT);
1773}
1774
Christopher Ferris469b62a2024-08-26 20:33:15 +00001775extern "C" void malloc_enable();
1776extern "C" void malloc_disable();
1777
1778TEST_F(CrasherTest, seccomp_tombstone_no_allocation) {
1779 int intercept_result;
1780 unique_fd output_fd;
1781
1782 static const auto dump_type = kDebuggerdTombstone;
1783 StartProcess(
1784 []() {
1785 std::thread a(foo);
1786 std::thread b(bar);
1787
1788 std::this_thread::sleep_for(100ms);
1789
1790 // Disable allocations to verify that nothing in the fallback
1791 // signal handler does an allocation.
1792 malloc_disable();
1793 raise_debugger_signal(dump_type);
1794 _exit(0);
1795 },
1796 &seccomp_fork);
1797
1798 StartIntercept(&output_fd, dump_type);
1799 FinishCrasher();
1800 AssertDeath(0);
1801 FinishIntercept(&intercept_result);
1802 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1803
1804 std::string result;
1805 ConsumeFd(std::move(output_fd), &result);
1806 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1807 ASSERT_BACKTRACE_FRAME(result, "foo");
1808 ASSERT_BACKTRACE_FRAME(result, "bar");
1809}
1810
1811TEST_F(CrasherTest, seccomp_backtrace_no_allocation) {
1812 int intercept_result;
1813 unique_fd output_fd;
1814
1815 static const auto dump_type = kDebuggerdNativeBacktrace;
1816 StartProcess(
1817 []() {
1818 std::thread a(foo);
1819 std::thread b(bar);
1820
1821 std::this_thread::sleep_for(100ms);
1822
1823 // Disable allocations to verify that nothing in the fallback
1824 // signal handler does an allocation.
1825 malloc_disable();
1826 raise_debugger_signal(dump_type);
1827 _exit(0);
1828 },
1829 &seccomp_fork);
1830
1831 StartIntercept(&output_fd, dump_type);
1832 FinishCrasher();
1833 AssertDeath(0);
1834 FinishIntercept(&intercept_result);
1835 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1836
1837 std::string result;
1838 ConsumeFd(std::move(output_fd), &result);
1839 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1840 ASSERT_BACKTRACE_FRAME(result, "foo");
1841 ASSERT_BACKTRACE_FRAME(result, "bar");
1842}
1843
Josh Gaofd13bf02017-08-18 15:37:26 -07001844TEST_F(CrasherTest, competing_tracer) {
1845 int intercept_result;
1846 unique_fd output_fd;
1847 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001848 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001849 });
1850
1851 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001852
1853 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001854 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001855
1856 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001857 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001858 ASSERT_TRUE(WIFSTOPPED(status));
1859 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1860
1861 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1862 FinishIntercept(&intercept_result);
1863 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1864
1865 std::string result;
1866 ConsumeFd(std::move(output_fd), &result);
1867 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1868 regex += std::to_string(gettid());
1869 regex += R"( \(.+debuggerd_test)";
1870 ASSERT_MATCH(result, regex.c_str());
1871
Christopher Ferris172b0a02019-09-18 17:48:30 -07001872 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001873 ASSERT_TRUE(WIFSTOPPED(status));
1874 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1875
Josh Gaofd13bf02017-08-18 15:37:26 -07001876 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1877 AssertDeath(SIGABRT);
1878}
1879
Mitch Phillips18ce5422023-01-19 14:23:49 -08001880struct GwpAsanTestParameters {
1881 size_t alloc_size;
1882 bool free_before_access;
1883 int access_offset;
1884 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1885};
1886
1887struct GwpAsanCrasherTest
1888 : CrasherTest,
1889 testing::WithParamInterface<
1890 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1891
1892GwpAsanTestParameters gwp_asan_tests[] = {
1893 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1894 "Use After Free, 0 bytes into a 7-byte allocation"},
1895 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1896 "Use After Free, 1 byte into a 15-byte allocation"},
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07001897 {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
1898 /* access_offset */ getpagesize() + 2,
1899 android::base::StringPrintf("Buffer Overflow, 2 bytes right of a %d-byte allocation",
1900 getpagesize())},
1901 {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
1902 /* access_offset */ -1,
1903 android::base::StringPrintf("Buffer Underflow, 1 byte left of a %d-byte allocation",
1904 getpagesize())},
Mitch Phillips18ce5422023-01-19 14:23:49 -08001905};
1906
1907INSTANTIATE_TEST_SUITE_P(
1908 GwpAsanTests, GwpAsanCrasherTest,
1909 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1910 /* recoverable */ testing::Bool(),
1911 /* seccomp */ testing::Bool()),
1912 [](const testing::TestParamInfo<
1913 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1914 const GwpAsanTestParameters& params = std::get<0>(info.param);
1915 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1916 name += testing::PrintToString(params.alloc_size);
1917 name += "Alloc";
1918 if (params.access_offset < 0) {
1919 name += "Left";
1920 name += testing::PrintToString(params.access_offset * -1);
1921 } else {
1922 name += "Right";
1923 name += testing::PrintToString(params.access_offset);
1924 }
1925 name += "Bytes";
1926 if (std::get<1>(info.param)) name += "Recoverable";
1927 if (std::get<2>(info.param)) name += "Seccomp";
1928 return name;
1929 });
1930
1931TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1932 if (mte_supported()) {
1933 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1934 // instead of GWP-ASan.
1935 GTEST_SKIP() << "Skipped on MTE.";
1936 }
1937 // Skip this test on HWASan, which will reliably catch test errors as well.
1938 SKIP_WITH_HWASAN;
1939
1940 GwpAsanTestParameters params = std::get<0>(GetParam());
1941 bool recoverable = std::get<1>(GetParam());
1942 LogcatCollector logcat_collector;
1943
1944 int intercept_result;
1945 unique_fd output_fd;
1946 StartProcess([&recoverable]() {
1947 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1948 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
Mitch Phillipsa2f53352024-04-09 15:59:12 +02001949 if (!recoverable) {
1950 env[3] = "GWP_ASAN_RECOVERABLE=false";
Mitch Phillips18ce5422023-01-19 14:23:49 -08001951 }
1952 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1953 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1954 "DISABLED_run_gwp_asan_test");
1955 std::string test_filter = "--gtest_filter=*";
1956 test_filter += test_name;
1957 std::string this_binary = android::base::GetExecutablePath();
1958 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1959 test_filter.c_str(), nullptr};
1960 // We check the crash report from a debuggerd handler and from logcat. The
1961 // echo from stdout/stderr of the subprocess trips up atest, because it
1962 // doesn't like that two tests started in a row without the first one
1963 // finishing (even though the second one is in a subprocess).
1964 close(STDOUT_FILENO);
1965 close(STDERR_FILENO);
1966 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1967 });
1968
1969 StartIntercept(&output_fd);
1970 FinishCrasher();
1971 if (recoverable) {
1972 AssertDeath(0);
1973 } else {
1974 AssertDeath(SIGSEGV);
1975 }
1976 FinishIntercept(&intercept_result);
1977
1978 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1979
1980 std::vector<std::string> log_sources(2);
1981 ConsumeFd(std::move(output_fd), &log_sources[0]);
1982 logcat_collector.Collect(&log_sources[1]);
1983
1984 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1985 // information. Make sure the recovery still works, but the report won't be
1986 // hugely useful, it looks like a regular SEGV.
1987 bool seccomp = std::get<2>(GetParam());
1988 if (!seccomp) {
1989 for (const auto& result : log_sources) {
1990 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1991 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1992 if (params.free_before_access) {
1993 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1994 }
1995 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1996 }
1997 }
1998}
1999
2000TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
2001 GwpAsanTestParameters params = std::get<0>(GetParam());
2002 bool seccomp = std::get<2>(GetParam());
2003 if (seccomp) {
2004 ScopedMinijail jail{minijail_new()};
2005 setup_jail(jail.get());
2006 minijail_enter(jail.get());
2007 }
2008
2009 // Use 'volatile' to prevent a very clever compiler eliminating the store.
2010 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
2011 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
2012 p[params.access_offset] = 42;
2013 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08002014
2015 bool recoverable = std::get<1>(GetParam());
2016 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
2017
2018 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
2019 // we end with at least one in a different slot), make sure the process still
2020 // doesn't crash.
2021 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
2022 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
2023 free(static_cast<void*>(const_cast<char*>(p)));
2024 free(static_cast<void*>(const_cast<char*>(p2)));
2025 *p = 42;
2026 *p2 = 42;
2027
2028 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
2029 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
2030 // coverage does. Thus, skip the atexit handlers.
2031 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08002032}
2033
Josh Gaobf06a402018-08-27 16:34:01 -07002034TEST_F(CrasherTest, fdsan_warning_abort_message) {
2035 int intercept_result;
2036 unique_fd output_fd;
2037
2038 StartProcess([]() {
2039 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07002040 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07002041 if (fd == -1) {
2042 abort();
2043 }
2044 close(fd.get());
2045 _exit(0);
2046 });
2047
2048 StartIntercept(&output_fd);
2049 FinishCrasher();
2050 AssertDeath(0);
2051 FinishIntercept(&intercept_result);
2052 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2053
2054 std::string result;
2055 ConsumeFd(std::move(output_fd), &result);
2056 ASSERT_MATCH(result, "Abort message: 'attempted to close");
2057}
2058
Josh Gaoc3c8c022017-02-13 16:36:18 -08002059TEST(crash_dump, zombie) {
2060 pid_t forkpid = fork();
2061
Josh Gaoc3c8c022017-02-13 16:36:18 -08002062 pid_t rc;
2063 int status;
2064
2065 if (forkpid == 0) {
2066 errno = 0;
2067 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
2068 if (rc != -1 || errno != ECHILD) {
2069 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
2070 }
2071
Josh Gaoa48b41b2019-12-13 14:11:04 -08002072 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08002073
2074 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07002075 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08002076 if (rc != -1 || errno != ECHILD) {
2077 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
2078 }
2079 _exit(0);
2080 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07002081 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08002082 ASSERT_EQ(forkpid, rc);
2083 ASSERT_TRUE(WIFEXITED(status));
2084 ASSERT_EQ(0, WEXITSTATUS(status));
2085 }
2086}
Josh Gao352a8452017-03-30 16:46:21 -07002087
2088TEST(tombstoned, no_notify) {
2089 // Do this a few times.
2090 for (int i = 0; i < 3; ++i) {
2091 pid_t pid = 123'456'789 + i;
2092
2093 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002094 InterceptResponse response = {};
2095 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2096 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2097 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002098
2099 {
2100 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01002101 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07002102 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2103 }
2104
2105 pid_t read_pid;
2106 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2107 ASSERT_EQ(read_pid, pid);
2108 }
2109}
2110
2111TEST(tombstoned, stress) {
2112 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
2113 static constexpr int kDumpCount = 100;
2114
2115 std::atomic<bool> start(false);
2116 std::vector<std::thread> threads;
2117 threads.emplace_back([&start]() {
2118 while (!start) {
2119 continue;
2120 }
2121
2122 // Use a way out of range pid, to avoid stomping on an actual process.
2123 pid_t pid_base = 1'000'000;
2124
2125 for (int dump = 0; dump < kDumpCount; ++dump) {
2126 pid_t pid = pid_base + dump;
2127
2128 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002129 InterceptResponse response = {};
2130 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2131 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2132 << "Error messeage: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002133
2134 // Pretend to crash, and then immediately close the socket.
2135 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
2136 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
2137 if (sockfd == -1) {
2138 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
2139 }
2140 TombstonedCrashPacket packet = {};
2141 packet.packet_type = CrashPacketType::kDumpRequest;
2142 packet.packet.dump_request.pid = pid;
2143 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
2144 FAIL() << "failed to write to tombstoned: " << strerror(errno);
2145 }
2146
2147 continue;
2148 }
2149 });
2150
2151 threads.emplace_back([&start]() {
2152 while (!start) {
2153 continue;
2154 }
2155
2156 // Use a way out of range pid, to avoid stomping on an actual process.
2157 pid_t pid_base = 2'000'000;
2158
2159 for (int dump = 0; dump < kDumpCount; ++dump) {
2160 pid_t pid = pid_base + dump;
2161
2162 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002163 InterceptResponse response = {};
2164 tombstoned_intercept(pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2165 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2166 << "Error message: " << response.error_message;
Josh Gao352a8452017-03-30 16:46:21 -07002167
2168 {
2169 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01002170 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07002171 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
2172 tombstoned_notify_completion(tombstoned_socket.get());
2173 }
2174
2175 // TODO: Fix the race that requires this sleep.
2176 std::this_thread::sleep_for(50ms);
2177
2178 pid_t read_pid;
2179 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
2180 ASSERT_EQ(read_pid, pid);
2181 }
2182 });
2183
2184 start = true;
2185
2186 for (std::thread& thread : threads) {
2187 thread.join();
2188 }
2189}
Narayan Kamathca5e9082017-06-02 15:42:06 +01002190
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002191TEST(tombstoned, intercept_java_trace_smoke) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002192 // Using a "real" PID is a little dangerous here - if the test fails
2193 // or crashes, we might end up getting a bogus / unreliable stack
2194 // trace.
2195 const pid_t self = getpid();
2196
2197 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002198 InterceptResponse response = {};
2199 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2200 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2201 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002202
Josh Gao76e1e302021-01-26 15:53:11 -08002203 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01002204 // should result in a "regular" FD and not the installed intercept.
2205 const char native[] = "native";
2206 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002207 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01002208 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
2209 tombstoned_notify_completion(tombstoned_socket.get());
2210
2211 // Then, connect to tombstoned asking for a java backtrace. This *should*
2212 // trigger the intercept.
2213 const char java[] = "java";
2214 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
2215 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
2216 tombstoned_notify_completion(tombstoned_socket.get());
2217
2218 char outbuf[sizeof(java)];
2219 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2220 ASSERT_STREQ("java", outbuf);
2221}
2222
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002223TEST(tombstoned, intercept_multiple_dump_types) {
Narayan Kamathca5e9082017-06-02 15:42:06 +01002224 const pid_t fake_pid = 1'234'567;
2225 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002226 InterceptResponse response = {};
2227 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdJavaBacktrace);
2228 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2229 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002230
2231 unique_fd intercept_fd_2, output_fd_2;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002232 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &response,
2233 kDebuggerdNativeBacktrace);
2234 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2235 << "Error message: " << response.error_message;
2236}
2237
2238TEST(tombstoned, intercept_bad_pid) {
2239 const pid_t fake_pid = -1;
2240 unique_fd intercept_fd, output_fd;
2241 InterceptResponse response = {};
2242 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2243 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2244 << "Error message: " << response.error_message;
2245 ASSERT_MATCH(response.error_message, "bad pid");
2246}
2247
2248TEST(tombstoned, intercept_bad_dump_types) {
2249 const pid_t fake_pid = 1'234'567;
2250 unique_fd intercept_fd, output_fd;
2251 InterceptResponse response = {};
2252 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response,
2253 static_cast<DebuggerdDumpType>(20));
2254 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2255 << "Error message: " << response.error_message;
2256 ASSERT_MATCH(response.error_message, "bad dump type \\[unknown\\]");
2257
2258 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdAnyIntercept);
2259 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2260 << "Error message: " << response.error_message;
2261 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdAnyIntercept");
2262
2263 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstoneProto);
2264 ASSERT_EQ(InterceptStatus::kFailed, response.status)
2265 << "Error message: " << response.error_message;
2266 ASSERT_MATCH(response.error_message, "bad dump type kDebuggerdTombstoneProto");
2267}
2268
2269TEST(tombstoned, intercept_already_registered) {
2270 const pid_t fake_pid = 1'234'567;
2271 unique_fd intercept_fd1, output_fd1;
2272 InterceptResponse response = {};
2273 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdTombstone);
2274 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2275 << "Error message: " << response.error_message;
2276
2277 unique_fd intercept_fd2, output_fd2;
2278 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdTombstone);
2279 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, response.status)
2280 << "Error message: " << response.error_message;
2281 ASSERT_MATCH(response.error_message, "already registered, type kDebuggerdTombstone");
2282}
2283
2284TEST(tombstoned, intercept_tombstone_proto_matched_to_tombstone) {
2285 const pid_t fake_pid = 1'234'567;
2286
2287 unique_fd intercept_fd, output_fd;
2288 InterceptResponse response = {};
2289 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2290 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2291 << "Error message: " << response.error_message;
2292
2293 const char data[] = "tombstone_proto";
2294 unique_fd tombstoned_socket, input_fd;
2295 ASSERT_TRUE(
2296 tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdTombstoneProto));
2297 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), data, sizeof(data)));
2298 tombstoned_notify_completion(tombstoned_socket.get());
2299
2300 char outbuf[sizeof(data)];
2301 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2302 ASSERT_STREQ("tombstone_proto", outbuf);
Narayan Kamathca5e9082017-06-02 15:42:06 +01002303}
2304
2305TEST(tombstoned, intercept_any) {
2306 const pid_t fake_pid = 1'234'567;
2307
2308 unique_fd intercept_fd, output_fd;
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002309 InterceptResponse response = {};
2310 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &response, kDebuggerdNativeBacktrace);
2311 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2312 << "Error message: " << response.error_message;
Narayan Kamathca5e9082017-06-02 15:42:06 +01002313
2314 const char any[] = "any";
2315 unique_fd tombstoned_socket, input_fd;
2316 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2317 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
2318 tombstoned_notify_completion(tombstoned_socket.get());
2319
2320 char outbuf[sizeof(any)];
2321 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
2322 ASSERT_STREQ("any", outbuf);
2323}
Josh Gao2b22ae12018-09-12 14:51:03 -07002324
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002325TEST(tombstoned, intercept_any_failed_with_multiple_intercepts) {
2326 const pid_t fake_pid = 1'234'567;
2327
2328 InterceptResponse response = {};
2329 unique_fd intercept_fd1, output_fd1;
2330 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2331 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2332 << "Error message: " << response.error_message;
2333
2334 unique_fd intercept_fd2, output_fd2;
2335 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2336 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2337 << "Error message: " << response.error_message;
2338
2339 unique_fd tombstoned_socket, input_fd;
2340 ASSERT_FALSE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
2341}
2342
2343TEST(tombstoned, intercept_multiple_verify_intercept) {
2344 // Need to use our pid for java since that will verify the pid.
2345 const pid_t fake_pid = getpid();
2346
2347 InterceptResponse response = {};
2348 unique_fd intercept_fd1, output_fd1;
2349 tombstoned_intercept(fake_pid, &intercept_fd1, &output_fd1, &response, kDebuggerdNativeBacktrace);
2350 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2351 << "Error message: " << response.error_message;
2352
2353 unique_fd intercept_fd2, output_fd2;
2354 tombstoned_intercept(fake_pid, &intercept_fd2, &output_fd2, &response, kDebuggerdJavaBacktrace);
2355 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2356 << "Error message: " << response.error_message;
2357
2358 unique_fd intercept_fd3, output_fd3;
2359 tombstoned_intercept(fake_pid, &intercept_fd3, &output_fd3, &response, kDebuggerdTombstone);
2360 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2361 << "Error message: " << response.error_message;
2362
2363 const char native_data[] = "native";
2364 unique_fd tombstoned_socket1, input_fd1;
2365 ASSERT_TRUE(
2366 tombstoned_connect(fake_pid, &tombstoned_socket1, &input_fd1, kDebuggerdNativeBacktrace));
2367 ASSERT_TRUE(android::base::WriteFully(input_fd1.get(), native_data, sizeof(native_data)));
2368 tombstoned_notify_completion(tombstoned_socket1.get());
2369
2370 char native_outbuf[sizeof(native_data)];
2371 ASSERT_TRUE(android::base::ReadFully(output_fd1.get(), native_outbuf, sizeof(native_outbuf)));
2372 ASSERT_STREQ("native", native_outbuf);
2373
2374 const char java_data[] = "java";
2375 unique_fd tombstoned_socket2, input_fd2;
2376 ASSERT_TRUE(
2377 tombstoned_connect(fake_pid, &tombstoned_socket2, &input_fd2, kDebuggerdJavaBacktrace));
2378 ASSERT_TRUE(android::base::WriteFully(input_fd2.get(), java_data, sizeof(java_data)));
2379 tombstoned_notify_completion(tombstoned_socket2.get());
2380
2381 char java_outbuf[sizeof(java_data)];
2382 ASSERT_TRUE(android::base::ReadFully(output_fd2.get(), java_outbuf, sizeof(java_outbuf)));
2383 ASSERT_STREQ("java", java_outbuf);
2384
2385 const char tomb_data[] = "tombstone";
2386 unique_fd tombstoned_socket3, input_fd3;
2387 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket3, &input_fd3, kDebuggerdTombstone));
2388 ASSERT_TRUE(android::base::WriteFully(input_fd3.get(), tomb_data, sizeof(tomb_data)));
2389 tombstoned_notify_completion(tombstoned_socket3.get());
2390
2391 char tomb_outbuf[sizeof(tomb_data)];
2392 ASSERT_TRUE(android::base::ReadFully(output_fd3.get(), tomb_outbuf, sizeof(tomb_outbuf)));
2393 ASSERT_STREQ("tombstone", tomb_outbuf);
2394}
2395
Josh Gao2b22ae12018-09-12 14:51:03 -07002396TEST(tombstoned, interceptless_backtrace) {
2397 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
2398 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
2399 std::map<int, time_t> result;
2400 for (int i = 0; i < 99; ++i) {
2401 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
2402 struct stat st;
2403 if (stat(path.c_str(), &st) == 0) {
2404 result[i] = st.st_mtim.tv_sec;
2405 }
2406 }
2407 return result;
2408 };
2409
2410 auto before = get_tombstone_timestamps();
2411 for (int i = 0; i < 50; ++i) {
2412 raise_debugger_signal(kDebuggerdNativeBacktrace);
2413 }
2414 auto after = get_tombstone_timestamps();
2415
2416 int diff = 0;
2417 for (int i = 0; i < 99; ++i) {
2418 if (after.count(i) == 0) {
2419 continue;
2420 }
2421 if (before.count(i) == 0) {
2422 ++diff;
2423 continue;
2424 }
2425 if (before[i] != after[i]) {
2426 ++diff;
2427 }
2428 }
2429
2430 // We can't be sure that nothing's crash looping in the background.
2431 // This should be good enough, though...
2432 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
2433}
Christopher Ferris481e8372019-07-15 17:13:24 -07002434
2435static __attribute__((__noinline__)) void overflow_stack(void* p) {
2436 void* buf[1];
2437 buf[0] = p;
2438 static volatile void* global = buf;
2439 if (global) {
2440 global = buf;
2441 overflow_stack(&buf);
2442 }
2443}
2444
2445TEST_F(CrasherTest, stack_overflow) {
2446 int intercept_result;
2447 unique_fd output_fd;
2448 StartProcess([]() { overflow_stack(nullptr); });
2449
2450 StartIntercept(&output_fd);
2451 FinishCrasher();
2452 AssertDeath(SIGSEGV);
2453 FinishIntercept(&intercept_result);
2454
2455 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2456
2457 std::string result;
2458 ConsumeFd(std::move(output_fd), &result);
2459 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
2460}
Josh Gao76e1e302021-01-26 15:53:11 -08002461
Christopher Ferris22035cc2023-01-31 17:50:22 -08002462static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002463 std::string test_lib(testing::internal::GetArgvs()[0]);
2464 auto const value = test_lib.find_last_of('/');
2465 if (value == std::string::npos) {
2466 test_lib = "./";
2467 } else {
2468 test_lib = test_lib.substr(0, value + 1) + "./";
2469 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08002470 return test_lib + "libcrash_test.so";
2471}
2472
2473static void CreateEmbeddedLibrary(int out_fd) {
2474 std::string test_lib(GetTestLibraryPath());
2475 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
2476 ASSERT_NE(fd.get(), -1);
2477 off_t file_size = lseek(fd, 0, SEEK_END);
2478 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2479 std::vector<uint8_t> contents(file_size);
2480 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2481
2482 // Put the shared library data at a pagesize() offset.
2483 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2484 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2485}
2486
2487TEST_F(CrasherTest, non_zero_offset_in_library) {
2488 int intercept_result;
2489 unique_fd output_fd;
2490 TemporaryFile tf;
2491 CreateEmbeddedLibrary(tf.fd);
2492 StartProcess([&tf]() {
2493 android_dlextinfo extinfo{};
2494 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2495 extinfo.library_fd = tf.fd;
2496 extinfo.library_fd_offset = 4 * getpagesize();
2497 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2498 if (handle == nullptr) {
2499 _exit(1);
2500 }
2501 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2502 if (crash_func == nullptr) {
2503 _exit(1);
2504 }
2505 crash_func();
2506 });
2507
2508 StartIntercept(&output_fd);
2509 FinishCrasher();
2510 AssertDeath(SIGSEGV);
2511 FinishIntercept(&intercept_result);
2512
2513 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2514
2515 std::string result;
2516 ConsumeFd(std::move(output_fd), &result);
2517
2518 // Verify the crash includes an offset value in the backtrace.
2519 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2520 tf.path, 4 * getpagesize());
2521 ASSERT_MATCH(result, match_str);
2522}
2523
2524static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2525 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002526
2527 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2528 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2529
2530 // Copy the shared so to a tempory directory.
2531 return system(cp_cmd.c_str()) == 0;
2532}
2533
2534TEST_F(CrasherTest, unreadable_elf) {
2535 int intercept_result;
2536 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002537 std::string tmp_so_name;
2538 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002539 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002540 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2541 _exit(1);
2542 }
2543 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2544 if (handle == nullptr) {
2545 _exit(1);
2546 }
2547 // Delete the original shared library so that we get the warning
2548 // about unreadable elf files.
2549 if (unlink(tmp_so_name.c_str()) == -1) {
2550 _exit(1);
2551 }
2552 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2553 if (crash_func == nullptr) {
2554 _exit(1);
2555 }
2556 crash_func();
2557 });
2558
2559 StartIntercept(&output_fd);
2560 FinishCrasher();
2561 AssertDeath(SIGSEGV);
2562 FinishIntercept(&intercept_result);
2563
2564 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2565
2566 std::string result;
2567 ConsumeFd(std::move(output_fd), &result);
2568 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002569 std::string match_str = "NOTE: " + tmp_so_name;
2570 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002571}
2572
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002573void CheckForTombstone(const struct stat& text_st, std::optional<std::string>& tombstone_file) {
2574 static std::regex tombstone_re("tombstone_\\d+");
Christopher Ferris35da2882021-02-17 15:39:06 -08002575 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2576 ASSERT_TRUE(dir_h != nullptr);
Christopher Ferris35da2882021-02-17 15:39:06 -08002577 dirent* entry;
2578 while ((entry = readdir(dir_h.get())) != nullptr) {
2579 if (!std::regex_match(entry->d_name, tombstone_re)) {
2580 continue;
2581 }
2582 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002583
2584 struct stat st;
2585 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2586 continue;
2587 }
2588
2589 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002590 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002591 break;
2592 }
2593 }
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002594}
Josh Gao76e1e302021-01-26 15:53:11 -08002595
Christopher Ferris20f50ec2024-01-03 02:30:03 +00002596TEST(tombstoned, proto) {
2597 const pid_t self = getpid();
2598 unique_fd tombstoned_socket, text_fd, proto_fd;
2599 ASSERT_TRUE(
2600 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2601
2602 tombstoned_notify_completion(tombstoned_socket.get());
2603
2604 ASSERT_NE(-1, text_fd.get());
2605 ASSERT_NE(-1, proto_fd.get());
2606
2607 struct stat text_st;
2608 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2609
2610 std::optional<std::string> tombstone_file;
2611 // Allow up to 5 seconds for the tombstone to be written to the system.
2612 const auto max_wait_time = std::chrono::seconds(5) * android::base::HwTimeoutMultiplier();
2613 const auto start = std::chrono::high_resolution_clock::now();
2614 while (true) {
2615 std::this_thread::sleep_for(100ms);
2616 CheckForTombstone(text_st, tombstone_file);
2617 if (tombstone_file) {
2618 break;
2619 }
2620 if (std::chrono::high_resolution_clock::now() - start > max_wait_time) {
2621 break;
2622 }
2623 }
2624
2625 ASSERT_TRUE(tombstone_file) << "Timed out trying to find tombstone file.";
Christopher Ferris35da2882021-02-17 15:39:06 -08002626 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002627
2628 struct stat proto_fd_st;
2629 struct stat proto_file_st;
2630 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2631 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2632
2633 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2634 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2635}
2636
2637TEST(tombstoned, proto_intercept) {
2638 const pid_t self = getpid();
2639 unique_fd intercept_fd, output_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08002640
Christopher Ferrisb92b52c2023-10-16 19:14:28 -07002641 InterceptResponse response = {};
2642 tombstoned_intercept(self, &intercept_fd, &output_fd, &response, kDebuggerdTombstone);
2643 ASSERT_EQ(InterceptStatus::kRegistered, response.status)
2644 << "Error message: " << response.error_message;
Josh Gao76e1e302021-01-26 15:53:11 -08002645
2646 unique_fd tombstoned_socket, text_fd, proto_fd;
2647 ASSERT_TRUE(
2648 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2649 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2650 tombstoned_notify_completion(tombstoned_socket.get());
2651
2652 text_fd.reset();
2653
2654 std::string output;
2655 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2656 ASSERT_EQ("foo", output);
2657}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002658
2659// Verify that when an intercept is present for the main thread, and the signal
2660// is received on a different thread, the intercept still works.
2661TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2662 StartProcess([]() {
2663 std::thread thread([]() {
2664 // Raise the signal on the side thread.
2665 raise_debugger_signal(kDebuggerdNativeBacktrace);
2666 });
2667 thread.join();
2668 _exit(0);
2669 });
2670
2671 unique_fd output_fd;
2672 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2673 FinishCrasher();
2674 AssertDeath(0);
2675
2676 int intercept_result;
2677 FinishIntercept(&intercept_result);
2678 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2679
2680 std::string result;
2681 ConsumeFd(std::move(output_fd), &result);
2682 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2683}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002684
2685static std::string format_pointer(uintptr_t ptr) {
2686#if defined(__LP64__)
2687 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2688 static_cast<uint32_t>(ptr & 0xffffffff));
2689#else
2690 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2691#endif
2692}
2693
2694static std::string format_pointer(void* ptr) {
2695 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2696}
2697
2698static std::string format_full_pointer(uintptr_t ptr) {
2699#if defined(__LP64__)
2700 return android::base::StringPrintf("%016" PRIx64, ptr);
2701#else
2702 return android::base::StringPrintf("%08x", ptr);
2703#endif
2704}
2705
2706static std::string format_full_pointer(void* ptr) {
2707 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2708}
2709
2710__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2711 int* crash_ptr = reinterpret_cast<int*>(ptr);
2712 *crash_ptr = 1;
2713 return *crash_ptr;
2714}
2715
2716// Verify that a fault address before the first map is properly handled.
2717TEST_F(CrasherTest, fault_address_before_first_map) {
2718 StartProcess([]() {
2719 ASSERT_EQ(0, crash_call(0x1024));
2720 _exit(0);
2721 });
2722
2723 unique_fd output_fd;
2724 StartIntercept(&output_fd);
2725 FinishCrasher();
2726 AssertDeath(SIGSEGV);
2727
2728 int intercept_result;
2729 FinishIntercept(&intercept_result);
2730 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2731
2732 std::string result;
2733 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002734 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002735
2736 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2737
2738 std::string match_str = android::base::StringPrintf(
2739 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2740 format_pointer(0x1024).c_str());
2741 ASSERT_MATCH(result, match_str);
2742}
2743
2744// Verify that a fault address after the last map is properly handled.
2745TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002746 // This makes assumptions about the memory layout that are not true in HWASan
2747 // processes.
2748 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002749 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2750 StartProcess([crash_uptr]() {
2751 ASSERT_EQ(0, crash_call(crash_uptr));
2752 _exit(0);
2753 });
2754
2755 unique_fd output_fd;
2756 StartIntercept(&output_fd);
2757 FinishCrasher();
2758 AssertDeath(SIGSEGV);
2759
2760 int intercept_result;
2761 FinishIntercept(&intercept_result);
2762 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2763
2764 std::string result;
2765 ConsumeFd(std::move(output_fd), &result);
2766
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002767 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2768 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002769 ASSERT_MATCH(result, match_str);
2770
Ryan Prichardbc227032024-02-29 14:40:57 -08002771 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002772
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002773 // Verifies that the fault address error message is at the end of the
2774 // maps section. To do this, the check below looks for the start of the
2775 // open files section or the start of the log file section. It's possible
2776 // for either of these sections to be present after the maps section right
2777 // now.
2778 // If the sections move around, this check might need to be modified.
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002779 match_str = android::base::StringPrintf(
Christopher Ferris3a0833c2023-07-28 13:07:53 -07002780 R"(\n--->Fault address falls at %s after any mapped regions\n(---------|\nopen files:))",
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002781 format_pointer(crash_uptr).c_str());
2782 ASSERT_MATCH(result, match_str);
2783}
2784
2785// Verify that a fault address between maps is properly handled.
2786TEST_F(CrasherTest, fault_address_between_maps) {
2787 // Create a map before the fork so it will be present in the child.
2788 void* start_ptr =
2789 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2790 ASSERT_NE(MAP_FAILED, start_ptr);
2791 // Unmap the page in the middle.
2792 void* middle_ptr =
2793 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2794 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2795
2796 StartProcess([middle_ptr]() {
2797 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2798 _exit(0);
2799 });
2800
2801 // Unmap the two maps.
2802 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2803 void* end_ptr =
2804 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2805 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2806
2807 unique_fd output_fd;
2808 StartIntercept(&output_fd);
2809 FinishCrasher();
2810 AssertDeath(SIGSEGV);
2811
2812 int intercept_result;
2813 FinishIntercept(&intercept_result);
2814 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2815
2816 std::string result;
2817 ConsumeFd(std::move(output_fd), &result);
2818
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002819 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2820 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002821 ASSERT_MATCH(result, match_str);
2822
Ryan Prichardbc227032024-02-29 14:40:57 -08002823 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002824
2825 match_str = android::base::StringPrintf(
2826 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2827 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2828 format_pointer(end_ptr).c_str());
2829 ASSERT_MATCH(result, match_str);
2830}
2831
2832// Verify that a fault address happens in the correct map.
2833TEST_F(CrasherTest, fault_address_in_map) {
2834 // Create a map before the fork so it will be present in the child.
2835 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2836 ASSERT_NE(MAP_FAILED, ptr);
2837
2838 StartProcess([ptr]() {
2839 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2840 _exit(0);
2841 });
2842
2843 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2844
2845 unique_fd output_fd;
2846 StartIntercept(&output_fd);
2847 FinishCrasher();
2848 AssertDeath(SIGSEGV);
2849
2850 int intercept_result;
2851 FinishIntercept(&intercept_result);
2852 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2853
2854 std::string result;
2855 ConsumeFd(std::move(output_fd), &result);
2856
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002857 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2858 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002859 ASSERT_MATCH(result, match_str);
2860
Ryan Prichardbc227032024-02-29 14:40:57 -08002861 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->\)\n)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002862
2863 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2864 ASSERT_MATCH(result, match_str);
2865}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002866
2867static constexpr uint32_t kDexData[] = {
2868 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2869 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2870 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2871 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2872 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2873 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2874 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2875 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2876 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2877 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2878 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2879 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2880 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2881 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2882 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2883 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2884 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2885};
2886
2887TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2888 StartProcess([]() {
2889 TemporaryDir td;
2890 std::string tmp_so_name;
2891 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2892 _exit(1);
2893 }
2894
2895 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2896 // move the library to which has a basename of libart.so.
2897 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2898 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2899 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2900 if (handle == nullptr) {
2901 _exit(1);
2902 }
2903
2904 void* ptr =
2905 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2906 ASSERT_TRUE(ptr != MAP_FAILED);
2907 memcpy(ptr, kDexData, sizeof(kDexData));
2908 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2909
2910 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2911 .symfile_size = sizeof(kDexData)};
2912
2913 JITDescriptor* dex_debug =
2914 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2915 ASSERT_TRUE(dex_debug != nullptr);
2916 dex_debug->version = 1;
2917 dex_debug->action_flag = 0;
2918 dex_debug->relevant_entry = 0;
2919 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2920
2921 // This sets the magic dex pc value for register 0, using the value
2922 // of register 1 + 0x102.
2923 asm(".cfi_escape "
2924 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2925 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2926 "0x13 /* DW_OP_drop */,"
2927 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2928
2929 // For each different architecture, set register one to the dex ptr mmap
2930 // created above. Then do a nullptr dereference to force a crash.
2931#if defined(__arm__)
2932 asm volatile(
2933 "mov r1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002934 "mov r2, #0\n"
2935 "str r2, [r2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002936 : [base] "+r"(ptr)
2937 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002938 : "r1", "r2", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002939#elif defined(__aarch64__)
2940 asm volatile(
2941 "mov x1, %[base]\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002942 "mov x2, #0\n"
2943 "str xzr, [x2]\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002944 : [base] "+r"(ptr)
2945 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002946 : "x1", "x2", "memory");
2947#elif defined(__riscv)
2948 // TODO: x1 is ra (the link register) on riscv64, so this might have
2949 // unintended consequences, but we'll need to change the .cfi_escape if so.
2950 asm volatile(
2951 "mv x1, %[base]\n"
2952 "sw zero, 0(zero)\n"
2953 : [base] "+r"(ptr)
2954 :
2955 : "x1", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002956#elif defined(__i386__)
2957 asm volatile(
2958 "mov %[base], %%ecx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002959 "movl $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002960 : [base] "+r"(ptr)
2961 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002962 : "ecx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002963#elif defined(__x86_64__)
2964 asm volatile(
2965 "mov %[base], %%rdx\n"
Elliott Hughes857e29c2023-03-20 15:48:30 -07002966 "movq $0, 0\n"
Christopher Ferris2038cc72021-09-15 03:57:10 +00002967 : [base] "+r"(ptr)
2968 :
Elliott Hughes857e29c2023-03-20 15:48:30 -07002969 : "rdx", "memory");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002970#else
2971#error "Unsupported architecture"
2972#endif
2973 _exit(0);
2974 });
2975
2976 unique_fd output_fd;
2977 StartIntercept(&output_fd);
2978 FinishCrasher();
2979 AssertDeath(SIGSEGV);
2980
2981 int intercept_result;
2982 FinishIntercept(&intercept_result);
2983 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2984
2985 std::string result;
2986 ConsumeFd(std::move(output_fd), &result);
2987
2988 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002989 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002990
2991 // Now verify that the dex_pc frame includes a proper function name.
2992 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2993}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002994
2995static std::string format_map_pointer(uintptr_t ptr) {
2996#if defined(__LP64__)
2997 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2998 static_cast<uint32_t>(ptr & 0xffffffff));
2999#else
3000 return android::base::StringPrintf("%08x", ptr);
3001#endif
3002}
3003
3004// Verify that map data is properly formatted.
3005TEST_F(CrasherTest, verify_map_format) {
3006 // Create multiple maps to make sure that the map data is formatted properly.
3007 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3008 ASSERT_NE(MAP_FAILED, none_map);
3009 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3010 ASSERT_NE(MAP_FAILED, r_map);
3011 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3012 ASSERT_NE(MAP_FAILED, w_map);
3013 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
3014 ASSERT_NE(MAP_FAILED, x_map);
3015
3016 TemporaryFile tf;
3017 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
3018 char c = 'f';
3019 ASSERT_EQ(1, write(tf.fd, &c, 1));
3020 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
3021 ASSERT_EQ(1, write(tf.fd, &c, 1));
3022 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
3023 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
3024 ASSERT_NE(MAP_FAILED, file_map);
3025
3026 StartProcess([]() { abort(); });
3027
3028 ASSERT_EQ(0, munmap(none_map, getpagesize()));
3029 ASSERT_EQ(0, munmap(r_map, getpagesize()));
3030 ASSERT_EQ(0, munmap(w_map, getpagesize()));
3031 ASSERT_EQ(0, munmap(x_map, getpagesize()));
3032 ASSERT_EQ(0, munmap(file_map, 0x3001));
3033
3034 unique_fd output_fd;
3035 StartIntercept(&output_fd);
3036 FinishCrasher();
3037 AssertDeath(SIGABRT);
3038 int intercept_result;
3039 FinishIntercept(&intercept_result);
3040
3041 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3042
3043 std::string result;
3044 ConsumeFd(std::move(output_fd), &result);
3045
3046 std::string match_str;
3047 // Verify none.
3048 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003049 " %s-%s --- 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003050 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003051 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str(),
3052 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003053 ASSERT_MATCH(result, match_str);
3054
3055 // Verify read-only.
3056 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003057 " %s-%s r-- 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003058 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003059 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str(),
3060 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003061 ASSERT_MATCH(result, match_str);
3062
3063 // Verify write-only.
3064 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003065 " %s-%s -w- 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003066 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003067 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str(),
3068 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003069 ASSERT_MATCH(result, match_str);
3070
3071 // Verify exec-only.
3072 match_str = android::base::StringPrintf(
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003073 " %s-%s --x 0 %x\\n",
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003074 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
Christopher Ferris2f77c2a2024-05-07 12:25:31 -07003075 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str(),
3076 getpagesize());
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003077 ASSERT_MATCH(result, match_str);
3078
3079 // Verify file map with non-zero offset and a name.
3080 match_str = android::base::StringPrintf(
3081 " %s-%s r-- 2000 4000 %s\\n",
3082 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
3083 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
3084 ASSERT_MATCH(result, match_str);
3085}
3086
3087// Verify that the tombstone map data is correct.
3088TEST_F(CrasherTest, verify_header) {
3089 StartProcess([]() { abort(); });
3090
3091 unique_fd output_fd;
3092 StartIntercept(&output_fd);
3093 FinishCrasher();
3094 AssertDeath(SIGABRT);
3095 int intercept_result;
3096 FinishIntercept(&intercept_result);
3097
3098 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3099
3100 std::string result;
3101 ConsumeFd(std::move(output_fd), &result);
3102
3103 std::string match_str = android::base::StringPrintf(
3104 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
3105 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
3106 android::base::GetProperty("ro.revision", "unknown").c_str());
3107 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
3108 ASSERT_MATCH(result, match_str);
3109}
3110
3111// Verify that the thread header is formatted properly.
3112TEST_F(CrasherTest, verify_thread_header) {
3113 void* shared_map =
3114 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
3115 ASSERT_NE(MAP_FAILED, shared_map);
3116 memset(shared_map, 0, sizeof(pid_t));
3117
3118 StartProcess([&shared_map]() {
3119 std::atomic_bool tid_written;
3120 std::thread thread([&tid_written, &shared_map]() {
3121 pid_t tid = gettid();
3122 memcpy(shared_map, &tid, sizeof(pid_t));
3123 tid_written = true;
3124 volatile bool done = false;
3125 while (!done)
3126 ;
3127 });
3128 thread.detach();
3129 while (!tid_written.load(std::memory_order_acquire))
3130 ;
3131 abort();
3132 });
3133
3134 pid_t primary_pid = crasher_pid;
3135
3136 unique_fd output_fd;
3137 StartIntercept(&output_fd);
3138 FinishCrasher();
3139 AssertDeath(SIGABRT);
3140 int intercept_result;
3141 FinishIntercept(&intercept_result);
3142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3143
3144 // Read the tid data out.
3145 pid_t tid;
3146 memcpy(&tid, shared_map, sizeof(pid_t));
3147 ASSERT_NE(0, tid);
3148
3149 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
3150
3151 std::string result;
3152 ConsumeFd(std::move(output_fd), &result);
3153
3154 // Verify that there are two headers, one where the tid is "primary_pid"
3155 // and the other where the tid is "tid".
3156 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
3157 primary_pid, primary_pid);
3158 ASSERT_MATCH(result, match_str);
3159
3160 match_str =
3161 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
3162 ASSERT_MATCH(result, match_str);
3163}
3164
3165// Verify that there is a BuildID present in the map section and set properly.
3166TEST_F(CrasherTest, verify_build_id) {
3167 StartProcess([]() { abort(); });
3168
3169 unique_fd output_fd;
3170 StartIntercept(&output_fd);
3171 FinishCrasher();
3172 AssertDeath(SIGABRT);
3173 int intercept_result;
3174 FinishIntercept(&intercept_result);
3175 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3176
3177 std::string result;
3178 ConsumeFd(std::move(output_fd), &result);
3179
3180 // Find every /system or /apex lib and verify the BuildID is displayed
3181 // properly.
3182 bool found_valid_elf = false;
3183 std::smatch match;
3184 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
3185 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
3186 result = match.suffix()) {
3187 if (prev_file == match[1]) {
3188 // Already checked this file.
3189 continue;
3190 }
3191
3192 prev_file = match[1];
Christopher Ferris15038902023-11-10 00:05:49 -08003193 auto elf_memory = unwindstack::Memory::CreateFileMemory(prev_file, 0);
3194 unwindstack::Elf elf(elf_memory);
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00003195 if (!elf.Init() || !elf.valid()) {
3196 // Skipping invalid elf files.
3197 continue;
3198 }
3199 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
3200
3201 found_valid_elf = true;
3202 }
3203 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
3204}
Christopher Ferrisbda10642023-04-24 18:14:53 -07003205
3206const char kLogMessage[] = "Should not see this log message.";
3207
3208// Verify that the logd process does not read the log.
3209TEST_F(CrasherTest, logd_skips_reading_logs) {
3210 StartProcess([]() {
3211 pthread_setname_np(pthread_self(), "logd");
3212 LOG(INFO) << kLogMessage;
3213 abort();
3214 });
3215
3216 unique_fd output_fd;
3217 StartIntercept(&output_fd);
3218 FinishCrasher();
3219 AssertDeath(SIGABRT);
3220 int intercept_result;
3221 FinishIntercept(&intercept_result);
3222 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3223
3224 std::string result;
3225 ConsumeFd(std::move(output_fd), &result);
3226 // logd should not contain our log message.
3227 ASSERT_NOT_MATCH(result, kLogMessage);
3228}
3229
3230// Verify that the logd process does not read the log when the non-main
3231// thread crashes.
3232TEST_F(CrasherTest, logd_skips_reading_logs_not_main_thread) {
3233 StartProcess([]() {
3234 pthread_setname_np(pthread_self(), "logd");
3235 LOG(INFO) << kLogMessage;
3236
3237 std::thread thread([]() {
3238 pthread_setname_np(pthread_self(), "not_logd_thread");
3239 // Raise the signal on the side thread.
3240 raise_debugger_signal(kDebuggerdTombstone);
3241 });
3242 thread.join();
3243 _exit(0);
3244 });
3245
3246 unique_fd output_fd;
3247 StartIntercept(&output_fd, kDebuggerdTombstone);
3248 FinishCrasher();
3249 AssertDeath(0);
3250
3251 int intercept_result;
3252 FinishIntercept(&intercept_result);
3253 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3254
3255 std::string result;
3256 ConsumeFd(std::move(output_fd), &result);
3257 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
3258 ASSERT_NOT_MATCH(result, kLogMessage);
3259}
Christopher Ferris98d62422023-05-24 20:01:10 +00003260
3261// Disable this test since there is a high liklihood that this would
3262// be flaky since it requires 500 messages being in the log.
3263TEST_F(CrasherTest, DISABLED_max_log_messages) {
3264 StartProcess([]() {
3265 for (size_t i = 0; i < 600; i++) {
3266 LOG(INFO) << "Message number " << i;
3267 }
3268 abort();
3269 });
3270
3271 unique_fd output_fd;
3272 StartIntercept(&output_fd);
3273 FinishCrasher();
3274 AssertDeath(SIGABRT);
3275 int intercept_result;
3276 FinishIntercept(&intercept_result);
3277 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3278
3279 std::string result;
3280 ConsumeFd(std::move(output_fd), &result);
3281 ASSERT_NOT_MATCH(result, "Message number 99");
3282 ASSERT_MATCH(result, "Message number 100");
3283 ASSERT_MATCH(result, "Message number 599");
3284}
3285
3286TEST_F(CrasherTest, log_with_newline) {
3287 StartProcess([]() {
3288 LOG(INFO) << "This line has a newline.\nThis is on the next line.";
3289 abort();
3290 });
3291
3292 unique_fd output_fd;
3293 StartIntercept(&output_fd);
3294 FinishCrasher();
3295 AssertDeath(SIGABRT);
3296 int intercept_result;
3297 FinishIntercept(&intercept_result);
3298 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
3299
3300 std::string result;
3301 ConsumeFd(std::move(output_fd), &result);
3302 ASSERT_MATCH(result, ":\\s*This line has a newline.");
3303 ASSERT_MATCH(result, ":\\s*This is on the next line.");
3304}