blob: 2cf5b18dffd2ef057224381870846f9eeb6271ba [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) {}; \
91 if (sigaction(SIGALRM, &new_sigaction, &new_sigaction) != 0) { \
92 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() {
116 bool force = true;
117 android_mallopt(M_INITIALIZE_GWP_ASAN, &force, sizeof(force));
118}
119
Narayan Kamatha73df602017-05-24 15:07:25 +0100120static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
Narayan Kamathca5e9082017-06-02 15:42:06 +0100121 InterceptStatus* status, DebuggerdDumpType intercept_type) {
Josh Gao460b3362017-03-30 16:40:47 -0700122 intercept_fd->reset(socket_local_client(kTombstonedInterceptSocketName,
123 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
124 if (intercept_fd->get() == -1) {
125 FAIL() << "failed to contact tombstoned: " << strerror(errno);
126 }
127
Nick Desaulniers67d52aa2019-10-07 23:28:15 -0700128 InterceptRequest req = {
129 .dump_type = intercept_type,
130 .pid = target_pid,
131 };
Josh Gao460b3362017-03-30 16:40:47 -0700132
133 unique_fd output_pipe_write;
134 if (!Pipe(output_fd, &output_pipe_write)) {
135 FAIL() << "failed to create output pipe: " << strerror(errno);
136 }
137
138 std::string pipe_size_str;
139 int pipe_buffer_size;
140 if (!android::base::ReadFileToString("/proc/sys/fs/pipe-max-size", &pipe_size_str)) {
141 FAIL() << "failed to read /proc/sys/fs/pipe-max-size: " << strerror(errno);
142 }
143
144 pipe_size_str = android::base::Trim(pipe_size_str);
145
146 if (!android::base::ParseInt(pipe_size_str.c_str(), &pipe_buffer_size, 0)) {
147 FAIL() << "failed to parse pipe max size";
148 }
149
150 if (fcntl(output_fd->get(), F_SETPIPE_SZ, pipe_buffer_size) != pipe_buffer_size) {
151 FAIL() << "failed to set pipe size: " << strerror(errno);
152 }
153
Josh Gao5675f3c2017-06-01 12:19:53 -0700154 ASSERT_GE(pipe_buffer_size, 1024 * 1024);
155
Josh Gao5f87bbd2019-01-09 17:01:49 -0800156 ssize_t rc = SendFileDescriptors(intercept_fd->get(), &req, sizeof(req), output_pipe_write.get());
157 output_pipe_write.reset();
158 if (rc != sizeof(req)) {
Josh Gao460b3362017-03-30 16:40:47 -0700159 FAIL() << "failed to send output fd to tombstoned: " << strerror(errno);
160 }
161
162 InterceptResponse response;
Josh Gao5f87bbd2019-01-09 17:01:49 -0800163 rc = TEMP_FAILURE_RETRY(read(intercept_fd->get(), &response, sizeof(response)));
Josh Gao460b3362017-03-30 16:40:47 -0700164 if (rc == -1) {
165 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
166 } else if (rc == 0) {
167 FAIL() << "failed to read response from tombstoned (EOF)";
168 } else if (rc != sizeof(response)) {
169 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
170 << ", received " << rc;
171 }
172
Narayan Kamathca5e9082017-06-02 15:42:06 +0100173 *status = response.status;
Josh Gao460b3362017-03-30 16:40:47 -0700174}
175
Elliott Hughesd13ea522022-01-13 09:20:26 -0800176static bool pac_supported() {
177#if defined(__aarch64__)
178 return getauxval(AT_HWCAP) & HWCAP_PACA;
179#else
180 return false;
181#endif
182}
183
Josh Gaocbe70cb2016-10-18 18:17:52 -0700184class CrasherTest : public ::testing::Test {
185 public:
186 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700187 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700188 unique_fd crasher_pipe;
189 unique_fd intercept_fd;
190
191 CrasherTest();
192 ~CrasherTest();
193
Narayan Kamatha73df602017-05-24 15:07:25 +0100194 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700195
196 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
197 void FinishIntercept(int* result);
198
Josh Gao2e7b8e22017-05-04 17:12:57 -0700199 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700200 void StartCrasher(const std::string& crash_type);
201 void FinishCrasher();
202 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700203
204 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700205};
206
207CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700208 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
209 android::base::SetProperty(kWaitForDebuggerKey, "0");
210
211 // Clear the old property too, just in case someone's been using it
212 // on this device. (We only document the new name, but we still support
213 // the old name so we don't break anyone's existing setups.)
214 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700215}
216
217CrasherTest::~CrasherTest() {
218 if (crasher_pid != -1) {
219 kill(crasher_pid, SIGKILL);
220 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700221 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700222 }
223
Elliott Hughese4781d52021-03-17 09:15:15 -0700224 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700225}
226
Narayan Kamatha73df602017-05-24 15:07:25 +0100227void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700228 if (crasher_pid == -1) {
229 FAIL() << "crasher hasn't been started";
230 }
231
Narayan Kamathca5e9082017-06-02 15:42:06 +0100232 InterceptStatus status;
233 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
234 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700235}
236
237void CrasherTest::FinishIntercept(int* result) {
238 InterceptResponse response;
239
Christopher Ferris11555f02019-09-20 14:18:55 -0700240 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700241 if (rc == -1) {
242 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
243 } else if (rc == 0) {
244 *result = -1;
245 } else if (rc != sizeof(response)) {
246 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
247 << ", received " << rc;
248 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700249 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700250 }
251}
252
Josh Gao2e7b8e22017-05-04 17:12:57 -0700253void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800254 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700255 unique_fd crasher_read_pipe;
256 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
257 FAIL() << "failed to create pipe: " << strerror(errno);
258 }
259
Josh Gao2e7b8e22017-05-04 17:12:57 -0700260 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700261 if (crasher_pid == -1) {
262 FAIL() << "fork failed: " << strerror(errno);
263 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800264 char dummy;
265 crasher_pipe.reset();
266 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800267 function();
268 _exit(0);
269 }
270}
271
Josh Gaocbe70cb2016-10-18 18:17:52 -0700272void CrasherTest::FinishCrasher() {
273 if (crasher_pipe == -1) {
274 FAIL() << "crasher pipe uninitialized";
275 }
276
Christopher Ferris172b0a02019-09-18 17:48:30 -0700277 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700278 if (rc == -1) {
279 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
280 } else if (rc == 0) {
281 FAIL() << "crasher pipe was closed";
282 }
283}
284
285void CrasherTest::AssertDeath(int signo) {
286 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700287 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700288 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700289 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
290 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700291 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700292 FAIL() << "failed to wait for crasher: " << strerror(errno);
293 }
294
Josh Gaoe06f2a42017-04-27 16:50:38 -0700295 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700296 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700297 ASSERT_EQ(0, WEXITSTATUS(signo));
298 } else {
299 ASSERT_FALSE(WIFEXITED(status));
300 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
301 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700302 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700303 crasher_pid = -1;
304}
305
306static void ConsumeFd(unique_fd fd, std::string* output) {
307 constexpr size_t read_length = PAGE_SIZE;
308 std::string result;
309
310 while (true) {
311 size_t offset = result.size();
312 result.resize(result.size() + PAGE_SIZE);
313 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
314 if (rc == -1) {
315 FAIL() << "read failed: " << strerror(errno);
316 } else if (rc == 0) {
317 result.resize(result.size() - PAGE_SIZE);
318 break;
319 }
320
321 result.resize(result.size() - PAGE_SIZE + rc);
322 }
323
324 *output = std::move(result);
325}
326
Mitch Phillips78f06702021-06-01 14:35:43 -0700327class LogcatCollector {
328 public:
329 LogcatCollector() { system("logcat -c"); }
330
331 void Collect(std::string* output) {
332 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
333 ASSERT_NE(cmd_stdout, nullptr);
334 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
335 ConsumeFd(std::move(tmp_fd), output);
336 pclose(cmd_stdout);
337 }
338};
339
Josh Gaocbe70cb2016-10-18 18:17:52 -0700340TEST_F(CrasherTest, smoke) {
341 int intercept_result;
342 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800343 StartProcess([]() {
344 *reinterpret_cast<volatile char*>(0xdead) = '1';
345 });
346
Josh Gaocbe70cb2016-10-18 18:17:52 -0700347 StartIntercept(&output_fd);
348 FinishCrasher();
349 AssertDeath(SIGSEGV);
350 FinishIntercept(&intercept_result);
351
352 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
353
354 std::string result;
355 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800356#ifdef __LP64__
357 ASSERT_MATCH(result,
358 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
359#else
360 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
361#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700362
363 if (mte_supported()) {
364 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700365 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
366 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700367 }
Elliott Hughesd13ea522022-01-13 09:20:26 -0800368
369 if (pac_supported()) {
370 // Test that the default PAC_ENABLED_KEYS value is set.
371 ASSERT_MATCH(result, R"(pac_enabled_keys: 000000000000000f)"
372 R"( \(PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY\))");
373 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700374}
375
Peter Collingbournef03af882020-03-20 18:09:00 -0700376TEST_F(CrasherTest, tagged_fault_addr) {
377#if !defined(__aarch64__)
378 GTEST_SKIP() << "Requires aarch64";
379#endif
380 int intercept_result;
381 unique_fd output_fd;
382 StartProcess([]() {
383 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
384 });
385
386 StartIntercept(&output_fd);
387 FinishCrasher();
388 AssertDeath(SIGSEGV);
389 FinishIntercept(&intercept_result);
390
391 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
392
393 std::string result;
394 ConsumeFd(std::move(output_fd), &result);
395
396 // The address can either be tagged (new kernels) or untagged (old kernels).
397 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800398 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700399}
400
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700401// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
402// compiler could still clobber the argument register before trapping, but that's unlikely.
403__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
404 __builtin_trap();
405}
406
407TEST_F(CrasherTest, heap_addr_in_register) {
408#if defined(__i386__)
409 GTEST_SKIP() << "architecture does not pass arguments in registers";
410#endif
411 int intercept_result;
412 unique_fd output_fd;
413 StartProcess([]() {
414 // Crash with a heap pointer in the first argument register.
415 Trap(malloc(1));
416 });
417
418 StartIntercept(&output_fd);
419 FinishCrasher();
420 int status;
421 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
422 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
423 // Don't test the signal number because different architectures use different signals for
424 // __builtin_trap().
425 FinishIntercept(&intercept_result);
426
427 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
428
429 std::string result;
430 ConsumeFd(std::move(output_fd), &result);
431
432#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800433 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700434#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800435 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700436#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800437 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700438#else
439 ASSERT_TRUE(false) << "unsupported architecture";
440#endif
441}
442
Peter Collingbournecd278072020-12-21 14:08:38 -0800443#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700444static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800445 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700446 abort();
447 }
448}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800449
450static void SetTagCheckingLevelAsync() {
451 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
452 abort();
453 }
454}
Peter Collingbournef8622522020-04-07 14:07:32 -0700455#endif
456
Mitch Phillips7168a212021-03-09 16:53:23 -0800457// Number of iterations required to reliably guarantee a GWP-ASan crash.
458// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
459// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
460// the counter reaches zero, we provide a sampled allocation. Then, double that
461// figure to allow for left/right allocation alignment, as this is done randomly
462// without bias.
463#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
464
465struct GwpAsanTestParameters {
466 size_t alloc_size;
467 bool free_before_access;
468 int access_offset;
469 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
470};
471
472struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
473
474GwpAsanTestParameters gwp_asan_tests[] = {
475 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
476 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
477 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
478 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
479};
480
481INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
482
483TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
484 if (mte_supported()) {
485 // Skip this test on MTE hardware, as MTE will reliably catch these errors
486 // instead of GWP-ASan.
487 GTEST_SKIP() << "Skipped on MTE.";
488 }
489
490 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700491 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800492
493 int intercept_result;
494 unique_fd output_fd;
495 StartProcess([&params]() {
496 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
497 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
498 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
499 p[params.access_offset] = 42;
500 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
501 }
502 });
503
504 StartIntercept(&output_fd);
505 FinishCrasher();
506 AssertDeath(SIGSEGV);
507 FinishIntercept(&intercept_result);
508
509 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
510
Mitch Phillips78f06702021-06-01 14:35:43 -0700511 std::vector<std::string> log_sources(2);
512 ConsumeFd(std::move(output_fd), &log_sources[0]);
513 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800514
Mitch Phillips78f06702021-06-01 14:35:43 -0700515 for (const auto& result : log_sources) {
516 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
517 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
518 if (params.free_before_access) {
519 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
520 }
521 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800522 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800523}
524
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800525struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
526
Peter Collingbourneaa544792021-05-13 13:53:37 -0700527INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800528
529TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800530#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700531 if (!mte_supported()) {
532 GTEST_SKIP() << "Requires MTE";
533 }
534
Peter Collingbourneaa544792021-05-13 13:53:37 -0700535 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
536 if (GetParam() == 0) {
537 return;
538 }
539
Mitch Phillips78f06702021-06-01 14:35:43 -0700540 LogcatCollector logcat_collector;
541
Peter Collingbournef8622522020-04-07 14:07:32 -0700542 int intercept_result;
543 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800544 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700545 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800546 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700547 free((void *)p);
548 p[0] = 42;
549 });
550
551 StartIntercept(&output_fd);
552 FinishCrasher();
553 AssertDeath(SIGSEGV);
554 FinishIntercept(&intercept_result);
555
556 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
557
Mitch Phillips78f06702021-06-01 14:35:43 -0700558 std::vector<std::string> log_sources(2);
559 ConsumeFd(std::move(output_fd), &log_sources[0]);
560 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700561 // Tag dump only available in the tombstone, not logcat.
562 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700563
Mitch Phillips78f06702021-06-01 14:35:43 -0700564 for (const auto& result : log_sources) {
565 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
566 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
567 std::to_string(GetParam()) + R"(-byte allocation)");
568 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
569 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
570 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700571#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800572 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700573#endif
574}
575
Peter Collingbournedc476342021-05-12 15:56:43 -0700576TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
577#if defined(__aarch64__)
578 if (!mte_supported()) {
579 GTEST_SKIP() << "Requires MTE";
580 }
581
582 int intercept_result;
583 unique_fd output_fd;
584 StartProcess([&]() {
585 SetTagCheckingLevelSync();
586 volatile int* p = (volatile int*)malloc(GetParam());
587 free((void *)p);
588 p[-1] = 42;
589 });
590
591 StartIntercept(&output_fd);
592 FinishCrasher();
593 AssertDeath(SIGSEGV);
594 FinishIntercept(&intercept_result);
595
596 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
597
598 std::string result;
599 ConsumeFd(std::move(output_fd), &result);
600
601 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
602 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
603#else
604 GTEST_SKIP() << "Requires aarch64";
605#endif
606}
607
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800608TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800609#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700610 if (!mte_supported()) {
611 GTEST_SKIP() << "Requires MTE";
612 }
613
Mitch Phillips78f06702021-06-01 14:35:43 -0700614 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700615 int intercept_result;
616 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800617 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700618 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800619 volatile char* p = (volatile char*)malloc(GetParam());
620 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700621 });
622
623 StartIntercept(&output_fd);
624 FinishCrasher();
625 AssertDeath(SIGSEGV);
626 FinishIntercept(&intercept_result);
627
628 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
629
Mitch Phillips78f06702021-06-01 14:35:43 -0700630 std::vector<std::string> log_sources(2);
631 ConsumeFd(std::move(output_fd), &log_sources[0]);
632 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700633
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700634 // Tag dump only in tombstone, not logcat, and tagging is not used for
635 // overflow protection in the scudo secondary (guard pages are used instead).
636 if (GetParam() < 0x10000) {
637 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
638 }
639
Mitch Phillips78f06702021-06-01 14:35:43 -0700640 for (const auto& result : log_sources) {
641 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
642 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
643 std::to_string(GetParam()) + R"(-byte allocation)");
644 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
645 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700646#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800647 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700648#endif
649}
650
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800651TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800652#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700653 if (!mte_supported()) {
654 GTEST_SKIP() << "Requires MTE";
655 }
656
657 int intercept_result;
658 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800659 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700660 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800661 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700662 p[-1] = 42;
663 });
664
665 StartIntercept(&output_fd);
666 FinishCrasher();
667 AssertDeath(SIGSEGV);
668 FinishIntercept(&intercept_result);
669
670 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
671
672 std::string result;
673 ConsumeFd(std::move(output_fd), &result);
674
675 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800676 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800677 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700678 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700679 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700680 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700681#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800682 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700683#endif
684}
685
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800686TEST_F(CrasherTest, mte_async) {
687#if defined(__aarch64__)
688 if (!mte_supported()) {
689 GTEST_SKIP() << "Requires MTE";
690 }
691
692 int intercept_result;
693 unique_fd output_fd;
694 StartProcess([&]() {
695 SetTagCheckingLevelAsync();
696 volatile int* p = (volatile int*)malloc(16);
697 p[-1] = 42;
698 });
699
700 StartIntercept(&output_fd);
701 FinishCrasher();
702 AssertDeath(SIGSEGV);
703 FinishIntercept(&intercept_result);
704
705 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
706
707 std::string result;
708 ConsumeFd(std::move(output_fd), &result);
709
710 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
711#else
712 GTEST_SKIP() << "Requires aarch64";
713#endif
714}
715
Peter Collingbournef8622522020-04-07 14:07:32 -0700716TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800717#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700718 if (!mte_supported()) {
719 GTEST_SKIP() << "Requires MTE";
720 }
721
Mitch Phillips78f06702021-06-01 14:35:43 -0700722 LogcatCollector logcat_collector;
723
Peter Collingbournef8622522020-04-07 14:07:32 -0700724 int intercept_result;
725 unique_fd output_fd;
726 StartProcess([]() {
727 SetTagCheckingLevelSync();
728
729 // Make two allocations with the same tag and close to one another. Check for both properties
730 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
731 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
732 // (some non-zero value << 56) apart.
733 //
734 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
735 // other.
736 std::set<uintptr_t> allocs;
737 for (int i = 0; i != 4096; ++i) {
738 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
739 auto it = allocs.insert(alloc).first;
740 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
741 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
742 }
743 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
744 *reinterpret_cast<int*>(alloc + 16) = 42;
745 }
746 }
747 });
748
749 StartIntercept(&output_fd);
750 FinishCrasher();
751 AssertDeath(SIGSEGV);
752 FinishIntercept(&intercept_result);
753
754 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
755
Mitch Phillips78f06702021-06-01 14:35:43 -0700756 std::vector<std::string> log_sources(2);
757 ConsumeFd(std::move(output_fd), &log_sources[0]);
758 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700759
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700760 // Tag dump only in the tombstone, not logcat.
761 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
762
Mitch Phillips78f06702021-06-01 14:35:43 -0700763 for (const auto& result : log_sources) {
764 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
765 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800766 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700767 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
768 // overflows), so we can't match explicitly for an underflow message.
769 ASSERT_MATCH(result,
770 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
771 // Ensure there's at least two allocation traces (one for each cause).
772 ASSERT_MATCH(
773 result,
774 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
775 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700776#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800777 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700778#endif
779}
780
Peter Collingbournecd278072020-12-21 14:08:38 -0800781#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700782static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700783 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
784 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
785 size_t page_size = getpagesize();
786 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
787 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
788 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700789 return 0;
790 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700791 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
792 PROT_READ | PROT_WRITE | PROT_MTE);
793 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
794 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
795 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
796 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
797 }
798 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700799}
800#endif
801
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700802TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800803#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700804 if (!mte_supported()) {
805 GTEST_SKIP() << "Requires MTE";
806 }
807
808 int intercept_result;
809 unique_fd output_fd;
810 StartProcess([&]() {
811 SetTagCheckingLevelSync();
812 Trap(reinterpret_cast<void *>(CreateTagMapping()));
813 });
814
815 StartIntercept(&output_fd);
816 FinishCrasher();
817 AssertDeath(SIGTRAP);
818 FinishIntercept(&intercept_result);
819
820 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
821
822 std::string result;
823 ConsumeFd(std::move(output_fd), &result);
824
825 ASSERT_MATCH(result, R"(memory near x0:
826.*
827.*
828 01.............0 0000000000000000 0000000000000000 ................
829 00.............0)");
830#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800831 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700832#endif
833}
834
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700835TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
836#if defined(__aarch64__)
837 if (!mte_supported()) {
838 GTEST_SKIP() << "Requires MTE";
839 }
840
841 int intercept_result;
842 unique_fd output_fd;
843 StartProcess([&]() {
844 SetTagCheckingLevelSync();
845 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
846 p[0] = 0; // Untagged pointer, tagged memory.
847 });
848
849 StartIntercept(&output_fd);
850 FinishCrasher();
851 AssertDeath(SIGSEGV);
852 FinishIntercept(&intercept_result);
853
854 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
855
856 std::string result;
857 ConsumeFd(std::move(output_fd), &result);
858
859 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
860\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
861#else
862 GTEST_SKIP() << "Requires aarch64";
863#endif
864}
865
866TEST_F(CrasherTest, mte_fault_tag_dump) {
867#if defined(__aarch64__)
868 if (!mte_supported()) {
869 GTEST_SKIP() << "Requires MTE";
870 }
871
872 int intercept_result;
873 unique_fd output_fd;
874 StartProcess([&]() {
875 SetTagCheckingLevelSync();
876 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
877 p[320] = 0; // Untagged pointer, tagged memory.
878 });
879
880 StartIntercept(&output_fd);
881 FinishCrasher();
882 AssertDeath(SIGSEGV);
883 FinishIntercept(&intercept_result);
884
885 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
886
887 std::string result;
888 ConsumeFd(std::move(output_fd), &result);
889
890 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
891\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
892\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
893\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
894)");
895#else
896 GTEST_SKIP() << "Requires aarch64";
897#endif
898}
899
900TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
901#if defined(__aarch64__)
902 if (!mte_supported()) {
903 GTEST_SKIP() << "Requires MTE";
904 }
905
906 int intercept_result;
907 unique_fd output_fd;
908 StartProcess([&]() {
909 SetTagCheckingLevelSync();
910 size_t page_size = getpagesize();
911 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
912 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
913 });
914
915 StartIntercept(&output_fd);
916 FinishCrasher();
917 AssertDeath(SIGSEGV);
918 FinishIntercept(&intercept_result);
919
920 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
921
922 std::string result;
923 ConsumeFd(std::move(output_fd), &result);
924
925 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
926 ASSERT_MATCH(result,
927 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
928\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
929
930)"); // Ensure truncation happened and there's a newline after the tag fault.
931#else
932 GTEST_SKIP() << "Requires aarch64";
933#endif
934}
935
Josh Gaocdea7502017-11-01 15:00:40 -0700936TEST_F(CrasherTest, LD_PRELOAD) {
937 int intercept_result;
938 unique_fd output_fd;
939 StartProcess([]() {
940 setenv("LD_PRELOAD", "nonexistent.so", 1);
941 *reinterpret_cast<volatile char*>(0xdead) = '1';
942 });
943
944 StartIntercept(&output_fd);
945 FinishCrasher();
946 AssertDeath(SIGSEGV);
947 FinishIntercept(&intercept_result);
948
949 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
950
951 std::string result;
952 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800953 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700954}
955
Josh Gaocbe70cb2016-10-18 18:17:52 -0700956TEST_F(CrasherTest, abort) {
957 int intercept_result;
958 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800959 StartProcess([]() {
960 abort();
961 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700962 StartIntercept(&output_fd);
963 FinishCrasher();
964 AssertDeath(SIGABRT);
965 FinishIntercept(&intercept_result);
966
967 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
968
969 std::string result;
970 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700971 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700972}
973
974TEST_F(CrasherTest, signal) {
975 int intercept_result;
976 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800977 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700978 while (true) {
979 sleep(1);
980 }
Josh Gao502cfd22017-02-17 01:39:15 -0800981 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700982 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700983 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700984 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
985
986 AssertDeath(SIGSEGV);
987 FinishIntercept(&intercept_result);
988
989 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
990
991 std::string result;
992 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700993 ASSERT_MATCH(
994 result,
995 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700996 ASSERT_MATCH(result, R"(backtrace:)");
997}
998
999TEST_F(CrasherTest, abort_message) {
1000 int intercept_result;
1001 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001002 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -08001003 // Arrived at experimentally;
1004 // logd truncates at 4062.
1005 // strlen("Abort message: ''") is 17.
1006 // That's 4045, but we also want a NUL.
1007 char buf[4045 + 1];
1008 memset(buf, 'x', sizeof(buf));
1009 buf[sizeof(buf) - 1] = '\0';
1010 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -08001011 abort();
1012 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001013 StartIntercept(&output_fd);
1014 FinishCrasher();
1015 AssertDeath(SIGABRT);
1016 FinishIntercept(&intercept_result);
1017
1018 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1019
1020 std::string result;
1021 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001022 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001023}
1024
Christopher Ferrise8891452021-08-17 17:34:53 -07001025TEST_F(CrasherTest, abort_message_newline_trimmed) {
1026 int intercept_result;
1027 unique_fd output_fd;
1028 StartProcess([]() {
1029 android_set_abort_message("Message with a newline.\n");
1030 abort();
1031 });
1032 StartIntercept(&output_fd);
1033 FinishCrasher();
1034 AssertDeath(SIGABRT);
1035 FinishIntercept(&intercept_result);
1036
1037 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1038
1039 std::string result;
1040 ConsumeFd(std::move(output_fd), &result);
1041 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1042}
1043
1044TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1045 int intercept_result;
1046 unique_fd output_fd;
1047 StartProcess([]() {
1048 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1049 abort();
1050 });
1051 StartIntercept(&output_fd);
1052 FinishCrasher();
1053 AssertDeath(SIGABRT);
1054 FinishIntercept(&intercept_result);
1055
1056 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1057
1058 std::string result;
1059 ConsumeFd(std::move(output_fd), &result);
1060 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1061}
1062
Josh Gaoe06f2a42017-04-27 16:50:38 -07001063TEST_F(CrasherTest, abort_message_backtrace) {
1064 int intercept_result;
1065 unique_fd output_fd;
1066 StartProcess([]() {
1067 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001068 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001069 exit(0);
1070 });
1071 StartIntercept(&output_fd);
1072 FinishCrasher();
1073 AssertDeath(0);
1074 FinishIntercept(&intercept_result);
1075
1076 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1077
1078 std::string result;
1079 ConsumeFd(std::move(output_fd), &result);
1080 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1081}
1082
Josh Gaocbe70cb2016-10-18 18:17:52 -07001083TEST_F(CrasherTest, intercept_timeout) {
1084 int intercept_result;
1085 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001086 StartProcess([]() {
1087 abort();
1088 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001089 StartIntercept(&output_fd);
1090
1091 // Don't let crasher finish until we timeout.
1092 FinishIntercept(&intercept_result);
1093
1094 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1095 << intercept_result << ")";
1096
1097 FinishCrasher();
1098 AssertDeath(SIGABRT);
1099}
1100
Elliott Hughese4781d52021-03-17 09:15:15 -07001101TEST_F(CrasherTest, wait_for_debugger) {
1102 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1103 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001104 }
1105 sleep(1);
1106
Josh Gao502cfd22017-02-17 01:39:15 -08001107 StartProcess([]() {
1108 abort();
1109 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001110 FinishCrasher();
1111
1112 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001113 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001114 ASSERT_TRUE(WIFSTOPPED(status));
1115 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1116
1117 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1118
1119 AssertDeath(SIGABRT);
1120}
1121
Josh Gaocbe70cb2016-10-18 18:17:52 -07001122TEST_F(CrasherTest, backtrace) {
1123 std::string result;
1124 int intercept_result;
1125 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001126
1127 StartProcess([]() {
1128 abort();
1129 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001130 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001131
1132 std::this_thread::sleep_for(500ms);
1133
1134 sigval val;
1135 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001136 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001137 FinishIntercept(&intercept_result);
1138 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1139 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001140 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001141
1142 int status;
1143 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1144
1145 StartIntercept(&output_fd);
1146 FinishCrasher();
1147 AssertDeath(SIGABRT);
1148 FinishIntercept(&intercept_result);
1149 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1150 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001151 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001152}
Josh Gaofca7ca32017-01-23 12:05:35 -08001153
1154TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001155 int intercept_result;
1156 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001157 StartProcess([]() {
1158 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001159 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001160 });
Josh Gao502cfd22017-02-17 01:39:15 -08001161
1162 StartIntercept(&output_fd);
1163 FinishCrasher();
1164 AssertDeath(SIGABRT);
1165 FinishIntercept(&intercept_result);
1166
1167 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1168
1169 std::string result;
1170 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001171 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001172}
1173
Josh Gao502cfd22017-02-17 01:39:15 -08001174TEST_F(CrasherTest, capabilities) {
1175 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1176
Josh Gaofca7ca32017-01-23 12:05:35 -08001177 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001178 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1179 err(1, "failed to set PR_SET_KEEPCAPS");
1180 }
1181
1182 if (setresuid(1, 1, 1) != 0) {
1183 err(1, "setresuid failed");
1184 }
1185
1186 __user_cap_header_struct capheader;
1187 __user_cap_data_struct capdata[2];
1188 memset(&capheader, 0, sizeof(capheader));
1189 memset(&capdata, 0, sizeof(capdata));
1190
1191 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1192 capheader.pid = 0;
1193
1194 // Turn on every third capability.
1195 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1196 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1197 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1198 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1199 }
1200
1201 // Make sure CAP_SYS_PTRACE is off.
1202 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1203 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1204
1205 if (capset(&capheader, &capdata[0]) != 0) {
1206 err(1, "capset failed");
1207 }
1208
1209 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1210 err(1, "failed to drop ambient capabilities");
1211 }
1212
Josh Gaoa5199a92017-04-03 13:18:34 -07001213 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001214 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001215 });
Josh Gao502cfd22017-02-17 01:39:15 -08001216
1217 unique_fd output_fd;
1218 StartIntercept(&output_fd);
1219 FinishCrasher();
1220 AssertDeath(SIGSYS);
1221
1222 std::string result;
1223 int intercept_result;
1224 FinishIntercept(&intercept_result);
1225 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1226 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001227 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001228 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001229}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001230
Josh Gao2e7b8e22017-05-04 17:12:57 -07001231TEST_F(CrasherTest, fake_pid) {
1232 int intercept_result;
1233 unique_fd output_fd;
1234
1235 // Prime the getpid/gettid caches.
1236 UNUSED(getpid());
1237 UNUSED(gettid());
1238
1239 std::function<pid_t()> clone_fn = []() {
1240 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1241 };
1242 StartProcess(
1243 []() {
1244 ASSERT_NE(getpid(), syscall(__NR_getpid));
1245 ASSERT_NE(gettid(), syscall(__NR_gettid));
1246 raise(SIGSEGV);
1247 },
1248 clone_fn);
1249
1250 StartIntercept(&output_fd);
1251 FinishCrasher();
1252 AssertDeath(SIGSEGV);
1253 FinishIntercept(&intercept_result);
1254
1255 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1256
1257 std::string result;
1258 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001259 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001260}
1261
Josh Gaoe04ca272018-01-16 15:38:17 -08001262static const char* const kDebuggerdSeccompPolicy =
1263 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1264
Josh Gao70adac62018-02-22 11:38:33 -08001265static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001266 std::string policy;
1267 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1268 PLOG(FATAL) << "failed to read policy file";
1269 }
1270
1271 // Allow a bunch of syscalls used by the tests.
1272 policy += "\nclone: 1";
1273 policy += "\nsigaltstack: 1";
1274 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001275 policy += "\ngetrlimit: 1";
1276 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001277
1278 FILE* tmp_file = tmpfile();
1279 if (!tmp_file) {
1280 PLOG(FATAL) << "tmpfile failed";
1281 }
1282
Christopher Ferris172b0a02019-09-18 17:48:30 -07001283 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001284 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1285 PLOG(FATAL) << "failed to write policy to tmpfile";
1286 }
1287
1288 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1289 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001290 }
1291
1292 ScopedMinijail jail{minijail_new()};
1293 if (!jail) {
1294 LOG(FATAL) << "failed to create minijail";
1295 }
1296
1297 minijail_no_new_privs(jail.get());
1298 minijail_log_seccomp_filter_failures(jail.get());
1299 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001300 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001301
1302 pid_t result = fork();
1303 if (result == -1) {
1304 return result;
1305 } else if (result != 0) {
1306 return result;
1307 }
1308
1309 // Spawn and detach a thread that spins forever.
1310 std::atomic<bool> thread_ready(false);
1311 std::thread thread([&jail, &thread_ready]() {
1312 minijail_enter(jail.get());
1313 thread_ready = true;
1314 for (;;)
1315 ;
1316 });
1317 thread.detach();
1318
1319 while (!thread_ready) {
1320 continue;
1321 }
1322
Josh Gao70adac62018-02-22 11:38:33 -08001323 if (prejail) {
1324 prejail();
1325 }
1326
Josh Gaoe04ca272018-01-16 15:38:17 -08001327 minijail_enter(jail.get());
1328 return result;
1329}
1330
Josh Gao70adac62018-02-22 11:38:33 -08001331static pid_t seccomp_fork() {
1332 return seccomp_fork_impl(nullptr);
1333}
1334
Josh Gaoe04ca272018-01-16 15:38:17 -08001335TEST_F(CrasherTest, seccomp_crash) {
1336 int intercept_result;
1337 unique_fd output_fd;
1338
1339 StartProcess([]() { abort(); }, &seccomp_fork);
1340
1341 StartIntercept(&output_fd);
1342 FinishCrasher();
1343 AssertDeath(SIGABRT);
1344 FinishIntercept(&intercept_result);
1345 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1346
1347 std::string result;
1348 ConsumeFd(std::move(output_fd), &result);
1349 ASSERT_BACKTRACE_FRAME(result, "abort");
1350}
1351
Josh Gao70adac62018-02-22 11:38:33 -08001352static pid_t seccomp_fork_rlimit() {
1353 return seccomp_fork_impl([]() {
1354 struct rlimit rlim = {
1355 .rlim_cur = 512 * 1024 * 1024,
1356 .rlim_max = 512 * 1024 * 1024,
1357 };
1358
1359 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1360 raise(SIGINT);
1361 }
1362 });
1363}
1364
1365TEST_F(CrasherTest, seccomp_crash_oom) {
1366 int intercept_result;
1367 unique_fd output_fd;
1368
1369 StartProcess(
1370 []() {
1371 std::vector<void*> vec;
1372 for (int i = 0; i < 512; ++i) {
1373 char* buf = static_cast<char*>(malloc(1024 * 1024));
1374 if (!buf) {
1375 abort();
1376 }
1377 memset(buf, 0xff, 1024 * 1024);
1378 vec.push_back(buf);
1379 }
1380 },
1381 &seccomp_fork_rlimit);
1382
1383 StartIntercept(&output_fd);
1384 FinishCrasher();
1385 AssertDeath(SIGABRT);
1386 FinishIntercept(&intercept_result);
1387 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1388
1389 // We can't actually generate a backtrace, just make sure that the process terminates.
1390}
1391
Josh Gaoe04ca272018-01-16 15:38:17 -08001392__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1393 siginfo_t siginfo;
1394 siginfo.si_code = SI_QUEUE;
1395 siginfo.si_pid = getpid();
1396 siginfo.si_uid = getuid();
1397
1398 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1399 PLOG(FATAL) << "invalid dump type";
1400 }
1401
1402 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1403
Josh Gaoa48b41b2019-12-13 14:11:04 -08001404 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001405 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1406 return false;
1407 }
1408
1409 return true;
1410}
1411
1412TEST_F(CrasherTest, seccomp_tombstone) {
1413 int intercept_result;
1414 unique_fd output_fd;
1415
1416 static const auto dump_type = kDebuggerdTombstone;
1417 StartProcess(
1418 []() {
1419 raise_debugger_signal(dump_type);
1420 _exit(0);
1421 },
1422 &seccomp_fork);
1423
1424 StartIntercept(&output_fd, dump_type);
1425 FinishCrasher();
1426 AssertDeath(0);
1427 FinishIntercept(&intercept_result);
1428 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1429
1430 std::string result;
1431 ConsumeFd(std::move(output_fd), &result);
1432 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1433}
1434
Josh Gao6f9eeec2018-09-12 13:55:47 -07001435extern "C" void foo() {
1436 LOG(INFO) << "foo";
1437 std::this_thread::sleep_for(1s);
1438}
1439
1440extern "C" void bar() {
1441 LOG(INFO) << "bar";
1442 std::this_thread::sleep_for(1s);
1443}
1444
Josh Gaoe04ca272018-01-16 15:38:17 -08001445TEST_F(CrasherTest, seccomp_backtrace) {
1446 int intercept_result;
1447 unique_fd output_fd;
1448
1449 static const auto dump_type = kDebuggerdNativeBacktrace;
1450 StartProcess(
1451 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001452 std::thread a(foo);
1453 std::thread b(bar);
1454
1455 std::this_thread::sleep_for(100ms);
1456
Josh Gaoe04ca272018-01-16 15:38:17 -08001457 raise_debugger_signal(dump_type);
1458 _exit(0);
1459 },
1460 &seccomp_fork);
1461
1462 StartIntercept(&output_fd, dump_type);
1463 FinishCrasher();
1464 AssertDeath(0);
1465 FinishIntercept(&intercept_result);
1466 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1467
1468 std::string result;
1469 ConsumeFd(std::move(output_fd), &result);
1470 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001471 ASSERT_BACKTRACE_FRAME(result, "foo");
1472 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001473}
1474
1475TEST_F(CrasherTest, seccomp_crash_logcat) {
1476 StartProcess([]() { abort(); }, &seccomp_fork);
1477 FinishCrasher();
1478
1479 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1480 AssertDeath(SIGABRT);
1481}
1482
Josh Gaofd13bf02017-08-18 15:37:26 -07001483TEST_F(CrasherTest, competing_tracer) {
1484 int intercept_result;
1485 unique_fd output_fd;
1486 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001487 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001488 });
1489
1490 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001491
1492 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001493 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001494
1495 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001496 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001497 ASSERT_TRUE(WIFSTOPPED(status));
1498 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1499
1500 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1501 FinishIntercept(&intercept_result);
1502 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1503
1504 std::string result;
1505 ConsumeFd(std::move(output_fd), &result);
1506 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1507 regex += std::to_string(gettid());
1508 regex += R"( \(.+debuggerd_test)";
1509 ASSERT_MATCH(result, regex.c_str());
1510
Christopher Ferris172b0a02019-09-18 17:48:30 -07001511 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001512 ASSERT_TRUE(WIFSTOPPED(status));
1513 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1514
Josh Gaofd13bf02017-08-18 15:37:26 -07001515 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1516 AssertDeath(SIGABRT);
1517}
1518
Josh Gaobf06a402018-08-27 16:34:01 -07001519TEST_F(CrasherTest, fdsan_warning_abort_message) {
1520 int intercept_result;
1521 unique_fd output_fd;
1522
1523 StartProcess([]() {
1524 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001525 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001526 if (fd == -1) {
1527 abort();
1528 }
1529 close(fd.get());
1530 _exit(0);
1531 });
1532
1533 StartIntercept(&output_fd);
1534 FinishCrasher();
1535 AssertDeath(0);
1536 FinishIntercept(&intercept_result);
1537 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1538
1539 std::string result;
1540 ConsumeFd(std::move(output_fd), &result);
1541 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1542}
1543
Josh Gaoc3c8c022017-02-13 16:36:18 -08001544TEST(crash_dump, zombie) {
1545 pid_t forkpid = fork();
1546
Josh Gaoc3c8c022017-02-13 16:36:18 -08001547 pid_t rc;
1548 int status;
1549
1550 if (forkpid == 0) {
1551 errno = 0;
1552 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1553 if (rc != -1 || errno != ECHILD) {
1554 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1555 }
1556
Josh Gaoa48b41b2019-12-13 14:11:04 -08001557 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001558
1559 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001560 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001561 if (rc != -1 || errno != ECHILD) {
1562 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1563 }
1564 _exit(0);
1565 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001566 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001567 ASSERT_EQ(forkpid, rc);
1568 ASSERT_TRUE(WIFEXITED(status));
1569 ASSERT_EQ(0, WEXITSTATUS(status));
1570 }
1571}
Josh Gao352a8452017-03-30 16:46:21 -07001572
1573TEST(tombstoned, no_notify) {
1574 // Do this a few times.
1575 for (int i = 0; i < 3; ++i) {
1576 pid_t pid = 123'456'789 + i;
1577
1578 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001579 InterceptStatus status;
1580 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1581 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001582
1583 {
1584 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001585 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001586 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1587 }
1588
1589 pid_t read_pid;
1590 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1591 ASSERT_EQ(read_pid, pid);
1592 }
1593}
1594
1595TEST(tombstoned, stress) {
1596 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1597 static constexpr int kDumpCount = 100;
1598
1599 std::atomic<bool> start(false);
1600 std::vector<std::thread> threads;
1601 threads.emplace_back([&start]() {
1602 while (!start) {
1603 continue;
1604 }
1605
1606 // Use a way out of range pid, to avoid stomping on an actual process.
1607 pid_t pid_base = 1'000'000;
1608
1609 for (int dump = 0; dump < kDumpCount; ++dump) {
1610 pid_t pid = pid_base + dump;
1611
1612 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001613 InterceptStatus status;
1614 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1615 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001616
1617 // Pretend to crash, and then immediately close the socket.
1618 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1619 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1620 if (sockfd == -1) {
1621 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1622 }
1623 TombstonedCrashPacket packet = {};
1624 packet.packet_type = CrashPacketType::kDumpRequest;
1625 packet.packet.dump_request.pid = pid;
1626 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1627 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1628 }
1629
1630 continue;
1631 }
1632 });
1633
1634 threads.emplace_back([&start]() {
1635 while (!start) {
1636 continue;
1637 }
1638
1639 // Use a way out of range pid, to avoid stomping on an actual process.
1640 pid_t pid_base = 2'000'000;
1641
1642 for (int dump = 0; dump < kDumpCount; ++dump) {
1643 pid_t pid = pid_base + dump;
1644
1645 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001646 InterceptStatus status;
1647 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1648 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001649
1650 {
1651 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001652 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001653 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1654 tombstoned_notify_completion(tombstoned_socket.get());
1655 }
1656
1657 // TODO: Fix the race that requires this sleep.
1658 std::this_thread::sleep_for(50ms);
1659
1660 pid_t read_pid;
1661 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1662 ASSERT_EQ(read_pid, pid);
1663 }
1664 });
1665
1666 start = true;
1667
1668 for (std::thread& thread : threads) {
1669 thread.join();
1670 }
1671}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001672
1673TEST(tombstoned, java_trace_intercept_smoke) {
1674 // Using a "real" PID is a little dangerous here - if the test fails
1675 // or crashes, we might end up getting a bogus / unreliable stack
1676 // trace.
1677 const pid_t self = getpid();
1678
1679 unique_fd intercept_fd, output_fd;
1680 InterceptStatus status;
1681 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1682 ASSERT_EQ(InterceptStatus::kRegistered, status);
1683
Josh Gao76e1e302021-01-26 15:53:11 -08001684 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001685 // should result in a "regular" FD and not the installed intercept.
1686 const char native[] = "native";
1687 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001688 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001689 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1690 tombstoned_notify_completion(tombstoned_socket.get());
1691
1692 // Then, connect to tombstoned asking for a java backtrace. This *should*
1693 // trigger the intercept.
1694 const char java[] = "java";
1695 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1696 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1697 tombstoned_notify_completion(tombstoned_socket.get());
1698
1699 char outbuf[sizeof(java)];
1700 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1701 ASSERT_STREQ("java", outbuf);
1702}
1703
1704TEST(tombstoned, multiple_intercepts) {
1705 const pid_t fake_pid = 1'234'567;
1706 unique_fd intercept_fd, output_fd;
1707 InterceptStatus status;
1708 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1709 ASSERT_EQ(InterceptStatus::kRegistered, status);
1710
1711 unique_fd intercept_fd_2, output_fd_2;
1712 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1713 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1714}
1715
1716TEST(tombstoned, intercept_any) {
1717 const pid_t fake_pid = 1'234'567;
1718
1719 unique_fd intercept_fd, output_fd;
1720 InterceptStatus status;
1721 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1722 ASSERT_EQ(InterceptStatus::kRegistered, status);
1723
1724 const char any[] = "any";
1725 unique_fd tombstoned_socket, input_fd;
1726 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1727 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1728 tombstoned_notify_completion(tombstoned_socket.get());
1729
1730 char outbuf[sizeof(any)];
1731 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1732 ASSERT_STREQ("any", outbuf);
1733}
Josh Gao2b22ae12018-09-12 14:51:03 -07001734
1735TEST(tombstoned, interceptless_backtrace) {
1736 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1737 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1738 std::map<int, time_t> result;
1739 for (int i = 0; i < 99; ++i) {
1740 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1741 struct stat st;
1742 if (stat(path.c_str(), &st) == 0) {
1743 result[i] = st.st_mtim.tv_sec;
1744 }
1745 }
1746 return result;
1747 };
1748
1749 auto before = get_tombstone_timestamps();
1750 for (int i = 0; i < 50; ++i) {
1751 raise_debugger_signal(kDebuggerdNativeBacktrace);
1752 }
1753 auto after = get_tombstone_timestamps();
1754
1755 int diff = 0;
1756 for (int i = 0; i < 99; ++i) {
1757 if (after.count(i) == 0) {
1758 continue;
1759 }
1760 if (before.count(i) == 0) {
1761 ++diff;
1762 continue;
1763 }
1764 if (before[i] != after[i]) {
1765 ++diff;
1766 }
1767 }
1768
1769 // We can't be sure that nothing's crash looping in the background.
1770 // This should be good enough, though...
1771 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1772}
Christopher Ferris481e8372019-07-15 17:13:24 -07001773
1774static __attribute__((__noinline__)) void overflow_stack(void* p) {
1775 void* buf[1];
1776 buf[0] = p;
1777 static volatile void* global = buf;
1778 if (global) {
1779 global = buf;
1780 overflow_stack(&buf);
1781 }
1782}
1783
1784TEST_F(CrasherTest, stack_overflow) {
1785 int intercept_result;
1786 unique_fd output_fd;
1787 StartProcess([]() { overflow_stack(nullptr); });
1788
1789 StartIntercept(&output_fd);
1790 FinishCrasher();
1791 AssertDeath(SIGSEGV);
1792 FinishIntercept(&intercept_result);
1793
1794 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1795
1796 std::string result;
1797 ConsumeFd(std::move(output_fd), &result);
1798 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1799}
Josh Gao76e1e302021-01-26 15:53:11 -08001800
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001801static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1802 std::string test_lib(testing::internal::GetArgvs()[0]);
1803 auto const value = test_lib.find_last_of('/');
1804 if (value == std::string::npos) {
1805 test_lib = "./";
1806 } else {
1807 test_lib = test_lib.substr(0, value + 1) + "./";
1808 }
1809 test_lib += "libcrash_test.so";
1810
1811 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1812 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1813
1814 // Copy the shared so to a tempory directory.
1815 return system(cp_cmd.c_str()) == 0;
1816}
1817
1818TEST_F(CrasherTest, unreadable_elf) {
1819 int intercept_result;
1820 unique_fd output_fd;
1821 StartProcess([]() {
1822 TemporaryDir td;
1823 std::string tmp_so_name;
1824 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1825 _exit(1);
1826 }
1827 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1828 if (handle == nullptr) {
1829 _exit(1);
1830 }
1831 // Delete the original shared library so that we get the warning
1832 // about unreadable elf files.
1833 if (unlink(tmp_so_name.c_str()) == -1) {
1834 _exit(1);
1835 }
1836 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1837 if (crash_func == nullptr) {
1838 _exit(1);
1839 }
1840 crash_func();
1841 });
1842
1843 StartIntercept(&output_fd);
1844 FinishCrasher();
1845 AssertDeath(SIGSEGV);
1846 FinishIntercept(&intercept_result);
1847
1848 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1849
1850 std::string result;
1851 ConsumeFd(std::move(output_fd), &result);
1852 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
1853}
1854
Josh Gao76e1e302021-01-26 15:53:11 -08001855TEST(tombstoned, proto) {
1856 const pid_t self = getpid();
1857 unique_fd tombstoned_socket, text_fd, proto_fd;
1858 ASSERT_TRUE(
1859 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1860
1861 tombstoned_notify_completion(tombstoned_socket.get());
1862
1863 ASSERT_NE(-1, text_fd.get());
1864 ASSERT_NE(-1, proto_fd.get());
1865
1866 struct stat text_st;
1867 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1868
1869 // Give tombstoned some time to link the files into place.
1870 std::this_thread::sleep_for(100ms);
1871
1872 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001873 std::optional<std::string> tombstone_file;
1874 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1875 ASSERT_TRUE(dir_h != nullptr);
1876 std::regex tombstone_re("tombstone_\\d+");
1877 dirent* entry;
1878 while ((entry = readdir(dir_h.get())) != nullptr) {
1879 if (!std::regex_match(entry->d_name, tombstone_re)) {
1880 continue;
1881 }
1882 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001883
1884 struct stat st;
1885 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1886 continue;
1887 }
1888
1889 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001890 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001891 break;
1892 }
1893 }
1894
Christopher Ferris35da2882021-02-17 15:39:06 -08001895 ASSERT_TRUE(tombstone_file);
1896 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001897
1898 struct stat proto_fd_st;
1899 struct stat proto_file_st;
1900 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1901 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1902
1903 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1904 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1905}
1906
1907TEST(tombstoned, proto_intercept) {
1908 const pid_t self = getpid();
1909 unique_fd intercept_fd, output_fd;
1910 InterceptStatus status;
1911
1912 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1913 ASSERT_EQ(InterceptStatus::kRegistered, status);
1914
1915 unique_fd tombstoned_socket, text_fd, proto_fd;
1916 ASSERT_TRUE(
1917 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1918 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1919 tombstoned_notify_completion(tombstoned_socket.get());
1920
1921 text_fd.reset();
1922
1923 std::string output;
1924 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1925 ASSERT_EQ("foo", output);
1926}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001927
1928// Verify that when an intercept is present for the main thread, and the signal
1929// is received on a different thread, the intercept still works.
1930TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1931 StartProcess([]() {
1932 std::thread thread([]() {
1933 // Raise the signal on the side thread.
1934 raise_debugger_signal(kDebuggerdNativeBacktrace);
1935 });
1936 thread.join();
1937 _exit(0);
1938 });
1939
1940 unique_fd output_fd;
1941 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1942 FinishCrasher();
1943 AssertDeath(0);
1944
1945 int intercept_result;
1946 FinishIntercept(&intercept_result);
1947 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1948
1949 std::string result;
1950 ConsumeFd(std::move(output_fd), &result);
1951 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1952}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001953
1954static std::string format_pointer(uintptr_t ptr) {
1955#if defined(__LP64__)
1956 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1957 static_cast<uint32_t>(ptr & 0xffffffff));
1958#else
1959 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1960#endif
1961}
1962
1963static std::string format_pointer(void* ptr) {
1964 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1965}
1966
1967static std::string format_full_pointer(uintptr_t ptr) {
1968#if defined(__LP64__)
1969 return android::base::StringPrintf("%016" PRIx64, ptr);
1970#else
1971 return android::base::StringPrintf("%08x", ptr);
1972#endif
1973}
1974
1975static std::string format_full_pointer(void* ptr) {
1976 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1977}
1978
1979__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1980 int* crash_ptr = reinterpret_cast<int*>(ptr);
1981 *crash_ptr = 1;
1982 return *crash_ptr;
1983}
1984
1985// Verify that a fault address before the first map is properly handled.
1986TEST_F(CrasherTest, fault_address_before_first_map) {
1987 StartProcess([]() {
1988 ASSERT_EQ(0, crash_call(0x1024));
1989 _exit(0);
1990 });
1991
1992 unique_fd output_fd;
1993 StartIntercept(&output_fd);
1994 FinishCrasher();
1995 AssertDeath(SIGSEGV);
1996
1997 int intercept_result;
1998 FinishIntercept(&intercept_result);
1999 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2000
2001 std::string result;
2002 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002003 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002004
2005 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
2006
2007 std::string match_str = android::base::StringPrintf(
2008 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
2009 format_pointer(0x1024).c_str());
2010 ASSERT_MATCH(result, match_str);
2011}
2012
2013// Verify that a fault address after the last map is properly handled.
2014TEST_F(CrasherTest, fault_address_after_last_map) {
2015 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2016 StartProcess([crash_uptr]() {
2017 ASSERT_EQ(0, crash_call(crash_uptr));
2018 _exit(0);
2019 });
2020
2021 unique_fd output_fd;
2022 StartIntercept(&output_fd);
2023 FinishCrasher();
2024 AssertDeath(SIGSEGV);
2025
2026 int intercept_result;
2027 FinishIntercept(&intercept_result);
2028 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2029
2030 std::string result;
2031 ConsumeFd(std::move(output_fd), &result);
2032
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002033 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2034 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002035 ASSERT_MATCH(result, match_str);
2036
2037 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2038
2039 // Assumes that the open files section comes after the map section.
2040 // If that assumption changes, the regex below needs to change.
2041 match_str = android::base::StringPrintf(
2042 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2043 format_pointer(crash_uptr).c_str());
2044 ASSERT_MATCH(result, match_str);
2045}
2046
2047// Verify that a fault address between maps is properly handled.
2048TEST_F(CrasherTest, fault_address_between_maps) {
2049 // Create a map before the fork so it will be present in the child.
2050 void* start_ptr =
2051 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2052 ASSERT_NE(MAP_FAILED, start_ptr);
2053 // Unmap the page in the middle.
2054 void* middle_ptr =
2055 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2056 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2057
2058 StartProcess([middle_ptr]() {
2059 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2060 _exit(0);
2061 });
2062
2063 // Unmap the two maps.
2064 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2065 void* end_ptr =
2066 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2067 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2068
2069 unique_fd output_fd;
2070 StartIntercept(&output_fd);
2071 FinishCrasher();
2072 AssertDeath(SIGSEGV);
2073
2074 int intercept_result;
2075 FinishIntercept(&intercept_result);
2076 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2077
2078 std::string result;
2079 ConsumeFd(std::move(output_fd), &result);
2080
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002081 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2082 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002083 ASSERT_MATCH(result, match_str);
2084
2085 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2086
2087 match_str = android::base::StringPrintf(
2088 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2089 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2090 format_pointer(end_ptr).c_str());
2091 ASSERT_MATCH(result, match_str);
2092}
2093
2094// Verify that a fault address happens in the correct map.
2095TEST_F(CrasherTest, fault_address_in_map) {
2096 // Create a map before the fork so it will be present in the child.
2097 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2098 ASSERT_NE(MAP_FAILED, ptr);
2099
2100 StartProcess([ptr]() {
2101 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2102 _exit(0);
2103 });
2104
2105 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2106
2107 unique_fd output_fd;
2108 StartIntercept(&output_fd);
2109 FinishCrasher();
2110 AssertDeath(SIGSEGV);
2111
2112 int intercept_result;
2113 FinishIntercept(&intercept_result);
2114 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2115
2116 std::string result;
2117 ConsumeFd(std::move(output_fd), &result);
2118
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002119 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2120 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002121 ASSERT_MATCH(result, match_str);
2122
2123 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2124
2125 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2126 ASSERT_MATCH(result, match_str);
2127}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002128
2129static constexpr uint32_t kDexData[] = {
2130 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2131 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2132 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2133 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2134 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2135 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2136 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2137 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2138 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2139 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2140 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2141 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2142 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2143 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2144 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2145 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2146 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2147};
2148
2149TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2150 StartProcess([]() {
2151 TemporaryDir td;
2152 std::string tmp_so_name;
2153 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2154 _exit(1);
2155 }
2156
2157 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2158 // move the library to which has a basename of libart.so.
2159 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2160 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2161 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2162 if (handle == nullptr) {
2163 _exit(1);
2164 }
2165
2166 void* ptr =
2167 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2168 ASSERT_TRUE(ptr != MAP_FAILED);
2169 memcpy(ptr, kDexData, sizeof(kDexData));
2170 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2171
2172 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2173 .symfile_size = sizeof(kDexData)};
2174
2175 JITDescriptor* dex_debug =
2176 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2177 ASSERT_TRUE(dex_debug != nullptr);
2178 dex_debug->version = 1;
2179 dex_debug->action_flag = 0;
2180 dex_debug->relevant_entry = 0;
2181 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2182
2183 // This sets the magic dex pc value for register 0, using the value
2184 // of register 1 + 0x102.
2185 asm(".cfi_escape "
2186 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2187 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2188 "0x13 /* DW_OP_drop */,"
2189 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2190
2191 // For each different architecture, set register one to the dex ptr mmap
2192 // created above. Then do a nullptr dereference to force a crash.
2193#if defined(__arm__)
2194 asm volatile(
2195 "mov r1, %[base]\n"
2196 "mov r2, 0\n"
2197 "str r3, [r2]\n"
2198 : [base] "+r"(ptr)
2199 :
2200 : "r1", "r2", "r3", "memory");
2201#elif defined(__aarch64__)
2202 asm volatile(
2203 "mov x1, %[base]\n"
2204 "mov x2, 0\n"
2205 "str x3, [x2]\n"
2206 : [base] "+r"(ptr)
2207 :
2208 : "x1", "x2", "x3", "memory");
2209#elif defined(__i386__)
2210 asm volatile(
2211 "mov %[base], %%ecx\n"
2212 "movl $0, %%edi\n"
2213 "movl 0(%%edi), %%edx\n"
2214 : [base] "+r"(ptr)
2215 :
2216 : "edi", "ecx", "edx", "memory");
2217#elif defined(__x86_64__)
2218 asm volatile(
2219 "mov %[base], %%rdx\n"
2220 "movq 0, %%rdi\n"
2221 "movq 0(%%rdi), %%rcx\n"
2222 : [base] "+r"(ptr)
2223 :
2224 : "rcx", "rdx", "rdi", "memory");
2225#else
2226#error "Unsupported architecture"
2227#endif
2228 _exit(0);
2229 });
2230
2231 unique_fd output_fd;
2232 StartIntercept(&output_fd);
2233 FinishCrasher();
2234 AssertDeath(SIGSEGV);
2235
2236 int intercept_result;
2237 FinishIntercept(&intercept_result);
2238 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2239
2240 std::string result;
2241 ConsumeFd(std::move(output_fd), &result);
2242
2243 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002244 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002245
2246 // Now verify that the dex_pc frame includes a proper function name.
2247 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2248}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002249
2250static std::string format_map_pointer(uintptr_t ptr) {
2251#if defined(__LP64__)
2252 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2253 static_cast<uint32_t>(ptr & 0xffffffff));
2254#else
2255 return android::base::StringPrintf("%08x", ptr);
2256#endif
2257}
2258
2259// Verify that map data is properly formatted.
2260TEST_F(CrasherTest, verify_map_format) {
2261 // Create multiple maps to make sure that the map data is formatted properly.
2262 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2263 ASSERT_NE(MAP_FAILED, none_map);
2264 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2265 ASSERT_NE(MAP_FAILED, r_map);
2266 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2267 ASSERT_NE(MAP_FAILED, w_map);
2268 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2269 ASSERT_NE(MAP_FAILED, x_map);
2270
2271 TemporaryFile tf;
2272 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2273 char c = 'f';
2274 ASSERT_EQ(1, write(tf.fd, &c, 1));
2275 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2276 ASSERT_EQ(1, write(tf.fd, &c, 1));
2277 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2278 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2279 ASSERT_NE(MAP_FAILED, file_map);
2280
2281 StartProcess([]() { abort(); });
2282
2283 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2284 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2285 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2286 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2287 ASSERT_EQ(0, munmap(file_map, 0x3001));
2288
2289 unique_fd output_fd;
2290 StartIntercept(&output_fd);
2291 FinishCrasher();
2292 AssertDeath(SIGABRT);
2293 int intercept_result;
2294 FinishIntercept(&intercept_result);
2295
2296 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2297
2298 std::string result;
2299 ConsumeFd(std::move(output_fd), &result);
2300
2301 std::string match_str;
2302 // Verify none.
2303 match_str = android::base::StringPrintf(
2304 " %s-%s --- 0 1000\\n",
2305 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2306 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2307 ASSERT_MATCH(result, match_str);
2308
2309 // Verify read-only.
2310 match_str = android::base::StringPrintf(
2311 " %s-%s r-- 0 1000\\n",
2312 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2313 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2314 ASSERT_MATCH(result, match_str);
2315
2316 // Verify write-only.
2317 match_str = android::base::StringPrintf(
2318 " %s-%s -w- 0 1000\\n",
2319 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2320 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2321 ASSERT_MATCH(result, match_str);
2322
2323 // Verify exec-only.
2324 match_str = android::base::StringPrintf(
2325 " %s-%s --x 0 1000\\n",
2326 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2327 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2328 ASSERT_MATCH(result, match_str);
2329
2330 // Verify file map with non-zero offset and a name.
2331 match_str = android::base::StringPrintf(
2332 " %s-%s r-- 2000 4000 %s\\n",
2333 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2334 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2335 ASSERT_MATCH(result, match_str);
2336}
2337
2338// Verify that the tombstone map data is correct.
2339TEST_F(CrasherTest, verify_header) {
2340 StartProcess([]() { abort(); });
2341
2342 unique_fd output_fd;
2343 StartIntercept(&output_fd);
2344 FinishCrasher();
2345 AssertDeath(SIGABRT);
2346 int intercept_result;
2347 FinishIntercept(&intercept_result);
2348
2349 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2350
2351 std::string result;
2352 ConsumeFd(std::move(output_fd), &result);
2353
2354 std::string match_str = android::base::StringPrintf(
2355 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2356 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2357 android::base::GetProperty("ro.revision", "unknown").c_str());
2358 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2359 ASSERT_MATCH(result, match_str);
2360}
2361
2362// Verify that the thread header is formatted properly.
2363TEST_F(CrasherTest, verify_thread_header) {
2364 void* shared_map =
2365 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2366 ASSERT_NE(MAP_FAILED, shared_map);
2367 memset(shared_map, 0, sizeof(pid_t));
2368
2369 StartProcess([&shared_map]() {
2370 std::atomic_bool tid_written;
2371 std::thread thread([&tid_written, &shared_map]() {
2372 pid_t tid = gettid();
2373 memcpy(shared_map, &tid, sizeof(pid_t));
2374 tid_written = true;
2375 volatile bool done = false;
2376 while (!done)
2377 ;
2378 });
2379 thread.detach();
2380 while (!tid_written.load(std::memory_order_acquire))
2381 ;
2382 abort();
2383 });
2384
2385 pid_t primary_pid = crasher_pid;
2386
2387 unique_fd output_fd;
2388 StartIntercept(&output_fd);
2389 FinishCrasher();
2390 AssertDeath(SIGABRT);
2391 int intercept_result;
2392 FinishIntercept(&intercept_result);
2393 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2394
2395 // Read the tid data out.
2396 pid_t tid;
2397 memcpy(&tid, shared_map, sizeof(pid_t));
2398 ASSERT_NE(0, tid);
2399
2400 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2401
2402 std::string result;
2403 ConsumeFd(std::move(output_fd), &result);
2404
2405 // Verify that there are two headers, one where the tid is "primary_pid"
2406 // and the other where the tid is "tid".
2407 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2408 primary_pid, primary_pid);
2409 ASSERT_MATCH(result, match_str);
2410
2411 match_str =
2412 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2413 ASSERT_MATCH(result, match_str);
2414}
2415
2416// Verify that there is a BuildID present in the map section and set properly.
2417TEST_F(CrasherTest, verify_build_id) {
2418 StartProcess([]() { abort(); });
2419
2420 unique_fd output_fd;
2421 StartIntercept(&output_fd);
2422 FinishCrasher();
2423 AssertDeath(SIGABRT);
2424 int intercept_result;
2425 FinishIntercept(&intercept_result);
2426 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2427
2428 std::string result;
2429 ConsumeFd(std::move(output_fd), &result);
2430
2431 // Find every /system or /apex lib and verify the BuildID is displayed
2432 // properly.
2433 bool found_valid_elf = false;
2434 std::smatch match;
2435 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2436 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2437 result = match.suffix()) {
2438 if (prev_file == match[1]) {
2439 // Already checked this file.
2440 continue;
2441 }
2442
2443 prev_file = match[1];
2444 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2445 if (!elf.Init() || !elf.valid()) {
2446 // Skipping invalid elf files.
2447 continue;
2448 }
2449 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2450
2451 found_valid_elf = true;
2452 }
2453 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2454}