blob: ed90ab468bdd5cbdcad50a78876ddd163f39abb2 [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
Josh Gaobf06a402018-08-27 16:34:01 -070039#include <android/fdsan.h>
Josh Gao502cfd22017-02-17 01:39:15 -080040#include <android/set_abort_message.h>
Mitch Phillips7168a212021-03-09 16:53:23 -080041#include <bionic/malloc.h>
Peter Collingbournef8622522020-04-07 14:07:32 -070042#include <bionic/mte.h>
Josh Gaoa48b41b2019-12-13 14:11:04 -080043#include <bionic/reserved_signals.h>
Josh Gao502cfd22017-02-17 01:39:15 -080044
Josh Gao5f87bbd2019-01-09 17:01:49 -080045#include <android-base/cmsg.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070046#include <android-base/file.h>
47#include <android-base/logging.h>
Josh Gao2e7b8e22017-05-04 17:12:57 -070048#include <android-base/macros.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070049#include <android-base/parseint.h>
50#include <android-base/properties.h>
Josh Gao2b22ae12018-09-12 14:51:03 -070051#include <android-base/stringprintf.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070052#include <android-base/strings.h>
Josh Gao30171a82017-04-27 19:48:44 -070053#include <android-base/test_utils.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070054#include <android-base/unique_fd.h>
55#include <cutils/sockets.h>
Mitch Phillips78f06702021-06-01 14:35:43 -070056#include <gmock/gmock.h>
Josh Gaocbe70cb2016-10-18 18:17:52 -070057#include <gtest/gtest.h>
58
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +000059#include <unwindstack/Elf.h>
60#include <unwindstack/Memory.h>
61
Josh Gaoe04ca272018-01-16 15:38:17 -080062#include <libminijail.h>
63#include <scoped_minijail.h>
64
Christopher Ferris2038cc72021-09-15 03:57:10 +000065#include "crash_test.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010066#include "debuggerd/handler.h"
Mitch Phillips5ddcea22021-04-19 09:59:17 -070067#include "libdebuggerd/utility.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010068#include "protocol.h"
69#include "tombstoned/tombstoned.h"
70#include "util.h"
71
Josh Gaocbe70cb2016-10-18 18:17:52 -070072using namespace std::chrono_literals;
Josh Gao5f87bbd2019-01-09 17:01:49 -080073
74using android::base::SendFileDescriptors;
Josh Gaocbe70cb2016-10-18 18:17:52 -070075using android::base::unique_fd;
Mitch Phillips78f06702021-06-01 14:35:43 -070076using ::testing::HasSubstr;
Josh Gaocbe70cb2016-10-18 18:17:52 -070077
78#if defined(__LP64__)
Josh Gaocbe70cb2016-10-18 18:17:52 -070079#define ARCH_SUFFIX "64"
80#else
Josh Gaocbe70cb2016-10-18 18:17:52 -070081#define ARCH_SUFFIX ""
82#endif
83
Elliott Hughese4781d52021-03-17 09:15:15 -070084constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -070085
86#define TIMEOUT(seconds, expr) \
87 [&]() { \
88 struct sigaction old_sigaction; \
89 struct sigaction new_sigaction = {}; \
90 new_sigaction.sa_handler = [](int) {}; \
Christopher Ferris16a7bc22022-01-31 13:08:54 -080091 if (sigaction(SIGALRM, &new_sigaction, &old_sigaction) != 0) { \
Josh Gaocbe70cb2016-10-18 18:17:52 -070092 err(1, "sigaction failed"); \
93 } \
94 alarm(seconds); \
95 auto value = expr; \
96 int saved_errno = errno; \
97 if (sigaction(SIGALRM, &old_sigaction, nullptr) != 0) { \
98 err(1, "sigaction failed"); \
99 } \
100 alarm(0); \
101 errno = saved_errno; \
102 return value; \
103 }()
104
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700105// Backtrace frame dump could contain:
106// #01 pc 0001cded /data/tmp/debuggerd_test32 (raise_debugger_signal+80)
107// or
108// #01 pc 00022a09 /data/tmp/debuggerd_test32 (offset 0x12000) (raise_debugger_signal+80)
Josh Gaoe04ca272018-01-16 15:38:17 -0800109#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
Chih-Hung Hsieh3249b3a2018-05-11 16:01:21 -0700110 ASSERT_MATCH(result, \
111 R"(#\d\d pc [0-9a-f]+\s+ \S+ (\(offset 0x[0-9a-f]+\) )?\()" frame_name R"(\+)");
Jaesung Chung58778e12017-06-15 18:20:34 +0900112
Mitch Phillips7168a212021-03-09 16:53:23 -0800113// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
114// process sampling, so we need to ensure we force GWP-ASan on.
115__attribute__((constructor)) static void enable_gwp_asan() {
Mitch Phillips1e096992022-03-22 15:59:31 -0700116 android_mallopt_gwp_asan_options_t opts;
117 // No, we're not an app, but let's turn ourselves on without sampling.
118 // Technically, if someone's using the *.default_app sysprops, they'll adjust
119 // our settings, but I don't think this will be common on a device that's
120 // running debuggerd_tests.
121 opts.desire = android_mallopt_gwp_asan_options_t::Action::TURN_ON_FOR_APP;
122 opts.program_name = "";
123 android_mallopt(M_INITIALIZE_GWP_ASAN, &opts, sizeof(android_mallopt_gwp_asan_options_t));
Mitch Phillips7168a212021-03-09 16:53:23 -0800124}
125
Narayan Kamatha73df602017-05-24 15:07:25 +0100126static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100127 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700128 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
129 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
130 if (intercept_fd->get() == -1) {
131 FAIL() << "failed to contact tombstoned: " << strerror(errno);
132 }
133
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700134 InterceptRequest req = {
135 .dump_type = intercept_type,
136 .pid = target_pid,
137 };
Josh Gao460b3362017-03-30 16:40:47 -0700138
139 unique_fd output_pipe_write;
140 if (!Pipe(output_fd, &output_pipe_write)) {
141 FAIL() << "failed to create output pipe: " << strerror(errno);
142 }
143
144 std::string pipe_size_str;
145 int pipe_buffer_size;
146 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
147 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
148 }
149
150 pipe_size_str = android::base::Trim(pipe_size_str);
151
152 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
153 FAIL() << "failed to parse pipe max size";
154 }
155
156 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
157 FAIL() << "failed to set pipe size: " << strerror(errno);
158 }
159
Josh Gao5675f3c2017-06-01 12:19:53 -0700160 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
161
Josh Gao5f87bbd2019-01-09 17:01:49 -0800162 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
163 output_pipe_write.reset();
164 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700165 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
166 }
167
168 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800169 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700170 if (rc == -1) {
171 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
172 } else if (rc == 0) {
173 FAIL() << "failed to read response from tombstoned (EOF)";
174 } else if (rc != sizeof(response)) {
175 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
176 << ", received " << rc;
177 }
178
Narayan Kamathca5e9082017-06-02 15:42:06 +0100179 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700180}
181
Elliott Hughesd13ea522022-01-13 09:20:26 -0800182static bool pac_supported() {
183#if defined(__aarch64__)
184 return getauxval(AT_HWCAP) & HWCAP_PACA;
185#else
186 return false;
187#endif
188}
189
Josh Gaocbe70cb2016-10-18 18:17:52 -0700190class CrasherTest : public ::testing::Test {
191 public:
192 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700193 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700194 unique_fd crasher_pipe;
195 unique_fd intercept_fd;
196
197 CrasherTest();
198 ~CrasherTest();
199
Narayan Kamatha73df602017-05-24 15:07:25 +0100200 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700201
202 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
203 void FinishIntercept(int* result);
204
Josh Gao2e7b8e22017-05-04 17:12:57 -0700205 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700206 void StartCrasher(const std::string& crash_type);
207 void FinishCrasher();
208 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700209
210 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700211};
212
213CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700214 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
215 android::base::SetProperty(kWaitForDebuggerKey, "0");
216
217 // Clear the old property too, just in case someone's been using it
218 // on this device. (We only document the new name, but we still support
219 // the old name so we don't break anyone's existing setups.)
220 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700221}
222
223CrasherTest::~CrasherTest() {
224 if (crasher_pid != -1) {
225 kill(crasher_pid, SIGKILL);
226 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700227 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 }
229
Elliott Hughese4781d52021-03-17 09:15:15 -0700230 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700231}
232
Narayan Kamatha73df602017-05-24 15:07:25 +0100233void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700234 if (crasher_pid == -1) {
235 FAIL() << "crasher hasn't been started";
236 }
237
Narayan Kamathca5e9082017-06-02 15:42:06 +0100238 InterceptStatus status;
239 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
240 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700241}
242
243void CrasherTest::FinishIntercept(int* result) {
244 InterceptResponse response;
245
Christopher Ferris11555f02019-09-20 14:18:55 -0700246 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700247 if (rc == -1) {
248 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
249 } else if (rc == 0) {
250 *result = -1;
251 } else if (rc != sizeof(response)) {
252 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
253 << ", received " << rc;
254 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700255 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700256 }
257}
258
Josh Gao2e7b8e22017-05-04 17:12:57 -0700259void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800260 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 unique_fd crasher_read_pipe;
262 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
263 FAIL() << "failed to create pipe: " << strerror(errno);
264 }
265
Josh Gao2e7b8e22017-05-04 17:12:57 -0700266 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700267 if (crasher_pid == -1) {
268 FAIL() << "fork failed: " << strerror(errno);
269 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800270 char dummy;
271 crasher_pipe.reset();
272 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800273 function();
274 _exit(0);
275 }
276}
277
Josh Gaocbe70cb2016-10-18 18:17:52 -0700278void CrasherTest::FinishCrasher() {
279 if (crasher_pipe == -1) {
280 FAIL() << "crasher pipe uninitialized";
281 }
282
Christopher Ferris172b0a02019-09-18 17:48:30 -0700283 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700284 if (rc == -1) {
285 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
286 } else if (rc == 0) {
287 FAIL() << "crasher pipe was closed";
288 }
289}
290
291void CrasherTest::AssertDeath(int signo) {
292 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700293 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700294 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700295 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
296 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700297 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700298 FAIL() << "failed to wait for crasher: " << strerror(errno);
299 }
300
Josh Gaoe06f2a42017-04-27 16:50:38 -0700301 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700302 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700303 ASSERT_EQ(0, WEXITSTATUS(signo));
304 } else {
305 ASSERT_FALSE(WIFEXITED(status));
306 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
307 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700308 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700309 crasher_pid = -1;
310}
311
312static void ConsumeFd(unique_fd fd, std::string* output) {
313 constexpr size_t read_length = PAGE_SIZE;
314 std::string result;
315
316 while (true) {
317 size_t offset = result.size();
318 result.resize(result.size() + PAGE_SIZE);
319 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
320 if (rc == -1) {
321 FAIL() << "read failed: " << strerror(errno);
322 } else if (rc == 0) {
323 result.resize(result.size() - PAGE_SIZE);
324 break;
325 }
326
327 result.resize(result.size() - PAGE_SIZE + rc);
328 }
329
330 *output = std::move(result);
331}
332
Mitch Phillips78f06702021-06-01 14:35:43 -0700333class LogcatCollector {
334 public:
335 LogcatCollector() { system("logcat -c"); }
336
337 void Collect(std::string* output) {
338 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
339 ASSERT_NE(cmd_stdout, nullptr);
340 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
341 ConsumeFd(std::move(tmp_fd), output);
342 pclose(cmd_stdout);
343 }
344};
345
Josh Gaocbe70cb2016-10-18 18:17:52 -0700346TEST_F(CrasherTest, smoke) {
347 int intercept_result;
348 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800349 StartProcess([]() {
350 *reinterpret_cast<volatile char*>(0xdead) = '1';
351 });
352
Josh Gaocbe70cb2016-10-18 18:17:52 -0700353 StartIntercept(&output_fd);
354 FinishCrasher();
355 AssertDeath(SIGSEGV);
356 FinishIntercept(&intercept_result);
357
358 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
359
360 std::string result;
361 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800362#ifdef __LP64__
363 ASSERT_MATCH(result,
364 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
365#else
366 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
367#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700368
369 if (mte_supported()) {
370 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700371 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
372 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700373 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800374
375 if (pac_supported()) {
376 // Test that the default PAC_ENABLED_KEYS value is set.
377 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
378 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
379 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700380}
381
Peter Collingbournef03af882020-03-20 18:09:00 -0700382TEST_F(CrasherTest, tagged_fault_addr) {
383#if !defined(__aarch64__)
384 GTEST_SKIP() << "Requires aarch64";
385#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700386 // HWASan crashes with SIGABRT on tag mismatch.
387 SKIP_WITH_HWASAN;
Peter Collingbournef03af882020-03-20 18:09:00 -0700388 int intercept_result;
389 unique_fd output_fd;
390 StartProcess([]() {
391 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
392 });
393
394 StartIntercept(&output_fd);
395 FinishCrasher();
396 AssertDeath(SIGSEGV);
397 FinishIntercept(&intercept_result);
398
399 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
400
401 std::string result;
402 ConsumeFd(std::move(output_fd), &result);
403
404 // The address can either be tagged (new kernels) or untagged (old kernels).
405 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800406 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700407}
408
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700409// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
410// compiler could still clobber the argument register before trapping, but that's unlikely.
411__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
412 __builtin_trap();
413}
414
415TEST_F(CrasherTest, heap_addr_in_register) {
416#if defined(__i386__)
417 GTEST_SKIP() << "architecture does not pass arguments in registers";
418#endif
Florian Mayerb4979292022-04-15 14:35:17 -0700419 // The memory dump in HWASan crashes sadly shows the memory near the registers
420 // in the HWASan dump function, rather the faulting context. This is a known
421 // issue.
422 SKIP_WITH_HWASAN;
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700423 int intercept_result;
424 unique_fd output_fd;
425 StartProcess([]() {
426 // Crash with a heap pointer in the first argument register.
427 Trap(malloc(1));
428 });
429
430 StartIntercept(&output_fd);
431 FinishCrasher();
432 int status;
433 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
434 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
435 // Don't test the signal number because different architectures use different signals for
436 // __builtin_trap().
437 FinishIntercept(&intercept_result);
438
439 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
440
441 std::string result;
442 ConsumeFd(std::move(output_fd), &result);
443
444#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800445 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700446#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800447 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700448#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800449 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700450#else
451 ASSERT_TRUE(false) << "unsupported architecture";
452#endif
453}
454
Peter Collingbournecd278072020-12-21 14:08:38 -0800455#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700456static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800457 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700458 abort();
459 }
460}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800461
462static void SetTagCheckingLevelAsync() {
463 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
464 abort();
465 }
466}
Peter Collingbournef8622522020-04-07 14:07:32 -0700467#endif
468
Mitch Phillips7168a212021-03-09 16:53:23 -0800469// Number of iterations required to reliably guarantee a GWP-ASan crash.
470// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
471// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
472// the counter reaches zero, we provide a sampled allocation. Then, double that
473// figure to allow for left/right allocation alignment, as this is done randomly
474// without bias.
475#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
476
477struct GwpAsanTestParameters {
478 size_t alloc_size;
479 bool free_before_access;
480 int access_offset;
481 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
482};
483
484struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
485
486GwpAsanTestParameters gwp_asan_tests[] = {
487 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
488 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
489 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
490 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
491};
492
493INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
494
495TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
496 if (mte_supported()) {
497 // Skip this test on MTE hardware, as MTE will reliably catch these errors
498 // instead of GWP-ASan.
499 GTEST_SKIP() << "Skipped on MTE.";
500 }
Florian Mayerb4979292022-04-15 14:35:17 -0700501 // Skip this test on HWASan, which will reliably catch test errors as well.
502 SKIP_WITH_HWASAN;
Mitch Phillips7168a212021-03-09 16:53:23 -0800503
504 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700505 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800506
507 int intercept_result;
508 unique_fd output_fd;
509 StartProcess([&params]() {
510 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
511 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
512 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
513 p[params.access_offset] = 42;
514 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
515 }
516 });
517
518 StartIntercept(&output_fd);
519 FinishCrasher();
520 AssertDeath(SIGSEGV);
521 FinishIntercept(&intercept_result);
522
523 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
524
Mitch Phillips78f06702021-06-01 14:35:43 -0700525 std::vector<std::string> log_sources(2);
526 ConsumeFd(std::move(output_fd), &log_sources[0]);
527 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800528
Mitch Phillips78f06702021-06-01 14:35:43 -0700529 for (const auto& result : log_sources) {
530 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
531 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
532 if (params.free_before_access) {
533 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
534 }
535 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800536 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800537}
538
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800539struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
540
Peter Collingbourneaa544792021-05-13 13:53:37 -0700541INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800542
543TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800544#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700545 if (!mte_supported()) {
546 GTEST_SKIP() << "Requires MTE";
547 }
548
Peter Collingbourneaa544792021-05-13 13:53:37 -0700549 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
550 if (GetParam() == 0) {
551 return;
552 }
553
Mitch Phillips78f06702021-06-01 14:35:43 -0700554 LogcatCollector logcat_collector;
555
Peter Collingbournef8622522020-04-07 14:07:32 -0700556 int intercept_result;
557 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800558 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700559 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800560 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700561 free((void *)p);
562 p[0] = 42;
563 });
564
565 StartIntercept(&output_fd);
566 FinishCrasher();
567 AssertDeath(SIGSEGV);
568 FinishIntercept(&intercept_result);
569
570 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
571
Mitch Phillips78f06702021-06-01 14:35:43 -0700572 std::vector<std::string> log_sources(2);
573 ConsumeFd(std::move(output_fd), &log_sources[0]);
574 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700575 // Tag dump only available in the tombstone, not logcat.
576 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700577
Mitch Phillips78f06702021-06-01 14:35:43 -0700578 for (const auto& result : log_sources) {
579 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
580 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
581 std::to_string(GetParam()) + R"(-byte allocation)");
582 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
583 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
584 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700585#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800586 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700587#endif
588}
589
Peter Collingbournedc476342021-05-12 15:56:43 -0700590TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
591#if defined(__aarch64__)
592 if (!mte_supported()) {
593 GTEST_SKIP() << "Requires MTE";
594 }
595
596 int intercept_result;
597 unique_fd output_fd;
598 StartProcess([&]() {
599 SetTagCheckingLevelSync();
600 volatile int* p = (volatile int*)malloc(GetParam());
601 free((void *)p);
602 p[-1] = 42;
603 });
604
605 StartIntercept(&output_fd);
606 FinishCrasher();
607 AssertDeath(SIGSEGV);
608 FinishIntercept(&intercept_result);
609
610 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
611
612 std::string result;
613 ConsumeFd(std::move(output_fd), &result);
614
615 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
616 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
617#else
618 GTEST_SKIP() << "Requires aarch64";
619#endif
620}
621
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800622TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800623#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700624 if (!mte_supported()) {
625 GTEST_SKIP() << "Requires MTE";
626 }
627
Mitch Phillips78f06702021-06-01 14:35:43 -0700628 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700629 int intercept_result;
630 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800631 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700632 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800633 volatile char* p = (volatile char*)malloc(GetParam());
634 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700635 });
636
637 StartIntercept(&output_fd);
638 FinishCrasher();
639 AssertDeath(SIGSEGV);
640 FinishIntercept(&intercept_result);
641
642 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
643
Mitch Phillips78f06702021-06-01 14:35:43 -0700644 std::vector<std::string> log_sources(2);
645 ConsumeFd(std::move(output_fd), &log_sources[0]);
646 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700647
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700648 // Tag dump only in tombstone, not logcat, and tagging is not used for
649 // overflow protection in the scudo secondary (guard pages are used instead).
650 if (GetParam() < 0x10000) {
651 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
652 }
653
Mitch Phillips78f06702021-06-01 14:35:43 -0700654 for (const auto& result : log_sources) {
655 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
656 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
657 std::to_string(GetParam()) + R"(-byte allocation)");
658 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
659 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700660#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800661 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700662#endif
663}
664
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800665TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800666#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700667 if (!mte_supported()) {
668 GTEST_SKIP() << "Requires MTE";
669 }
670
671 int intercept_result;
672 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800673 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700674 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800675 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700676 p[-1] = 42;
677 });
678
679 StartIntercept(&output_fd);
680 FinishCrasher();
681 AssertDeath(SIGSEGV);
682 FinishIntercept(&intercept_result);
683
684 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
685
686 std::string result;
687 ConsumeFd(std::move(output_fd), &result);
688
689 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800690 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800691 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700692 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700693 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700694 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700695#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800696 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700697#endif
698}
699
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800700TEST_F(CrasherTest, mte_async) {
701#if defined(__aarch64__)
702 if (!mte_supported()) {
703 GTEST_SKIP() << "Requires MTE";
704 }
705
706 int intercept_result;
707 unique_fd output_fd;
708 StartProcess([&]() {
709 SetTagCheckingLevelAsync();
710 volatile int* p = (volatile int*)malloc(16);
711 p[-1] = 42;
712 });
713
714 StartIntercept(&output_fd);
715 FinishCrasher();
716 AssertDeath(SIGSEGV);
717 FinishIntercept(&intercept_result);
718
719 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
720
721 std::string result;
722 ConsumeFd(std::move(output_fd), &result);
723
724 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
725#else
726 GTEST_SKIP() << "Requires aarch64";
727#endif
728}
729
Peter Collingbournef8622522020-04-07 14:07:32 -0700730TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800731#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700732 if (!mte_supported()) {
733 GTEST_SKIP() << "Requires MTE";
734 }
735
Mitch Phillips78f06702021-06-01 14:35:43 -0700736 LogcatCollector logcat_collector;
737
Peter Collingbournef8622522020-04-07 14:07:32 -0700738 int intercept_result;
739 unique_fd output_fd;
740 StartProcess([]() {
741 SetTagCheckingLevelSync();
742
743 // Make two allocations with the same tag and close to one another. Check for both properties
744 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
745 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
746 // (some non-zero value << 56) apart.
747 //
748 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
749 // other.
750 std::set<uintptr_t> allocs;
751 for (int i = 0; i != 4096; ++i) {
752 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
753 auto it = allocs.insert(alloc).first;
754 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
755 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
756 }
757 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
758 *reinterpret_cast<int*>(alloc + 16) = 42;
759 }
760 }
761 });
762
763 StartIntercept(&output_fd);
764 FinishCrasher();
765 AssertDeath(SIGSEGV);
766 FinishIntercept(&intercept_result);
767
768 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
769
Mitch Phillips78f06702021-06-01 14:35:43 -0700770 std::vector<std::string> log_sources(2);
771 ConsumeFd(std::move(output_fd), &log_sources[0]);
772 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700773
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700774 // Tag dump only in the tombstone, not logcat.
775 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
776
Mitch Phillips78f06702021-06-01 14:35:43 -0700777 for (const auto& result : log_sources) {
778 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
779 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800780 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700781 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
782 // overflows), so we can't match explicitly for an underflow message.
783 ASSERT_MATCH(result,
784 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
785 // Ensure there's at least two allocation traces (one for each cause).
786 ASSERT_MATCH(
787 result,
788 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
789 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700790#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800791 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700792#endif
793}
794
Peter Collingbournecd278072020-12-21 14:08:38 -0800795#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700796static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700797 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
798 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
799 size_t page_size = getpagesize();
800 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
801 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
802 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700803 return 0;
804 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700805 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
806 PROT_READ | PROT_WRITE | PROT_MTE);
807 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
808 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
809 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
810 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
811 }
812 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700813}
814#endif
815
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700816TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800817#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700818 if (!mte_supported()) {
819 GTEST_SKIP() << "Requires MTE";
820 }
821
822 int intercept_result;
823 unique_fd output_fd;
824 StartProcess([&]() {
825 SetTagCheckingLevelSync();
826 Trap(reinterpret_cast<void *>(CreateTagMapping()));
827 });
828
829 StartIntercept(&output_fd);
830 FinishCrasher();
831 AssertDeath(SIGTRAP);
832 FinishIntercept(&intercept_result);
833
834 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
835
836 std::string result;
837 ConsumeFd(std::move(output_fd), &result);
838
839 ASSERT_MATCH(result, R"(memory near x0:
840.*
841.*
842 01.............0 0000000000000000 0000000000000000 ................
843 00.............0)");
844#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800845 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700846#endif
847}
848
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700849TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
850#if defined(__aarch64__)
851 if (!mte_supported()) {
852 GTEST_SKIP() << "Requires MTE";
853 }
854
855 int intercept_result;
856 unique_fd output_fd;
857 StartProcess([&]() {
858 SetTagCheckingLevelSync();
859 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
860 p[0] = 0; // Untagged pointer, tagged memory.
861 });
862
863 StartIntercept(&output_fd);
864 FinishCrasher();
865 AssertDeath(SIGSEGV);
866 FinishIntercept(&intercept_result);
867
868 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
869
870 std::string result;
871 ConsumeFd(std::move(output_fd), &result);
872
873 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
874\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
875#else
876 GTEST_SKIP() << "Requires aarch64";
877#endif
878}
879
880TEST_F(CrasherTest, mte_fault_tag_dump) {
881#if defined(__aarch64__)
882 if (!mte_supported()) {
883 GTEST_SKIP() << "Requires MTE";
884 }
885
886 int intercept_result;
887 unique_fd output_fd;
888 StartProcess([&]() {
889 SetTagCheckingLevelSync();
890 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
891 p[320] = 0; // Untagged pointer, tagged memory.
892 });
893
894 StartIntercept(&output_fd);
895 FinishCrasher();
896 AssertDeath(SIGSEGV);
897 FinishIntercept(&intercept_result);
898
899 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
900
901 std::string result;
902 ConsumeFd(std::move(output_fd), &result);
903
904 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
905\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
906\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
907\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
908)");
909#else
910 GTEST_SKIP() << "Requires aarch64";
911#endif
912}
913
914TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
915#if defined(__aarch64__)
916 if (!mte_supported()) {
917 GTEST_SKIP() << "Requires MTE";
918 }
919
920 int intercept_result;
921 unique_fd output_fd;
922 StartProcess([&]() {
923 SetTagCheckingLevelSync();
924 size_t page_size = getpagesize();
925 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
926 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
927 });
928
929 StartIntercept(&output_fd);
930 FinishCrasher();
931 AssertDeath(SIGSEGV);
932 FinishIntercept(&intercept_result);
933
934 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
935
936 std::string result;
937 ConsumeFd(std::move(output_fd), &result);
938
939 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
940 ASSERT_MATCH(result,
941 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
942\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
943
944)"); // Ensure truncation happened and there's a newline after the tag fault.
945#else
946 GTEST_SKIP() << "Requires aarch64";
947#endif
948}
949
Josh Gaocdea7502017-11-01 15:00:40 -0700950TEST_F(CrasherTest, LD_PRELOAD) {
951 int intercept_result;
952 unique_fd output_fd;
953 StartProcess([]() {
954 setenv("LD_PRELOAD", "nonexistent.so", 1);
955 *reinterpret_cast<volatile char*>(0xdead) = '1';
956 });
957
958 StartIntercept(&output_fd);
959 FinishCrasher();
960 AssertDeath(SIGSEGV);
961 FinishIntercept(&intercept_result);
962
963 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
964
965 std::string result;
966 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800967 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700968}
969
Josh Gaocbe70cb2016-10-18 18:17:52 -0700970TEST_F(CrasherTest, abort) {
971 int intercept_result;
972 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800973 StartProcess([]() {
974 abort();
975 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700976 StartIntercept(&output_fd);
977 FinishCrasher();
978 AssertDeath(SIGABRT);
979 FinishIntercept(&intercept_result);
980
981 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
982
983 std::string result;
984 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700985 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700986}
987
988TEST_F(CrasherTest, signal) {
989 int intercept_result;
990 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800991 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700992 while (true) {
993 sleep(1);
994 }
Josh Gao502cfd22017-02-17 01:39:15 -0800995 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700996 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700997 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700998 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
999
1000 AssertDeath(SIGSEGV);
1001 FinishIntercept(&intercept_result);
1002
1003 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1004
1005 std::string result;
1006 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -07001007 ASSERT_MATCH(
1008 result,
1009 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001010 ASSERT_MATCH(result, R"(backtrace:)");
1011}
1012
1013TEST_F(CrasherTest, abort_message) {
1014 int intercept_result;
1015 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001016 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001017 // Arrived at experimentally;
1018 // logd truncates at 4062.
1019 // strlen("Abort message: ''") is 17.
1020 // That's 4045, but we also want a NUL.
1021 char buf[4045 + 1];
1022 memset(buf, 'x', sizeof(buf));
1023 buf[sizeof(buf) - 1] = '\0';
1024 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001025 abort();
1026 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001027 StartIntercept(&output_fd);
1028 FinishCrasher();
1029 AssertDeath(SIGABRT);
1030 FinishIntercept(&intercept_result);
1031
1032 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1033
1034 std::string result;
1035 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001036 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001037}
1038
Christopher Ferrise8891452021-08-17 17:34:53 -07001039TEST_F(CrasherTest, abort_message_newline_trimmed) {
1040 int intercept_result;
1041 unique_fd output_fd;
1042 StartProcess([]() {
1043 android_set_abort_message("Message with a newline.\n");
1044 abort();
1045 });
1046 StartIntercept(&output_fd);
1047 FinishCrasher();
1048 AssertDeath(SIGABRT);
1049 FinishIntercept(&intercept_result);
1050
1051 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1052
1053 std::string result;
1054 ConsumeFd(std::move(output_fd), &result);
1055 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1056}
1057
1058TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1059 int intercept_result;
1060 unique_fd output_fd;
1061 StartProcess([]() {
1062 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1063 abort();
1064 });
1065 StartIntercept(&output_fd);
1066 FinishCrasher();
1067 AssertDeath(SIGABRT);
1068 FinishIntercept(&intercept_result);
1069
1070 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1071
1072 std::string result;
1073 ConsumeFd(std::move(output_fd), &result);
1074 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1075}
1076
Josh Gaoe06f2a42017-04-27 16:50:38 -07001077TEST_F(CrasherTest, abort_message_backtrace) {
1078 int intercept_result;
1079 unique_fd output_fd;
1080 StartProcess([]() {
1081 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001082 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001083 exit(0);
1084 });
1085 StartIntercept(&output_fd);
1086 FinishCrasher();
1087 AssertDeath(0);
1088 FinishIntercept(&intercept_result);
1089
1090 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1091
1092 std::string result;
1093 ConsumeFd(std::move(output_fd), &result);
1094 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1095}
1096
Josh Gaocbe70cb2016-10-18 18:17:52 -07001097TEST_F(CrasherTest, intercept_timeout) {
1098 int intercept_result;
1099 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001100 StartProcess([]() {
1101 abort();
1102 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001103 StartIntercept(&output_fd);
1104
1105 // Don't let crasher finish until we timeout.
1106 FinishIntercept(&intercept_result);
1107
1108 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1109 << intercept_result << ")";
1110
1111 FinishCrasher();
1112 AssertDeath(SIGABRT);
1113}
1114
Elliott Hughese4781d52021-03-17 09:15:15 -07001115TEST_F(CrasherTest, wait_for_debugger) {
1116 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1117 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001118 }
1119 sleep(1);
1120
Josh Gao502cfd22017-02-17 01:39:15 -08001121 StartProcess([]() {
1122 abort();
1123 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001124 FinishCrasher();
1125
1126 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001127 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001128 ASSERT_TRUE(WIFSTOPPED(status));
1129 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1130
1131 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1132
1133 AssertDeath(SIGABRT);
1134}
1135
Josh Gaocbe70cb2016-10-18 18:17:52 -07001136TEST_F(CrasherTest, backtrace) {
1137 std::string result;
1138 int intercept_result;
1139 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001140
1141 StartProcess([]() {
1142 abort();
1143 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001144 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001145
1146 std::this_thread::sleep_for(500ms);
1147
1148 sigval val;
1149 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001150 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001151 FinishIntercept(&intercept_result);
1152 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1153 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001154 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001155
1156 int status;
1157 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1158
1159 StartIntercept(&output_fd);
1160 FinishCrasher();
1161 AssertDeath(SIGABRT);
1162 FinishIntercept(&intercept_result);
1163 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1164 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001165 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001166}
Josh Gaofca7ca32017-01-23 12:05:35 -08001167
1168TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001169 int intercept_result;
1170 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001171 StartProcess([]() {
1172 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001173 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001174 });
Josh Gao502cfd22017-02-17 01:39:15 -08001175
1176 StartIntercept(&output_fd);
1177 FinishCrasher();
1178 AssertDeath(SIGABRT);
1179 FinishIntercept(&intercept_result);
1180
1181 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1182
1183 std::string result;
1184 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001185 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001186}
1187
Josh Gao502cfd22017-02-17 01:39:15 -08001188TEST_F(CrasherTest, capabilities) {
1189 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1190
Josh Gaofca7ca32017-01-23 12:05:35 -08001191 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001192 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1193 err(1, "failed to set PR_SET_KEEPCAPS");
1194 }
1195
1196 if (setresuid(1, 1, 1) != 0) {
1197 err(1, "setresuid failed");
1198 }
1199
1200 __user_cap_header_struct capheader;
1201 __user_cap_data_struct capdata[2];
1202 memset(&capheader, 0, sizeof(capheader));
1203 memset(&capdata, 0, sizeof(capdata));
1204
1205 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1206 capheader.pid = 0;
1207
1208 // Turn on every third capability.
1209 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1210 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1211 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1212 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1213 }
1214
1215 // Make sure CAP_SYS_PTRACE is off.
1216 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1217 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1218
1219 if (capset(&capheader, &capdata[0]) != 0) {
1220 err(1, "capset failed");
1221 }
1222
1223 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1224 err(1, "failed to drop ambient capabilities");
1225 }
1226
Josh Gaoa5199a92017-04-03 13:18:34 -07001227 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001228 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001229 });
Josh Gao502cfd22017-02-17 01:39:15 -08001230
1231 unique_fd output_fd;
1232 StartIntercept(&output_fd);
1233 FinishCrasher();
1234 AssertDeath(SIGSYS);
1235
1236 std::string result;
1237 int intercept_result;
1238 FinishIntercept(&intercept_result);
1239 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1240 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001241 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001242 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001243}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001244
Josh Gao2e7b8e22017-05-04 17:12:57 -07001245TEST_F(CrasherTest, fake_pid) {
1246 int intercept_result;
1247 unique_fd output_fd;
1248
1249 // Prime the getpid/gettid caches.
1250 UNUSED(getpid());
1251 UNUSED(gettid());
1252
1253 std::function<pid_t()> clone_fn = []() {
1254 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1255 };
1256 StartProcess(
1257 []() {
1258 ASSERT_NE(getpid(), syscall(__NR_getpid));
1259 ASSERT_NE(gettid(), syscall(__NR_gettid));
1260 raise(SIGSEGV);
1261 },
1262 clone_fn);
1263
1264 StartIntercept(&output_fd);
1265 FinishCrasher();
1266 AssertDeath(SIGSEGV);
1267 FinishIntercept(&intercept_result);
1268
1269 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1270
1271 std::string result;
1272 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001273 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001274}
1275
Josh Gaoe04ca272018-01-16 15:38:17 -08001276static const char* const kDebuggerdSeccompPolicy =
1277 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1278
Josh Gao70adac62018-02-22 11:38:33 -08001279static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001280 std::string policy;
1281 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1282 PLOG(FATAL) << "failed to read policy file";
1283 }
1284
1285 // Allow a bunch of syscalls used by the tests.
1286 policy += "\nclone: 1";
1287 policy += "\nsigaltstack: 1";
1288 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001289 policy += "\ngetrlimit: 1";
1290 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001291
1292 FILE* tmp_file = tmpfile();
1293 if (!tmp_file) {
1294 PLOG(FATAL) << "tmpfile failed";
1295 }
1296
Christopher Ferris172b0a02019-09-18 17:48:30 -07001297 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001298 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1299 PLOG(FATAL) << "failed to write policy to tmpfile";
1300 }
1301
1302 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1303 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001304 }
1305
1306 ScopedMinijail jail{minijail_new()};
1307 if (!jail) {
1308 LOG(FATAL) << "failed to create minijail";
1309 }
1310
1311 minijail_no_new_privs(jail.get());
1312 minijail_log_seccomp_filter_failures(jail.get());
1313 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001314 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001315
1316 pid_t result = fork();
1317 if (result == -1) {
1318 return result;
1319 } else if (result != 0) {
1320 return result;
1321 }
1322
1323 // Spawn and detach a thread that spins forever.
1324 std::atomic<bool> thread_ready(false);
1325 std::thread thread([&jail, &thread_ready]() {
1326 minijail_enter(jail.get());
1327 thread_ready = true;
1328 for (;;)
1329 ;
1330 });
1331 thread.detach();
1332
1333 while (!thread_ready) {
1334 continue;
1335 }
1336
Josh Gao70adac62018-02-22 11:38:33 -08001337 if (prejail) {
1338 prejail();
1339 }
1340
Josh Gaoe04ca272018-01-16 15:38:17 -08001341 minijail_enter(jail.get());
1342 return result;
1343}
1344
Josh Gao70adac62018-02-22 11:38:33 -08001345static pid_t seccomp_fork() {
1346 return seccomp_fork_impl(nullptr);
1347}
1348
Josh Gaoe04ca272018-01-16 15:38:17 -08001349TEST_F(CrasherTest, seccomp_crash) {
1350 int intercept_result;
1351 unique_fd output_fd;
1352
1353 StartProcess([]() { abort(); }, &seccomp_fork);
1354
1355 StartIntercept(&output_fd);
1356 FinishCrasher();
1357 AssertDeath(SIGABRT);
1358 FinishIntercept(&intercept_result);
1359 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1360
1361 std::string result;
1362 ConsumeFd(std::move(output_fd), &result);
1363 ASSERT_BACKTRACE_FRAME(result, "abort");
1364}
1365
Josh Gao70adac62018-02-22 11:38:33 -08001366static pid_t seccomp_fork_rlimit() {
1367 return seccomp_fork_impl([]() {
1368 struct rlimit rlim = {
1369 .rlim_cur = 512 * 1024 * 1024,
1370 .rlim_max = 512 * 1024 * 1024,
1371 };
1372
1373 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1374 raise(SIGINT);
1375 }
1376 });
1377}
1378
1379TEST_F(CrasherTest, seccomp_crash_oom) {
1380 int intercept_result;
1381 unique_fd output_fd;
1382
1383 StartProcess(
1384 []() {
1385 std::vector<void*> vec;
1386 for (int i = 0; i < 512; ++i) {
1387 char* buf = static_cast<char*>(malloc(1024 * 1024));
1388 if (!buf) {
1389 abort();
1390 }
1391 memset(buf, 0xff, 1024 * 1024);
1392 vec.push_back(buf);
1393 }
1394 },
1395 &seccomp_fork_rlimit);
1396
1397 StartIntercept(&output_fd);
1398 FinishCrasher();
1399 AssertDeath(SIGABRT);
1400 FinishIntercept(&intercept_result);
1401 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1402
1403 // We can't actually generate a backtrace, just make sure that the process terminates.
1404}
1405
Josh Gaoe04ca272018-01-16 15:38:17 -08001406__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1407 siginfo_t siginfo;
1408 siginfo.si_code = SI_QUEUE;
1409 siginfo.si_pid = getpid();
1410 siginfo.si_uid = getuid();
1411
1412 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1413 PLOG(FATAL) << "invalid dump type";
1414 }
1415
1416 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1417
Josh Gaoa48b41b2019-12-13 14:11:04 -08001418 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001419 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1420 return false;
1421 }
1422
1423 return true;
1424}
1425
Christopher Ferrisb999b822022-02-09 17:57:21 -08001426extern "C" void foo() {
1427 LOG(INFO) << "foo";
1428 std::this_thread::sleep_for(1s);
1429}
1430
1431extern "C" void bar() {
1432 LOG(INFO) << "bar";
1433 std::this_thread::sleep_for(1s);
1434}
1435
Josh Gaoe04ca272018-01-16 15:38:17 -08001436TEST_F(CrasherTest, seccomp_tombstone) {
1437 int intercept_result;
1438 unique_fd output_fd;
1439
1440 static const auto dump_type = kDebuggerdTombstone;
1441 StartProcess(
1442 []() {
Christopher Ferrisb999b822022-02-09 17:57:21 -08001443 std::thread a(foo);
1444 std::thread b(bar);
1445
1446 std::this_thread::sleep_for(100ms);
1447
Josh Gaoe04ca272018-01-16 15:38:17 -08001448 raise_debugger_signal(dump_type);
1449 _exit(0);
1450 },
1451 &seccomp_fork);
1452
1453 StartIntercept(&output_fd, dump_type);
1454 FinishCrasher();
1455 AssertDeath(0);
1456 FinishIntercept(&intercept_result);
1457 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1458
1459 std::string result;
1460 ConsumeFd(std::move(output_fd), &result);
1461 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Christopher Ferrisb999b822022-02-09 17:57:21 -08001462 ASSERT_BACKTRACE_FRAME(result, "foo");
1463 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001464}
1465
Christopher Ferris303c6be2022-05-24 17:08:33 -07001466TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
1467 int intercept_result;
1468 unique_fd output_fd;
1469
1470 static const auto dump_type = kDebuggerdTombstone;
1471 StartProcess(
1472 []() {
1473 std::thread abort_thread([] { abort(); });
1474 abort_thread.join();
1475 },
1476 &seccomp_fork);
1477
1478 StartIntercept(&output_fd, dump_type);
1479 FinishCrasher();
1480 AssertDeath(SIGABRT);
1481 FinishIntercept(&intercept_result);
1482 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1483
1484 std::string result;
1485 ConsumeFd(std::move(output_fd), &result);
1486 ASSERT_BACKTRACE_FRAME(result, "abort");
1487}
1488
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001489TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
1490 int intercept_result;
1491 unique_fd output_fd;
1492
1493 static const auto dump_type = kDebuggerdTombstone;
1494 StartProcess(
1495 []() {
1496 std::thread a(foo);
1497 std::thread b(bar);
1498
1499 std::this_thread::sleep_for(100ms);
1500
1501 std::thread abort_thread([] { abort(); });
1502 abort_thread.join();
1503 },
1504 &seccomp_fork);
1505
1506 StartIntercept(&output_fd, dump_type);
1507 FinishCrasher();
1508 AssertDeath(SIGABRT);
1509 FinishIntercept(&intercept_result);
1510 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1511
1512 std::string result;
1513 ConsumeFd(std::move(output_fd), &result);
1514 ASSERT_BACKTRACE_FRAME(result, "abort");
1515 ASSERT_BACKTRACE_FRAME(result, "foo");
1516 ASSERT_BACKTRACE_FRAME(result, "bar");
1517 ASSERT_BACKTRACE_FRAME(result, "main");
1518}
1519
Josh Gaoe04ca272018-01-16 15:38:17 -08001520TEST_F(CrasherTest, seccomp_backtrace) {
1521 int intercept_result;
1522 unique_fd output_fd;
1523
1524 static const auto dump_type = kDebuggerdNativeBacktrace;
1525 StartProcess(
1526 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001527 std::thread a(foo);
1528 std::thread b(bar);
1529
1530 std::this_thread::sleep_for(100ms);
1531
Josh Gaoe04ca272018-01-16 15:38:17 -08001532 raise_debugger_signal(dump_type);
1533 _exit(0);
1534 },
1535 &seccomp_fork);
1536
1537 StartIntercept(&output_fd, dump_type);
1538 FinishCrasher();
1539 AssertDeath(0);
1540 FinishIntercept(&intercept_result);
1541 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1542
1543 std::string result;
1544 ConsumeFd(std::move(output_fd), &result);
1545 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001546 ASSERT_BACKTRACE_FRAME(result, "foo");
1547 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001548}
1549
Christopher Ferris7c2e7e32022-05-27 12:57:58 -07001550TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
1551 int intercept_result;
1552 unique_fd output_fd;
1553
1554 static const auto dump_type = kDebuggerdNativeBacktrace;
1555 StartProcess(
1556 []() {
1557 std::thread a(foo);
1558 std::thread b(bar);
1559
1560 std::this_thread::sleep_for(100ms);
1561
1562 std::thread raise_thread([] {
1563 raise_debugger_signal(dump_type);
1564 _exit(0);
1565 });
1566 raise_thread.join();
1567 },
1568 &seccomp_fork);
1569
1570 StartIntercept(&output_fd, dump_type);
1571 FinishCrasher();
1572 AssertDeath(0);
1573 FinishIntercept(&intercept_result);
1574 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1575
1576 std::string result;
1577 ConsumeFd(std::move(output_fd), &result);
1578 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1579 ASSERT_BACKTRACE_FRAME(result, "foo");
1580 ASSERT_BACKTRACE_FRAME(result, "bar");
1581 ASSERT_BACKTRACE_FRAME(result, "main");
1582}
1583
Josh Gaoe04ca272018-01-16 15:38:17 -08001584TEST_F(CrasherTest, seccomp_crash_logcat) {
1585 StartProcess([]() { abort(); }, &seccomp_fork);
1586 FinishCrasher();
1587
1588 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1589 AssertDeath(SIGABRT);
1590}
1591
Josh Gaofd13bf02017-08-18 15:37:26 -07001592TEST_F(CrasherTest, competing_tracer) {
1593 int intercept_result;
1594 unique_fd output_fd;
1595 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001596 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001597 });
1598
1599 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001600
1601 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001602 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001603
1604 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001605 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001606 ASSERT_TRUE(WIFSTOPPED(status));
1607 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1608
1609 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1610 FinishIntercept(&intercept_result);
1611 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1612
1613 std::string result;
1614 ConsumeFd(std::move(output_fd), &result);
1615 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1616 regex += std::to_string(gettid());
1617 regex += R"( \(.+debuggerd_test)";
1618 ASSERT_MATCH(result, regex.c_str());
1619
Christopher Ferris172b0a02019-09-18 17:48:30 -07001620 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001621 ASSERT_TRUE(WIFSTOPPED(status));
1622 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1623
Josh Gaofd13bf02017-08-18 15:37:26 -07001624 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1625 AssertDeath(SIGABRT);
1626}
1627
Josh Gaobf06a402018-08-27 16:34:01 -07001628TEST_F(CrasherTest, fdsan_warning_abort_message) {
1629 int intercept_result;
1630 unique_fd output_fd;
1631
1632 StartProcess([]() {
1633 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001634 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001635 if (fd == -1) {
1636 abort();
1637 }
1638 close(fd.get());
1639 _exit(0);
1640 });
1641
1642 StartIntercept(&output_fd);
1643 FinishCrasher();
1644 AssertDeath(0);
1645 FinishIntercept(&intercept_result);
1646 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1647
1648 std::string result;
1649 ConsumeFd(std::move(output_fd), &result);
1650 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1651}
1652
Josh Gaoc3c8c022017-02-13 16:36:18 -08001653TEST(crash_dump, zombie) {
1654 pid_t forkpid = fork();
1655
Josh Gaoc3c8c022017-02-13 16:36:18 -08001656 pid_t rc;
1657 int status;
1658
1659 if (forkpid == 0) {
1660 errno = 0;
1661 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1662 if (rc != -1 || errno != ECHILD) {
1663 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1664 }
1665
Josh Gaoa48b41b2019-12-13 14:11:04 -08001666 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001667
1668 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001669 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001670 if (rc != -1 || errno != ECHILD) {
1671 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1672 }
1673 _exit(0);
1674 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001675 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001676 ASSERT_EQ(forkpid, rc);
1677 ASSERT_TRUE(WIFEXITED(status));
1678 ASSERT_EQ(0, WEXITSTATUS(status));
1679 }
1680}
Josh Gao352a8452017-03-30 16:46:21 -07001681
1682TEST(tombstoned, no_notify) {
1683 // Do this a few times.
1684 for (int i = 0; i < 3; ++i) {
1685 pid_t pid = 123'456'789 + i;
1686
1687 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001688 InterceptStatus status;
1689 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1690 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001691
1692 {
1693 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001694 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001695 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1696 }
1697
1698 pid_t read_pid;
1699 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1700 ASSERT_EQ(read_pid, pid);
1701 }
1702}
1703
1704TEST(tombstoned, stress) {
1705 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1706 static constexpr int kDumpCount = 100;
1707
1708 std::atomic<bool> start(false);
1709 std::vector<std::thread> threads;
1710 threads.emplace_back([&start]() {
1711 while (!start) {
1712 continue;
1713 }
1714
1715 // Use a way out of range pid, to avoid stomping on an actual process.
1716 pid_t pid_base = 1'000'000;
1717
1718 for (int dump = 0; dump < kDumpCount; ++dump) {
1719 pid_t pid = pid_base + dump;
1720
1721 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001722 InterceptStatus status;
1723 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1724 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001725
1726 // Pretend to crash, and then immediately close the socket.
1727 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1728 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1729 if (sockfd == -1) {
1730 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1731 }
1732 TombstonedCrashPacket packet = {};
1733 packet.packet_type = CrashPacketType::kDumpRequest;
1734 packet.packet.dump_request.pid = pid;
1735 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1736 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1737 }
1738
1739 continue;
1740 }
1741 });
1742
1743 threads.emplace_back([&start]() {
1744 while (!start) {
1745 continue;
1746 }
1747
1748 // Use a way out of range pid, to avoid stomping on an actual process.
1749 pid_t pid_base = 2'000'000;
1750
1751 for (int dump = 0; dump < kDumpCount; ++dump) {
1752 pid_t pid = pid_base + dump;
1753
1754 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001755 InterceptStatus status;
1756 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1757 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001758
1759 {
1760 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001761 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001762 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1763 tombstoned_notify_completion(tombstoned_socket.get());
1764 }
1765
1766 // TODO: Fix the race that requires this sleep.
1767 std::this_thread::sleep_for(50ms);
1768
1769 pid_t read_pid;
1770 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1771 ASSERT_EQ(read_pid, pid);
1772 }
1773 });
1774
1775 start = true;
1776
1777 for (std::thread& thread : threads) {
1778 thread.join();
1779 }
1780}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001781
1782TEST(tombstoned, java_trace_intercept_smoke) {
1783 // Using a "real" PID is a little dangerous here - if the test fails
1784 // or crashes, we might end up getting a bogus / unreliable stack
1785 // trace.
1786 const pid_t self = getpid();
1787
1788 unique_fd intercept_fd, output_fd;
1789 InterceptStatus status;
1790 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1791 ASSERT_EQ(InterceptStatus::kRegistered, status);
1792
Josh Gao76e1e302021-01-26 15:53:11 -08001793 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001794 // should result in a "regular" FD and not the installed intercept.
1795 const char native[] = "native";
1796 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001797 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001798 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1799 tombstoned_notify_completion(tombstoned_socket.get());
1800
1801 // Then, connect to tombstoned asking for a java backtrace. This *should*
1802 // trigger the intercept.
1803 const char java[] = "java";
1804 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1805 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1806 tombstoned_notify_completion(tombstoned_socket.get());
1807
1808 char outbuf[sizeof(java)];
1809 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1810 ASSERT_STREQ("java", outbuf);
1811}
1812
1813TEST(tombstoned, multiple_intercepts) {
1814 const pid_t fake_pid = 1'234'567;
1815 unique_fd intercept_fd, output_fd;
1816 InterceptStatus status;
1817 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1818 ASSERT_EQ(InterceptStatus::kRegistered, status);
1819
1820 unique_fd intercept_fd_2, output_fd_2;
1821 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1822 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1823}
1824
1825TEST(tombstoned, intercept_any) {
1826 const pid_t fake_pid = 1'234'567;
1827
1828 unique_fd intercept_fd, output_fd;
1829 InterceptStatus status;
1830 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1831 ASSERT_EQ(InterceptStatus::kRegistered, status);
1832
1833 const char any[] = "any";
1834 unique_fd tombstoned_socket, input_fd;
1835 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1836 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1837 tombstoned_notify_completion(tombstoned_socket.get());
1838
1839 char outbuf[sizeof(any)];
1840 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1841 ASSERT_STREQ("any", outbuf);
1842}
Josh Gao2b22ae12018-09-12 14:51:03 -07001843
1844TEST(tombstoned, interceptless_backtrace) {
1845 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1846 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1847 std::map<int, time_t> result;
1848 for (int i = 0; i < 99; ++i) {
1849 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1850 struct stat st;
1851 if (stat(path.c_str(), &st) == 0) {
1852 result[i] = st.st_mtim.tv_sec;
1853 }
1854 }
1855 return result;
1856 };
1857
1858 auto before = get_tombstone_timestamps();
1859 for (int i = 0; i < 50; ++i) {
1860 raise_debugger_signal(kDebuggerdNativeBacktrace);
1861 }
1862 auto after = get_tombstone_timestamps();
1863
1864 int diff = 0;
1865 for (int i = 0; i < 99; ++i) {
1866 if (after.count(i) == 0) {
1867 continue;
1868 }
1869 if (before.count(i) == 0) {
1870 ++diff;
1871 continue;
1872 }
1873 if (before[i] != after[i]) {
1874 ++diff;
1875 }
1876 }
1877
1878 // We can't be sure that nothing's crash looping in the background.
1879 // This should be good enough, though...
1880 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1881}
Christopher Ferris481e8372019-07-15 17:13:24 -07001882
1883static __attribute__((__noinline__)) void overflow_stack(void* p) {
1884 void* buf[1];
1885 buf[0] = p;
1886 static volatile void* global = buf;
1887 if (global) {
1888 global = buf;
1889 overflow_stack(&buf);
1890 }
1891}
1892
1893TEST_F(CrasherTest, stack_overflow) {
1894 int intercept_result;
1895 unique_fd output_fd;
1896 StartProcess([]() { overflow_stack(nullptr); });
1897
1898 StartIntercept(&output_fd);
1899 FinishCrasher();
1900 AssertDeath(SIGSEGV);
1901 FinishIntercept(&intercept_result);
1902
1903 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1904
1905 std::string result;
1906 ConsumeFd(std::move(output_fd), &result);
1907 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1908}
Josh Gao76e1e302021-01-26 15:53:11 -08001909
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001910static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1911 std::string test_lib(testing::internal::GetArgvs()[0]);
1912 auto const value = test_lib.find_last_of('/');
1913 if (value == std::string::npos) {
1914 test_lib = "./";
1915 } else {
1916 test_lib = test_lib.substr(0, value + 1) + "./";
1917 }
1918 test_lib += "libcrash_test.so";
1919
1920 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1921 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1922
1923 // Copy the shared so to a tempory directory.
1924 return system(cp_cmd.c_str()) == 0;
1925}
1926
1927TEST_F(CrasherTest, unreadable_elf) {
1928 int intercept_result;
1929 unique_fd output_fd;
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001930 std::string tmp_so_name;
1931 StartProcess([&tmp_so_name]() {
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001932 TemporaryDir td;
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001933 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1934 _exit(1);
1935 }
1936 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1937 if (handle == nullptr) {
1938 _exit(1);
1939 }
1940 // Delete the original shared library so that we get the warning
1941 // about unreadable elf files.
1942 if (unlink(tmp_so_name.c_str()) == -1) {
1943 _exit(1);
1944 }
1945 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1946 if (crash_func == nullptr) {
1947 _exit(1);
1948 }
1949 crash_func();
1950 });
1951
1952 StartIntercept(&output_fd);
1953 FinishCrasher();
1954 AssertDeath(SIGSEGV);
1955 FinishIntercept(&intercept_result);
1956
1957 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1958
1959 std::string result;
1960 ConsumeFd(std::move(output_fd), &result);
1961 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
Christopher Ferrisc95047d2022-03-14 15:02:11 -07001962 std::string match_str = "NOTE: " + tmp_so_name;
1963 ASSERT_MATCH(result, match_str);
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001964}
1965
Josh Gao76e1e302021-01-26 15:53:11 -08001966TEST(tombstoned, proto) {
1967 const pid_t self = getpid();
1968 unique_fd tombstoned_socket, text_fd, proto_fd;
1969 ASSERT_TRUE(
1970 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1971
1972 tombstoned_notify_completion(tombstoned_socket.get());
1973
1974 ASSERT_NE(-1, text_fd.get());
1975 ASSERT_NE(-1, proto_fd.get());
1976
1977 struct stat text_st;
1978 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1979
1980 // Give tombstoned some time to link the files into place.
1981 std::this_thread::sleep_for(100ms);
1982
1983 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001984 std::optional<std::string> tombstone_file;
1985 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1986 ASSERT_TRUE(dir_h != nullptr);
1987 std::regex tombstone_re("tombstone_\\d+");
1988 dirent* entry;
1989 while ((entry = readdir(dir_h.get())) != nullptr) {
1990 if (!std::regex_match(entry->d_name, tombstone_re)) {
1991 continue;
1992 }
1993 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001994
1995 struct stat st;
1996 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1997 continue;
1998 }
1999
2000 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08002001 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08002002 break;
2003 }
2004 }
2005
Christopher Ferris35da2882021-02-17 15:39:06 -08002006 ASSERT_TRUE(tombstone_file);
2007 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08002008
2009 struct stat proto_fd_st;
2010 struct stat proto_file_st;
2011 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
2012 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
2013
2014 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
2015 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
2016}
2017
2018TEST(tombstoned, proto_intercept) {
2019 const pid_t self = getpid();
2020 unique_fd intercept_fd, output_fd;
2021 InterceptStatus status;
2022
2023 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
2024 ASSERT_EQ(InterceptStatus::kRegistered, status);
2025
2026 unique_fd tombstoned_socket, text_fd, proto_fd;
2027 ASSERT_TRUE(
2028 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
2029 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
2030 tombstoned_notify_completion(tombstoned_socket.get());
2031
2032 text_fd.reset();
2033
2034 std::string output;
2035 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
2036 ASSERT_EQ("foo", output);
2037}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07002038
2039// Verify that when an intercept is present for the main thread, and the signal
2040// is received on a different thread, the intercept still works.
2041TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
2042 StartProcess([]() {
2043 std::thread thread([]() {
2044 // Raise the signal on the side thread.
2045 raise_debugger_signal(kDebuggerdNativeBacktrace);
2046 });
2047 thread.join();
2048 _exit(0);
2049 });
2050
2051 unique_fd output_fd;
2052 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
2053 FinishCrasher();
2054 AssertDeath(0);
2055
2056 int intercept_result;
2057 FinishIntercept(&intercept_result);
2058 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2059
2060 std::string result;
2061 ConsumeFd(std::move(output_fd), &result);
2062 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
2063}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002064
2065static std::string format_pointer(uintptr_t ptr) {
2066#if defined(__LP64__)
2067 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2068 static_cast<uint32_t>(ptr & 0xffffffff));
2069#else
2070 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
2071#endif
2072}
2073
2074static std::string format_pointer(void* ptr) {
2075 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
2076}
2077
2078static std::string format_full_pointer(uintptr_t ptr) {
2079#if defined(__LP64__)
2080 return android::base::StringPrintf("%016" PRIx64, ptr);
2081#else
2082 return android::base::StringPrintf("%08x", ptr);
2083#endif
2084}
2085
2086static std::string format_full_pointer(void* ptr) {
2087 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
2088}
2089
2090__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
2091 int* crash_ptr = reinterpret_cast<int*>(ptr);
2092 *crash_ptr = 1;
2093 return *crash_ptr;
2094}
2095
2096// Verify that a fault address before the first map is properly handled.
2097TEST_F(CrasherTest, fault_address_before_first_map) {
2098 StartProcess([]() {
2099 ASSERT_EQ(0, crash_call(0x1024));
2100 _exit(0);
2101 });
2102
2103 unique_fd output_fd;
2104 StartIntercept(&output_fd);
2105 FinishCrasher();
2106 AssertDeath(SIGSEGV);
2107
2108 int intercept_result;
2109 FinishIntercept(&intercept_result);
2110 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2111
2112 std::string result;
2113 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002114 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002115
2116 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2117
2118 std::string match_str = android::base::StringPrintf(
2119 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2120 format_pointer(0x1024).c_str());
2121 ASSERT_MATCH(result, match_str);
2122}
2123
2124// Verify that a fault address after the last map is properly handled.
2125TEST_F(CrasherTest, fault_address_after_last_map) {
Florian Mayerb4979292022-04-15 14:35:17 -07002126 // This makes assumptions about the memory layout that are not true in HWASan
2127 // processes.
2128 SKIP_WITH_HWASAN;
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002129 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2130 StartProcess([crash_uptr]() {
2131 ASSERT_EQ(0, crash_call(crash_uptr));
2132 _exit(0);
2133 });
2134
2135 unique_fd output_fd;
2136 StartIntercept(&output_fd);
2137 FinishCrasher();
2138 AssertDeath(SIGSEGV);
2139
2140 int intercept_result;
2141 FinishIntercept(&intercept_result);
2142 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2143
2144 std::string result;
2145 ConsumeFd(std::move(output_fd), &result);
2146
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002147 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2148 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002149 ASSERT_MATCH(result, match_str);
2150
2151 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2152
2153 // Assumes that the open files section comes after the map section.
2154 // If that assumption changes, the regex below needs to change.
2155 match_str = android::base::StringPrintf(
2156 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2157 format_pointer(crash_uptr).c_str());
2158 ASSERT_MATCH(result, match_str);
2159}
2160
2161// Verify that a fault address between maps is properly handled.
2162TEST_F(CrasherTest, fault_address_between_maps) {
2163 // Create a map before the fork so it will be present in the child.
2164 void* start_ptr =
2165 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2166 ASSERT_NE(MAP_FAILED, start_ptr);
2167 // Unmap the page in the middle.
2168 void* middle_ptr =
2169 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2170 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2171
2172 StartProcess([middle_ptr]() {
2173 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2174 _exit(0);
2175 });
2176
2177 // Unmap the two maps.
2178 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2179 void* end_ptr =
2180 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2181 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2182
2183 unique_fd output_fd;
2184 StartIntercept(&output_fd);
2185 FinishCrasher();
2186 AssertDeath(SIGSEGV);
2187
2188 int intercept_result;
2189 FinishIntercept(&intercept_result);
2190 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2191
2192 std::string result;
2193 ConsumeFd(std::move(output_fd), &result);
2194
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002195 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2196 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002197 ASSERT_MATCH(result, match_str);
2198
2199 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2200
2201 match_str = android::base::StringPrintf(
2202 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2203 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2204 format_pointer(end_ptr).c_str());
2205 ASSERT_MATCH(result, match_str);
2206}
2207
2208// Verify that a fault address happens in the correct map.
2209TEST_F(CrasherTest, fault_address_in_map) {
2210 // Create a map before the fork so it will be present in the child.
2211 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2212 ASSERT_NE(MAP_FAILED, ptr);
2213
2214 StartProcess([ptr]() {
2215 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2216 _exit(0);
2217 });
2218
2219 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2220
2221 unique_fd output_fd;
2222 StartIntercept(&output_fd);
2223 FinishCrasher();
2224 AssertDeath(SIGSEGV);
2225
2226 int intercept_result;
2227 FinishIntercept(&intercept_result);
2228 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2229
2230 std::string result;
2231 ConsumeFd(std::move(output_fd), &result);
2232
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002233 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2234 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002235 ASSERT_MATCH(result, match_str);
2236
2237 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2238
2239 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2240 ASSERT_MATCH(result, match_str);
2241}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002242
2243static constexpr uint32_t kDexData[] = {
2244 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2245 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2246 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2247 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2248 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2249 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2250 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2251 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2252 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2253 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2254 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2255 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2256 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2257 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2258 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2259 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2260 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2261};
2262
2263TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2264 StartProcess([]() {
2265 TemporaryDir td;
2266 std::string tmp_so_name;
2267 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2268 _exit(1);
2269 }
2270
2271 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2272 // move the library to which has a basename of libart.so.
2273 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2274 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2275 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2276 if (handle == nullptr) {
2277 _exit(1);
2278 }
2279
2280 void* ptr =
2281 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2282 ASSERT_TRUE(ptr != MAP_FAILED);
2283 memcpy(ptr, kDexData, sizeof(kDexData));
2284 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2285
2286 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2287 .symfile_size = sizeof(kDexData)};
2288
2289 JITDescriptor* dex_debug =
2290 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2291 ASSERT_TRUE(dex_debug != nullptr);
2292 dex_debug->version = 1;
2293 dex_debug->action_flag = 0;
2294 dex_debug->relevant_entry = 0;
2295 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2296
2297 // This sets the magic dex pc value for register 0, using the value
2298 // of register 1 + 0x102.
2299 asm(".cfi_escape "
2300 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2301 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2302 "0x13 /* DW_OP_drop */,"
2303 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2304
2305 // For each different architecture, set register one to the dex ptr mmap
2306 // created above. Then do a nullptr dereference to force a crash.
2307#if defined(__arm__)
2308 asm volatile(
2309 "mov r1, %[base]\n"
2310 "mov r2, 0\n"
2311 "str r3, [r2]\n"
2312 : [base] "+r"(ptr)
2313 :
2314 : "r1", "r2", "r3", "memory");
2315#elif defined(__aarch64__)
2316 asm volatile(
2317 "mov x1, %[base]\n"
2318 "mov x2, 0\n"
2319 "str x3, [x2]\n"
2320 : [base] "+r"(ptr)
2321 :
2322 : "x1", "x2", "x3", "memory");
2323#elif defined(__i386__)
2324 asm volatile(
2325 "mov %[base], %%ecx\n"
2326 "movl $0, %%edi\n"
2327 "movl 0(%%edi), %%edx\n"
2328 : [base] "+r"(ptr)
2329 :
2330 : "edi", "ecx", "edx", "memory");
2331#elif defined(__x86_64__)
2332 asm volatile(
2333 "mov %[base], %%rdx\n"
2334 "movq 0, %%rdi\n"
2335 "movq 0(%%rdi), %%rcx\n"
2336 : [base] "+r"(ptr)
2337 :
2338 : "rcx", "rdx", "rdi", "memory");
2339#else
2340#error "Unsupported architecture"
2341#endif
2342 _exit(0);
2343 });
2344
2345 unique_fd output_fd;
2346 StartIntercept(&output_fd);
2347 FinishCrasher();
2348 AssertDeath(SIGSEGV);
2349
2350 int intercept_result;
2351 FinishIntercept(&intercept_result);
2352 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2353
2354 std::string result;
2355 ConsumeFd(std::move(output_fd), &result);
2356
2357 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002358 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002359
2360 // Now verify that the dex_pc frame includes a proper function name.
2361 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2362}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002363
2364static std::string format_map_pointer(uintptr_t ptr) {
2365#if defined(__LP64__)
2366 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2367 static_cast<uint32_t>(ptr & 0xffffffff));
2368#else
2369 return android::base::StringPrintf("%08x", ptr);
2370#endif
2371}
2372
2373// Verify that map data is properly formatted.
2374TEST_F(CrasherTest, verify_map_format) {
2375 // Create multiple maps to make sure that the map data is formatted properly.
2376 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2377 ASSERT_NE(MAP_FAILED, none_map);
2378 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2379 ASSERT_NE(MAP_FAILED, r_map);
2380 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2381 ASSERT_NE(MAP_FAILED, w_map);
2382 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2383 ASSERT_NE(MAP_FAILED, x_map);
2384
2385 TemporaryFile tf;
2386 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2387 char c = 'f';
2388 ASSERT_EQ(1, write(tf.fd, &c, 1));
2389 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2390 ASSERT_EQ(1, write(tf.fd, &c, 1));
2391 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2392 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2393 ASSERT_NE(MAP_FAILED, file_map);
2394
2395 StartProcess([]() { abort(); });
2396
2397 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2398 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2399 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2400 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2401 ASSERT_EQ(0, munmap(file_map, 0x3001));
2402
2403 unique_fd output_fd;
2404 StartIntercept(&output_fd);
2405 FinishCrasher();
2406 AssertDeath(SIGABRT);
2407 int intercept_result;
2408 FinishIntercept(&intercept_result);
2409
2410 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2411
2412 std::string result;
2413 ConsumeFd(std::move(output_fd), &result);
2414
2415 std::string match_str;
2416 // Verify none.
2417 match_str = android::base::StringPrintf(
2418 " %s-%s --- 0 1000\\n",
2419 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2420 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2421 ASSERT_MATCH(result, match_str);
2422
2423 // Verify read-only.
2424 match_str = android::base::StringPrintf(
2425 " %s-%s r-- 0 1000\\n",
2426 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2427 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2428 ASSERT_MATCH(result, match_str);
2429
2430 // Verify write-only.
2431 match_str = android::base::StringPrintf(
2432 " %s-%s -w- 0 1000\\n",
2433 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2434 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2435 ASSERT_MATCH(result, match_str);
2436
2437 // Verify exec-only.
2438 match_str = android::base::StringPrintf(
2439 " %s-%s --x 0 1000\\n",
2440 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2441 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2442 ASSERT_MATCH(result, match_str);
2443
2444 // Verify file map with non-zero offset and a name.
2445 match_str = android::base::StringPrintf(
2446 " %s-%s r-- 2000 4000 %s\\n",
2447 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2448 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2449 ASSERT_MATCH(result, match_str);
2450}
2451
2452// Verify that the tombstone map data is correct.
2453TEST_F(CrasherTest, verify_header) {
2454 StartProcess([]() { abort(); });
2455
2456 unique_fd output_fd;
2457 StartIntercept(&output_fd);
2458 FinishCrasher();
2459 AssertDeath(SIGABRT);
2460 int intercept_result;
2461 FinishIntercept(&intercept_result);
2462
2463 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2464
2465 std::string result;
2466 ConsumeFd(std::move(output_fd), &result);
2467
2468 std::string match_str = android::base::StringPrintf(
2469 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2470 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2471 android::base::GetProperty("ro.revision", "unknown").c_str());
2472 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2473 ASSERT_MATCH(result, match_str);
2474}
2475
2476// Verify that the thread header is formatted properly.
2477TEST_F(CrasherTest, verify_thread_header) {
2478 void* shared_map =
2479 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2480 ASSERT_NE(MAP_FAILED, shared_map);
2481 memset(shared_map, 0, sizeof(pid_t));
2482
2483 StartProcess([&shared_map]() {
2484 std::atomic_bool tid_written;
2485 std::thread thread([&tid_written, &shared_map]() {
2486 pid_t tid = gettid();
2487 memcpy(shared_map, &tid, sizeof(pid_t));
2488 tid_written = true;
2489 volatile bool done = false;
2490 while (!done)
2491 ;
2492 });
2493 thread.detach();
2494 while (!tid_written.load(std::memory_order_acquire))
2495 ;
2496 abort();
2497 });
2498
2499 pid_t primary_pid = crasher_pid;
2500
2501 unique_fd output_fd;
2502 StartIntercept(&output_fd);
2503 FinishCrasher();
2504 AssertDeath(SIGABRT);
2505 int intercept_result;
2506 FinishIntercept(&intercept_result);
2507 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2508
2509 // Read the tid data out.
2510 pid_t tid;
2511 memcpy(&tid, shared_map, sizeof(pid_t));
2512 ASSERT_NE(0, tid);
2513
2514 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2515
2516 std::string result;
2517 ConsumeFd(std::move(output_fd), &result);
2518
2519 // Verify that there are two headers, one where the tid is "primary_pid"
2520 // and the other where the tid is "tid".
2521 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2522 primary_pid, primary_pid);
2523 ASSERT_MATCH(result, match_str);
2524
2525 match_str =
2526 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2527 ASSERT_MATCH(result, match_str);
2528}
2529
2530// Verify that there is a BuildID present in the map section and set properly.
2531TEST_F(CrasherTest, verify_build_id) {
2532 StartProcess([]() { abort(); });
2533
2534 unique_fd output_fd;
2535 StartIntercept(&output_fd);
2536 FinishCrasher();
2537 AssertDeath(SIGABRT);
2538 int intercept_result;
2539 FinishIntercept(&intercept_result);
2540 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2541
2542 std::string result;
2543 ConsumeFd(std::move(output_fd), &result);
2544
2545 // Find every /system or /apex lib and verify the BuildID is displayed
2546 // properly.
2547 bool found_valid_elf = false;
2548 std::smatch match;
2549 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2550 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2551 result = match.suffix()) {
2552 if (prev_file == match[1]) {
2553 // Already checked this file.
2554 continue;
2555 }
2556
2557 prev_file = match[1];
2558 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2559 if (!elf.Init() || !elf.valid()) {
2560 // Skipping invalid elf files.
2561 continue;
2562 }
2563 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2564
2565 found_valid_elf = true;
2566 }
2567 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2568}