blob: a8d7de6ec5aef6ef56956110ba99a436ab828b84 [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 Phillips5ddcea22021-04-19 09:59:17 -070068#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010069#include "protocol.h"
70#include "tombstoned/tombstoned.h"
71#include "util.h"
72
Josh Gaocbe70cb2016-10-18 18:17:52 -070073using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080074
75using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070076using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070077using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070078
79#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070080#define ARCH_SUFFIX "64"
81#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070082#define ARCH_SUFFIX ""
83#endif
84
Elliott Hughese4781d52021-03-17 09:15:15 -070085constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070086
87#define TIMEOUT(seconds, expr) \
88 [&]() { \
89 struct sigaction old_sigaction; \
90 struct sigaction new_sigaction = {}; \
91 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080092 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070093 err(1, "sigaction failed"); \
94 } \
95 alarm(seconds); \
96 auto value = expr; \
97 int saved_errno = errno; \
98 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
99 err(1, "sigaction failed"); \
100 } \
101 alarm(0); \
102 errno = saved_errno; \
103 return value; \
104 }()
105
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700106// Backtrace frame dump could contain:
107// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
108// or
109// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800110#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700111 ASSERT_MATCH(result, \
112 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900113
Mitch Phillips7168a212021-03-09 16:53:23 -0800114// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
115// process sampling, so we need to ensure we force GWP-ASan on.
116__attribute__((constructor)) static void enable_gwp_asan() {
Mitch Phillips1e096992022-03-22 15:59:31 -0700117 android_mallopt_gwp_asan_options_t opts;
118 // No, we're not an app, but let's turn ourselves on without sampling.
119 // Technically, if someone's using the *.default_app sysprops, they'll adjust
120 // our settings, but I don't think this will be common on a device that's
121 // running debuggerd_tests.
122 opts.desire = android_mallopt_gwp_asan_options_t::Action::TURN_ON_FOR_APP;
123 opts.program_name = "";
124 android_mallopt(M_INITIALIZE_GWP_ASAN, &opts, sizeof(android_mallopt_gwp_asan_options_t));
Mitch Phillips7168a212021-03-09 16:53:23 -0800125}
126
Narayan Kamatha73df602017-05-24 15:07:25 +0100127static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100128 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700129 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
130 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
131 if (intercept_fd->get() == -1) {
132 FAIL() << "failed to contact tombstoned: " << strerror(errno);
133 }
134
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700135 InterceptRequest req = {
136 .dump_type = intercept_type,
137 .pid = target_pid,
138 };
Josh Gao460b3362017-03-30 16:40:47 -0700139
140 unique_fd output_pipe_write;
141 if (!Pipe(output_fd, &output_pipe_write)) {
142 FAIL() << "failed to create output pipe: " << strerror(errno);
143 }
144
145 std::string pipe_size_str;
146 int pipe_buffer_size;
147 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
148 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
149 }
150
151 pipe_size_str = android::base::Trim(pipe_size_str);
152
153 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
154 FAIL() << "failed to parse pipe max size";
155 }
156
157 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
158 FAIL() << "failed to set pipe size: " << strerror(errno);
159 }
160
Josh Gao5675f3c2017-06-01 12:19:53 -0700161 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
162
Josh Gao5f87bbd2019-01-09 17:01:49 -0800163 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
164 output_pipe_write.reset();
165 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700166 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
167 }
168
169 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800170 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700171 if (rc == -1) {
172 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
173 } else if (rc == 0) {
174 FAIL() << "failed to read response from tombstoned (EOF)";
175 } else if (rc != sizeof(response)) {
176 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
177 << ", received " << rc;
178 }
179
Narayan Kamathca5e9082017-06-02 15:42:06 +0100180 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700181}
182
Elliott Hughesd13ea522022-01-13 09:20:26 -0800183static bool pac_supported() {
184#if defined(__aarch64__)
185 return getauxval(AT_HWCAP) & HWCAP_PACA;
186#else
187 return false;
188#endif
189}
190
Josh Gaocbe70cb2016-10-18 18:17:52 -0700191class CrasherTest : public ::testing::Test {
192 public:
193 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700194 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700195 unique_fd crasher_pipe;
196 unique_fd intercept_fd;
197
198 CrasherTest();
199 ~CrasherTest();
200
Narayan Kamatha73df602017-05-24 15:07:25 +0100201 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700202
203 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
204 void FinishIntercept(int* result);
205
Josh Gao2e7b8e22017-05-04 17:12:57 -0700206 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700207 void StartCrasher(const std::string& crash_type);
208 void FinishCrasher();
209 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700210
211 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700212};
213
214CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700215 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
216 android::base::SetProperty(kWaitForDebuggerKey, "0");
217
218 // Clear the old property too, just in case someone's been using it
219 // on this device. (We only document the new name, but we still support
220 // the old name so we don't break anyone's existing setups.)
221 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222}
223
224CrasherTest::~CrasherTest() {
225 if (crasher_pid != -1) {
226 kill(crasher_pid, SIGKILL);
227 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700228 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700229 }
230
Elliott Hughese4781d52021-03-17 09:15:15 -0700231 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700232}
233
Narayan Kamatha73df602017-05-24 15:07:25 +0100234void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700235 if (crasher_pid == -1) {
236 FAIL() << "crasher hasn't been started";
237 }
238
Narayan Kamathca5e9082017-06-02 15:42:06 +0100239 InterceptStatus status;
240 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
241 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700242}
243
244void CrasherTest::FinishIntercept(int* result) {
245 InterceptResponse response;
246
Christopher Ferris11555f02019-09-20 14:18:55 -0700247 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700248 if (rc == -1) {
249 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
250 } else if (rc == 0) {
251 *result = -1;
252 } else if (rc != sizeof(response)) {
253 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
254 << ", received " << rc;
255 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700256 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700257 }
258}
259
Josh Gao2e7b8e22017-05-04 17:12:57 -0700260void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800261 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700262 unique_fd crasher_read_pipe;
263 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
264 FAIL() << "failed to create pipe: " << strerror(errno);
265 }
266
Josh Gao2e7b8e22017-05-04 17:12:57 -0700267 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700268 if (crasher_pid == -1) {
269 FAIL() << "fork failed: " << strerror(errno);
270 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800271 char dummy;
272 crasher_pipe.reset();
273 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800274 function();
275 _exit(0);
276 }
277}
278
Josh Gaocbe70cb2016-10-18 18:17:52 -0700279void CrasherTest::FinishCrasher() {
280 if (crasher_pipe == -1) {
281 FAIL() << "crasher pipe uninitialized";
282 }
283
Christopher Ferris172b0a02019-09-18 17:48:30 -0700284 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700285 if (rc == -1) {
286 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
287 } else if (rc == 0) {
288 FAIL() << "crasher pipe was closed";
289 }
290}
291
292void CrasherTest::AssertDeath(int signo) {
293 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700294 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700295 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700296 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
297 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700298 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700299 FAIL() << "failed to wait for crasher: " << strerror(errno);
300 }
301
Josh Gaoe06f2a42017-04-27 16:50:38 -0700302 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700303 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700304 ASSERT_EQ(0, WEXITSTATUS(signo));
305 } else {
306 ASSERT_FALSE(WIFEXITED(status));
307 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
308 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700309 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700310 crasher_pid = -1;
311}
312
313static void ConsumeFd(unique_fd fd, std::string* output) {
314 constexpr size_t read_length = PAGE_SIZE;
315 std::string result;
316
317 while (true) {
318 size_t offset = result.size();
319 result.resize(result.size() + PAGE_SIZE);
320 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
321 if (rc == -1) {
322 FAIL() << "read failed: " << strerror(errno);
323 } else if (rc == 0) {
324 result.resize(result.size() - PAGE_SIZE);
325 break;
326 }
327
328 result.resize(result.size() - PAGE_SIZE + rc);
329 }
330
331 *output = std::move(result);
332}
333
Mitch Phillips78f06702021-06-01 14:35:43 -0700334class LogcatCollector {
335 public:
336 LogcatCollector() { system("logcat -c"); }
337
338 void Collect(std::string* output) {
339 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
340 ASSERT_NE(cmd_stdout, nullptr);
341 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
342 ConsumeFd(std::move(tmp_fd), output);
343 pclose(cmd_stdout);
344 }
345};
346
Josh Gaocbe70cb2016-10-18 18:17:52 -0700347TEST_F(CrasherTest, smoke) {
348 int intercept_result;
349 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800350 StartProcess([]() {
351 *reinterpret_cast<volatile char*>(0xdead) = '1';
352 });
353
Josh Gaocbe70cb2016-10-18 18:17:52 -0700354 StartIntercept(&output_fd);
355 FinishCrasher();
356 AssertDeath(SIGSEGV);
357 FinishIntercept(&intercept_result);
358
359 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
360
361 std::string result;
362 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800363#ifdef __LP64__
364 ASSERT_MATCH(result,
365 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
366#else
367 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
368#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700369
370 if (mte_supported()) {
371 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700372 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
373 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700374 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800375
376 if (pac_supported()) {
377 // Test that the default PAC_ENABLED_KEYS value is set.
378 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
379 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
380 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700381}
382
Peter Collingbournef03af882020-03-20 18:09:00 -0700383TEST_F(CrasherTest, tagged_fault_addr) {
384#if !defined(__aarch64__)
385 GTEST_SKIP() << "Requires aarch64";
386#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700387 // HWASan crashes with SIGABRT on tag mismatch.
388 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700389 int intercept_result;
390 unique_fd output_fd;
391 StartProcess([]() {
392 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
393 });
394
395 StartIntercept(&output_fd);
396 FinishCrasher();
397 AssertDeath(SIGSEGV);
398 FinishIntercept(&intercept_result);
399
400 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
401
402 std::string result;
403 ConsumeFd(std::move(output_fd), &result);
404
405 // The address can either be tagged (new kernels) or untagged (old kernels).
406 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800407 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700408}
409
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700410void CrasherTest::Trap(void* ptr) {
411 void (*volatile f)(void*) = nullptr;
412 __asm__ __volatile__("" : : "r"(f) : "memory");
413 f(ptr);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700414}
415
416TEST_F(CrasherTest, heap_addr_in_register) {
417#if defined(__i386__)
418 GTEST_SKIP() << "architecture does not pass arguments in registers";
419#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700420 // The memory dump in HWASan crashes sadly shows the memory near the registers
421 // in the HWASan dump function, rather the faulting context. This is a known
422 // issue.
423 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700424 int intercept_result;
425 unique_fd output_fd;
426 StartProcess([]() {
427 // Crash with a heap pointer in the first argument register.
428 Trap(malloc(1));
429 });
430
431 StartIntercept(&output_fd);
432 FinishCrasher();
433 int status;
434 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
435 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
436 // Don't test the signal number because different architectures use different signals for
437 // __builtin_trap().
438 FinishIntercept(&intercept_result);
439
440 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
441
442 std::string result;
443 ConsumeFd(std::move(output_fd), &result);
444
445#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800446 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700447#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800448 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
haocheng.zy@linux.alibaba.com3f4d0362022-09-10 11:38:19 +0800449#elif defined(__riscv)
450 ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700451#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800452 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700453#else
454 ASSERT_TRUE(false) << "unsupported architecture";
455#endif
456}
457
Peter Collingbournecd278072020-12-21 14:08:38 -0800458#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700459static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800460 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700461 abort();
462 }
463}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800464
465static void SetTagCheckingLevelAsync() {
466 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
467 abort();
468 }
469}
Peter Collingbournef8622522020-04-07 14:07:32 -0700470#endif
471
Mitch Phillips7168a212021-03-09 16:53:23 -0800472// Number of iterations required to reliably guarantee a GWP-ASan crash.
473// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
474// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
475// the counter reaches zero, we provide a sampled allocation. Then, double that
476// figure to allow for left/right allocation alignment, as this is done randomly
477// without bias.
478#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
479
480struct GwpAsanTestParameters {
481 size_t alloc_size;
482 bool free_before_access;
483 int access_offset;
484 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
485};
486
487struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
488
489GwpAsanTestParameters gwp_asan_tests[] = {
490 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
491 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
492 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
493 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
494};
495
496INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
497
498TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
499 if (mte_supported()) {
500 // Skip this test on MTE hardware, as MTE will reliably catch these errors
501 // instead of GWP-ASan.
502 GTEST_SKIP() << "Skipped on MTE.";
503 }
Florian Mayerb4979292022-04-15 14:35:17 -0700504 // Skip this test on HWASan, which will reliably catch test errors as well.
505 SKIP_WITH_HWASAN;
Mitch Phillips7168a212021-03-09 16:53:23 -0800506
507 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700508 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800509
510 int intercept_result;
511 unique_fd output_fd;
512 StartProcess([&params]() {
513 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
514 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
515 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
516 p[params.access_offset] = 42;
517 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
518 }
519 });
520
521 StartIntercept(&output_fd);
522 FinishCrasher();
523 AssertDeath(SIGSEGV);
524 FinishIntercept(&intercept_result);
525
526 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
527
Mitch Phillips78f06702021-06-01 14:35:43 -0700528 std::vector<std::string> log_sources(2);
529 ConsumeFd(std::move(output_fd), &log_sources[0]);
530 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800531
Mitch Phillips78f06702021-06-01 14:35:43 -0700532 for (const auto& result : log_sources) {
533 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
534 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
535 if (params.free_before_access) {
536 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
537 }
538 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800539 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800540}
541
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800542struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
543
Peter Collingbourneaa544792021-05-13 13:53:37 -0700544INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800545
546TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800547#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700548 if (!mte_supported()) {
549 GTEST_SKIP() << "Requires MTE";
550 }
551
Peter Collingbourneaa544792021-05-13 13:53:37 -0700552 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
553 if (GetParam() == 0) {
554 return;
555 }
556
Mitch Phillips78f06702021-06-01 14:35:43 -0700557 LogcatCollector logcat_collector;
558
Peter Collingbournef8622522020-04-07 14:07:32 -0700559 int intercept_result;
560 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800561 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700562 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800563 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700564 free((void *)p);
565 p[0] = 42;
566 });
567
568 StartIntercept(&output_fd);
569 FinishCrasher();
570 AssertDeath(SIGSEGV);
571 FinishIntercept(&intercept_result);
572
573 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
574
Mitch Phillips78f06702021-06-01 14:35:43 -0700575 std::vector<std::string> log_sources(2);
576 ConsumeFd(std::move(output_fd), &log_sources[0]);
577 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700578 // Tag dump only available in the tombstone, not logcat.
579 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700580
Mitch Phillips78f06702021-06-01 14:35:43 -0700581 for (const auto& result : log_sources) {
582 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
583 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
584 std::to_string(GetParam()) + R"(-byte allocation)");
585 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
586 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
587 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700588#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800589 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700590#endif
591}
592
Peter Collingbournedc476342021-05-12 15:56:43 -0700593TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
594#if defined(__aarch64__)
595 if (!mte_supported()) {
596 GTEST_SKIP() << "Requires MTE";
597 }
598
599 int intercept_result;
600 unique_fd output_fd;
601 StartProcess([&]() {
602 SetTagCheckingLevelSync();
603 volatile int* p = (volatile int*)malloc(GetParam());
604 free((void *)p);
605 p[-1] = 42;
606 });
607
608 StartIntercept(&output_fd);
609 FinishCrasher();
610 AssertDeath(SIGSEGV);
611 FinishIntercept(&intercept_result);
612
613 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
614
615 std::string result;
616 ConsumeFd(std::move(output_fd), &result);
617
618 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
619 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
620#else
621 GTEST_SKIP() << "Requires aarch64";
622#endif
623}
624
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800625TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800626#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700627 if (!mte_supported()) {
628 GTEST_SKIP() << "Requires MTE";
629 }
630
Mitch Phillips78f06702021-06-01 14:35:43 -0700631 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700632 int intercept_result;
633 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800634 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700635 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800636 volatile char* p = (volatile char*)malloc(GetParam());
637 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700638 });
639
640 StartIntercept(&output_fd);
641 FinishCrasher();
642 AssertDeath(SIGSEGV);
643 FinishIntercept(&intercept_result);
644
645 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
646
Mitch Phillips78f06702021-06-01 14:35:43 -0700647 std::vector<std::string> log_sources(2);
648 ConsumeFd(std::move(output_fd), &log_sources[0]);
649 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700650
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700651 // Tag dump only in tombstone, not logcat, and tagging is not used for
652 // overflow protection in the scudo secondary (guard pages are used instead).
653 if (GetParam() < 0x10000) {
654 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
655 }
656
Mitch Phillips78f06702021-06-01 14:35:43 -0700657 for (const auto& result : log_sources) {
658 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
659 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
660 std::to_string(GetParam()) + R"(-byte allocation)");
661 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
662 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700663#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800664 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700665#endif
666}
667
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800668TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800669#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700670 if (!mte_supported()) {
671 GTEST_SKIP() << "Requires MTE";
672 }
673
674 int intercept_result;
675 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800676 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700677 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800678 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700679 p[-1] = 42;
680 });
681
682 StartIntercept(&output_fd);
683 FinishCrasher();
684 AssertDeath(SIGSEGV);
685 FinishIntercept(&intercept_result);
686
687 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
688
689 std::string result;
690 ConsumeFd(std::move(output_fd), &result);
691
692 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800693 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800694 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700695 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700696 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700697 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700698#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800699 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700700#endif
701}
702
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800703TEST_F(CrasherTest, mte_async) {
704#if defined(__aarch64__)
705 if (!mte_supported()) {
706 GTEST_SKIP() << "Requires MTE";
707 }
708
709 int intercept_result;
710 unique_fd output_fd;
711 StartProcess([&]() {
712 SetTagCheckingLevelAsync();
713 volatile int* p = (volatile int*)malloc(16);
714 p[-1] = 42;
715 });
716
717 StartIntercept(&output_fd);
718 FinishCrasher();
719 AssertDeath(SIGSEGV);
720 FinishIntercept(&intercept_result);
721
722 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
723
724 std::string result;
725 ConsumeFd(std::move(output_fd), &result);
726
727 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
728#else
729 GTEST_SKIP() << "Requires aarch64";
730#endif
731}
732
Peter Collingbournef8622522020-04-07 14:07:32 -0700733TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800734#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700735 if (!mte_supported()) {
736 GTEST_SKIP() << "Requires MTE";
737 }
738
Mitch Phillips78f06702021-06-01 14:35:43 -0700739 LogcatCollector logcat_collector;
740
Peter Collingbournef8622522020-04-07 14:07:32 -0700741 int intercept_result;
742 unique_fd output_fd;
743 StartProcess([]() {
744 SetTagCheckingLevelSync();
745
746 // Make two allocations with the same tag and close to one another. Check for both properties
747 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
748 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
749 // (some non-zero value << 56) apart.
750 //
751 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
752 // other.
753 std::set<uintptr_t> allocs;
754 for (int i = 0; i != 4096; ++i) {
755 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
756 auto it = allocs.insert(alloc).first;
757 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
758 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
759 }
760 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
761 *reinterpret_cast<int*>(alloc + 16) = 42;
762 }
763 }
764 });
765
766 StartIntercept(&output_fd);
767 FinishCrasher();
768 AssertDeath(SIGSEGV);
769 FinishIntercept(&intercept_result);
770
771 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
772
Mitch Phillips78f06702021-06-01 14:35:43 -0700773 std::vector<std::string> log_sources(2);
774 ConsumeFd(std::move(output_fd), &log_sources[0]);
775 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700776
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700777 // Tag dump only in the tombstone, not logcat.
778 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
779
Mitch Phillips78f06702021-06-01 14:35:43 -0700780 for (const auto& result : log_sources) {
781 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
782 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800783 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700784 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
785 // overflows), so we can't match explicitly for an underflow message.
786 ASSERT_MATCH(result,
787 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
788 // Ensure there's at least two allocation traces (one for each cause).
789 ASSERT_MATCH(
790 result,
791 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
792 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700793#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800794 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700795#endif
796}
797
Peter Collingbournecd278072020-12-21 14:08:38 -0800798#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700799static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700800 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
801 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
802 size_t page_size = getpagesize();
803 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
804 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
805 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700806 return 0;
807 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700808 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
809 PROT_READ | PROT_WRITE | PROT_MTE);
810 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
811 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
812 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
813 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
814 }
815 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700816}
817#endif
818
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700819TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800820#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700821 if (!mte_supported()) {
822 GTEST_SKIP() << "Requires MTE";
823 }
824
825 int intercept_result;
826 unique_fd output_fd;
827 StartProcess([&]() {
828 SetTagCheckingLevelSync();
829 Trap(reinterpret_cast<void *>(CreateTagMapping()));
830 });
831
832 StartIntercept(&output_fd);
833 FinishCrasher();
Evgenii Stepanov361455e2022-10-13 16:23:08 -0700834 AssertDeath(SIGSEGV);
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700835 FinishIntercept(&intercept_result);
836
837 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
838
839 std::string result;
840 ConsumeFd(std::move(output_fd), &result);
841
842 ASSERT_MATCH(result, R"(memory near x0:
843.*
844.*
845 01.............0 0000000000000000 0000000000000000 ................
846 00.............0)");
847#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800848 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700849#endif
850}
851
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700852TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
853#if defined(__aarch64__)
854 if (!mte_supported()) {
855 GTEST_SKIP() << "Requires MTE";
856 }
857
858 int intercept_result;
859 unique_fd output_fd;
860 StartProcess([&]() {
861 SetTagCheckingLevelSync();
862 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
863 p[0] = 0; // Untagged pointer, tagged memory.
864 });
865
866 StartIntercept(&output_fd);
867 FinishCrasher();
868 AssertDeath(SIGSEGV);
869 FinishIntercept(&intercept_result);
870
871 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
872
873 std::string result;
874 ConsumeFd(std::move(output_fd), &result);
875
876 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
877\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
878#else
879 GTEST_SKIP() << "Requires aarch64";
880#endif
881}
882
883TEST_F(CrasherTest, mte_fault_tag_dump) {
884#if defined(__aarch64__)
885 if (!mte_supported()) {
886 GTEST_SKIP() << "Requires MTE";
887 }
888
889 int intercept_result;
890 unique_fd output_fd;
891 StartProcess([&]() {
892 SetTagCheckingLevelSync();
893 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
894 p[320] = 0; // Untagged pointer, tagged memory.
895 });
896
897 StartIntercept(&output_fd);
898 FinishCrasher();
899 AssertDeath(SIGSEGV);
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);
906
907 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
908\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
909\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
910\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
911)");
912#else
913 GTEST_SKIP() << "Requires aarch64";
914#endif
915}
916
917TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
918#if defined(__aarch64__)
919 if (!mte_supported()) {
920 GTEST_SKIP() << "Requires MTE";
921 }
922
923 int intercept_result;
924 unique_fd output_fd;
925 StartProcess([&]() {
926 SetTagCheckingLevelSync();
927 size_t page_size = getpagesize();
928 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
929 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
930 });
931
932 StartIntercept(&output_fd);
933 FinishCrasher();
934 AssertDeath(SIGSEGV);
935 FinishIntercept(&intercept_result);
936
937 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
938
939 std::string result;
940 ConsumeFd(std::move(output_fd), &result);
941
942 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
943 ASSERT_MATCH(result,
944 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
945\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
946
947)"); // Ensure truncation happened and there's a newline after the tag fault.
948#else
949 GTEST_SKIP() << "Requires aarch64";
950#endif
951}
952
Josh Gaocdea7502017-11-01 15:00:40 -0700953TEST_F(CrasherTest, LD_PRELOAD) {
954 int intercept_result;
955 unique_fd output_fd;
956 StartProcess([]() {
957 setenv("LD_PRELOAD", "nonexistent.so", 1);
958 *reinterpret_cast<volatile char*>(0xdead) = '1';
959 });
960
961 StartIntercept(&output_fd);
962 FinishCrasher();
963 AssertDeath(SIGSEGV);
964 FinishIntercept(&intercept_result);
965
966 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
967
968 std::string result;
969 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800970 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700971}
972
Josh Gaocbe70cb2016-10-18 18:17:52 -0700973TEST_F(CrasherTest, abort) {
974 int intercept_result;
975 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800976 StartProcess([]() {
977 abort();
978 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700979 StartIntercept(&output_fd);
980 FinishCrasher();
981 AssertDeath(SIGABRT);
982 FinishIntercept(&intercept_result);
983
984 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
985
986 std::string result;
987 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700988 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700989}
990
991TEST_F(CrasherTest, signal) {
992 int intercept_result;
993 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800994 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700995 while (true) {
996 sleep(1);
997 }
Josh Gao502cfd22017-02-17 01:39:15 -0800998 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700999 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001000 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -07001001 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
1002
1003 AssertDeath(SIGSEGV);
1004 FinishIntercept(&intercept_result);
1005
1006 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1007
1008 std::string result;
1009 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -07001010 ASSERT_MATCH(
1011 result,
1012 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001013 ASSERT_MATCH(result, R"(backtrace:)");
1014}
1015
1016TEST_F(CrasherTest, abort_message) {
1017 int intercept_result;
1018 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001019 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001020 // Arrived at experimentally;
1021 // logd truncates at 4062.
1022 // strlen("Abort message: ''") is 17.
1023 // That's 4045, but we also want a NUL.
1024 char buf[4045 + 1];
1025 memset(buf, 'x', sizeof(buf));
1026 buf[sizeof(buf) - 1] = '\0';
1027 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001028 abort();
1029 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001030 StartIntercept(&output_fd);
1031 FinishCrasher();
1032 AssertDeath(SIGABRT);
1033 FinishIntercept(&intercept_result);
1034
1035 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1036
1037 std::string result;
1038 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001039 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001040}
1041
Christopher Ferrise8891452021-08-17 17:34:53 -07001042TEST_F(CrasherTest, abort_message_newline_trimmed) {
1043 int intercept_result;
1044 unique_fd output_fd;
1045 StartProcess([]() {
1046 android_set_abort_message("Message with a newline.\n");
1047 abort();
1048 });
1049 StartIntercept(&output_fd);
1050 FinishCrasher();
1051 AssertDeath(SIGABRT);
1052 FinishIntercept(&intercept_result);
1053
1054 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1055
1056 std::string result;
1057 ConsumeFd(std::move(output_fd), &result);
1058 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1059}
1060
1061TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1062 int intercept_result;
1063 unique_fd output_fd;
1064 StartProcess([]() {
1065 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1066 abort();
1067 });
1068 StartIntercept(&output_fd);
1069 FinishCrasher();
1070 AssertDeath(SIGABRT);
1071 FinishIntercept(&intercept_result);
1072
1073 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1074
1075 std::string result;
1076 ConsumeFd(std::move(output_fd), &result);
1077 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1078}
1079
Josh Gaoe06f2a42017-04-27 16:50:38 -07001080TEST_F(CrasherTest, abort_message_backtrace) {
1081 int intercept_result;
1082 unique_fd output_fd;
1083 StartProcess([]() {
1084 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001085 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001086 exit(0);
1087 });
1088 StartIntercept(&output_fd);
1089 FinishCrasher();
1090 AssertDeath(0);
1091 FinishIntercept(&intercept_result);
1092
1093 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1094
1095 std::string result;
1096 ConsumeFd(std::move(output_fd), &result);
1097 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1098}
1099
Josh Gaocbe70cb2016-10-18 18:17:52 -07001100TEST_F(CrasherTest, intercept_timeout) {
1101 int intercept_result;
1102 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001103 StartProcess([]() {
1104 abort();
1105 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001106 StartIntercept(&output_fd);
1107
1108 // Don't let crasher finish until we timeout.
1109 FinishIntercept(&intercept_result);
1110
1111 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1112 << intercept_result << ")";
1113
1114 FinishCrasher();
1115 AssertDeath(SIGABRT);
1116}
1117
Elliott Hughese4781d52021-03-17 09:15:15 -07001118TEST_F(CrasherTest, wait_for_debugger) {
1119 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1120 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001121 }
1122 sleep(1);
1123
Josh Gao502cfd22017-02-17 01:39:15 -08001124 StartProcess([]() {
1125 abort();
1126 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001127 FinishCrasher();
1128
1129 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001130 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001131 ASSERT_TRUE(WIFSTOPPED(status));
1132 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1133
1134 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1135
1136 AssertDeath(SIGABRT);
1137}
1138
Josh Gaocbe70cb2016-10-18 18:17:52 -07001139TEST_F(CrasherTest, backtrace) {
1140 std::string result;
1141 int intercept_result;
1142 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001143
1144 StartProcess([]() {
1145 abort();
1146 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001147 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001148
1149 std::this_thread::sleep_for(500ms);
1150
1151 sigval val;
1152 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001153 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001154 FinishIntercept(&intercept_result);
1155 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1156 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001157 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001158
1159 int status;
1160 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1161
1162 StartIntercept(&output_fd);
1163 FinishCrasher();
1164 AssertDeath(SIGABRT);
1165 FinishIntercept(&intercept_result);
1166 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1167 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001168 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001169}
Josh Gaofca7ca32017-01-23 12:05:35 -08001170
1171TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001172 int intercept_result;
1173 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001174 StartProcess([]() {
1175 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001176 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001177 });
Josh Gao502cfd22017-02-17 01:39:15 -08001178
1179 StartIntercept(&output_fd);
1180 FinishCrasher();
1181 AssertDeath(SIGABRT);
1182 FinishIntercept(&intercept_result);
1183
1184 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1185
1186 std::string result;
1187 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001188 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001189}
1190
Josh Gao502cfd22017-02-17 01:39:15 -08001191TEST_F(CrasherTest, capabilities) {
1192 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1193
Josh Gaofca7ca32017-01-23 12:05:35 -08001194 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001195 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1196 err(1, "failed to set PR_SET_KEEPCAPS");
1197 }
1198
1199 if (setresuid(1, 1, 1) != 0) {
1200 err(1, "setresuid failed");
1201 }
1202
1203 __user_cap_header_struct capheader;
1204 __user_cap_data_struct capdata[2];
1205 memset(&capheader, 0, sizeof(capheader));
1206 memset(&capdata, 0, sizeof(capdata));
1207
1208 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1209 capheader.pid = 0;
1210
1211 // Turn on every third capability.
1212 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1213 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1214 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1215 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1216 }
1217
1218 // Make sure CAP_SYS_PTRACE is off.
1219 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1220 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1221
1222 if (capset(&capheader, &capdata[0]) != 0) {
1223 err(1, "capset failed");
1224 }
1225
1226 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1227 err(1, "failed to drop ambient capabilities");
1228 }
1229
Josh Gaoa5199a92017-04-03 13:18:34 -07001230 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001231 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001232 });
Josh Gao502cfd22017-02-17 01:39:15 -08001233
1234 unique_fd output_fd;
1235 StartIntercept(&output_fd);
1236 FinishCrasher();
1237 AssertDeath(SIGSYS);
1238
1239 std::string result;
1240 int intercept_result;
1241 FinishIntercept(&intercept_result);
1242 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1243 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001244 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001245 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001246}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001247
Josh Gao2e7b8e22017-05-04 17:12:57 -07001248TEST_F(CrasherTest, fake_pid) {
1249 int intercept_result;
1250 unique_fd output_fd;
1251
1252 // Prime the getpid/gettid caches.
1253 UNUSED(getpid());
1254 UNUSED(gettid());
1255
1256 std::function<pid_t()> clone_fn = []() {
1257 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1258 };
1259 StartProcess(
1260 []() {
1261 ASSERT_NE(getpid(), syscall(__NR_getpid));
1262 ASSERT_NE(gettid(), syscall(__NR_gettid));
1263 raise(SIGSEGV);
1264 },
1265 clone_fn);
1266
1267 StartIntercept(&output_fd);
1268 FinishCrasher();
1269 AssertDeath(SIGSEGV);
1270 FinishIntercept(&intercept_result);
1271
1272 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1273
1274 std::string result;
1275 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001276 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001277}
1278
Josh Gaoe04ca272018-01-16 15:38:17 -08001279static const char* const kDebuggerdSeccompPolicy =
1280 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1281
Josh Gao70adac62018-02-22 11:38:33 -08001282static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001283 std::string policy;
1284 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1285 PLOG(FATAL) << "failed to read policy file";
1286 }
1287
1288 // Allow a bunch of syscalls used by the tests.
1289 policy += "\nclone: 1";
1290 policy += "\nsigaltstack: 1";
1291 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001292 policy += "\ngetrlimit: 1";
1293 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001294
1295 FILE* tmp_file = tmpfile();
1296 if (!tmp_file) {
1297 PLOG(FATAL) << "tmpfile failed";
1298 }
1299
Christopher Ferris172b0a02019-09-18 17:48:30 -07001300 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001301 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1302 PLOG(FATAL) << "failed to write policy to tmpfile";
1303 }
1304
1305 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1306 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001307 }
1308
1309 ScopedMinijail jail{minijail_new()};
1310 if (!jail) {
1311 LOG(FATAL) << "failed to create minijail";
1312 }
1313
1314 minijail_no_new_privs(jail.get());
1315 minijail_log_seccomp_filter_failures(jail.get());
1316 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001317 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001318
1319 pid_t result = fork();
1320 if (result == -1) {
1321 return result;
1322 } else if (result != 0) {
1323 return result;
1324 }
1325
1326 // Spawn and detach a thread that spins forever.
1327 std::atomic<bool> thread_ready(false);
1328 std::thread thread([&jail, &thread_ready]() {
1329 minijail_enter(jail.get());
1330 thread_ready = true;
1331 for (;;)
1332 ;
1333 });
1334 thread.detach();
1335
1336 while (!thread_ready) {
1337 continue;
1338 }
1339
Josh Gao70adac62018-02-22 11:38:33 -08001340 if (prejail) {
1341 prejail();
1342 }
1343
Josh Gaoe04ca272018-01-16 15:38:17 -08001344 minijail_enter(jail.get());
1345 return result;
1346}
1347
Josh Gao70adac62018-02-22 11:38:33 -08001348static pid_t seccomp_fork() {
1349 return seccomp_fork_impl(nullptr);
1350}
1351
Josh Gaoe04ca272018-01-16 15:38:17 -08001352TEST_F(CrasherTest, seccomp_crash) {
1353 int intercept_result;
1354 unique_fd output_fd;
1355
1356 StartProcess([]() { abort(); }, &seccomp_fork);
1357
1358 StartIntercept(&output_fd);
1359 FinishCrasher();
1360 AssertDeath(SIGABRT);
1361 FinishIntercept(&intercept_result);
1362 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1363
1364 std::string result;
1365 ConsumeFd(std::move(output_fd), &result);
1366 ASSERT_BACKTRACE_FRAME(result, "abort");
1367}
1368
Josh Gao70adac62018-02-22 11:38:33 -08001369static pid_t seccomp_fork_rlimit() {
1370 return seccomp_fork_impl([]() {
1371 struct rlimit rlim = {
1372 .rlim_cur = 512 * 1024 * 1024,
1373 .rlim_max = 512 * 1024 * 1024,
1374 };
1375
1376 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1377 raise(SIGINT);
1378 }
1379 });
1380}
1381
1382TEST_F(CrasherTest, seccomp_crash_oom) {
1383 int intercept_result;
1384 unique_fd output_fd;
1385
1386 StartProcess(
1387 []() {
1388 std::vector<void*> vec;
1389 for (int i = 0; i < 512; ++i) {
1390 char* buf = static_cast<char*>(malloc(1024 * 1024));
1391 if (!buf) {
1392 abort();
1393 }
1394 memset(buf, 0xff, 1024 * 1024);
1395 vec.push_back(buf);
1396 }
1397 },
1398 &seccomp_fork_rlimit);
1399
1400 StartIntercept(&output_fd);
1401 FinishCrasher();
1402 AssertDeath(SIGABRT);
1403 FinishIntercept(&intercept_result);
1404 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1405
1406 // We can't actually generate a backtrace, just make sure that the process terminates.
1407}
1408
Elliott Hughesb795d6f2022-09-14 20:15:19 +00001409__attribute__((__noinline__)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001410 siginfo_t siginfo;
1411 siginfo.si_code = SI_QUEUE;
1412 siginfo.si_pid = getpid();
1413 siginfo.si_uid = getuid();
1414
1415 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1416 PLOG(FATAL) << "invalid dump type";
1417 }
1418
1419 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1420
Josh Gaoa48b41b2019-12-13 14:11:04 -08001421 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001422 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1423 return false;
1424 }
1425
1426 return true;
1427}
1428
Christopher Ferrisb999b822022-02-09 17:57:21 -08001429extern "C" void foo() {
1430 LOG(INFO) << "foo";
1431 std::this_thread::sleep_for(1s);
1432}
1433
1434extern "C" void bar() {
1435 LOG(INFO) << "bar";
1436 std::this_thread::sleep_for(1s);
1437}
1438
Josh Gaoe04ca272018-01-16 15:38:17 -08001439TEST_F(CrasherTest, seccomp_tombstone) {
1440 int intercept_result;
1441 unique_fd output_fd;
1442
1443 static const auto dump_type = kDebuggerdTombstone;
1444 StartProcess(
1445 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001446 std::thread a(foo);
1447 std::thread b(bar);
1448
1449 std::this_thread::sleep_for(100ms);
1450
Josh Gaoe04ca272018-01-16 15:38:17 -08001451 raise_debugger_signal(dump_type);
1452 _exit(0);
1453 },
1454 &seccomp_fork);
1455
1456 StartIntercept(&output_fd, dump_type);
1457 FinishCrasher();
1458 AssertDeath(0);
1459 FinishIntercept(&intercept_result);
1460 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1461
1462 std::string result;
1463 ConsumeFd(std::move(output_fd), &result);
1464 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001465 ASSERT_BACKTRACE_FRAME(result, "foo");
1466 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001467}
1468
Christopher Ferris303c6be2022-05-24 17:08:33 -07001469TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1470 int intercept_result;
1471 unique_fd output_fd;
1472
1473 static const auto dump_type = kDebuggerdTombstone;
1474 StartProcess(
1475 []() {
1476 std::thread abort_thread([] { abort(); });
1477 abort_thread.join();
1478 },
1479 &seccomp_fork);
1480
1481 StartIntercept(&output_fd, dump_type);
1482 FinishCrasher();
1483 AssertDeath(SIGABRT);
1484 FinishIntercept(&intercept_result);
1485 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1486
1487 std::string result;
1488 ConsumeFd(std::move(output_fd), &result);
1489 ASSERT_BACKTRACE_FRAME(result, "abort");
1490}
1491
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001492TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1493 int intercept_result;
1494 unique_fd output_fd;
1495
1496 static const auto dump_type = kDebuggerdTombstone;
1497 StartProcess(
1498 []() {
1499 std::thread a(foo);
1500 std::thread b(bar);
1501
1502 std::this_thread::sleep_for(100ms);
1503
1504 std::thread abort_thread([] { abort(); });
1505 abort_thread.join();
1506 },
1507 &seccomp_fork);
1508
1509 StartIntercept(&output_fd, dump_type);
1510 FinishCrasher();
1511 AssertDeath(SIGABRT);
1512 FinishIntercept(&intercept_result);
1513 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1514
1515 std::string result;
1516 ConsumeFd(std::move(output_fd), &result);
1517 ASSERT_BACKTRACE_FRAME(result, "abort");
1518 ASSERT_BACKTRACE_FRAME(result, "foo");
1519 ASSERT_BACKTRACE_FRAME(result, "bar");
1520 ASSERT_BACKTRACE_FRAME(result, "main");
1521}
1522
Josh Gaoe04ca272018-01-16 15:38:17 -08001523TEST_F(CrasherTest, seccomp_backtrace) {
1524 int intercept_result;
1525 unique_fd output_fd;
1526
1527 static const auto dump_type = kDebuggerdNativeBacktrace;
1528 StartProcess(
1529 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001530 std::thread a(foo);
1531 std::thread b(bar);
1532
1533 std::this_thread::sleep_for(100ms);
1534
Josh Gaoe04ca272018-01-16 15:38:17 -08001535 raise_debugger_signal(dump_type);
1536 _exit(0);
1537 },
1538 &seccomp_fork);
1539
1540 StartIntercept(&output_fd, dump_type);
1541 FinishCrasher();
1542 AssertDeath(0);
1543 FinishIntercept(&intercept_result);
1544 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1545
1546 std::string result;
1547 ConsumeFd(std::move(output_fd), &result);
1548 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001549 ASSERT_BACKTRACE_FRAME(result, "foo");
1550 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001551}
1552
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001553TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1554 int intercept_result;
1555 unique_fd output_fd;
1556
1557 static const auto dump_type = kDebuggerdNativeBacktrace;
1558 StartProcess(
1559 []() {
1560 std::thread a(foo);
1561 std::thread b(bar);
1562
1563 std::this_thread::sleep_for(100ms);
1564
1565 std::thread raise_thread([] {
1566 raise_debugger_signal(dump_type);
1567 _exit(0);
1568 });
1569 raise_thread.join();
1570 },
1571 &seccomp_fork);
1572
1573 StartIntercept(&output_fd, dump_type);
1574 FinishCrasher();
1575 AssertDeath(0);
1576 FinishIntercept(&intercept_result);
1577 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1578
1579 std::string result;
1580 ConsumeFd(std::move(output_fd), &result);
1581 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1582 ASSERT_BACKTRACE_FRAME(result, "foo");
1583 ASSERT_BACKTRACE_FRAME(result, "bar");
1584 ASSERT_BACKTRACE_FRAME(result, "main");
1585}
1586
Josh Gaoe04ca272018-01-16 15:38:17 -08001587TEST_F(CrasherTest, seccomp_crash_logcat) {
1588 StartProcess([]() { abort(); }, &seccomp_fork);
1589 FinishCrasher();
1590
1591 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1592 AssertDeath(SIGABRT);
1593}
1594
Josh Gaofd13bf02017-08-18 15:37:26 -07001595TEST_F(CrasherTest, competing_tracer) {
1596 int intercept_result;
1597 unique_fd output_fd;
1598 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001599 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001600 });
1601
1602 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001603
1604 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001605 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001606
1607 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001608 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001609 ASSERT_TRUE(WIFSTOPPED(status));
1610 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1611
1612 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1613 FinishIntercept(&intercept_result);
1614 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1615
1616 std::string result;
1617 ConsumeFd(std::move(output_fd), &result);
1618 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1619 regex += std::to_string(gettid());
1620 regex += R"( \(.+debuggerd_test)";
1621 ASSERT_MATCH(result, regex.c_str());
1622
Christopher Ferris172b0a02019-09-18 17:48:30 -07001623 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001624 ASSERT_TRUE(WIFSTOPPED(status));
1625 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1626
Josh Gaofd13bf02017-08-18 15:37:26 -07001627 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1628 AssertDeath(SIGABRT);
1629}
1630
Josh Gaobf06a402018-08-27 16:34:01 -07001631TEST_F(CrasherTest, fdsan_warning_abort_message) {
1632 int intercept_result;
1633 unique_fd output_fd;
1634
1635 StartProcess([]() {
1636 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001637 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001638 if (fd == -1) {
1639 abort();
1640 }
1641 close(fd.get());
1642 _exit(0);
1643 });
1644
1645 StartIntercept(&output_fd);
1646 FinishCrasher();
1647 AssertDeath(0);
1648 FinishIntercept(&intercept_result);
1649 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1650
1651 std::string result;
1652 ConsumeFd(std::move(output_fd), &result);
1653 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1654}
1655
Josh Gaoc3c8c022017-02-13 16:36:18 -08001656TEST(crash_dump, zombie) {
1657 pid_t forkpid = fork();
1658
Josh Gaoc3c8c022017-02-13 16:36:18 -08001659 pid_t rc;
1660 int status;
1661
1662 if (forkpid == 0) {
1663 errno = 0;
1664 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1665 if (rc != -1 || errno != ECHILD) {
1666 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1667 }
1668
Josh Gaoa48b41b2019-12-13 14:11:04 -08001669 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001670
1671 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001672 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001673 if (rc != -1 || errno != ECHILD) {
1674 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1675 }
1676 _exit(0);
1677 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001678 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001679 ASSERT_EQ(forkpid, rc);
1680 ASSERT_TRUE(WIFEXITED(status));
1681 ASSERT_EQ(0, WEXITSTATUS(status));
1682 }
1683}
Josh Gao352a8452017-03-30 16:46:21 -07001684
1685TEST(tombstoned, no_notify) {
1686 // Do this a few times.
1687 for (int i = 0; i < 3; ++i) {
1688 pid_t pid = 123'456'789 + i;
1689
1690 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001691 InterceptStatus status;
1692 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1693 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001694
1695 {
1696 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001697 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001698 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1699 }
1700
1701 pid_t read_pid;
1702 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1703 ASSERT_EQ(read_pid, pid);
1704 }
1705}
1706
1707TEST(tombstoned, stress) {
1708 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1709 static constexpr int kDumpCount = 100;
1710
1711 std::atomic<bool> start(false);
1712 std::vector<std::thread> threads;
1713 threads.emplace_back([&start]() {
1714 while (!start) {
1715 continue;
1716 }
1717
1718 // Use a way out of range pid, to avoid stomping on an actual process.
1719 pid_t pid_base = 1'000'000;
1720
1721 for (int dump = 0; dump < kDumpCount; ++dump) {
1722 pid_t pid = pid_base + dump;
1723
1724 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001725 InterceptStatus status;
1726 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1727 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001728
1729 // Pretend to crash, and then immediately close the socket.
1730 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1731 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1732 if (sockfd == -1) {
1733 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1734 }
1735 TombstonedCrashPacket packet = {};
1736 packet.packet_type = CrashPacketType::kDumpRequest;
1737 packet.packet.dump_request.pid = pid;
1738 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1739 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1740 }
1741
1742 continue;
1743 }
1744 });
1745
1746 threads.emplace_back([&start]() {
1747 while (!start) {
1748 continue;
1749 }
1750
1751 // Use a way out of range pid, to avoid stomping on an actual process.
1752 pid_t pid_base = 2'000'000;
1753
1754 for (int dump = 0; dump < kDumpCount; ++dump) {
1755 pid_t pid = pid_base + dump;
1756
1757 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001758 InterceptStatus status;
1759 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1760 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001761
1762 {
1763 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001764 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001765 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1766 tombstoned_notify_completion(tombstoned_socket.get());
1767 }
1768
1769 // TODO: Fix the race that requires this sleep.
1770 std::this_thread::sleep_for(50ms);
1771
1772 pid_t read_pid;
1773 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1774 ASSERT_EQ(read_pid, pid);
1775 }
1776 });
1777
1778 start = true;
1779
1780 for (std::thread& thread : threads) {
1781 thread.join();
1782 }
1783}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001784
1785TEST(tombstoned, java_trace_intercept_smoke) {
1786 // Using a "real" PID is a little dangerous here - if the test fails
1787 // or crashes, we might end up getting a bogus / unreliable stack
1788 // trace.
1789 const pid_t self = getpid();
1790
1791 unique_fd intercept_fd, output_fd;
1792 InterceptStatus status;
1793 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1794 ASSERT_EQ(InterceptStatus::kRegistered, status);
1795
Josh Gao76e1e302021-01-26 15:53:11 -08001796 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001797 // should result in a "regular" FD and not the installed intercept.
1798 const char native[] = "native";
1799 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001800 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001801 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1802 tombstoned_notify_completion(tombstoned_socket.get());
1803
1804 // Then, connect to tombstoned asking for a java backtrace. This *should*
1805 // trigger the intercept.
1806 const char java[] = "java";
1807 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1808 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1809 tombstoned_notify_completion(tombstoned_socket.get());
1810
1811 char outbuf[sizeof(java)];
1812 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1813 ASSERT_STREQ("java", outbuf);
1814}
1815
1816TEST(tombstoned, multiple_intercepts) {
1817 const pid_t fake_pid = 1'234'567;
1818 unique_fd intercept_fd, output_fd;
1819 InterceptStatus status;
1820 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1821 ASSERT_EQ(InterceptStatus::kRegistered, status);
1822
1823 unique_fd intercept_fd_2, output_fd_2;
1824 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1825 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1826}
1827
1828TEST(tombstoned, intercept_any) {
1829 const pid_t fake_pid = 1'234'567;
1830
1831 unique_fd intercept_fd, output_fd;
1832 InterceptStatus status;
1833 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1834 ASSERT_EQ(InterceptStatus::kRegistered, status);
1835
1836 const char any[] = "any";
1837 unique_fd tombstoned_socket, input_fd;
1838 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1839 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1840 tombstoned_notify_completion(tombstoned_socket.get());
1841
1842 char outbuf[sizeof(any)];
1843 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1844 ASSERT_STREQ("any", outbuf);
1845}
Josh Gao2b22ae12018-09-12 14:51:03 -07001846
1847TEST(tombstoned, interceptless_backtrace) {
1848 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1849 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1850 std::map<int, time_t> result;
1851 for (int i = 0; i < 99; ++i) {
1852 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1853 struct stat st;
1854 if (stat(path.c_str(), &st) == 0) {
1855 result[i] = st.st_mtim.tv_sec;
1856 }
1857 }
1858 return result;
1859 };
1860
1861 auto before = get_tombstone_timestamps();
1862 for (int i = 0; i < 50; ++i) {
1863 raise_debugger_signal(kDebuggerdNativeBacktrace);
1864 }
1865 auto after = get_tombstone_timestamps();
1866
1867 int diff = 0;
1868 for (int i = 0; i < 99; ++i) {
1869 if (after.count(i) == 0) {
1870 continue;
1871 }
1872 if (before.count(i) == 0) {
1873 ++diff;
1874 continue;
1875 }
1876 if (before[i] != after[i]) {
1877 ++diff;
1878 }
1879 }
1880
1881 // We can't be sure that nothing's crash looping in the background.
1882 // This should be good enough, though...
1883 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1884}
Christopher Ferris481e8372019-07-15 17:13:24 -07001885
1886static __attribute__((__noinline__)) void overflow_stack(void* p) {
1887 void* buf[1];
1888 buf[0] = p;
1889 static volatile void* global = buf;
1890 if (global) {
1891 global = buf;
1892 overflow_stack(&buf);
1893 }
1894}
1895
1896TEST_F(CrasherTest, stack_overflow) {
1897 int intercept_result;
1898 unique_fd output_fd;
1899 StartProcess([]() { overflow_stack(nullptr); });
1900
1901 StartIntercept(&output_fd);
1902 FinishCrasher();
1903 AssertDeath(SIGSEGV);
1904 FinishIntercept(&intercept_result);
1905
1906 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1907
1908 std::string result;
1909 ConsumeFd(std::move(output_fd), &result);
1910 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1911}
Josh Gao76e1e302021-01-26 15:53:11 -08001912
Christopher Ferris22035cc2023-01-31 17:50:22 -08001913static std::string GetTestLibraryPath() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001914 std::string test_lib(testing::internal::GetArgvs()[0]);
1915 auto const value = test_lib.find_last_of('/');
1916 if (value == std::string::npos) {
1917 test_lib = "./";
1918 } else {
1919 test_lib = test_lib.substr(0, value + 1) + "./";
1920 }
Christopher Ferris22035cc2023-01-31 17:50:22 -08001921 return test_lib + "libcrash_test.so";
1922}
1923
1924static void CreateEmbeddedLibrary(int out_fd) {
1925 std::string test_lib(GetTestLibraryPath());
1926 android::base::unique_fd fd(open(test_lib.c_str(), O_RDONLY | O_CLOEXEC));
1927 ASSERT_NE(fd.get(), -1);
1928 off_t file_size = lseek(fd, 0, SEEK_END);
1929 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
1930 std::vector<uint8_t> contents(file_size);
1931 ASSERT_TRUE(android::base::ReadFully(fd, contents.data(), contents.size()));
1932
1933 // Put the shared library data at a pagesize() offset.
1934 ASSERT_EQ(lseek(out_fd, 4 * getpagesize(), SEEK_CUR), 4 * getpagesize());
1935 ASSERT_EQ(static_cast<size_t>(write(out_fd, contents.data(), contents.size())), contents.size());
1936}
1937
1938TEST_F(CrasherTest, non_zero_offset_in_library) {
1939 int intercept_result;
1940 unique_fd output_fd;
1941 TemporaryFile tf;
1942 CreateEmbeddedLibrary(tf.fd);
1943 StartProcess([&tf]() {
1944 android_dlextinfo extinfo{};
1945 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
1946 extinfo.library_fd = tf.fd;
1947 extinfo.library_fd_offset = 4 * getpagesize();
1948 void* handle = android_dlopen_ext(tf.path, RTLD_NOW, &extinfo);
1949 if (handle == nullptr) {
1950 _exit(1);
1951 }
1952 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1953 if (crash_func == nullptr) {
1954 _exit(1);
1955 }
1956 crash_func();
1957 });
1958
1959 StartIntercept(&output_fd);
1960 FinishCrasher();
1961 AssertDeath(SIGSEGV);
1962 FinishIntercept(&intercept_result);
1963
1964 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1965
1966 std::string result;
1967 ConsumeFd(std::move(output_fd), &result);
1968
1969 // Verify the crash includes an offset value in the backtrace.
1970 std::string match_str = android::base::StringPrintf("%s\\!libcrash_test.so \\(offset 0x%x\\)",
1971 tf.path, 4 * getpagesize());
1972 ASSERT_MATCH(result, match_str);
1973}
1974
1975static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1976 std::string test_lib(GetTestLibraryPath());
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001977
1978 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1979 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1980
1981 // Copy the shared so to a tempory directory.
1982 return system(cp_cmd.c_str()) == 0;
1983}
1984
1985TEST_F(CrasherTest, unreadable_elf) {
1986 int intercept_result;
1987 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001988 std::string tmp_so_name;
1989 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001990 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001991 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1992 _exit(1);
1993 }
1994 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1995 if (handle == nullptr) {
1996 _exit(1);
1997 }
1998 // Delete the original shared library so that we get the warning
1999 // about unreadable elf files.
2000 if (unlink(tmp_so_name.c_str()) == -1) {
2001 _exit(1);
2002 }
2003 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
2004 if (crash_func == nullptr) {
2005 _exit(1);
2006 }
2007 crash_func();
2008 });
2009
2010 StartIntercept(&output_fd);
2011 FinishCrasher();
2012 AssertDeath(SIGSEGV);
2013 FinishIntercept(&intercept_result);
2014
2015 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2016
2017 std::string result;
2018 ConsumeFd(std::move(output_fd), &result);
2019 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07002020 std::string match_str = "NOTE: " + tmp_so_name;
2021 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07002022}
2023
Josh Gao76e1e302021-01-26 15:53:11 -08002024TEST(tombstoned, proto) {
2025 const pid_t self = getpid();
2026 unique_fd tombstoned_socket, text_fd, proto_fd;
2027 ASSERT_TRUE(
2028 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2029
2030 tombstoned_notify_completion(tombstoned_socket.get());
2031
2032 ASSERT_NE(-1, text_fd.get());
2033 ASSERT_NE(-1, proto_fd.get());
2034
2035 struct stat text_st;
2036 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
2037
2038 // Give tombstoned some time to link the files into place.
2039 std::this_thread::sleep_for(100ms);
2040
2041 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08002042 std::optional<std::string> tombstone_file;
2043 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
2044 ASSERT_TRUE(dir_h != nullptr);
2045 std::regex tombstone_re("tombstone_\\d+");
2046 dirent* entry;
2047 while ((entry = readdir(dir_h.get())) != nullptr) {
2048 if (!std::regex_match(entry->d_name, tombstone_re)) {
2049 continue;
2050 }
2051 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08002052
2053 struct stat st;
2054 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
2055 continue;
2056 }
2057
2058 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002059 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002060 break;
2061 }
2062 }
2063
Christopher Ferris35da2882021-02-17 15:39:06 -08002064 ASSERT_TRUE(tombstone_file);
2065 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002066
2067 struct stat proto_fd_st;
2068 struct stat proto_file_st;
2069 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2070 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2071
2072 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2073 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2074}
2075
2076TEST(tombstoned, proto_intercept) {
2077 const pid_t self = getpid();
2078 unique_fd intercept_fd, output_fd;
2079 InterceptStatus status;
2080
2081 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2082 ASSERT_EQ(InterceptStatus::kRegistered, status);
2083
2084 unique_fd tombstoned_socket, text_fd, proto_fd;
2085 ASSERT_TRUE(
2086 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2087 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2088 tombstoned_notify_completion(tombstoned_socket.get());
2089
2090 text_fd.reset();
2091
2092 std::string output;
2093 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2094 ASSERT_EQ("foo", output);
2095}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002096
2097// Verify that when an intercept is present for the main thread, and the signal
2098// is received on a different thread, the intercept still works.
2099TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2100 StartProcess([]() {
2101 std::thread thread([]() {
2102 // Raise the signal on the side thread.
2103 raise_debugger_signal(kDebuggerdNativeBacktrace);
2104 });
2105 thread.join();
2106 _exit(0);
2107 });
2108
2109 unique_fd output_fd;
2110 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2111 FinishCrasher();
2112 AssertDeath(0);
2113
2114 int intercept_result;
2115 FinishIntercept(&intercept_result);
2116 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2117
2118 std::string result;
2119 ConsumeFd(std::move(output_fd), &result);
2120 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2121}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002122
2123static std::string format_pointer(uintptr_t ptr) {
2124#if defined(__LP64__)
2125 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2126 static_cast<uint32_t>(ptr & 0xffffffff));
2127#else
2128 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2129#endif
2130}
2131
2132static std::string format_pointer(void* ptr) {
2133 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2134}
2135
2136static std::string format_full_pointer(uintptr_t ptr) {
2137#if defined(__LP64__)
2138 return android::base::StringPrintf("%016" PRIx64, ptr);
2139#else
2140 return android::base::StringPrintf("%08x", ptr);
2141#endif
2142}
2143
2144static std::string format_full_pointer(void* ptr) {
2145 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2146}
2147
2148__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2149 int* crash_ptr = reinterpret_cast<int*>(ptr);
2150 *crash_ptr = 1;
2151 return *crash_ptr;
2152}
2153
2154// Verify that a fault address before the first map is properly handled.
2155TEST_F(CrasherTest, fault_address_before_first_map) {
2156 StartProcess([]() {
2157 ASSERT_EQ(0, crash_call(0x1024));
2158 _exit(0);
2159 });
2160
2161 unique_fd output_fd;
2162 StartIntercept(&output_fd);
2163 FinishCrasher();
2164 AssertDeath(SIGSEGV);
2165
2166 int intercept_result;
2167 FinishIntercept(&intercept_result);
2168 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2169
2170 std::string result;
2171 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002172 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002173
2174 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2175
2176 std::string match_str = android::base::StringPrintf(
2177 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2178 format_pointer(0x1024).c_str());
2179 ASSERT_MATCH(result, match_str);
2180}
2181
2182// Verify that a fault address after the last map is properly handled.
2183TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002184 // This makes assumptions about the memory layout that are not true in HWASan
2185 // processes.
2186 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002187 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2188 StartProcess([crash_uptr]() {
2189 ASSERT_EQ(0, crash_call(crash_uptr));
2190 _exit(0);
2191 });
2192
2193 unique_fd output_fd;
2194 StartIntercept(&output_fd);
2195 FinishCrasher();
2196 AssertDeath(SIGSEGV);
2197
2198 int intercept_result;
2199 FinishIntercept(&intercept_result);
2200 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2201
2202 std::string result;
2203 ConsumeFd(std::move(output_fd), &result);
2204
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002205 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2206 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002207 ASSERT_MATCH(result, match_str);
2208
2209 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2210
2211 // Assumes that the open files section comes after the map section.
2212 // If that assumption changes, the regex below needs to change.
2213 match_str = android::base::StringPrintf(
2214 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2215 format_pointer(crash_uptr).c_str());
2216 ASSERT_MATCH(result, match_str);
2217}
2218
2219// Verify that a fault address between maps is properly handled.
2220TEST_F(CrasherTest, fault_address_between_maps) {
2221 // Create a map before the fork so it will be present in the child.
2222 void* start_ptr =
2223 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2224 ASSERT_NE(MAP_FAILED, start_ptr);
2225 // Unmap the page in the middle.
2226 void* middle_ptr =
2227 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2228 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2229
2230 StartProcess([middle_ptr]() {
2231 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2232 _exit(0);
2233 });
2234
2235 // Unmap the two maps.
2236 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2237 void* end_ptr =
2238 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2239 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2240
2241 unique_fd output_fd;
2242 StartIntercept(&output_fd);
2243 FinishCrasher();
2244 AssertDeath(SIGSEGV);
2245
2246 int intercept_result;
2247 FinishIntercept(&intercept_result);
2248 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2249
2250 std::string result;
2251 ConsumeFd(std::move(output_fd), &result);
2252
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002253 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2254 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002255 ASSERT_MATCH(result, match_str);
2256
2257 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2258
2259 match_str = android::base::StringPrintf(
2260 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2261 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2262 format_pointer(end_ptr).c_str());
2263 ASSERT_MATCH(result, match_str);
2264}
2265
2266// Verify that a fault address happens in the correct map.
2267TEST_F(CrasherTest, fault_address_in_map) {
2268 // Create a map before the fork so it will be present in the child.
2269 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2270 ASSERT_NE(MAP_FAILED, ptr);
2271
2272 StartProcess([ptr]() {
2273 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2274 _exit(0);
2275 });
2276
2277 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2278
2279 unique_fd output_fd;
2280 StartIntercept(&output_fd);
2281 FinishCrasher();
2282 AssertDeath(SIGSEGV);
2283
2284 int intercept_result;
2285 FinishIntercept(&intercept_result);
2286 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2287
2288 std::string result;
2289 ConsumeFd(std::move(output_fd), &result);
2290
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002291 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2292 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002293 ASSERT_MATCH(result, match_str);
2294
2295 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2296
2297 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2298 ASSERT_MATCH(result, match_str);
2299}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002300
2301static constexpr uint32_t kDexData[] = {
2302 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2303 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2304 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2305 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2306 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2307 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2308 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2309 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2310 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2311 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2312 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2313 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2314 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2315 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2316 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2317 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2318 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2319};
2320
2321TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2322 StartProcess([]() {
2323 TemporaryDir td;
2324 std::string tmp_so_name;
2325 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2326 _exit(1);
2327 }
2328
2329 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2330 // move the library to which has a basename of libart.so.
2331 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2332 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2333 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2334 if (handle == nullptr) {
2335 _exit(1);
2336 }
2337
2338 void* ptr =
2339 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2340 ASSERT_TRUE(ptr != MAP_FAILED);
2341 memcpy(ptr, kDexData, sizeof(kDexData));
2342 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2343
2344 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2345 .symfile_size = sizeof(kDexData)};
2346
2347 JITDescriptor* dex_debug =
2348 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2349 ASSERT_TRUE(dex_debug != nullptr);
2350 dex_debug->version = 1;
2351 dex_debug->action_flag = 0;
2352 dex_debug->relevant_entry = 0;
2353 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2354
2355 // This sets the magic dex pc value for register 0, using the value
2356 // of register 1 + 0x102.
2357 asm(".cfi_escape "
2358 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2359 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2360 "0x13 /* DW_OP_drop */,"
2361 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2362
2363 // For each different architecture, set register one to the dex ptr mmap
2364 // created above. Then do a nullptr dereference to force a crash.
2365#if defined(__arm__)
2366 asm volatile(
2367 "mov r1, %[base]\n"
2368 "mov r2, 0\n"
2369 "str r3, [r2]\n"
2370 : [base] "+r"(ptr)
2371 :
2372 : "r1", "r2", "r3", "memory");
2373#elif defined(__aarch64__)
2374 asm volatile(
2375 "mov x1, %[base]\n"
2376 "mov x2, 0\n"
2377 "str x3, [x2]\n"
2378 : [base] "+r"(ptr)
2379 :
2380 : "x1", "x2", "x3", "memory");
2381#elif defined(__i386__)
2382 asm volatile(
2383 "mov %[base], %%ecx\n"
2384 "movl $0, %%edi\n"
2385 "movl 0(%%edi), %%edx\n"
2386 : [base] "+r"(ptr)
2387 :
2388 : "edi", "ecx", "edx", "memory");
2389#elif defined(__x86_64__)
2390 asm volatile(
2391 "mov %[base], %%rdx\n"
2392 "movq 0, %%rdi\n"
2393 "movq 0(%%rdi), %%rcx\n"
2394 : [base] "+r"(ptr)
2395 :
2396 : "rcx", "rdx", "rdi", "memory");
2397#else
2398#error "Unsupported architecture"
2399#endif
2400 _exit(0);
2401 });
2402
2403 unique_fd output_fd;
2404 StartIntercept(&output_fd);
2405 FinishCrasher();
2406 AssertDeath(SIGSEGV);
2407
2408 int intercept_result;
2409 FinishIntercept(&intercept_result);
2410 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2411
2412 std::string result;
2413 ConsumeFd(std::move(output_fd), &result);
2414
2415 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002416 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002417
2418 // Now verify that the dex_pc frame includes a proper function name.
2419 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2420}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002421
2422static std::string format_map_pointer(uintptr_t ptr) {
2423#if defined(__LP64__)
2424 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2425 static_cast<uint32_t>(ptr & 0xffffffff));
2426#else
2427 return android::base::StringPrintf("%08x", ptr);
2428#endif
2429}
2430
2431// Verify that map data is properly formatted.
2432TEST_F(CrasherTest, verify_map_format) {
2433 // Create multiple maps to make sure that the map data is formatted properly.
2434 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2435 ASSERT_NE(MAP_FAILED, none_map);
2436 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2437 ASSERT_NE(MAP_FAILED, r_map);
2438 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2439 ASSERT_NE(MAP_FAILED, w_map);
2440 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2441 ASSERT_NE(MAP_FAILED, x_map);
2442
2443 TemporaryFile tf;
2444 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2445 char c = 'f';
2446 ASSERT_EQ(1, write(tf.fd, &c, 1));
2447 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2448 ASSERT_EQ(1, write(tf.fd, &c, 1));
2449 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2450 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2451 ASSERT_NE(MAP_FAILED, file_map);
2452
2453 StartProcess([]() { abort(); });
2454
2455 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2456 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2457 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2458 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2459 ASSERT_EQ(0, munmap(file_map, 0x3001));
2460
2461 unique_fd output_fd;
2462 StartIntercept(&output_fd);
2463 FinishCrasher();
2464 AssertDeath(SIGABRT);
2465 int intercept_result;
2466 FinishIntercept(&intercept_result);
2467
2468 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2469
2470 std::string result;
2471 ConsumeFd(std::move(output_fd), &result);
2472
2473 std::string match_str;
2474 // Verify none.
2475 match_str = android::base::StringPrintf(
2476 " %s-%s --- 0 1000\\n",
2477 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2478 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2479 ASSERT_MATCH(result, match_str);
2480
2481 // Verify read-only.
2482 match_str = android::base::StringPrintf(
2483 " %s-%s r-- 0 1000\\n",
2484 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2485 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2486 ASSERT_MATCH(result, match_str);
2487
2488 // Verify write-only.
2489 match_str = android::base::StringPrintf(
2490 " %s-%s -w- 0 1000\\n",
2491 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2492 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2493 ASSERT_MATCH(result, match_str);
2494
2495 // Verify exec-only.
2496 match_str = android::base::StringPrintf(
2497 " %s-%s --x 0 1000\\n",
2498 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2499 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2500 ASSERT_MATCH(result, match_str);
2501
2502 // Verify file map with non-zero offset and a name.
2503 match_str = android::base::StringPrintf(
2504 " %s-%s r-- 2000 4000 %s\\n",
2505 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2506 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2507 ASSERT_MATCH(result, match_str);
2508}
2509
2510// Verify that the tombstone map data is correct.
2511TEST_F(CrasherTest, verify_header) {
2512 StartProcess([]() { abort(); });
2513
2514 unique_fd output_fd;
2515 StartIntercept(&output_fd);
2516 FinishCrasher();
2517 AssertDeath(SIGABRT);
2518 int intercept_result;
2519 FinishIntercept(&intercept_result);
2520
2521 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2522
2523 std::string result;
2524 ConsumeFd(std::move(output_fd), &result);
2525
2526 std::string match_str = android::base::StringPrintf(
2527 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2528 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2529 android::base::GetProperty("ro.revision", "unknown").c_str());
2530 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2531 ASSERT_MATCH(result, match_str);
2532}
2533
2534// Verify that the thread header is formatted properly.
2535TEST_F(CrasherTest, verify_thread_header) {
2536 void* shared_map =
2537 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2538 ASSERT_NE(MAP_FAILED, shared_map);
2539 memset(shared_map, 0, sizeof(pid_t));
2540
2541 StartProcess([&shared_map]() {
2542 std::atomic_bool tid_written;
2543 std::thread thread([&tid_written, &shared_map]() {
2544 pid_t tid = gettid();
2545 memcpy(shared_map, &tid, sizeof(pid_t));
2546 tid_written = true;
2547 volatile bool done = false;
2548 while (!done)
2549 ;
2550 });
2551 thread.detach();
2552 while (!tid_written.load(std::memory_order_acquire))
2553 ;
2554 abort();
2555 });
2556
2557 pid_t primary_pid = crasher_pid;
2558
2559 unique_fd output_fd;
2560 StartIntercept(&output_fd);
2561 FinishCrasher();
2562 AssertDeath(SIGABRT);
2563 int intercept_result;
2564 FinishIntercept(&intercept_result);
2565 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2566
2567 // Read the tid data out.
2568 pid_t tid;
2569 memcpy(&tid, shared_map, sizeof(pid_t));
2570 ASSERT_NE(0, tid);
2571
2572 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2573
2574 std::string result;
2575 ConsumeFd(std::move(output_fd), &result);
2576
2577 // Verify that there are two headers, one where the tid is "primary_pid"
2578 // and the other where the tid is "tid".
2579 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2580 primary_pid, primary_pid);
2581 ASSERT_MATCH(result, match_str);
2582
2583 match_str =
2584 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2585 ASSERT_MATCH(result, match_str);
2586}
2587
2588// Verify that there is a BuildID present in the map section and set properly.
2589TEST_F(CrasherTest, verify_build_id) {
2590 StartProcess([]() { abort(); });
2591
2592 unique_fd output_fd;
2593 StartIntercept(&output_fd);
2594 FinishCrasher();
2595 AssertDeath(SIGABRT);
2596 int intercept_result;
2597 FinishIntercept(&intercept_result);
2598 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2599
2600 std::string result;
2601 ConsumeFd(std::move(output_fd), &result);
2602
2603 // Find every /system or /apex lib and verify the BuildID is displayed
2604 // properly.
2605 bool found_valid_elf = false;
2606 std::smatch match;
2607 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2608 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2609 result = match.suffix()) {
2610 if (prev_file == match[1]) {
2611 // Already checked this file.
2612 continue;
2613 }
2614
2615 prev_file = match[1];
2616 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2617 if (!elf.Init() || !elf.valid()) {
2618 // Skipping invalid elf files.
2619 continue;
2620 }
2621 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2622
2623 found_valid_elf = true;
2624 }
2625 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2626}