blob: 895c111e38803386266beb4f69b3da7f8e07b8af [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)));
1683}
1684
Josh Gaobf06a402018-08-27 16:34:01 -07001685TEST_F(CrasherTest, fdsan_warning_abort_message) {
1686 int intercept_result;
1687 unique_fd output_fd;
1688
1689 StartProcess([]() {
1690 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001691 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001692 if (fd == -1) {
1693 abort();
1694 }
1695 close(fd.get());
1696 _exit(0);
1697 });
1698
1699 StartIntercept(&output_fd);
1700 FinishCrasher();
1701 AssertDeath(0);
1702 FinishIntercept(&intercept_result);
1703 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1704
1705 std::string result;
1706 ConsumeFd(std::move(output_fd), &result);
1707 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1708}
1709
Josh Gaoc3c8c022017-02-13 16:36:18 -08001710TEST(crash_dump, zombie) {
1711 pid_t forkpid = fork();
1712
Josh Gaoc3c8c022017-02-13 16:36:18 -08001713 pid_t rc;
1714 int status;
1715
1716 if (forkpid == 0) {
1717 errno = 0;
1718 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1719 if (rc != -1 || errno != ECHILD) {
1720 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1721 }
1722
Josh Gaoa48b41b2019-12-13 14:11:04 -08001723 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001724
1725 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001726 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001727 if (rc != -1 || errno != ECHILD) {
1728 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1729 }
1730 _exit(0);
1731 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001732 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001733 ASSERT_EQ(forkpid, rc);
1734 ASSERT_TRUE(WIFEXITED(status));
1735 ASSERT_EQ(0, WEXITSTATUS(status));
1736 }
1737}
Josh Gao352a8452017-03-30 16:46:21 -07001738
1739TEST(tombstoned, no_notify) {
1740 // Do this a few times.
1741 for (int i = 0; i < 3; ++i) {
1742 pid_t pid = 123'456'789 + i;
1743
1744 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001745 InterceptStatus status;
1746 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1747 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001748
1749 {
1750 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001751 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001752 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1753 }
1754
1755 pid_t read_pid;
1756 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1757 ASSERT_EQ(read_pid, pid);
1758 }
1759}
1760
1761TEST(tombstoned, stress) {
1762 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1763 static constexpr int kDumpCount = 100;
1764
1765 std::atomic<bool> start(false);
1766 std::vector<std::thread> threads;
1767 threads.emplace_back([&start]() {
1768 while (!start) {
1769 continue;
1770 }
1771
1772 // Use a way out of range pid, to avoid stomping on an actual process.
1773 pid_t pid_base = 1'000'000;
1774
1775 for (int dump = 0; dump < kDumpCount; ++dump) {
1776 pid_t pid = pid_base + dump;
1777
1778 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001779 InterceptStatus status;
1780 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1781 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001782
1783 // Pretend to crash, and then immediately close the socket.
1784 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1785 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1786 if (sockfd == -1) {
1787 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1788 }
1789 TombstonedCrashPacket packet = {};
1790 packet.packet_type = CrashPacketType::kDumpRequest;
1791 packet.packet.dump_request.pid = pid;
1792 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1793 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1794 }
1795
1796 continue;
1797 }
1798 });
1799
1800 threads.emplace_back([&start]() {
1801 while (!start) {
1802 continue;
1803 }
1804
1805 // Use a way out of range pid, to avoid stomping on an actual process.
1806 pid_t pid_base = 2'000'000;
1807
1808 for (int dump = 0; dump < kDumpCount; ++dump) {
1809 pid_t pid = pid_base + dump;
1810
1811 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001812 InterceptStatus status;
1813 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1814 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001815
1816 {
1817 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001818 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001819 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1820 tombstoned_notify_completion(tombstoned_socket.get());
1821 }
1822
1823 // TODO: Fix the race that requires this sleep.
1824 std::this_thread::sleep_for(50ms);
1825
1826 pid_t read_pid;
1827 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1828 ASSERT_EQ(read_pid, pid);
1829 }
1830 });
1831
1832 start = true;
1833
1834 for (std::thread& thread : threads) {
1835 thread.join();
1836 }
1837}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001838
1839TEST(tombstoned, java_trace_intercept_smoke) {
1840 // Using a "real" PID is a little dangerous here - if the test fails
1841 // or crashes, we might end up getting a bogus / unreliable stack
1842 // trace.
1843 const pid_t self = getpid();
1844
1845 unique_fd intercept_fd, output_fd;
1846 InterceptStatus status;
1847 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1848 ASSERT_EQ(InterceptStatus::kRegistered, status);
1849
Josh Gao76e1e302021-01-26 15:53:11 -08001850 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001851 // should result in a "regular" FD and not the installed intercept.
1852 const char native[] = "native";
1853 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001854 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001855 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1856 tombstoned_notify_completion(tombstoned_socket.get());
1857
1858 // Then, connect to tombstoned asking for a java backtrace. This *should*
1859 // trigger the intercept.
1860 const char java[] = "java";
1861 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1862 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1863 tombstoned_notify_completion(tombstoned_socket.get());
1864
1865 char outbuf[sizeof(java)];
1866 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1867 ASSERT_STREQ("java", outbuf);
1868}
1869
1870TEST(tombstoned, multiple_intercepts) {
1871 const pid_t fake_pid = 1'234'567;
1872 unique_fd intercept_fd, output_fd;
1873 InterceptStatus status;
1874 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1875 ASSERT_EQ(InterceptStatus::kRegistered, status);
1876
1877 unique_fd intercept_fd_2, output_fd_2;
1878 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1879 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1880}
1881
1882TEST(tombstoned, intercept_any) {
1883 const pid_t fake_pid = 1'234'567;
1884
1885 unique_fd intercept_fd, output_fd;
1886 InterceptStatus status;
1887 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1888 ASSERT_EQ(InterceptStatus::kRegistered, status);
1889
1890 const char any[] = "any";
1891 unique_fd tombstoned_socket, input_fd;
1892 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1893 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1894 tombstoned_notify_completion(tombstoned_socket.get());
1895
1896 char outbuf[sizeof(any)];
1897 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1898 ASSERT_STREQ("any", outbuf);
1899}
Josh Gao2b22ae12018-09-12 14:51:03 -07001900
1901TEST(tombstoned, interceptless_backtrace) {
1902 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1903 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1904 std::map<int, time_t> result;
1905 for (int i = 0; i < 99; ++i) {
1906 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1907 struct stat st;
1908 if (stat(path.c_str(), &st) == 0) {
1909 result[i] = st.st_mtim.tv_sec;
1910 }
1911 }
1912 return result;
1913 };
1914
1915 auto before = get_tombstone_timestamps();
1916 for (int i = 0; i < 50; ++i) {
1917 raise_debugger_signal(kDebuggerdNativeBacktrace);
1918 }
1919 auto after = get_tombstone_timestamps();
1920
1921 int diff = 0;
1922 for (int i = 0; i < 99; ++i) {
1923 if (after.count(i) == 0) {
1924 continue;
1925 }
1926 if (before.count(i) == 0) {
1927 ++diff;
1928 continue;
1929 }
1930 if (before[i] != after[i]) {
1931 ++diff;
1932 }
1933 }
1934
1935 // We can't be sure that nothing's crash looping in the background.
1936 // This should be good enough, though...
1937 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1938}
Christopher Ferris481e8372019-07-15 17:13:24 -07001939
1940static __attribute__((__noinline__)) void overflow_stack(void* p) {
1941 void* buf[1];
1942 buf[0] = p;
1943 static volatile void* global = buf;
1944 if (global) {
1945 global = buf;
1946 overflow_stack(&buf);
1947 }
1948}
1949
1950TEST_F(CrasherTest, stack_overflow) {
1951 int intercept_result;
1952 unique_fd output_fd;
1953 StartProcess([]() { overflow_stack(nullptr); });
1954
1955 StartIntercept(&output_fd);
1956 FinishCrasher();
1957 AssertDeath(SIGSEGV);
1958 FinishIntercept(&intercept_result);
1959
1960 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1961
1962 std::string result;
1963 ConsumeFd(std::move(output_fd), &result);
1964 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1965}
Josh Gao76e1e302021-01-26 15:53:11 -08001966
Christopher Ferris22035cc2023-01-31 17:50:22 -08001967static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001968 std::string test_lib(testing::internal::GetArgvs()[0]);
1969 auto const value = test_lib.find_last_of('/');
1970 if (value == std::string::npos) {
1971 test_lib = "./";
1972 } else {
1973 test_lib = test_lib.substr(0, value + 1) + "./";
1974 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08001975 return test_lib + "libcrash_test.so";
1976}
1977
1978static void CreateEmbeddedLibrary(int out_fd) {
1979 std::string test_lib(GetTestLibraryPath());
1980 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
1981 ASSERT_NE(fd.get(), -1);
1982 off_t file_size = lseek(fd, 0, SEEK_END);
1983 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
1984 std::vector<uint8_t> contents(file_size);
1985 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
1986
1987 // Put the shared library data at a pagesize() offset.
1988 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
1989 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
1990}
1991
1992TEST_F(CrasherTest, non_zero_offset_in_library) {
1993 int intercept_result;
1994 unique_fd output_fd;
1995 TemporaryFile tf;
1996 CreateEmbeddedLibrary(tf.fd);
1997 StartProcess([&tf]() {
1998 android_dlextinfo extinfo{};
1999 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
2000 extinfo.library_fd = tf.fd;
2001 extinfo.library_fd_offset = 4 * getpagesize();
2002 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
2003 if (handle == nullptr) {
2004 _exit(1);
2005 }
2006 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2007 if (crash_func == nullptr) {
2008 _exit(1);
2009 }
2010 crash_func();
2011 });
2012
2013 StartIntercept(&output_fd);
2014 FinishCrasher();
2015 AssertDeath(SIGSEGV);
2016 FinishIntercept(&intercept_result);
2017
2018 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2019
2020 std::string result;
2021 ConsumeFd(std::move(output_fd), &result);
2022
2023 // Verify the crash includes an offset value in the backtrace.
2024 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
2025 tf.path, 4 * getpagesize());
2026 ASSERT_MATCH(result, match_str);
2027}
2028
2029static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
2030 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002031
2032 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
2033 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
2034
2035 // Copy the shared so to a tempory directory.
2036 return system(cp_cmd.c_str()) == 0;
2037}
2038
2039TEST_F(CrasherTest, unreadable_elf) {
2040 int intercept_result;
2041 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002042 std::string tmp_so_name;
2043 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002044 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002045 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2046 _exit(1);
2047 }
2048 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
2049 if (handle == nullptr) {
2050 _exit(1);
2051 }
2052 // Delete the original shared library so that we get the warning
2053 // about unreadable elf files.
2054 if (unlink(tmp_so_name.c_str()) == -1) {
2055 _exit(1);
2056 }
2057 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2058 if (crash_func == nullptr) {
2059 _exit(1);
2060 }
2061 crash_func();
2062 });
2063
2064 StartIntercept(&output_fd);
2065 FinishCrasher();
2066 AssertDeath(SIGSEGV);
2067 FinishIntercept(&intercept_result);
2068
2069 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2070
2071 std::string result;
2072 ConsumeFd(std::move(output_fd), &result);
2073 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002074 std::string match_str = "NOTE: " + tmp_so_name;
2075 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002076}
2077
Josh Gao76e1e302021-01-26 15:53:11 -08002078TEST(tombstoned, proto) {
2079 const pid_t self = getpid();
2080 unique_fd tombstoned_socket, text_fd, proto_fd;
2081 ASSERT_TRUE(
2082 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2083
2084 tombstoned_notify_completion(tombstoned_socket.get());
2085
2086 ASSERT_NE(-1, text_fd.get());
2087 ASSERT_NE(-1, proto_fd.get());
2088
2089 struct stat text_st;
2090 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2091
2092 // Give tombstoned some time to link the files into place.
2093 std::this_thread::sleep_for(100ms);
2094
2095 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08002096 std::optional<std::string> tombstone_file;
2097 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2098 ASSERT_TRUE(dir_h != nullptr);
2099 std::regex tombstone_re("tombstone_\\d+");
2100 dirent* entry;
2101 while ((entry = readdir(dir_h.get())) != nullptr) {
2102 if (!std::regex_match(entry->d_name, tombstone_re)) {
2103 continue;
2104 }
2105 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002106
2107 struct stat st;
2108 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2109 continue;
2110 }
2111
2112 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002113 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002114 break;
2115 }
2116 }
2117
Christopher Ferris35da2882021-02-17 15:39:06 -08002118 ASSERT_TRUE(tombstone_file);
2119 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002120
2121 struct stat proto_fd_st;
2122 struct stat proto_file_st;
2123 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2124 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2125
2126 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2127 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2128}
2129
2130TEST(tombstoned, proto_intercept) {
2131 const pid_t self = getpid();
2132 unique_fd intercept_fd, output_fd;
2133 InterceptStatus status;
2134
2135 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2136 ASSERT_EQ(InterceptStatus::kRegistered, status);
2137
2138 unique_fd tombstoned_socket, text_fd, proto_fd;
2139 ASSERT_TRUE(
2140 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2141 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2142 tombstoned_notify_completion(tombstoned_socket.get());
2143
2144 text_fd.reset();
2145
2146 std::string output;
2147 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2148 ASSERT_EQ("foo", output);
2149}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002150
2151// Verify that when an intercept is present for the main thread, and the signal
2152// is received on a different thread, the intercept still works.
2153TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2154 StartProcess([]() {
2155 std::thread thread([]() {
2156 // Raise the signal on the side thread.
2157 raise_debugger_signal(kDebuggerdNativeBacktrace);
2158 });
2159 thread.join();
2160 _exit(0);
2161 });
2162
2163 unique_fd output_fd;
2164 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2165 FinishCrasher();
2166 AssertDeath(0);
2167
2168 int intercept_result;
2169 FinishIntercept(&intercept_result);
2170 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2171
2172 std::string result;
2173 ConsumeFd(std::move(output_fd), &result);
2174 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2175}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002176
2177static std::string format_pointer(uintptr_t ptr) {
2178#if defined(__LP64__)
2179 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2180 static_cast<uint32_t>(ptr & 0xffffffff));
2181#else
2182 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2183#endif
2184}
2185
2186static std::string format_pointer(void* ptr) {
2187 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2188}
2189
2190static std::string format_full_pointer(uintptr_t ptr) {
2191#if defined(__LP64__)
2192 return android::base::StringPrintf("%016" PRIx64, ptr);
2193#else
2194 return android::base::StringPrintf("%08x", ptr);
2195#endif
2196}
2197
2198static std::string format_full_pointer(void* ptr) {
2199 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2200}
2201
2202__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2203 int* crash_ptr = reinterpret_cast<int*>(ptr);
2204 *crash_ptr = 1;
2205 return *crash_ptr;
2206}
2207
2208// Verify that a fault address before the first map is properly handled.
2209TEST_F(CrasherTest, fault_address_before_first_map) {
2210 StartProcess([]() {
2211 ASSERT_EQ(0, crash_call(0x1024));
2212 _exit(0);
2213 });
2214
2215 unique_fd output_fd;
2216 StartIntercept(&output_fd);
2217 FinishCrasher();
2218 AssertDeath(SIGSEGV);
2219
2220 int intercept_result;
2221 FinishIntercept(&intercept_result);
2222 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2223
2224 std::string result;
2225 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002226 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002227
2228 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2229
2230 std::string match_str = android::base::StringPrintf(
2231 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2232 format_pointer(0x1024).c_str());
2233 ASSERT_MATCH(result, match_str);
2234}
2235
2236// Verify that a fault address after the last map is properly handled.
2237TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002238 // This makes assumptions about the memory layout that are not true in HWASan
2239 // processes.
2240 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002241 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2242 StartProcess([crash_uptr]() {
2243 ASSERT_EQ(0, crash_call(crash_uptr));
2244 _exit(0);
2245 });
2246
2247 unique_fd output_fd;
2248 StartIntercept(&output_fd);
2249 FinishCrasher();
2250 AssertDeath(SIGSEGV);
2251
2252 int intercept_result;
2253 FinishIntercept(&intercept_result);
2254 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2255
2256 std::string result;
2257 ConsumeFd(std::move(output_fd), &result);
2258
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002259 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2260 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002261 ASSERT_MATCH(result, match_str);
2262
2263 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2264
2265 // Assumes that the open files section comes after the map section.
2266 // If that assumption changes, the regex below needs to change.
2267 match_str = android::base::StringPrintf(
2268 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2269 format_pointer(crash_uptr).c_str());
2270 ASSERT_MATCH(result, match_str);
2271}
2272
2273// Verify that a fault address between maps is properly handled.
2274TEST_F(CrasherTest, fault_address_between_maps) {
2275 // Create a map before the fork so it will be present in the child.
2276 void* start_ptr =
2277 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2278 ASSERT_NE(MAP_FAILED, start_ptr);
2279 // Unmap the page in the middle.
2280 void* middle_ptr =
2281 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2282 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2283
2284 StartProcess([middle_ptr]() {
2285 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2286 _exit(0);
2287 });
2288
2289 // Unmap the two maps.
2290 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2291 void* end_ptr =
2292 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2293 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2294
2295 unique_fd output_fd;
2296 StartIntercept(&output_fd);
2297 FinishCrasher();
2298 AssertDeath(SIGSEGV);
2299
2300 int intercept_result;
2301 FinishIntercept(&intercept_result);
2302 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2303
2304 std::string result;
2305 ConsumeFd(std::move(output_fd), &result);
2306
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002307 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2308 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002309 ASSERT_MATCH(result, match_str);
2310
2311 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2312
2313 match_str = android::base::StringPrintf(
2314 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2315 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2316 format_pointer(end_ptr).c_str());
2317 ASSERT_MATCH(result, match_str);
2318}
2319
2320// Verify that a fault address happens in the correct map.
2321TEST_F(CrasherTest, fault_address_in_map) {
2322 // Create a map before the fork so it will be present in the child.
2323 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2324 ASSERT_NE(MAP_FAILED, ptr);
2325
2326 StartProcess([ptr]() {
2327 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2328 _exit(0);
2329 });
2330
2331 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2332
2333 unique_fd output_fd;
2334 StartIntercept(&output_fd);
2335 FinishCrasher();
2336 AssertDeath(SIGSEGV);
2337
2338 int intercept_result;
2339 FinishIntercept(&intercept_result);
2340 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2341
2342 std::string result;
2343 ConsumeFd(std::move(output_fd), &result);
2344
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002345 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2346 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002347 ASSERT_MATCH(result, match_str);
2348
2349 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2350
2351 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2352 ASSERT_MATCH(result, match_str);
2353}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002354
2355static constexpr uint32_t kDexData[] = {
2356 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2357 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2358 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2359 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2360 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2361 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2362 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2363 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2364 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2365 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2366 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2367 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2368 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2369 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2370 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2371 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2372 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2373};
2374
2375TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2376 StartProcess([]() {
2377 TemporaryDir td;
2378 std::string tmp_so_name;
2379 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2380 _exit(1);
2381 }
2382
2383 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2384 // move the library to which has a basename of libart.so.
2385 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2386 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2387 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2388 if (handle == nullptr) {
2389 _exit(1);
2390 }
2391
2392 void* ptr =
2393 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2394 ASSERT_TRUE(ptr != MAP_FAILED);
2395 memcpy(ptr, kDexData, sizeof(kDexData));
2396 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2397
2398 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2399 .symfile_size = sizeof(kDexData)};
2400
2401 JITDescriptor* dex_debug =
2402 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2403 ASSERT_TRUE(dex_debug != nullptr);
2404 dex_debug->version = 1;
2405 dex_debug->action_flag = 0;
2406 dex_debug->relevant_entry = 0;
2407 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2408
2409 // This sets the magic dex pc value for register 0, using the value
2410 // of register 1 + 0x102.
2411 asm(".cfi_escape "
2412 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2413 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2414 "0x13 /* DW_OP_drop */,"
2415 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2416
2417 // For each different architecture, set register one to the dex ptr mmap
2418 // created above. Then do a nullptr dereference to force a crash.
2419#if defined(__arm__)
2420 asm volatile(
2421 "mov r1, %[base]\n"
2422 "mov r2, 0\n"
2423 "str r3, [r2]\n"
2424 : [base] "+r"(ptr)
2425 :
2426 : "r1", "r2", "r3", "memory");
2427#elif defined(__aarch64__)
2428 asm volatile(
2429 "mov x1, %[base]\n"
2430 "mov x2, 0\n"
2431 "str x3, [x2]\n"
2432 : [base] "+r"(ptr)
2433 :
2434 : "x1", "x2", "x3", "memory");
2435#elif defined(__i386__)
2436 asm volatile(
2437 "mov %[base], %%ecx\n"
2438 "movl $0, %%edi\n"
2439 "movl 0(%%edi), %%edx\n"
2440 : [base] "+r"(ptr)
2441 :
2442 : "edi", "ecx", "edx", "memory");
2443#elif defined(__x86_64__)
2444 asm volatile(
2445 "mov %[base], %%rdx\n"
2446 "movq 0, %%rdi\n"
2447 "movq 0(%%rdi), %%rcx\n"
2448 : [base] "+r"(ptr)
2449 :
2450 : "rcx", "rdx", "rdi", "memory");
2451#else
2452#error "Unsupported architecture"
2453#endif
2454 _exit(0);
2455 });
2456
2457 unique_fd output_fd;
2458 StartIntercept(&output_fd);
2459 FinishCrasher();
2460 AssertDeath(SIGSEGV);
2461
2462 int intercept_result;
2463 FinishIntercept(&intercept_result);
2464 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2465
2466 std::string result;
2467 ConsumeFd(std::move(output_fd), &result);
2468
2469 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002470 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002471
2472 // Now verify that the dex_pc frame includes a proper function name.
2473 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2474}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002475
2476static std::string format_map_pointer(uintptr_t ptr) {
2477#if defined(__LP64__)
2478 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2479 static_cast<uint32_t>(ptr & 0xffffffff));
2480#else
2481 return android::base::StringPrintf("%08x", ptr);
2482#endif
2483}
2484
2485// Verify that map data is properly formatted.
2486TEST_F(CrasherTest, verify_map_format) {
2487 // Create multiple maps to make sure that the map data is formatted properly.
2488 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2489 ASSERT_NE(MAP_FAILED, none_map);
2490 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2491 ASSERT_NE(MAP_FAILED, r_map);
2492 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2493 ASSERT_NE(MAP_FAILED, w_map);
2494 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2495 ASSERT_NE(MAP_FAILED, x_map);
2496
2497 TemporaryFile tf;
2498 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2499 char c = 'f';
2500 ASSERT_EQ(1, write(tf.fd, &c, 1));
2501 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2502 ASSERT_EQ(1, write(tf.fd, &c, 1));
2503 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2504 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2505 ASSERT_NE(MAP_FAILED, file_map);
2506
2507 StartProcess([]() { abort(); });
2508
2509 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2510 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2511 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2512 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2513 ASSERT_EQ(0, munmap(file_map, 0x3001));
2514
2515 unique_fd output_fd;
2516 StartIntercept(&output_fd);
2517 FinishCrasher();
2518 AssertDeath(SIGABRT);
2519 int intercept_result;
2520 FinishIntercept(&intercept_result);
2521
2522 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2523
2524 std::string result;
2525 ConsumeFd(std::move(output_fd), &result);
2526
2527 std::string match_str;
2528 // Verify none.
2529 match_str = android::base::StringPrintf(
2530 " %s-%s --- 0 1000\\n",
2531 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2532 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2533 ASSERT_MATCH(result, match_str);
2534
2535 // Verify read-only.
2536 match_str = android::base::StringPrintf(
2537 " %s-%s r-- 0 1000\\n",
2538 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2539 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2540 ASSERT_MATCH(result, match_str);
2541
2542 // Verify write-only.
2543 match_str = android::base::StringPrintf(
2544 " %s-%s -w- 0 1000\\n",
2545 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2546 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2547 ASSERT_MATCH(result, match_str);
2548
2549 // Verify exec-only.
2550 match_str = android::base::StringPrintf(
2551 " %s-%s --x 0 1000\\n",
2552 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2553 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2554 ASSERT_MATCH(result, match_str);
2555
2556 // Verify file map with non-zero offset and a name.
2557 match_str = android::base::StringPrintf(
2558 " %s-%s r-- 2000 4000 %s\\n",
2559 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2560 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2561 ASSERT_MATCH(result, match_str);
2562}
2563
2564// Verify that the tombstone map data is correct.
2565TEST_F(CrasherTest, verify_header) {
2566 StartProcess([]() { abort(); });
2567
2568 unique_fd output_fd;
2569 StartIntercept(&output_fd);
2570 FinishCrasher();
2571 AssertDeath(SIGABRT);
2572 int intercept_result;
2573 FinishIntercept(&intercept_result);
2574
2575 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2576
2577 std::string result;
2578 ConsumeFd(std::move(output_fd), &result);
2579
2580 std::string match_str = android::base::StringPrintf(
2581 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2582 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2583 android::base::GetProperty("ro.revision", "unknown").c_str());
2584 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2585 ASSERT_MATCH(result, match_str);
2586}
2587
2588// Verify that the thread header is formatted properly.
2589TEST_F(CrasherTest, verify_thread_header) {
2590 void* shared_map =
2591 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2592 ASSERT_NE(MAP_FAILED, shared_map);
2593 memset(shared_map, 0, sizeof(pid_t));
2594
2595 StartProcess([&shared_map]() {
2596 std::atomic_bool tid_written;
2597 std::thread thread([&tid_written, &shared_map]() {
2598 pid_t tid = gettid();
2599 memcpy(shared_map, &tid, sizeof(pid_t));
2600 tid_written = true;
2601 volatile bool done = false;
2602 while (!done)
2603 ;
2604 });
2605 thread.detach();
2606 while (!tid_written.load(std::memory_order_acquire))
2607 ;
2608 abort();
2609 });
2610
2611 pid_t primary_pid = crasher_pid;
2612
2613 unique_fd output_fd;
2614 StartIntercept(&output_fd);
2615 FinishCrasher();
2616 AssertDeath(SIGABRT);
2617 int intercept_result;
2618 FinishIntercept(&intercept_result);
2619 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2620
2621 // Read the tid data out.
2622 pid_t tid;
2623 memcpy(&tid, shared_map, sizeof(pid_t));
2624 ASSERT_NE(0, tid);
2625
2626 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2627
2628 std::string result;
2629 ConsumeFd(std::move(output_fd), &result);
2630
2631 // Verify that there are two headers, one where the tid is "primary_pid"
2632 // and the other where the tid is "tid".
2633 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2634 primary_pid, primary_pid);
2635 ASSERT_MATCH(result, match_str);
2636
2637 match_str =
2638 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2639 ASSERT_MATCH(result, match_str);
2640}
2641
2642// Verify that there is a BuildID present in the map section and set properly.
2643TEST_F(CrasherTest, verify_build_id) {
2644 StartProcess([]() { abort(); });
2645
2646 unique_fd output_fd;
2647 StartIntercept(&output_fd);
2648 FinishCrasher();
2649 AssertDeath(SIGABRT);
2650 int intercept_result;
2651 FinishIntercept(&intercept_result);
2652 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2653
2654 std::string result;
2655 ConsumeFd(std::move(output_fd), &result);
2656
2657 // Find every /system or /apex lib and verify the BuildID is displayed
2658 // properly.
2659 bool found_valid_elf = false;
2660 std::smatch match;
2661 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2662 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2663 result = match.suffix()) {
2664 if (prev_file == match[1]) {
2665 // Already checked this file.
2666 continue;
2667 }
2668
2669 prev_file = match[1];
2670 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2671 if (!elf.Init() || !elf.valid()) {
2672 // Skipping invalid elf files.
2673 continue;
2674 }
2675 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2676
2677 found_valid_elf = true;
2678 }
2679 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2680}