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