blob: 4d60ddbf75ab883e4eceba9fec0629d663663323 [file] [log] [blame]
Josh Gaocbe70cb2016-10-18 18:17:52 -07001/*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Christopher Ferris35da2882021-02-17 15:39:06 -080017#include <dirent.h>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070018#include <dlfcn.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070019#include <err.h>
20#include <fcntl.h>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000021#include <linux/prctl.h>
Elliott Hughes03b283a2021-01-15 11:34:26 -080022#include <malloc.h>
Josh Gaocdea7502017-11-01 15:00:40 -070023#include <stdlib.h>
Josh Gao502cfd22017-02-17 01:39:15 -080024#include <sys/capability.h>
Peter Collingbournefe8997a2020-07-20 15:08:52 -070025#include <sys/mman.h>
Josh Gaofca7ca32017-01-23 12:05:35 -080026#include <sys/prctl.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070027#include <sys/ptrace.h>
Josh Gao70adac62018-02-22 11:38:33 -080028#include <sys/resource.h>
Dan Albertc38057a2017-10-11 11:35:40 -070029#include <sys/syscall.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070030#include <sys/types.h>
Josh Gaofd13bf02017-08-18 15:37:26 -070031#include <unistd.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070032
33#include <chrono>
34#include <regex>
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000035#include <set>
Christopher Ferrisfe751c52021-04-16 09:40:40 -070036#include <string>
Josh Gaocbe70cb2016-10-18 18:17:52 -070037#include <thread>
38
Christopher Ferris22035cc2023-01-31 17:50:22 -080039#include <android/dlext.h>
Josh Gaobf06a402018-08-27 16:34:01 -070040#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080041#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080042#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070043#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080044#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080045
Josh Gao5f87bbd2019-01-09 17:01:49 -080046#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070047#include <android-base/file.h>
48#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070049#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070050#include <android-base/parseint.h>
51#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070052#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070053#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070054#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070055#include <android-base/unique_fd.h>
56#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070057#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070058#include <gtest/gtest.h>
59
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000060#include <unwindstack/Elf.h>
61#include <unwindstack/Memory.h>
62
Josh Gaoe04ca272018-01-16 15:38:17 -080063#include <libminijail.h>
64#include <scoped_minijail.h>
65
Christopher Ferris2038cc72021-09-15 03:57:10 +000066#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010067#include "debuggerd/handler.h"
Mitch Phillips18ce5422023-01-19 14:23:49 -080068#include "gtest/gtest.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070069#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010070#include "protocol.h"
71#include "tombstoned/tombstoned.h"
72#include "util.h"
73
Josh Gaocbe70cb2016-10-18 18:17:52 -070074using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080075
76using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070077using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070078using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070079
80#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070081#define ARCH_SUFFIX "64"
82#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070083#define ARCH_SUFFIX ""
84#endif
85
Elliott Hughese4781d52021-03-17 09:15:15 -070086constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070087
88#define TIMEOUT(seconds, expr) \
89 [&]() { \
90 struct sigaction old_sigaction; \
91 struct sigaction new_sigaction = {}; \
92 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080093 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070094 err(1, "sigaction failed"); \
95 } \
96 alarm(seconds); \
97 auto value = expr; \
98 int saved_errno = errno; \
99 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
100 err(1, "sigaction failed"); \
101 } \
102 alarm(0); \
103 errno = saved_errno; \
104 return value; \
105 }()
106
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700107// Backtrace frame dump could contain:
108// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
109// or
110// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800111#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700112 ASSERT_MATCH(result, \
113 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900114
Narayan Kamatha73df602017-05-24 15:07:25 +0100115static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100116 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700117 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
118 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
119 if (intercept_fd->get() == -1) {
120 FAIL() << "failed to contact tombstoned: " << strerror(errno);
121 }
122
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700123 InterceptRequest req = {
124 .dump_type = intercept_type,
125 .pid = target_pid,
126 };
Josh Gao460b3362017-03-30 16:40:47 -0700127
128 unique_fd output_pipe_write;
129 if (!Pipe(output_fd, &output_pipe_write)) {
130 FAIL() << "failed to create output pipe: " << strerror(errno);
131 }
132
133 std::string pipe_size_str;
134 int pipe_buffer_size;
135 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
136 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
137 }
138
139 pipe_size_str = android::base::Trim(pipe_size_str);
140
141 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
142 FAIL() << "failed to parse pipe max size";
143 }
144
145 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
146 FAIL() << "failed to set pipe size: " << strerror(errno);
147 }
148
Josh Gao5675f3c2017-06-01 12:19:53 -0700149 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
150
Josh Gao5f87bbd2019-01-09 17:01:49 -0800151 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
152 output_pipe_write.reset();
153 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700154 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
155 }
156
157 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800158 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700159 if (rc == -1) {
160 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
161 } else if (rc == 0) {
162 FAIL() << "failed to read response from tombstoned (EOF)";
163 } else if (rc != sizeof(response)) {
164 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
165 << ", received " << rc;
166 }
167
Narayan Kamathca5e9082017-06-02 15:42:06 +0100168 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700169}
170
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
Narayan Kamathca5e9082017-06-02 15:42:06 +0100227 InterceptStatus status;
228 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
229 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700230}
231
232void CrasherTest::FinishIntercept(int* result) {
233 InterceptResponse response;
234
Christopher Ferris11555f02019-09-20 14:18:55 -0700235 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700236 if (rc == -1) {
237 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
238 } else if (rc == 0) {
239 *result = -1;
240 } else if (rc != sizeof(response)) {
241 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
242 << ", received " << rc;
243 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700244 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700245 }
246}
247
Josh Gao2e7b8e22017-05-04 17:12:57 -0700248void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800249 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700250 unique_fd crasher_read_pipe;
251 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
252 FAIL() << "failed to create pipe: " << strerror(errno);
253 }
254
Josh Gao2e7b8e22017-05-04 17:12:57 -0700255 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700256 if (crasher_pid == -1) {
257 FAIL() << "fork failed: " << strerror(errno);
258 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800259 char dummy;
260 crasher_pipe.reset();
261 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800262 function();
263 _exit(0);
264 }
265}
266
Josh Gaocbe70cb2016-10-18 18:17:52 -0700267void CrasherTest::FinishCrasher() {
268 if (crasher_pipe == -1) {
269 FAIL() << "crasher pipe uninitialized";
270 }
271
Christopher Ferris172b0a02019-09-18 17:48:30 -0700272 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700273 if (rc == -1) {
274 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
275 } else if (rc == 0) {
276 FAIL() << "crasher pipe was closed";
277 }
278}
279
280void CrasherTest::AssertDeath(int signo) {
281 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700282 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700283 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700284 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
285 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700286 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700287 FAIL() << "failed to wait for crasher: " << strerror(errno);
288 }
289
Josh Gaoe06f2a42017-04-27 16:50:38 -0700290 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700291 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700292 ASSERT_EQ(0, WEXITSTATUS(signo));
293 } else {
294 ASSERT_FALSE(WIFEXITED(status));
295 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
296 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700297 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 crasher_pid = -1;
299}
300
301static void ConsumeFd(unique_fd fd, std::string* output) {
302 constexpr size_t read_length = PAGE_SIZE;
303 std::string result;
304
305 while (true) {
306 size_t offset = result.size();
307 result.resize(result.size() + PAGE_SIZE);
308 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
309 if (rc == -1) {
310 FAIL() << "read failed: " << strerror(errno);
311 } else if (rc == 0) {
312 result.resize(result.size() - PAGE_SIZE);
313 break;
314 }
315
316 result.resize(result.size() - PAGE_SIZE + rc);
317 }
318
319 *output = std::move(result);
320}
321
Mitch Phillips78f06702021-06-01 14:35:43 -0700322class LogcatCollector {
323 public:
324 LogcatCollector() { system("logcat -c"); }
325
326 void Collect(std::string* output) {
327 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
328 ASSERT_NE(cmd_stdout, nullptr);
329 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
330 ConsumeFd(std::move(tmp_fd), output);
331 pclose(cmd_stdout);
332 }
333};
334
Josh Gaocbe70cb2016-10-18 18:17:52 -0700335TEST_F(CrasherTest, smoke) {
336 int intercept_result;
337 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800338 StartProcess([]() {
339 *reinterpret_cast<volatile char*>(0xdead) = '1';
340 });
341
Josh Gaocbe70cb2016-10-18 18:17:52 -0700342 StartIntercept(&output_fd);
343 FinishCrasher();
344 AssertDeath(SIGSEGV);
345 FinishIntercept(&intercept_result);
346
347 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
348
349 std::string result;
350 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800351#ifdef __LP64__
352 ASSERT_MATCH(result,
353 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
354#else
355 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
356#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700357
358 if (mte_supported()) {
359 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700360 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
361 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700362 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800363
364 if (pac_supported()) {
365 // Test that the default PAC_ENABLED_KEYS value is set.
366 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
367 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
368 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700369}
370
Peter Collingbournef03af882020-03-20 18:09:00 -0700371TEST_F(CrasherTest, tagged_fault_addr) {
372#if !defined(__aarch64__)
373 GTEST_SKIP() << "Requires aarch64";
374#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700375 // HWASan crashes with SIGABRT on tag mismatch.
376 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700377 int intercept_result;
378 unique_fd output_fd;
379 StartProcess([]() {
380 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
381 });
382
383 StartIntercept(&output_fd);
384 FinishCrasher();
385 AssertDeath(SIGSEGV);
386 FinishIntercept(&intercept_result);
387
388 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
389
390 std::string result;
391 ConsumeFd(std::move(output_fd), &result);
392
393 // The address can either be tagged (new kernels) or untagged (old kernels).
394 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800395 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700396}
397
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700398void CrasherTest::Trap(void* ptr) {
399 void (*volatile f)(void*) = nullptr;
400 __asm__ __volatile__("" : : "r"(f) : "memory");
401 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700402}
403
404TEST_F(CrasherTest, heap_addr_in_register) {
405#if defined(__i386__)
406 GTEST_SKIP() << "architecture does not pass arguments in registers";
407#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700408 // The memory dump in HWASan crashes sadly shows the memory near the registers
409 // in the HWASan dump function, rather the faulting context. This is a known
410 // issue.
411 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700412 int intercept_result;
413 unique_fd output_fd;
414 StartProcess([]() {
415 // Crash with a heap pointer in the first argument register.
416 Trap(malloc(1));
417 });
418
419 StartIntercept(&output_fd);
420 FinishCrasher();
421 int status;
422 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
423 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
424 // Don't test the signal number because different architectures use different signals for
425 // __builtin_trap().
426 FinishIntercept(&intercept_result);
427
428 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
429
430 std::string result;
431 ConsumeFd(std::move(output_fd), &result);
432
433#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800434 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700435#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800436 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800437#elif defined(__riscv)
438 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700439#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800440 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700441#else
442 ASSERT_TRUE(false) << "unsupported architecture";
443#endif
444}
445
Peter Collingbournecd278072020-12-21 14:08:38 -0800446#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700447static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800448 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700449 abort();
450 }
451}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800452
453static void SetTagCheckingLevelAsync() {
454 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
455 abort();
456 }
457}
Peter Collingbournef8622522020-04-07 14:07:32 -0700458#endif
459
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800460struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
461
Peter Collingbourneaa544792021-05-13 13:53:37 -0700462INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800463
464TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800465#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700466 if (!mte_supported()) {
467 GTEST_SKIP() << "Requires MTE";
468 }
469
Peter Collingbourneaa544792021-05-13 13:53:37 -0700470 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
471 if (GetParam() == 0) {
472 return;
473 }
474
Mitch Phillips78f06702021-06-01 14:35:43 -0700475 LogcatCollector logcat_collector;
476
Peter Collingbournef8622522020-04-07 14:07:32 -0700477 int intercept_result;
478 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800479 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700480 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800481 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700482 free((void *)p);
483 p[0] = 42;
484 });
485
486 StartIntercept(&output_fd);
487 FinishCrasher();
488 AssertDeath(SIGSEGV);
489 FinishIntercept(&intercept_result);
490
491 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
492
Mitch Phillips78f06702021-06-01 14:35:43 -0700493 std::vector<std::string> log_sources(2);
494 ConsumeFd(std::move(output_fd), &log_sources[0]);
495 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700496 // Tag dump only available in the tombstone, not logcat.
497 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700498
Mitch Phillips78f06702021-06-01 14:35:43 -0700499 for (const auto& result : log_sources) {
500 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
501 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
502 std::to_string(GetParam()) + R"(-byte allocation)");
503 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
504 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
505 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700506#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800507 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700508#endif
509}
510
Peter Collingbournedc476342021-05-12 15:56:43 -0700511TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
512#if defined(__aarch64__)
513 if (!mte_supported()) {
514 GTEST_SKIP() << "Requires MTE";
515 }
516
517 int intercept_result;
518 unique_fd output_fd;
519 StartProcess([&]() {
520 SetTagCheckingLevelSync();
521 volatile int* p = (volatile int*)malloc(GetParam());
522 free((void *)p);
523 p[-1] = 42;
524 });
525
526 StartIntercept(&output_fd);
527 FinishCrasher();
528 AssertDeath(SIGSEGV);
529 FinishIntercept(&intercept_result);
530
531 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
532
533 std::string result;
534 ConsumeFd(std::move(output_fd), &result);
535
536 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
537 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
538#else
539 GTEST_SKIP() << "Requires aarch64";
540#endif
541}
542
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800543TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800544#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700545 if (!mte_supported()) {
546 GTEST_SKIP() << "Requires MTE";
547 }
548
Mitch Phillips78f06702021-06-01 14:35:43 -0700549 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700550 int intercept_result;
551 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800552 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700553 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800554 volatile char* p = (volatile char*)malloc(GetParam());
555 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700556 });
557
558 StartIntercept(&output_fd);
559 FinishCrasher();
560 AssertDeath(SIGSEGV);
561 FinishIntercept(&intercept_result);
562
563 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
564
Mitch Phillips78f06702021-06-01 14:35:43 -0700565 std::vector<std::string> log_sources(2);
566 ConsumeFd(std::move(output_fd), &log_sources[0]);
567 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700568
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700569 // Tag dump only in tombstone, not logcat, and tagging is not used for
570 // overflow protection in the scudo secondary (guard pages are used instead).
571 if (GetParam() < 0x10000) {
572 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
573 }
574
Mitch Phillips78f06702021-06-01 14:35:43 -0700575 for (const auto& result : log_sources) {
576 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
577 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
578 std::to_string(GetParam()) + R"(-byte allocation)");
579 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
580 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700581#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800582 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700583#endif
584}
585
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800586TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800587#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700588 if (!mte_supported()) {
589 GTEST_SKIP() << "Requires MTE";
590 }
591
592 int intercept_result;
593 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800594 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700595 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800596 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700597 p[-1] = 42;
598 });
599
600 StartIntercept(&output_fd);
601 FinishCrasher();
602 AssertDeath(SIGSEGV);
603 FinishIntercept(&intercept_result);
604
605 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
606
607 std::string result;
608 ConsumeFd(std::move(output_fd), &result);
609
610 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800611 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800612 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700613 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700614 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700615 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700616#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800617 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700618#endif
619}
620
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800621TEST_F(CrasherTest, mte_async) {
622#if defined(__aarch64__)
623 if (!mte_supported()) {
624 GTEST_SKIP() << "Requires MTE";
625 }
626
627 int intercept_result;
628 unique_fd output_fd;
629 StartProcess([&]() {
630 SetTagCheckingLevelAsync();
631 volatile int* p = (volatile int*)malloc(16);
632 p[-1] = 42;
633 });
634
635 StartIntercept(&output_fd);
636 FinishCrasher();
637 AssertDeath(SIGSEGV);
638 FinishIntercept(&intercept_result);
639
640 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
641
642 std::string result;
643 ConsumeFd(std::move(output_fd), &result);
644
645 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
646#else
647 GTEST_SKIP() << "Requires aarch64";
648#endif
649}
650
Peter Collingbournef8622522020-04-07 14:07:32 -0700651TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800652#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700653 if (!mte_supported()) {
654 GTEST_SKIP() << "Requires MTE";
655 }
656
Mitch Phillips78f06702021-06-01 14:35:43 -0700657 LogcatCollector logcat_collector;
658
Peter Collingbournef8622522020-04-07 14:07:32 -0700659 int intercept_result;
660 unique_fd output_fd;
661 StartProcess([]() {
662 SetTagCheckingLevelSync();
663
664 // Make two allocations with the same tag and close to one another. Check for both properties
665 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
666 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
667 // (some non-zero value << 56) apart.
668 //
669 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
670 // other.
671 std::set<uintptr_t> allocs;
672 for (int i = 0; i != 4096; ++i) {
673 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
674 auto it = allocs.insert(alloc).first;
675 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
676 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
677 }
678 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
679 *reinterpret_cast<int*>(alloc + 16) = 42;
680 }
681 }
682 });
683
684 StartIntercept(&output_fd);
685 FinishCrasher();
686 AssertDeath(SIGSEGV);
687 FinishIntercept(&intercept_result);
688
689 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
690
Mitch Phillips78f06702021-06-01 14:35:43 -0700691 std::vector<std::string> log_sources(2);
692 ConsumeFd(std::move(output_fd), &log_sources[0]);
693 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700694
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700695 // Tag dump only in the tombstone, not logcat.
696 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
697
Mitch Phillips78f06702021-06-01 14:35:43 -0700698 for (const auto& result : log_sources) {
699 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
700 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800701 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700702 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
703 // overflows), so we can't match explicitly for an underflow message.
704 ASSERT_MATCH(result,
705 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
706 // Ensure there's at least two allocation traces (one for each cause).
707 ASSERT_MATCH(
708 result,
709 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
710 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700711#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800712 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700713#endif
714}
715
Peter Collingbournecd278072020-12-21 14:08:38 -0800716#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700717static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700718 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
719 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
720 size_t page_size = getpagesize();
721 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
722 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
723 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700724 return 0;
725 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700726 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
727 PROT_READ | PROT_WRITE | PROT_MTE);
728 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
729 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
730 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
731 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
732 }
733 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700734}
735#endif
736
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700737TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800738#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700739 if (!mte_supported()) {
740 GTEST_SKIP() << "Requires MTE";
741 }
742
743 int intercept_result;
744 unique_fd output_fd;
745 StartProcess([&]() {
746 SetTagCheckingLevelSync();
747 Trap(reinterpret_cast<void *>(CreateTagMapping()));
748 });
749
750 StartIntercept(&output_fd);
751 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700752 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700753 FinishIntercept(&intercept_result);
754
755 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
756
757 std::string result;
758 ConsumeFd(std::move(output_fd), &result);
759
760 ASSERT_MATCH(result, R"(memory near x0:
761.*
762.*
763 01.............0 0000000000000000 0000000000000000 ................
764 00.............0)");
765#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800766 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700767#endif
768}
769
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700770TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
771#if defined(__aarch64__)
772 if (!mte_supported()) {
773 GTEST_SKIP() << "Requires MTE";
774 }
775
776 int intercept_result;
777 unique_fd output_fd;
778 StartProcess([&]() {
779 SetTagCheckingLevelSync();
780 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
781 p[0] = 0; // Untagged pointer, tagged memory.
782 });
783
784 StartIntercept(&output_fd);
785 FinishCrasher();
786 AssertDeath(SIGSEGV);
787 FinishIntercept(&intercept_result);
788
789 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
790
791 std::string result;
792 ConsumeFd(std::move(output_fd), &result);
793
794 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
795\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
796#else
797 GTEST_SKIP() << "Requires aarch64";
798#endif
799}
800
801TEST_F(CrasherTest, mte_fault_tag_dump) {
802#if defined(__aarch64__)
803 if (!mte_supported()) {
804 GTEST_SKIP() << "Requires MTE";
805 }
806
807 int intercept_result;
808 unique_fd output_fd;
809 StartProcess([&]() {
810 SetTagCheckingLevelSync();
811 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
812 p[320] = 0; // Untagged pointer, tagged memory.
813 });
814
815 StartIntercept(&output_fd);
816 FinishCrasher();
817 AssertDeath(SIGSEGV);
818 FinishIntercept(&intercept_result);
819
820 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
821
822 std::string result;
823 ConsumeFd(std::move(output_fd), &result);
824
825 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
826\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
827\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
828\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
829)");
830#else
831 GTEST_SKIP() << "Requires aarch64";
832#endif
833}
834
835TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
836#if defined(__aarch64__)
837 if (!mte_supported()) {
838 GTEST_SKIP() << "Requires MTE";
839 }
840
841 int intercept_result;
842 unique_fd output_fd;
843 StartProcess([&]() {
844 SetTagCheckingLevelSync();
845 size_t page_size = getpagesize();
846 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
847 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
848 });
849
850 StartIntercept(&output_fd);
851 FinishCrasher();
852 AssertDeath(SIGSEGV);
853 FinishIntercept(&intercept_result);
854
855 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
856
857 std::string result;
858 ConsumeFd(std::move(output_fd), &result);
859
860 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
861 ASSERT_MATCH(result,
862 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
863\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
864
865)"); // Ensure truncation happened and there's a newline after the tag fault.
866#else
867 GTEST_SKIP() << "Requires aarch64";
868#endif
869}
870
Josh Gaocdea7502017-11-01 15:00:40 -0700871TEST_F(CrasherTest, LD_PRELOAD) {
872 int intercept_result;
873 unique_fd output_fd;
874 StartProcess([]() {
875 setenv("LD_PRELOAD", "nonexistent.so", 1);
876 *reinterpret_cast<volatile char*>(0xdead) = '1';
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);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800888 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700889}
890
Josh Gaocbe70cb2016-10-18 18:17:52 -0700891TEST_F(CrasherTest, abort) {
892 int intercept_result;
893 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800894 StartProcess([]() {
895 abort();
896 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700897 StartIntercept(&output_fd);
898 FinishCrasher();
899 AssertDeath(SIGABRT);
900 FinishIntercept(&intercept_result);
901
902 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
903
904 std::string result;
905 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700906 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700907}
908
909TEST_F(CrasherTest, signal) {
910 int intercept_result;
911 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800912 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700913 while (true) {
914 sleep(1);
915 }
Josh Gao502cfd22017-02-17 01:39:15 -0800916 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700917 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700918 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700919 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
920
921 AssertDeath(SIGSEGV);
922 FinishIntercept(&intercept_result);
923
924 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
925
926 std::string result;
927 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700928 ASSERT_MATCH(
929 result,
930 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700931 ASSERT_MATCH(result, R"(backtrace:)");
932}
933
934TEST_F(CrasherTest, abort_message) {
935 int intercept_result;
936 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800937 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800938 // Arrived at experimentally;
939 // logd truncates at 4062.
940 // strlen("Abort message: ''") is 17.
941 // That's 4045, but we also want a NUL.
942 char buf[4045 + 1];
943 memset(buf, 'x', sizeof(buf));
944 buf[sizeof(buf) - 1] = '\0';
945 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800946 abort();
947 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700948 StartIntercept(&output_fd);
949 FinishCrasher();
950 AssertDeath(SIGABRT);
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);
Josh Gao1cc7bd82018-02-13 13:16:17 -0800957 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700958}
959
Christopher Ferrise8891452021-08-17 17:34:53 -0700960TEST_F(CrasherTest, abort_message_newline_trimmed) {
961 int intercept_result;
962 unique_fd output_fd;
963 StartProcess([]() {
964 android_set_abort_message("Message with a newline.\n");
965 abort();
966 });
967 StartIntercept(&output_fd);
968 FinishCrasher();
969 AssertDeath(SIGABRT);
970 FinishIntercept(&intercept_result);
971
972 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
973
974 std::string result;
975 ConsumeFd(std::move(output_fd), &result);
976 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
977}
978
979TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
980 int intercept_result;
981 unique_fd output_fd;
982 StartProcess([]() {
983 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
984 abort();
985 });
986 StartIntercept(&output_fd);
987 FinishCrasher();
988 AssertDeath(SIGABRT);
989 FinishIntercept(&intercept_result);
990
991 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
992
993 std::string result;
994 ConsumeFd(std::move(output_fd), &result);
995 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
996}
997
Josh Gaoe06f2a42017-04-27 16:50:38 -0700998TEST_F(CrasherTest, abort_message_backtrace) {
999 int intercept_result;
1000 unique_fd output_fd;
1001 StartProcess([]() {
1002 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001003 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001004 exit(0);
1005 });
1006 StartIntercept(&output_fd);
1007 FinishCrasher();
1008 AssertDeath(0);
1009 FinishIntercept(&intercept_result);
1010
1011 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1012
1013 std::string result;
1014 ConsumeFd(std::move(output_fd), &result);
1015 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1016}
1017
Josh Gaocbe70cb2016-10-18 18:17:52 -07001018TEST_F(CrasherTest, intercept_timeout) {
1019 int intercept_result;
1020 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001021 StartProcess([]() {
1022 abort();
1023 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001024 StartIntercept(&output_fd);
1025
1026 // Don't let crasher finish until we timeout.
1027 FinishIntercept(&intercept_result);
1028
1029 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1030 << intercept_result << ")";
1031
1032 FinishCrasher();
1033 AssertDeath(SIGABRT);
1034}
1035
Elliott Hughese4781d52021-03-17 09:15:15 -07001036TEST_F(CrasherTest, wait_for_debugger) {
1037 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1038 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001039 }
1040 sleep(1);
1041
Josh Gao502cfd22017-02-17 01:39:15 -08001042 StartProcess([]() {
1043 abort();
1044 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001045 FinishCrasher();
1046
1047 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001048 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001049 ASSERT_TRUE(WIFSTOPPED(status));
1050 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1051
1052 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1053
1054 AssertDeath(SIGABRT);
1055}
1056
Josh Gaocbe70cb2016-10-18 18:17:52 -07001057TEST_F(CrasherTest, backtrace) {
1058 std::string result;
1059 int intercept_result;
1060 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001061
1062 StartProcess([]() {
1063 abort();
1064 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001065 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001066
1067 std::this_thread::sleep_for(500ms);
1068
1069 sigval val;
1070 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001071 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001072 FinishIntercept(&intercept_result);
1073 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1074 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001075 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001076
1077 int status;
1078 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1079
1080 StartIntercept(&output_fd);
1081 FinishCrasher();
1082 AssertDeath(SIGABRT);
1083 FinishIntercept(&intercept_result);
1084 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1085 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001086 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001087}
Josh Gaofca7ca32017-01-23 12:05:35 -08001088
1089TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001090 int intercept_result;
1091 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001092 StartProcess([]() {
1093 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001094 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001095 });
Josh Gao502cfd22017-02-17 01:39:15 -08001096
1097 StartIntercept(&output_fd);
1098 FinishCrasher();
1099 AssertDeath(SIGABRT);
1100 FinishIntercept(&intercept_result);
1101
1102 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1103
1104 std::string result;
1105 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001106 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001107}
1108
Josh Gao502cfd22017-02-17 01:39:15 -08001109TEST_F(CrasherTest, capabilities) {
1110 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1111
Josh Gaofca7ca32017-01-23 12:05:35 -08001112 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001113 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1114 err(1, "failed to set PR_SET_KEEPCAPS");
1115 }
1116
1117 if (setresuid(1, 1, 1) != 0) {
1118 err(1, "setresuid failed");
1119 }
1120
1121 __user_cap_header_struct capheader;
1122 __user_cap_data_struct capdata[2];
1123 memset(&capheader, 0, sizeof(capheader));
1124 memset(&capdata, 0, sizeof(capdata));
1125
1126 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1127 capheader.pid = 0;
1128
1129 // Turn on every third capability.
1130 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1131 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1132 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1133 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1134 }
1135
1136 // Make sure CAP_SYS_PTRACE is off.
1137 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1138 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1139
1140 if (capset(&capheader, &capdata[0]) != 0) {
1141 err(1, "capset failed");
1142 }
1143
1144 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1145 err(1, "failed to drop ambient capabilities");
1146 }
1147
Josh Gaoa5199a92017-04-03 13:18:34 -07001148 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001149 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001150 });
Josh Gao502cfd22017-02-17 01:39:15 -08001151
1152 unique_fd output_fd;
1153 StartIntercept(&output_fd);
1154 FinishCrasher();
1155 AssertDeath(SIGSYS);
1156
1157 std::string result;
1158 int intercept_result;
1159 FinishIntercept(&intercept_result);
1160 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1161 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001162 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001163 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001164}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001165
Josh Gao2e7b8e22017-05-04 17:12:57 -07001166TEST_F(CrasherTest, fake_pid) {
1167 int intercept_result;
1168 unique_fd output_fd;
1169
1170 // Prime the getpid/gettid caches.
1171 UNUSED(getpid());
1172 UNUSED(gettid());
1173
1174 std::function<pid_t()> clone_fn = []() {
1175 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1176 };
1177 StartProcess(
1178 []() {
1179 ASSERT_NE(getpid(), syscall(__NR_getpid));
1180 ASSERT_NE(gettid(), syscall(__NR_gettid));
1181 raise(SIGSEGV);
1182 },
1183 clone_fn);
1184
1185 StartIntercept(&output_fd);
1186 FinishCrasher();
1187 AssertDeath(SIGSEGV);
1188 FinishIntercept(&intercept_result);
1189
1190 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1191
1192 std::string result;
1193 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001194 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001195}
1196
Josh Gaoe04ca272018-01-16 15:38:17 -08001197static const char* const kDebuggerdSeccompPolicy =
1198 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1199
Mitch Phillips18ce5422023-01-19 14:23:49 -08001200static void setup_jail(minijail* jail) {
1201 if (!jail) {
1202 LOG(FATAL) << "failed to create minijail";
1203 }
1204
Josh Gao6f9eeec2018-09-12 13:55:47 -07001205 std::string policy;
1206 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1207 PLOG(FATAL) << "failed to read policy file";
1208 }
1209
1210 // Allow a bunch of syscalls used by the tests.
1211 policy += "\nclone: 1";
1212 policy += "\nsigaltstack: 1";
1213 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001214 policy += "\ngetrlimit: 1";
1215 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001216
1217 FILE* tmp_file = tmpfile();
1218 if (!tmp_file) {
1219 PLOG(FATAL) << "tmpfile failed";
1220 }
1221
Christopher Ferris172b0a02019-09-18 17:48:30 -07001222 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001223 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1224 PLOG(FATAL) << "failed to write policy to tmpfile";
1225 }
1226
1227 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1228 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001229 }
1230
Mitch Phillips18ce5422023-01-19 14:23:49 -08001231 minijail_no_new_privs(jail);
1232 minijail_log_seccomp_filter_failures(jail);
1233 minijail_use_seccomp_filter(jail);
1234 minijail_parse_seccomp_filters_from_fd(jail, tmp_fd.release());
1235}
Josh Gaoe04ca272018-01-16 15:38:17 -08001236
Mitch Phillips18ce5422023-01-19 14:23:49 -08001237static pid_t seccomp_fork_impl(void (*prejail)()) {
1238 ScopedMinijail jail{minijail_new()};
1239 setup_jail(jail.get());
Josh Gaoe04ca272018-01-16 15:38:17 -08001240
1241 pid_t result = fork();
1242 if (result == -1) {
1243 return result;
1244 } else if (result != 0) {
1245 return result;
1246 }
1247
1248 // Spawn and detach a thread that spins forever.
1249 std::atomic<bool> thread_ready(false);
1250 std::thread thread([&jail, &thread_ready]() {
1251 minijail_enter(jail.get());
1252 thread_ready = true;
1253 for (;;)
1254 ;
1255 });
1256 thread.detach();
1257
1258 while (!thread_ready) {
1259 continue;
1260 }
1261
Josh Gao70adac62018-02-22 11:38:33 -08001262 if (prejail) {
1263 prejail();
1264 }
1265
Josh Gaoe04ca272018-01-16 15:38:17 -08001266 minijail_enter(jail.get());
1267 return result;
1268}
1269
Josh Gao70adac62018-02-22 11:38:33 -08001270static pid_t seccomp_fork() {
1271 return seccomp_fork_impl(nullptr);
1272}
1273
Josh Gaoe04ca272018-01-16 15:38:17 -08001274TEST_F(CrasherTest, seccomp_crash) {
1275 int intercept_result;
1276 unique_fd output_fd;
1277
1278 StartProcess([]() { abort(); }, &seccomp_fork);
1279
1280 StartIntercept(&output_fd);
1281 FinishCrasher();
1282 AssertDeath(SIGABRT);
1283 FinishIntercept(&intercept_result);
1284 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1285
1286 std::string result;
1287 ConsumeFd(std::move(output_fd), &result);
1288 ASSERT_BACKTRACE_FRAME(result, "abort");
1289}
1290
Josh Gao70adac62018-02-22 11:38:33 -08001291static pid_t seccomp_fork_rlimit() {
1292 return seccomp_fork_impl([]() {
1293 struct rlimit rlim = {
1294 .rlim_cur = 512 * 1024 * 1024,
1295 .rlim_max = 512 * 1024 * 1024,
1296 };
1297
1298 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1299 raise(SIGINT);
1300 }
1301 });
1302}
1303
1304TEST_F(CrasherTest, seccomp_crash_oom) {
1305 int intercept_result;
1306 unique_fd output_fd;
1307
1308 StartProcess(
1309 []() {
1310 std::vector<void*> vec;
1311 for (int i = 0; i < 512; ++i) {
1312 char* buf = static_cast<char*>(malloc(1024 * 1024));
1313 if (!buf) {
1314 abort();
1315 }
1316 memset(buf, 0xff, 1024 * 1024);
1317 vec.push_back(buf);
1318 }
1319 },
1320 &seccomp_fork_rlimit);
1321
1322 StartIntercept(&output_fd);
1323 FinishCrasher();
1324 AssertDeath(SIGABRT);
1325 FinishIntercept(&intercept_result);
1326 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1327
1328 // We can't actually generate a backtrace, just make sure that the process terminates.
1329}
1330
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001331__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001332 siginfo_t siginfo;
1333 siginfo.si_code = SI_QUEUE;
1334 siginfo.si_pid = getpid();
1335 siginfo.si_uid = getuid();
1336
1337 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1338 PLOG(FATAL) << "invalid dump type";
1339 }
1340
1341 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1342
Josh Gaoa48b41b2019-12-13 14:11:04 -08001343 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001344 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1345 return false;
1346 }
1347
1348 return true;
1349}
1350
Christopher Ferrisb999b822022-02-09 17:57:21 -08001351extern "C" void foo() {
1352 LOG(INFO) << "foo";
1353 std::this_thread::sleep_for(1s);
1354}
1355
1356extern "C" void bar() {
1357 LOG(INFO) << "bar";
1358 std::this_thread::sleep_for(1s);
1359}
1360
Josh Gaoe04ca272018-01-16 15:38:17 -08001361TEST_F(CrasherTest, seccomp_tombstone) {
1362 int intercept_result;
1363 unique_fd output_fd;
1364
1365 static const auto dump_type = kDebuggerdTombstone;
1366 StartProcess(
1367 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001368 std::thread a(foo);
1369 std::thread b(bar);
1370
1371 std::this_thread::sleep_for(100ms);
1372
Josh Gaoe04ca272018-01-16 15:38:17 -08001373 raise_debugger_signal(dump_type);
1374 _exit(0);
1375 },
1376 &seccomp_fork);
1377
1378 StartIntercept(&output_fd, dump_type);
1379 FinishCrasher();
1380 AssertDeath(0);
1381 FinishIntercept(&intercept_result);
1382 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1383
1384 std::string result;
1385 ConsumeFd(std::move(output_fd), &result);
1386 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001387 ASSERT_BACKTRACE_FRAME(result, "foo");
1388 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001389}
1390
Christopher Ferris303c6be2022-05-24 17:08:33 -07001391TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1392 int intercept_result;
1393 unique_fd output_fd;
1394
1395 static const auto dump_type = kDebuggerdTombstone;
1396 StartProcess(
1397 []() {
1398 std::thread abort_thread([] { abort(); });
1399 abort_thread.join();
1400 },
1401 &seccomp_fork);
1402
1403 StartIntercept(&output_fd, dump_type);
1404 FinishCrasher();
1405 AssertDeath(SIGABRT);
1406 FinishIntercept(&intercept_result);
1407 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1408
1409 std::string result;
1410 ConsumeFd(std::move(output_fd), &result);
1411 ASSERT_BACKTRACE_FRAME(result, "abort");
1412}
1413
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001414TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1415 int intercept_result;
1416 unique_fd output_fd;
1417
1418 static const auto dump_type = kDebuggerdTombstone;
1419 StartProcess(
1420 []() {
1421 std::thread a(foo);
1422 std::thread b(bar);
1423
1424 std::this_thread::sleep_for(100ms);
1425
1426 std::thread abort_thread([] { abort(); });
1427 abort_thread.join();
1428 },
1429 &seccomp_fork);
1430
1431 StartIntercept(&output_fd, dump_type);
1432 FinishCrasher();
1433 AssertDeath(SIGABRT);
1434 FinishIntercept(&intercept_result);
1435 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1436
1437 std::string result;
1438 ConsumeFd(std::move(output_fd), &result);
1439 ASSERT_BACKTRACE_FRAME(result, "abort");
1440 ASSERT_BACKTRACE_FRAME(result, "foo");
1441 ASSERT_BACKTRACE_FRAME(result, "bar");
1442 ASSERT_BACKTRACE_FRAME(result, "main");
1443}
1444
Josh Gaoe04ca272018-01-16 15:38:17 -08001445TEST_F(CrasherTest, seccomp_backtrace) {
1446 int intercept_result;
1447 unique_fd output_fd;
1448
1449 static const auto dump_type = kDebuggerdNativeBacktrace;
1450 StartProcess(
1451 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001452 std::thread a(foo);
1453 std::thread b(bar);
1454
1455 std::this_thread::sleep_for(100ms);
1456
Josh Gaoe04ca272018-01-16 15:38:17 -08001457 raise_debugger_signal(dump_type);
1458 _exit(0);
1459 },
1460 &seccomp_fork);
1461
1462 StartIntercept(&output_fd, dump_type);
1463 FinishCrasher();
1464 AssertDeath(0);
1465 FinishIntercept(&intercept_result);
1466 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1467
1468 std::string result;
1469 ConsumeFd(std::move(output_fd), &result);
1470 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001471 ASSERT_BACKTRACE_FRAME(result, "foo");
1472 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001473}
1474
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001475TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1476 int intercept_result;
1477 unique_fd output_fd;
1478
1479 static const auto dump_type = kDebuggerdNativeBacktrace;
1480 StartProcess(
1481 []() {
1482 std::thread a(foo);
1483 std::thread b(bar);
1484
1485 std::this_thread::sleep_for(100ms);
1486
1487 std::thread raise_thread([] {
1488 raise_debugger_signal(dump_type);
1489 _exit(0);
1490 });
1491 raise_thread.join();
1492 },
1493 &seccomp_fork);
1494
1495 StartIntercept(&output_fd, dump_type);
1496 FinishCrasher();
1497 AssertDeath(0);
1498 FinishIntercept(&intercept_result);
1499 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1500
1501 std::string result;
1502 ConsumeFd(std::move(output_fd), &result);
1503 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1504 ASSERT_BACKTRACE_FRAME(result, "foo");
1505 ASSERT_BACKTRACE_FRAME(result, "bar");
1506 ASSERT_BACKTRACE_FRAME(result, "main");
1507}
1508
Josh Gaoe04ca272018-01-16 15:38:17 -08001509TEST_F(CrasherTest, seccomp_crash_logcat) {
1510 StartProcess([]() { abort(); }, &seccomp_fork);
1511 FinishCrasher();
1512
1513 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1514 AssertDeath(SIGABRT);
1515}
1516
Josh Gaofd13bf02017-08-18 15:37:26 -07001517TEST_F(CrasherTest, competing_tracer) {
1518 int intercept_result;
1519 unique_fd output_fd;
1520 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001521 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001522 });
1523
1524 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001525
1526 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001527 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001528
1529 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001530 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001531 ASSERT_TRUE(WIFSTOPPED(status));
1532 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1533
1534 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1535 FinishIntercept(&intercept_result);
1536 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1537
1538 std::string result;
1539 ConsumeFd(std::move(output_fd), &result);
1540 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1541 regex += std::to_string(gettid());
1542 regex += R"( \(.+debuggerd_test)";
1543 ASSERT_MATCH(result, regex.c_str());
1544
Christopher Ferris172b0a02019-09-18 17:48:30 -07001545 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001546 ASSERT_TRUE(WIFSTOPPED(status));
1547 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1548
Josh Gaofd13bf02017-08-18 15:37:26 -07001549 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1550 AssertDeath(SIGABRT);
1551}
1552
Mitch Phillips18ce5422023-01-19 14:23:49 -08001553struct GwpAsanTestParameters {
1554 size_t alloc_size;
1555 bool free_before_access;
1556 int access_offset;
1557 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
1558};
1559
1560struct GwpAsanCrasherTest
1561 : CrasherTest,
1562 testing::WithParamInterface<
1563 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>> {};
1564
1565GwpAsanTestParameters gwp_asan_tests[] = {
1566 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0,
1567 "Use After Free, 0 bytes into a 7-byte allocation"},
1568 {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
1569 "Use After Free, 1 byte into a 15-byte allocation"},
1570 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
1571 "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
1572 {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
1573 "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
1574};
1575
1576INSTANTIATE_TEST_SUITE_P(
1577 GwpAsanTests, GwpAsanCrasherTest,
1578 testing::Combine(testing::ValuesIn(gwp_asan_tests),
1579 /* recoverable */ testing::Bool(),
1580 /* seccomp */ testing::Bool()),
1581 [](const testing::TestParamInfo<
1582 std::tuple<GwpAsanTestParameters, /* recoverable */ bool, /* seccomp */ bool>>& info) {
1583 const GwpAsanTestParameters& params = std::get<0>(info.param);
1584 std::string name = params.free_before_access ? "UseAfterFree" : "Overflow";
1585 name += testing::PrintToString(params.alloc_size);
1586 name += "Alloc";
1587 if (params.access_offset < 0) {
1588 name += "Left";
1589 name += testing::PrintToString(params.access_offset * -1);
1590 } else {
1591 name += "Right";
1592 name += testing::PrintToString(params.access_offset);
1593 }
1594 name += "Bytes";
1595 if (std::get<1>(info.param)) name += "Recoverable";
1596 if (std::get<2>(info.param)) name += "Seccomp";
1597 return name;
1598 });
1599
1600TEST_P(GwpAsanCrasherTest, run_gwp_asan_test) {
1601 if (mte_supported()) {
1602 // Skip this test on MTE hardware, as MTE will reliably catch these errors
1603 // instead of GWP-ASan.
1604 GTEST_SKIP() << "Skipped on MTE.";
1605 }
1606 // Skip this test on HWASan, which will reliably catch test errors as well.
1607 SKIP_WITH_HWASAN;
1608
1609 GwpAsanTestParameters params = std::get<0>(GetParam());
1610 bool recoverable = std::get<1>(GetParam());
1611 LogcatCollector logcat_collector;
1612
1613 int intercept_result;
1614 unique_fd output_fd;
1615 StartProcess([&recoverable]() {
1616 const char* env[] = {"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1",
1617 "GWP_ASAN_MAX_ALLOCS=40000", nullptr, nullptr};
1618 if (recoverable) {
1619 env[3] = "GWP_ASAN_RECOVERABLE=true";
1620 }
1621 std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
1622 test_name = std::regex_replace(test_name, std::regex("run_gwp_asan_test"),
1623 "DISABLED_run_gwp_asan_test");
1624 std::string test_filter = "--gtest_filter=*";
1625 test_filter += test_name;
1626 std::string this_binary = android::base::GetExecutablePath();
1627 const char* args[] = {this_binary.c_str(), "--gtest_also_run_disabled_tests",
1628 test_filter.c_str(), nullptr};
1629 // We check the crash report from a debuggerd handler and from logcat. The
1630 // echo from stdout/stderr of the subprocess trips up atest, because it
1631 // doesn't like that two tests started in a row without the first one
1632 // finishing (even though the second one is in a subprocess).
1633 close(STDOUT_FILENO);
1634 close(STDERR_FILENO);
1635 execve(this_binary.c_str(), const_cast<char**>(args), const_cast<char**>(env));
1636 });
1637
1638 StartIntercept(&output_fd);
1639 FinishCrasher();
1640 if (recoverable) {
1641 AssertDeath(0);
1642 } else {
1643 AssertDeath(SIGSEGV);
1644 }
1645 FinishIntercept(&intercept_result);
1646
1647 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1648
1649 std::vector<std::string> log_sources(2);
1650 ConsumeFd(std::move(output_fd), &log_sources[0]);
1651 logcat_collector.Collect(&log_sources[1]);
1652
1653 // seccomp forces the fallback handler, which doesn't print GWP-ASan debugging
1654 // information. Make sure the recovery still works, but the report won't be
1655 // hugely useful, it looks like a regular SEGV.
1656 bool seccomp = std::get<2>(GetParam());
1657 if (!seccomp) {
1658 for (const auto& result : log_sources) {
1659 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
1660 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
1661 if (params.free_before_access) {
1662 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
1663 }
1664 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
1665 }
1666 }
1667}
1668
1669TEST_P(GwpAsanCrasherTest, DISABLED_run_gwp_asan_test) {
1670 GwpAsanTestParameters params = std::get<0>(GetParam());
1671 bool seccomp = std::get<2>(GetParam());
1672 if (seccomp) {
1673 ScopedMinijail jail{minijail_new()};
1674 setup_jail(jail.get());
1675 minijail_enter(jail.get());
1676 }
1677
1678 // Use 'volatile' to prevent a very clever compiler eliminating the store.
1679 char* volatile p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1680 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
1681 p[params.access_offset] = 42;
1682 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
Mitch Phillips70aa2192023-02-22 11:31:36 -08001683
1684 bool recoverable = std::get<1>(GetParam());
1685 ASSERT_TRUE(recoverable); // Non-recoverable should have crashed.
1686
1687 // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
1688 // we end with at least one in a different slot), make sure the process still
1689 // doesn't crash.
1690 p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1691 char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
1692 free(static_cast<void*>(const_cast<char*>(p)));
1693 free(static_cast<void*>(const_cast<char*>(p2)));
1694 *p = 42;
1695 *p2 = 42;
1696
1697 // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
1698 // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
1699 // coverage does. Thus, skip the atexit handlers.
1700 _exit(0);
Mitch Phillips18ce5422023-01-19 14:23:49 -08001701}
1702
Josh Gaobf06a402018-08-27 16:34:01 -07001703TEST_F(CrasherTest, fdsan_warning_abort_message) {
1704 int intercept_result;
1705 unique_fd output_fd;
1706
1707 StartProcess([]() {
1708 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001709 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001710 if (fd == -1) {
1711 abort();
1712 }
1713 close(fd.get());
1714 _exit(0);
1715 });
1716
1717 StartIntercept(&output_fd);
1718 FinishCrasher();
1719 AssertDeath(0);
1720 FinishIntercept(&intercept_result);
1721 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1722
1723 std::string result;
1724 ConsumeFd(std::move(output_fd), &result);
1725 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1726}
1727
Josh Gaoc3c8c022017-02-13 16:36:18 -08001728TEST(crash_dump, zombie) {
1729 pid_t forkpid = fork();
1730
Josh Gaoc3c8c022017-02-13 16:36:18 -08001731 pid_t rc;
1732 int status;
1733
1734 if (forkpid == 0) {
1735 errno = 0;
1736 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1737 if (rc != -1 || errno != ECHILD) {
1738 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1739 }
1740
Josh Gaoa48b41b2019-12-13 14:11:04 -08001741 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001742
1743 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001744 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001745 if (rc != -1 || errno != ECHILD) {
1746 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1747 }
1748 _exit(0);
1749 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001750 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001751 ASSERT_EQ(forkpid, rc);
1752 ASSERT_TRUE(WIFEXITED(status));
1753 ASSERT_EQ(0, WEXITSTATUS(status));
1754 }
1755}
Josh Gao352a8452017-03-30 16:46:21 -07001756
1757TEST(tombstoned, no_notify) {
1758 // Do this a few times.
1759 for (int i = 0; i < 3; ++i) {
1760 pid_t pid = 123'456'789 + i;
1761
1762 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001763 InterceptStatus status;
1764 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1765 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001766
1767 {
1768 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001769 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001770 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1771 }
1772
1773 pid_t read_pid;
1774 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1775 ASSERT_EQ(read_pid, pid);
1776 }
1777}
1778
1779TEST(tombstoned, stress) {
1780 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1781 static constexpr int kDumpCount = 100;
1782
1783 std::atomic<bool> start(false);
1784 std::vector<std::thread> threads;
1785 threads.emplace_back([&start]() {
1786 while (!start) {
1787 continue;
1788 }
1789
1790 // Use a way out of range pid, to avoid stomping on an actual process.
1791 pid_t pid_base = 1'000'000;
1792
1793 for (int dump = 0; dump < kDumpCount; ++dump) {
1794 pid_t pid = pid_base + dump;
1795
1796 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001797 InterceptStatus status;
1798 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1799 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001800
1801 // Pretend to crash, and then immediately close the socket.
1802 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1803 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1804 if (sockfd == -1) {
1805 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1806 }
1807 TombstonedCrashPacket packet = {};
1808 packet.packet_type = CrashPacketType::kDumpRequest;
1809 packet.packet.dump_request.pid = pid;
1810 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1811 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1812 }
1813
1814 continue;
1815 }
1816 });
1817
1818 threads.emplace_back([&start]() {
1819 while (!start) {
1820 continue;
1821 }
1822
1823 // Use a way out of range pid, to avoid stomping on an actual process.
1824 pid_t pid_base = 2'000'000;
1825
1826 for (int dump = 0; dump < kDumpCount; ++dump) {
1827 pid_t pid = pid_base + dump;
1828
1829 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001830 InterceptStatus status;
1831 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1832 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001833
1834 {
1835 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001836 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001837 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1838 tombstoned_notify_completion(tombstoned_socket.get());
1839 }
1840
1841 // TODO: Fix the race that requires this sleep.
1842 std::this_thread::sleep_for(50ms);
1843
1844 pid_t read_pid;
1845 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1846 ASSERT_EQ(read_pid, pid);
1847 }
1848 });
1849
1850 start = true;
1851
1852 for (std::thread& thread : threads) {
1853 thread.join();
1854 }
1855}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001856
1857TEST(tombstoned, java_trace_intercept_smoke) {
1858 // Using a "real" PID is a little dangerous here - if the test fails
1859 // or crashes, we might end up getting a bogus / unreliable stack
1860 // trace.
1861 const pid_t self = getpid();
1862
1863 unique_fd intercept_fd, output_fd;
1864 InterceptStatus status;
1865 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1866 ASSERT_EQ(InterceptStatus::kRegistered, status);
1867
Josh Gao76e1e302021-01-26 15:53:11 -08001868 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001869 // should result in a "regular" FD and not the installed intercept.
1870 const char native[] = "native";
1871 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001872 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001873 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1874 tombstoned_notify_completion(tombstoned_socket.get());
1875
1876 // Then, connect to tombstoned asking for a java backtrace. This *should*
1877 // trigger the intercept.
1878 const char java[] = "java";
1879 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1880 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1881 tombstoned_notify_completion(tombstoned_socket.get());
1882
1883 char outbuf[sizeof(java)];
1884 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1885 ASSERT_STREQ("java", outbuf);
1886}
1887
1888TEST(tombstoned, multiple_intercepts) {
1889 const pid_t fake_pid = 1'234'567;
1890 unique_fd intercept_fd, output_fd;
1891 InterceptStatus status;
1892 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1893 ASSERT_EQ(InterceptStatus::kRegistered, status);
1894
1895 unique_fd intercept_fd_2, output_fd_2;
1896 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1897 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1898}
1899
1900TEST(tombstoned, intercept_any) {
1901 const pid_t fake_pid = 1'234'567;
1902
1903 unique_fd intercept_fd, output_fd;
1904 InterceptStatus status;
1905 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1906 ASSERT_EQ(InterceptStatus::kRegistered, status);
1907
1908 const char any[] = "any";
1909 unique_fd tombstoned_socket, input_fd;
1910 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1911 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1912 tombstoned_notify_completion(tombstoned_socket.get());
1913
1914 char outbuf[sizeof(any)];
1915 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1916 ASSERT_STREQ("any", outbuf);
1917}
Josh Gao2b22ae12018-09-12 14:51:03 -07001918
1919TEST(tombstoned, interceptless_backtrace) {
1920 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1921 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1922 std::map<int, time_t> result;
1923 for (int i = 0; i < 99; ++i) {
1924 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1925 struct stat st;
1926 if (stat(path.c_str(), &st) == 0) {
1927 result[i] = st.st_mtim.tv_sec;
1928 }
1929 }
1930 return result;
1931 };
1932
1933 auto before = get_tombstone_timestamps();
1934 for (int i = 0; i < 50; ++i) {
1935 raise_debugger_signal(kDebuggerdNativeBacktrace);
1936 }
1937 auto after = get_tombstone_timestamps();
1938
1939 int diff = 0;
1940 for (int i = 0; i < 99; ++i) {
1941 if (after.count(i) == 0) {
1942 continue;
1943 }
1944 if (before.count(i) == 0) {
1945 ++diff;
1946 continue;
1947 }
1948 if (before[i] != after[i]) {
1949 ++diff;
1950 }
1951 }
1952
1953 // We can't be sure that nothing's crash looping in the background.
1954 // This should be good enough, though...
1955 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1956}
Christopher Ferris481e8372019-07-15 17:13:24 -07001957
1958static __attribute__((__noinline__)) void overflow_stack(void* p) {
1959 void* buf[1];
1960 buf[0] = p;
1961 static volatile void* global = buf;
1962 if (global) {
1963 global = buf;
1964 overflow_stack(&buf);
1965 }
1966}
1967
1968TEST_F(CrasherTest, stack_overflow) {
1969 int intercept_result;
1970 unique_fd output_fd;
1971 StartProcess([]() { overflow_stack(nullptr); });
1972
1973 StartIntercept(&output_fd);
1974 FinishCrasher();
1975 AssertDeath(SIGSEGV);
1976 FinishIntercept(&intercept_result);
1977
1978 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1979
1980 std::string result;
1981 ConsumeFd(std::move(output_fd), &result);
1982 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1983}
Josh Gao76e1e302021-01-26 15:53:11 -08001984
Christopher Ferris22035cc2023-01-31 17:50:22 -08001985static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001986 std::string test_lib(testing::internal::GetArgvs()[0]);
1987 auto const value = test_lib.find_last_of('/');
1988 if (value == std::string::npos) {
1989 test_lib = "./";
1990 } else {
1991 test_lib = test_lib.substr(0, value + 1) + "./";
1992 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08001993 return test_lib + "libcrash_test.so";
1994}
1995
1996static void CreateEmbeddedLibrary(int out_fd) {
1997 std::string test_lib(GetTestLibraryPath());
1998 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
1999 ASSERT_NE(fd.get(), -1);
2000 off_t file_size = lseek(fd, 0, SEEK_END);
2001 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
2002 std::vector<uint8_t> contents(file_size);
2003 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
2004
2005 // Put the shared library data at a pagesize() offset.
2006 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
2007 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
2008}
2009
2010TEST_F(CrasherTest, non_zero_offset_in_library) {
2011 int intercept_result;
2012 unique_fd output_fd;
2013 TemporaryFile tf;
2014 CreateEmbeddedLibrary(tf.fd);
2015 StartProcess([&tf]() {
2016 android_dlextinfo extinfo{};
2017 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2018 extinfo.library_fd = tf.fd;
2019 extinfo.library_fd_offset = 4 * getpagesize();
2020 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2021 if (handle == nullptr) {
2022 _exit(1);
2023 }
2024 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2025 if (crash_func == nullptr) {
2026 _exit(1);
2027 }
2028 crash_func();
2029 });
2030
2031 StartIntercept(&output_fd);
2032 FinishCrasher();
2033 AssertDeath(SIGSEGV);
2034 FinishIntercept(&intercept_result);
2035
2036 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2037
2038 std::string result;
2039 ConsumeFd(std::move(output_fd), &result);
2040
2041 // Verify the crash includes an offset value in the backtrace.
2042 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2043 tf.path, 4 * getpagesize());
2044 ASSERT_MATCH(result, match_str);
2045}
2046
2047static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2048 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002049
2050 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2051 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2052
2053 // Copy the shared so to a tempory directory.
2054 return system(cp_cmd.c_str()) == 0;
2055}
2056
2057TEST_F(CrasherTest, unreadable_elf) {
2058 int intercept_result;
2059 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002060 std::string tmp_so_name;
2061 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002062 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002063 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2064 _exit(1);
2065 }
2066 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2067 if (handle == nullptr) {
2068 _exit(1);
2069 }
2070 // Delete the original shared library so that we get the warning
2071 // about unreadable elf files.
2072 if (unlink(tmp_so_name.c_str()) == -1) {
2073 _exit(1);
2074 }
2075 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2076 if (crash_func == nullptr) {
2077 _exit(1);
2078 }
2079 crash_func();
2080 });
2081
2082 StartIntercept(&output_fd);
2083 FinishCrasher();
2084 AssertDeath(SIGSEGV);
2085 FinishIntercept(&intercept_result);
2086
2087 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2088
2089 std::string result;
2090 ConsumeFd(std::move(output_fd), &result);
2091 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002092 std::string match_str = "NOTE: " + tmp_so_name;
2093 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002094}
2095
Josh Gao76e1e302021-01-26 15:53:11 -08002096TEST(tombstoned, proto) {
2097 const pid_t self = getpid();
2098 unique_fd tombstoned_socket, text_fd, proto_fd;
2099 ASSERT_TRUE(
2100 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2101
2102 tombstoned_notify_completion(tombstoned_socket.get());
2103
2104 ASSERT_NE(-1, text_fd.get());
2105 ASSERT_NE(-1, proto_fd.get());
2106
2107 struct stat text_st;
2108 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2109
2110 // Give tombstoned some time to link the files into place.
2111 std::this_thread::sleep_for(100ms);
2112
2113 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08002114 std::optional<std::string> tombstone_file;
2115 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2116 ASSERT_TRUE(dir_h != nullptr);
2117 std::regex tombstone_re("tombstone_\\d+");
2118 dirent* entry;
2119 while ((entry = readdir(dir_h.get())) != nullptr) {
2120 if (!std::regex_match(entry->d_name, tombstone_re)) {
2121 continue;
2122 }
2123 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002124
2125 struct stat st;
2126 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2127 continue;
2128 }
2129
2130 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002131 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002132 break;
2133 }
2134 }
2135
Christopher Ferris35da2882021-02-17 15:39:06 -08002136 ASSERT_TRUE(tombstone_file);
2137 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002138
2139 struct stat proto_fd_st;
2140 struct stat proto_file_st;
2141 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2142 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2143
2144 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2145 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2146}
2147
2148TEST(tombstoned, proto_intercept) {
2149 const pid_t self = getpid();
2150 unique_fd intercept_fd, output_fd;
2151 InterceptStatus status;
2152
2153 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2154 ASSERT_EQ(InterceptStatus::kRegistered, status);
2155
2156 unique_fd tombstoned_socket, text_fd, proto_fd;
2157 ASSERT_TRUE(
2158 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2159 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2160 tombstoned_notify_completion(tombstoned_socket.get());
2161
2162 text_fd.reset();
2163
2164 std::string output;
2165 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2166 ASSERT_EQ("foo", output);
2167}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002168
2169// Verify that when an intercept is present for the main thread, and the signal
2170// is received on a different thread, the intercept still works.
2171TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2172 StartProcess([]() {
2173 std::thread thread([]() {
2174 // Raise the signal on the side thread.
2175 raise_debugger_signal(kDebuggerdNativeBacktrace);
2176 });
2177 thread.join();
2178 _exit(0);
2179 });
2180
2181 unique_fd output_fd;
2182 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2183 FinishCrasher();
2184 AssertDeath(0);
2185
2186 int intercept_result;
2187 FinishIntercept(&intercept_result);
2188 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2189
2190 std::string result;
2191 ConsumeFd(std::move(output_fd), &result);
2192 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2193}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002194
2195static std::string format_pointer(uintptr_t ptr) {
2196#if defined(__LP64__)
2197 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2198 static_cast<uint32_t>(ptr & 0xffffffff));
2199#else
2200 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2201#endif
2202}
2203
2204static std::string format_pointer(void* ptr) {
2205 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2206}
2207
2208static std::string format_full_pointer(uintptr_t ptr) {
2209#if defined(__LP64__)
2210 return android::base::StringPrintf("%016" PRIx64, ptr);
2211#else
2212 return android::base::StringPrintf("%08x", ptr);
2213#endif
2214}
2215
2216static std::string format_full_pointer(void* ptr) {
2217 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2218}
2219
2220__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2221 int* crash_ptr = reinterpret_cast<int*>(ptr);
2222 *crash_ptr = 1;
2223 return *crash_ptr;
2224}
2225
2226// Verify that a fault address before the first map is properly handled.
2227TEST_F(CrasherTest, fault_address_before_first_map) {
2228 StartProcess([]() {
2229 ASSERT_EQ(0, crash_call(0x1024));
2230 _exit(0);
2231 });
2232
2233 unique_fd output_fd;
2234 StartIntercept(&output_fd);
2235 FinishCrasher();
2236 AssertDeath(SIGSEGV);
2237
2238 int intercept_result;
2239 FinishIntercept(&intercept_result);
2240 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2241
2242 std::string result;
2243 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002244 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002245
2246 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2247
2248 std::string match_str = android::base::StringPrintf(
2249 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2250 format_pointer(0x1024).c_str());
2251 ASSERT_MATCH(result, match_str);
2252}
2253
2254// Verify that a fault address after the last map is properly handled.
2255TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002256 // This makes assumptions about the memory layout that are not true in HWASan
2257 // processes.
2258 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002259 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2260 StartProcess([crash_uptr]() {
2261 ASSERT_EQ(0, crash_call(crash_uptr));
2262 _exit(0);
2263 });
2264
2265 unique_fd output_fd;
2266 StartIntercept(&output_fd);
2267 FinishCrasher();
2268 AssertDeath(SIGSEGV);
2269
2270 int intercept_result;
2271 FinishIntercept(&intercept_result);
2272 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2273
2274 std::string result;
2275 ConsumeFd(std::move(output_fd), &result);
2276
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002277 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2278 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002279 ASSERT_MATCH(result, match_str);
2280
2281 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2282
2283 // Assumes that the open files section comes after the map section.
2284 // If that assumption changes, the regex below needs to change.
2285 match_str = android::base::StringPrintf(
2286 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2287 format_pointer(crash_uptr).c_str());
2288 ASSERT_MATCH(result, match_str);
2289}
2290
2291// Verify that a fault address between maps is properly handled.
2292TEST_F(CrasherTest, fault_address_between_maps) {
2293 // Create a map before the fork so it will be present in the child.
2294 void* start_ptr =
2295 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2296 ASSERT_NE(MAP_FAILED, start_ptr);
2297 // Unmap the page in the middle.
2298 void* middle_ptr =
2299 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2300 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2301
2302 StartProcess([middle_ptr]() {
2303 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2304 _exit(0);
2305 });
2306
2307 // Unmap the two maps.
2308 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2309 void* end_ptr =
2310 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2311 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2312
2313 unique_fd output_fd;
2314 StartIntercept(&output_fd);
2315 FinishCrasher();
2316 AssertDeath(SIGSEGV);
2317
2318 int intercept_result;
2319 FinishIntercept(&intercept_result);
2320 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2321
2322 std::string result;
2323 ConsumeFd(std::move(output_fd), &result);
2324
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002325 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2326 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002327 ASSERT_MATCH(result, match_str);
2328
2329 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2330
2331 match_str = android::base::StringPrintf(
2332 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2333 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2334 format_pointer(end_ptr).c_str());
2335 ASSERT_MATCH(result, match_str);
2336}
2337
2338// Verify that a fault address happens in the correct map.
2339TEST_F(CrasherTest, fault_address_in_map) {
2340 // Create a map before the fork so it will be present in the child.
2341 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2342 ASSERT_NE(MAP_FAILED, ptr);
2343
2344 StartProcess([ptr]() {
2345 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2346 _exit(0);
2347 });
2348
2349 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2350
2351 unique_fd output_fd;
2352 StartIntercept(&output_fd);
2353 FinishCrasher();
2354 AssertDeath(SIGSEGV);
2355
2356 int intercept_result;
2357 FinishIntercept(&intercept_result);
2358 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2359
2360 std::string result;
2361 ConsumeFd(std::move(output_fd), &result);
2362
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002363 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2364 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002365 ASSERT_MATCH(result, match_str);
2366
2367 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2368
2369 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2370 ASSERT_MATCH(result, match_str);
2371}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002372
2373static constexpr uint32_t kDexData[] = {
2374 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2375 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2376 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2377 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2378 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2379 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2380 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2381 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2382 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2383 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2384 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2385 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2386 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2387 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2388 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2389 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2390 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2391};
2392
2393TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2394 StartProcess([]() {
2395 TemporaryDir td;
2396 std::string tmp_so_name;
2397 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2398 _exit(1);
2399 }
2400
2401 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2402 // move the library to which has a basename of libart.so.
2403 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2404 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2405 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2406 if (handle == nullptr) {
2407 _exit(1);
2408 }
2409
2410 void* ptr =
2411 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2412 ASSERT_TRUE(ptr != MAP_FAILED);
2413 memcpy(ptr, kDexData, sizeof(kDexData));
2414 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2415
2416 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2417 .symfile_size = sizeof(kDexData)};
2418
2419 JITDescriptor* dex_debug =
2420 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2421 ASSERT_TRUE(dex_debug != nullptr);
2422 dex_debug->version = 1;
2423 dex_debug->action_flag = 0;
2424 dex_debug->relevant_entry = 0;
2425 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2426
2427 // This sets the magic dex pc value for register 0, using the value
2428 // of register 1 + 0x102.
2429 asm(".cfi_escape "
2430 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2431 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2432 "0x13 /* DW_OP_drop */,"
2433 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2434
2435 // For each different architecture, set register one to the dex ptr mmap
2436 // created above. Then do a nullptr dereference to force a crash.
2437#if defined(__arm__)
2438 asm volatile(
2439 "mov r1, %[base]\n"
2440 "mov r2, 0\n"
2441 "str r3, [r2]\n"
2442 : [base] "+r"(ptr)
2443 :
2444 : "r1", "r2", "r3", "memory");
2445#elif defined(__aarch64__)
2446 asm volatile(
2447 "mov x1, %[base]\n"
2448 "mov x2, 0\n"
2449 "str x3, [x2]\n"
2450 : [base] "+r"(ptr)
2451 :
2452 : "x1", "x2", "x3", "memory");
2453#elif defined(__i386__)
2454 asm volatile(
2455 "mov %[base], %%ecx\n"
2456 "movl $0, %%edi\n"
2457 "movl 0(%%edi), %%edx\n"
2458 : [base] "+r"(ptr)
2459 :
2460 : "edi", "ecx", "edx", "memory");
2461#elif defined(__x86_64__)
2462 asm volatile(
2463 "mov %[base], %%rdx\n"
2464 "movq 0, %%rdi\n"
2465 "movq 0(%%rdi), %%rcx\n"
2466 : [base] "+r"(ptr)
2467 :
2468 : "rcx", "rdx", "rdi", "memory");
2469#else
2470#error "Unsupported architecture"
2471#endif
2472 _exit(0);
2473 });
2474
2475 unique_fd output_fd;
2476 StartIntercept(&output_fd);
2477 FinishCrasher();
2478 AssertDeath(SIGSEGV);
2479
2480 int intercept_result;
2481 FinishIntercept(&intercept_result);
2482 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2483
2484 std::string result;
2485 ConsumeFd(std::move(output_fd), &result);
2486
2487 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002488 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002489
2490 // Now verify that the dex_pc frame includes a proper function name.
2491 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2492}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002493
2494static std::string format_map_pointer(uintptr_t ptr) {
2495#if defined(__LP64__)
2496 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2497 static_cast<uint32_t>(ptr & 0xffffffff));
2498#else
2499 return android::base::StringPrintf("%08x", ptr);
2500#endif
2501}
2502
2503// Verify that map data is properly formatted.
2504TEST_F(CrasherTest, verify_map_format) {
2505 // Create multiple maps to make sure that the map data is formatted properly.
2506 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2507 ASSERT_NE(MAP_FAILED, none_map);
2508 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2509 ASSERT_NE(MAP_FAILED, r_map);
2510 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2511 ASSERT_NE(MAP_FAILED, w_map);
2512 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2513 ASSERT_NE(MAP_FAILED, x_map);
2514
2515 TemporaryFile tf;
2516 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2517 char c = 'f';
2518 ASSERT_EQ(1, write(tf.fd, &c, 1));
2519 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2520 ASSERT_EQ(1, write(tf.fd, &c, 1));
2521 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2522 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2523 ASSERT_NE(MAP_FAILED, file_map);
2524
2525 StartProcess([]() { abort(); });
2526
2527 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2528 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2529 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2530 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2531 ASSERT_EQ(0, munmap(file_map, 0x3001));
2532
2533 unique_fd output_fd;
2534 StartIntercept(&output_fd);
2535 FinishCrasher();
2536 AssertDeath(SIGABRT);
2537 int intercept_result;
2538 FinishIntercept(&intercept_result);
2539
2540 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2541
2542 std::string result;
2543 ConsumeFd(std::move(output_fd), &result);
2544
2545 std::string match_str;
2546 // Verify none.
2547 match_str = android::base::StringPrintf(
2548 " %s-%s --- 0 1000\\n",
2549 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2550 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2551 ASSERT_MATCH(result, match_str);
2552
2553 // Verify read-only.
2554 match_str = android::base::StringPrintf(
2555 " %s-%s r-- 0 1000\\n",
2556 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2557 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2558 ASSERT_MATCH(result, match_str);
2559
2560 // Verify write-only.
2561 match_str = android::base::StringPrintf(
2562 " %s-%s -w- 0 1000\\n",
2563 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2564 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2565 ASSERT_MATCH(result, match_str);
2566
2567 // Verify exec-only.
2568 match_str = android::base::StringPrintf(
2569 " %s-%s --x 0 1000\\n",
2570 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2571 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2572 ASSERT_MATCH(result, match_str);
2573
2574 // Verify file map with non-zero offset and a name.
2575 match_str = android::base::StringPrintf(
2576 " %s-%s r-- 2000 4000 %s\\n",
2577 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2578 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2579 ASSERT_MATCH(result, match_str);
2580}
2581
2582// Verify that the tombstone map data is correct.
2583TEST_F(CrasherTest, verify_header) {
2584 StartProcess([]() { abort(); });
2585
2586 unique_fd output_fd;
2587 StartIntercept(&output_fd);
2588 FinishCrasher();
2589 AssertDeath(SIGABRT);
2590 int intercept_result;
2591 FinishIntercept(&intercept_result);
2592
2593 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2594
2595 std::string result;
2596 ConsumeFd(std::move(output_fd), &result);
2597
2598 std::string match_str = android::base::StringPrintf(
2599 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2600 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2601 android::base::GetProperty("ro.revision", "unknown").c_str());
2602 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2603 ASSERT_MATCH(result, match_str);
2604}
2605
2606// Verify that the thread header is formatted properly.
2607TEST_F(CrasherTest, verify_thread_header) {
2608 void* shared_map =
2609 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2610 ASSERT_NE(MAP_FAILED, shared_map);
2611 memset(shared_map, 0, sizeof(pid_t));
2612
2613 StartProcess([&shared_map]() {
2614 std::atomic_bool tid_written;
2615 std::thread thread([&tid_written, &shared_map]() {
2616 pid_t tid = gettid();
2617 memcpy(shared_map, &tid, sizeof(pid_t));
2618 tid_written = true;
2619 volatile bool done = false;
2620 while (!done)
2621 ;
2622 });
2623 thread.detach();
2624 while (!tid_written.load(std::memory_order_acquire))
2625 ;
2626 abort();
2627 });
2628
2629 pid_t primary_pid = crasher_pid;
2630
2631 unique_fd output_fd;
2632 StartIntercept(&output_fd);
2633 FinishCrasher();
2634 AssertDeath(SIGABRT);
2635 int intercept_result;
2636 FinishIntercept(&intercept_result);
2637 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2638
2639 // Read the tid data out.
2640 pid_t tid;
2641 memcpy(&tid, shared_map, sizeof(pid_t));
2642 ASSERT_NE(0, tid);
2643
2644 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2645
2646 std::string result;
2647 ConsumeFd(std::move(output_fd), &result);
2648
2649 // Verify that there are two headers, one where the tid is "primary_pid"
2650 // and the other where the tid is "tid".
2651 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2652 primary_pid, primary_pid);
2653 ASSERT_MATCH(result, match_str);
2654
2655 match_str =
2656 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2657 ASSERT_MATCH(result, match_str);
2658}
2659
2660// Verify that there is a BuildID present in the map section and set properly.
2661TEST_F(CrasherTest, verify_build_id) {
2662 StartProcess([]() { abort(); });
2663
2664 unique_fd output_fd;
2665 StartIntercept(&output_fd);
2666 FinishCrasher();
2667 AssertDeath(SIGABRT);
2668 int intercept_result;
2669 FinishIntercept(&intercept_result);
2670 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2671
2672 std::string result;
2673 ConsumeFd(std::move(output_fd), &result);
2674
2675 // Find every /system or /apex lib and verify the BuildID is displayed
2676 // properly.
2677 bool found_valid_elf = false;
2678 std::smatch match;
2679 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2680 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2681 result = match.suffix()) {
2682 if (prev_file == match[1]) {
2683 // Already checked this file.
2684 continue;
2685 }
2686
2687 prev_file = match[1];
2688 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2689 if (!elf.Init() || !elf.valid()) {
2690 // Skipping invalid elf files.
2691 continue;
2692 }
2693 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2694
2695 found_valid_elf = true;
2696 }
2697 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2698}