blob: b10776786aba09518b536f3eb50fc5e0023b3d32 [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
Josh Gaocbe70cb2016-10-18 18:17:52 -0700176class CrasherTest : public ::testing::Test {
177 public:
178 pid_t crasher_pid = -1;
Elliott Hughese4781d52021-03-17 09:15:15 -0700179 bool previous_wait_for_debugger;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700180 unique_fd crasher_pipe;
181 unique_fd intercept_fd;
182
183 CrasherTest();
184 ~CrasherTest();
185
Narayan Kamatha73df602017-05-24 15:07:25 +0100186 void StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type = kDebuggerdTombstone);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700187
188 // Returns -1 if we fail to read a response from tombstoned, otherwise the received return code.
189 void FinishIntercept(int* result);
190
Josh Gao2e7b8e22017-05-04 17:12:57 -0700191 void StartProcess(std::function<void()> function, std::function<pid_t()> forker = fork);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700192 void StartCrasher(const std::string& crash_type);
193 void FinishCrasher();
194 void AssertDeath(int signo);
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700195
196 static void Trap(void* ptr);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700197};
198
199CrasherTest::CrasherTest() {
Elliott Hughese4781d52021-03-17 09:15:15 -0700200 previous_wait_for_debugger = android::base::GetBoolProperty(kWaitForDebuggerKey, false);
201 android::base::SetProperty(kWaitForDebuggerKey, "0");
202
203 // Clear the old property too, just in case someone's been using it
204 // on this device. (We only document the new name, but we still support
205 // the old name so we don't break anyone's existing setups.)
206 android::base::SetProperty("debug.debuggerd.wait_for_gdb", "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700207}
208
209CrasherTest::~CrasherTest() {
210 if (crasher_pid != -1) {
211 kill(crasher_pid, SIGKILL);
212 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -0700213 TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700214 }
215
Elliott Hughese4781d52021-03-17 09:15:15 -0700216 android::base::SetProperty(kWaitForDebuggerKey, previous_wait_for_debugger ? "1" : "0");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700217}
218
Narayan Kamatha73df602017-05-24 15:07:25 +0100219void CrasherTest::StartIntercept(unique_fd* output_fd, DebuggerdDumpType intercept_type) {
Josh Gaocbe70cb2016-10-18 18:17:52 -0700220 if (crasher_pid == -1) {
221 FAIL() << "crasher hasn't been started";
222 }
223
Narayan Kamathca5e9082017-06-02 15:42:06 +0100224 InterceptStatus status;
225 tombstoned_intercept(crasher_pid, &this->intercept_fd, output_fd, &status, intercept_type);
226 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700227}
228
229void CrasherTest::FinishIntercept(int* result) {
230 InterceptResponse response;
231
Christopher Ferris11555f02019-09-20 14:18:55 -0700232 ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700233 if (rc == -1) {
234 FAIL() << "failed to read response from tombstoned: " << strerror(errno);
235 } else if (rc == 0) {
236 *result = -1;
237 } else if (rc != sizeof(response)) {
238 FAIL() << "received packet of unexpected length from tombstoned: expected " << sizeof(response)
239 << ", received " << rc;
240 } else {
Josh Gao460b3362017-03-30 16:40:47 -0700241 *result = response.status == InterceptStatus::kStarted ? 1 : 0;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700242 }
243}
244
Josh Gao2e7b8e22017-05-04 17:12:57 -0700245void CrasherTest::StartProcess(std::function<void()> function, std::function<pid_t()> forker) {
Josh Gaofca7ca32017-01-23 12:05:35 -0800246 unique_fd read_pipe;
Josh Gaocbe70cb2016-10-18 18:17:52 -0700247 unique_fd crasher_read_pipe;
248 if (!Pipe(&crasher_read_pipe, &crasher_pipe)) {
249 FAIL() << "failed to create pipe: " << strerror(errno);
250 }
251
Josh Gao2e7b8e22017-05-04 17:12:57 -0700252 crasher_pid = forker();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700253 if (crasher_pid == -1) {
254 FAIL() << "fork failed: " << strerror(errno);
255 } else if (crasher_pid == 0) {
Josh Gao502cfd22017-02-17 01:39:15 -0800256 char dummy;
257 crasher_pipe.reset();
258 TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
Josh Gaofca7ca32017-01-23 12:05:35 -0800259 function();
260 _exit(0);
261 }
262}
263
Josh Gaocbe70cb2016-10-18 18:17:52 -0700264void CrasherTest::FinishCrasher() {
265 if (crasher_pipe == -1) {
266 FAIL() << "crasher pipe uninitialized";
267 }
268
Christopher Ferris172b0a02019-09-18 17:48:30 -0700269 ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700270 if (rc == -1) {
271 FAIL() << "failed to write to crasher pipe: " << strerror(errno);
272 } else if (rc == 0) {
273 FAIL() << "crasher pipe was closed";
274 }
275}
276
277void CrasherTest::AssertDeath(int signo) {
278 int status;
Christopher Ferris11555f02019-09-20 14:18:55 -0700279 pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700280 if (pid != crasher_pid) {
Christopher Ferrisafc0ff72019-06-26 15:08:51 -0700281 printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
282 strerror(errno));
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700283 sleep(100);
Josh Gaocbe70cb2016-10-18 18:17:52 -0700284 FAIL() << "failed to wait for crasher: " << strerror(errno);
285 }
286
Josh Gaoe06f2a42017-04-27 16:50:38 -0700287 if (signo == 0) {
Christopher Ferris67022562021-04-16 13:30:32 -0700288 ASSERT_TRUE(WIFEXITED(status)) << "Terminated due to unexpected signal " << WTERMSIG(status);
Josh Gaoe06f2a42017-04-27 16:50:38 -0700289 ASSERT_EQ(0, WEXITSTATUS(signo));
290 } else {
291 ASSERT_FALSE(WIFEXITED(status));
292 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
293 ASSERT_EQ(signo, WTERMSIG(status));
Josh Gaocbe70cb2016-10-18 18:17:52 -0700294 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700295 crasher_pid = -1;
296}
297
298static void ConsumeFd(unique_fd fd, std::string* output) {
299 constexpr size_t read_length = PAGE_SIZE;
300 std::string result;
301
302 while (true) {
303 size_t offset = result.size();
304 result.resize(result.size() + PAGE_SIZE);
305 ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &result[offset], read_length));
306 if (rc == -1) {
307 FAIL() << "read failed: " << strerror(errno);
308 } else if (rc == 0) {
309 result.resize(result.size() - PAGE_SIZE);
310 break;
311 }
312
313 result.resize(result.size() - PAGE_SIZE + rc);
314 }
315
316 *output = std::move(result);
317}
318
Mitch Phillips78f06702021-06-01 14:35:43 -0700319class LogcatCollector {
320 public:
321 LogcatCollector() { system("logcat -c"); }
322
323 void Collect(std::string* output) {
324 FILE* cmd_stdout = popen("logcat -d '*:S DEBUG'", "r");
325 ASSERT_NE(cmd_stdout, nullptr);
326 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(cmd_stdout))));
327 ConsumeFd(std::move(tmp_fd), output);
328 pclose(cmd_stdout);
329 }
330};
331
Josh Gaocbe70cb2016-10-18 18:17:52 -0700332TEST_F(CrasherTest, smoke) {
333 int intercept_result;
334 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800335 StartProcess([]() {
336 *reinterpret_cast<volatile char*>(0xdead) = '1';
337 });
338
Josh Gaocbe70cb2016-10-18 18:17:52 -0700339 StartIntercept(&output_fd);
340 FinishCrasher();
341 AssertDeath(SIGSEGV);
342 FinishIntercept(&intercept_result);
343
344 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
345
346 std::string result;
347 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800348#ifdef __LP64__
349 ASSERT_MATCH(result,
350 R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
351#else
352 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
353#endif
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700354
355 if (mte_supported()) {
356 // Test that the default TAGGED_ADDR_CTRL value is set.
Peter Collingbourne47d784e2021-11-05 18:40:52 -0700357 ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)"
358 R"( \(PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe\))");
Peter Collingbourne864f15d2020-09-14 20:27:36 -0700359 }
Josh Gaocbe70cb2016-10-18 18:17:52 -0700360}
361
Peter Collingbournef03af882020-03-20 18:09:00 -0700362TEST_F(CrasherTest, tagged_fault_addr) {
363#if !defined(__aarch64__)
364 GTEST_SKIP() << "Requires aarch64";
365#endif
366 int intercept_result;
367 unique_fd output_fd;
368 StartProcess([]() {
369 *reinterpret_cast<volatile char*>(0x100000000000dead) = '1';
370 });
371
372 StartIntercept(&output_fd);
373 FinishCrasher();
374 AssertDeath(SIGSEGV);
375 FinishIntercept(&intercept_result);
376
377 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
378
379 std::string result;
380 ConsumeFd(std::move(output_fd), &result);
381
382 // The address can either be tagged (new kernels) or untagged (old kernels).
383 ASSERT_MATCH(
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800384 result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
Peter Collingbournef03af882020-03-20 18:09:00 -0700385}
386
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700387// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
388// compiler could still clobber the argument register before trapping, but that's unlikely.
389__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
390 __builtin_trap();
391}
392
393TEST_F(CrasherTest, heap_addr_in_register) {
394#if defined(__i386__)
395 GTEST_SKIP() << "architecture does not pass arguments in registers";
396#endif
397 int intercept_result;
398 unique_fd output_fd;
399 StartProcess([]() {
400 // Crash with a heap pointer in the first argument register.
401 Trap(malloc(1));
402 });
403
404 StartIntercept(&output_fd);
405 FinishCrasher();
406 int status;
407 ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
408 ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
409 // Don't test the signal number because different architectures use different signals for
410 // __builtin_trap().
411 FinishIntercept(&intercept_result);
412
413 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
414
415 std::string result;
416 ConsumeFd(std::move(output_fd), &result);
417
418#if defined(__aarch64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800419 ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700420#elif defined(__arm__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800421 ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700422#elif defined(__x86_64__)
Peter Collingbourne0ea08c22021-02-05 14:59:08 -0800423 ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
Peter Collingbourne10e428d2020-07-17 14:49:31 -0700424#else
425 ASSERT_TRUE(false) << "unsupported architecture";
426#endif
427}
428
Peter Collingbournecd278072020-12-21 14:08:38 -0800429#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700430static void SetTagCheckingLevelSync() {
Elliott Hughes03b283a2021-01-15 11:34:26 -0800431 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
Peter Collingbournef8622522020-04-07 14:07:32 -0700432 abort();
433 }
434}
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800435
436static void SetTagCheckingLevelAsync() {
437 if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_ASYNC) == 0) {
438 abort();
439 }
440}
Peter Collingbournef8622522020-04-07 14:07:32 -0700441#endif
442
Mitch Phillips7168a212021-03-09 16:53:23 -0800443// Number of iterations required to reliably guarantee a GWP-ASan crash.
444// GWP-ASan's sample rate is not truly nondeterministic, it initialises a
445// thread-local counter at 2*SampleRate, and decrements on each malloc(). Once
446// the counter reaches zero, we provide a sampled allocation. Then, double that
447// figure to allow for left/right allocation alignment, as this is done randomly
448// without bias.
449#define GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH (0x20000)
450
451struct GwpAsanTestParameters {
452 size_t alloc_size;
453 bool free_before_access;
454 int access_offset;
455 std::string cause_needle; // Needle to be found in the "Cause: [GWP-ASan]" line.
456};
457
458struct GwpAsanCrasherTest : CrasherTest, testing::WithParamInterface<GwpAsanTestParameters> {};
459
460GwpAsanTestParameters gwp_asan_tests[] = {
461 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 0, "Use After Free, 0 bytes into a 7-byte allocation"},
462 {/* alloc_size */ 7, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 7-byte allocation"},
463 {/* alloc_size */ 7, /* free_before_access */ false, /* access_offset */ 16, "Buffer Overflow, 9 bytes right of a 7-byte allocation"},
464 {/* alloc_size */ 16, /* free_before_access */ false, /* access_offset */ -1, "Buffer Underflow, 1 byte left of a 16-byte allocation"},
465};
466
467INSTANTIATE_TEST_SUITE_P(GwpAsanTests, GwpAsanCrasherTest, testing::ValuesIn(gwp_asan_tests));
468
469TEST_P(GwpAsanCrasherTest, gwp_asan_uaf) {
470 if (mte_supported()) {
471 // Skip this test on MTE hardware, as MTE will reliably catch these errors
472 // instead of GWP-ASan.
473 GTEST_SKIP() << "Skipped on MTE.";
474 }
475
476 GwpAsanTestParameters params = GetParam();
Mitch Phillips78f06702021-06-01 14:35:43 -0700477 LogcatCollector logcat_collector;
Mitch Phillips7168a212021-03-09 16:53:23 -0800478
479 int intercept_result;
480 unique_fd output_fd;
481 StartProcess([&params]() {
482 for (unsigned i = 0; i < GWP_ASAN_ITERATIONS_TO_ENSURE_CRASH; ++i) {
483 volatile char* p = reinterpret_cast<volatile char*>(malloc(params.alloc_size));
484 if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
485 p[params.access_offset] = 42;
486 if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
487 }
488 });
489
490 StartIntercept(&output_fd);
491 FinishCrasher();
492 AssertDeath(SIGSEGV);
493 FinishIntercept(&intercept_result);
494
495 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
496
Mitch Phillips78f06702021-06-01 14:35:43 -0700497 std::vector<std::string> log_sources(2);
498 ConsumeFd(std::move(output_fd), &log_sources[0]);
499 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips7168a212021-03-09 16:53:23 -0800500
Mitch Phillips78f06702021-06-01 14:35:43 -0700501 for (const auto& result : log_sources) {
502 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\))");
503 ASSERT_MATCH(result, R"(Cause: \[GWP-ASan\]: )" + params.cause_needle);
504 if (params.free_before_access) {
505 ASSERT_MATCH(result, R"(deallocated by thread .*\n.*#00 pc)");
506 }
507 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*\n.*#00 pc)");
Mitch Phillips7168a212021-03-09 16:53:23 -0800508 }
Mitch Phillips7168a212021-03-09 16:53:23 -0800509}
510
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800511struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
512
Peter Collingbourneaa544792021-05-13 13:53:37 -0700513INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800514
515TEST_P(SizeParamCrasherTest, mte_uaf) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800516#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700517 if (!mte_supported()) {
518 GTEST_SKIP() << "Requires MTE";
519 }
520
Peter Collingbourneaa544792021-05-13 13:53:37 -0700521 // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
522 if (GetParam() == 0) {
523 return;
524 }
525
Mitch Phillips78f06702021-06-01 14:35:43 -0700526 LogcatCollector logcat_collector;
527
Peter Collingbournef8622522020-04-07 14:07:32 -0700528 int intercept_result;
529 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800530 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700531 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800532 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700533 free((void *)p);
534 p[0] = 42;
535 });
536
537 StartIntercept(&output_fd);
538 FinishCrasher();
539 AssertDeath(SIGSEGV);
540 FinishIntercept(&intercept_result);
541
542 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
543
Mitch Phillips78f06702021-06-01 14:35:43 -0700544 std::vector<std::string> log_sources(2);
545 ConsumeFd(std::move(output_fd), &log_sources[0]);
546 logcat_collector.Collect(&log_sources[1]);
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700547 // Tag dump only available in the tombstone, not logcat.
548 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700549
Mitch Phillips78f06702021-06-01 14:35:43 -0700550 for (const auto& result : log_sources) {
551 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
552 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 0 bytes into a )" +
553 std::to_string(GetParam()) + R"(-byte allocation)");
554 ASSERT_MATCH(result, R"(deallocated by thread .*?\n.*#00 pc)");
555 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
556 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700557#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800558 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700559#endif
560}
561
Peter Collingbournedc476342021-05-12 15:56:43 -0700562TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
563#if defined(__aarch64__)
564 if (!mte_supported()) {
565 GTEST_SKIP() << "Requires MTE";
566 }
567
568 int intercept_result;
569 unique_fd output_fd;
570 StartProcess([&]() {
571 SetTagCheckingLevelSync();
572 volatile int* p = (volatile int*)malloc(GetParam());
573 free((void *)p);
574 p[-1] = 42;
575 });
576
577 StartIntercept(&output_fd);
578 FinishCrasher();
579 AssertDeath(SIGSEGV);
580 FinishIntercept(&intercept_result);
581
582 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
583
584 std::string result;
585 ConsumeFd(std::move(output_fd), &result);
586
587 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
588 ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
589#else
590 GTEST_SKIP() << "Requires aarch64";
591#endif
592}
593
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800594TEST_P(SizeParamCrasherTest, mte_overflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800595#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700596 if (!mte_supported()) {
597 GTEST_SKIP() << "Requires MTE";
598 }
599
Mitch Phillips78f06702021-06-01 14:35:43 -0700600 LogcatCollector logcat_collector;
Peter Collingbournef8622522020-04-07 14:07:32 -0700601 int intercept_result;
602 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800603 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700604 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800605 volatile char* p = (volatile char*)malloc(GetParam());
606 p[GetParam()] = 42;
Peter Collingbournef8622522020-04-07 14:07:32 -0700607 });
608
609 StartIntercept(&output_fd);
610 FinishCrasher();
611 AssertDeath(SIGSEGV);
612 FinishIntercept(&intercept_result);
613
614 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
615
Mitch Phillips78f06702021-06-01 14:35:43 -0700616 std::vector<std::string> log_sources(2);
617 ConsumeFd(std::move(output_fd), &log_sources[0]);
618 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700619
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700620 // Tag dump only in tombstone, not logcat, and tagging is not used for
621 // overflow protection in the scudo secondary (guard pages are used instead).
622 if (GetParam() < 0x10000) {
623 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
624 }
625
Mitch Phillips78f06702021-06-01 14:35:43 -0700626 for (const auto& result : log_sources) {
627 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
628 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a )" +
629 std::to_string(GetParam()) + R"(-byte allocation)");
630 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*?\n.*#00 pc)");
631 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700632#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800633 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700634#endif
635}
636
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800637TEST_P(SizeParamCrasherTest, mte_underflow) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800638#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700639 if (!mte_supported()) {
640 GTEST_SKIP() << "Requires MTE";
641 }
642
643 int intercept_result;
644 unique_fd output_fd;
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800645 StartProcess([&]() {
Peter Collingbournef8622522020-04-07 14:07:32 -0700646 SetTagCheckingLevelSync();
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800647 volatile int* p = (volatile int*)malloc(GetParam());
Peter Collingbournef8622522020-04-07 14:07:32 -0700648 p[-1] = 42;
649 });
650
651 StartIntercept(&output_fd);
652 FinishCrasher();
653 AssertDeath(SIGSEGV);
654 FinishIntercept(&intercept_result);
655
656 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
657
658 std::string result;
659 ConsumeFd(std::move(output_fd), &result);
660
661 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 9 \(SEGV_MTESERR\))");
Peter Collingbournebb4b49c2021-01-06 21:02:19 -0800662 ASSERT_MATCH(result, R"(Cause: \[MTE\]: Buffer Underflow, 4 bytes left of a )" +
Peter Collingbourne1a1f7d72021-03-08 16:53:54 -0800663 std::to_string(GetParam()) + R"(-byte allocation)");
Mitch Phillips78f06702021-06-01 14:35:43 -0700664 ASSERT_MATCH(result, R"((^|\s)allocated by thread .*
Peter Collingbournebbe69052020-05-08 10:11:19 -0700665 #00 pc)");
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700666 ASSERT_MATCH(result, "Memory tags around the fault address");
Peter Collingbournef8622522020-04-07 14:07:32 -0700667#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800668 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700669#endif
670}
671
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800672TEST_F(CrasherTest, mte_async) {
673#if defined(__aarch64__)
674 if (!mte_supported()) {
675 GTEST_SKIP() << "Requires MTE";
676 }
677
678 int intercept_result;
679 unique_fd output_fd;
680 StartProcess([&]() {
681 SetTagCheckingLevelAsync();
682 volatile int* p = (volatile int*)malloc(16);
683 p[-1] = 42;
684 });
685
686 StartIntercept(&output_fd);
687 FinishCrasher();
688 AssertDeath(SIGSEGV);
689 FinishIntercept(&intercept_result);
690
691 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
692
693 std::string result;
694 ConsumeFd(std::move(output_fd), &result);
695
696 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
697#else
698 GTEST_SKIP() << "Requires aarch64";
699#endif
700}
701
Peter Collingbournef8622522020-04-07 14:07:32 -0700702TEST_F(CrasherTest, mte_multiple_causes) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800703#if defined(__aarch64__)
Peter Collingbournef8622522020-04-07 14:07:32 -0700704 if (!mte_supported()) {
705 GTEST_SKIP() << "Requires MTE";
706 }
707
Mitch Phillips78f06702021-06-01 14:35:43 -0700708 LogcatCollector logcat_collector;
709
Peter Collingbournef8622522020-04-07 14:07:32 -0700710 int intercept_result;
711 unique_fd output_fd;
712 StartProcess([]() {
713 SetTagCheckingLevelSync();
714
715 // Make two allocations with the same tag and close to one another. Check for both properties
716 // with a bounds check -- this relies on the fact that only if the allocations have the same tag
717 // would they be measured as closer than 128 bytes to each other. Otherwise they would be about
718 // (some non-zero value << 56) apart.
719 //
720 // The out-of-bounds access will be considered either an overflow of one or an underflow of the
721 // other.
722 std::set<uintptr_t> allocs;
723 for (int i = 0; i != 4096; ++i) {
724 uintptr_t alloc = reinterpret_cast<uintptr_t>(malloc(16));
725 auto it = allocs.insert(alloc).first;
726 if (it != allocs.begin() && *std::prev(it) + 128 > alloc) {
727 *reinterpret_cast<int*>(*std::prev(it) + 16) = 42;
728 }
729 if (std::next(it) != allocs.end() && alloc + 128 > *std::next(it)) {
730 *reinterpret_cast<int*>(alloc + 16) = 42;
731 }
732 }
733 });
734
735 StartIntercept(&output_fd);
736 FinishCrasher();
737 AssertDeath(SIGSEGV);
738 FinishIntercept(&intercept_result);
739
740 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
741
Mitch Phillips78f06702021-06-01 14:35:43 -0700742 std::vector<std::string> log_sources(2);
743 ConsumeFd(std::move(output_fd), &log_sources[0]);
744 logcat_collector.Collect(&log_sources[1]);
Peter Collingbournef8622522020-04-07 14:07:32 -0700745
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700746 // Tag dump only in the tombstone, not logcat.
747 ASSERT_MATCH(log_sources[0], "Memory tags around the fault address");
748
Mitch Phillips78f06702021-06-01 14:35:43 -0700749 for (const auto& result : log_sources) {
750 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\))");
751 ASSERT_THAT(result, HasSubstr("Note: multiple potential causes for this crash were detected, "
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800752 "listing them in decreasing order of likelihood."));
Mitch Phillips78f06702021-06-01 14:35:43 -0700753 // Adjacent untracked allocations may cause us to see the wrong underflow here (or only
754 // overflows), so we can't match explicitly for an underflow message.
755 ASSERT_MATCH(result,
756 R"(Cause: \[MTE\]: Buffer Overflow, 0 bytes right of a 16-byte allocation)");
757 // Ensure there's at least two allocation traces (one for each cause).
758 ASSERT_MATCH(
759 result,
760 R"((^|\s)allocated by thread .*?\n.*#00 pc(.|\n)*?(^|\s)allocated by thread .*?\n.*#00 pc)");
761 }
Peter Collingbournef8622522020-04-07 14:07:32 -0700762#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800763 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournef8622522020-04-07 14:07:32 -0700764#endif
765}
766
Peter Collingbournecd278072020-12-21 14:08:38 -0800767#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700768static uintptr_t CreateTagMapping() {
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700769 // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right
770 // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE.
771 size_t page_size = getpagesize();
772 void* mapping = mmap(nullptr, page_size * 3, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
773 uintptr_t mapping_uptr = reinterpret_cast<uintptr_t>(mapping);
774 if (mapping == MAP_FAILED) {
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700775 return 0;
776 }
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700777 mprotect(reinterpret_cast<void*>(mapping_uptr + page_size), page_size,
778 PROT_READ | PROT_WRITE | PROT_MTE);
779 // Stripe the mapping, where even granules get tag '1', and odd granules get tag '0'.
780 for (uintptr_t offset = 0; offset < page_size; offset += 2 * kTagGranuleSize) {
781 uintptr_t tagged_addr = mapping_uptr + page_size + offset + (1ULL << 56);
782 __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" : : "r"(tagged_addr) : "memory");
783 }
784 return mapping_uptr + page_size;
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700785}
786#endif
787
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700788TEST_F(CrasherTest, mte_register_tag_dump) {
Peter Collingbournecd278072020-12-21 14:08:38 -0800789#if defined(__aarch64__)
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700790 if (!mte_supported()) {
791 GTEST_SKIP() << "Requires MTE";
792 }
793
794 int intercept_result;
795 unique_fd output_fd;
796 StartProcess([&]() {
797 SetTagCheckingLevelSync();
798 Trap(reinterpret_cast<void *>(CreateTagMapping()));
799 });
800
801 StartIntercept(&output_fd);
802 FinishCrasher();
803 AssertDeath(SIGTRAP);
804 FinishIntercept(&intercept_result);
805
806 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
807
808 std::string result;
809 ConsumeFd(std::move(output_fd), &result);
810
811 ASSERT_MATCH(result, R"(memory near x0:
812.*
813.*
814 01.............0 0000000000000000 0000000000000000 ................
815 00.............0)");
816#else
Peter Collingbournecd278072020-12-21 14:08:38 -0800817 GTEST_SKIP() << "Requires aarch64";
Peter Collingbournefe8997a2020-07-20 15:08:52 -0700818#endif
819}
820
Mitch Phillips5ddcea22021-04-19 09:59:17 -0700821TEST_F(CrasherTest, mte_fault_tag_dump_front_truncated) {
822#if defined(__aarch64__)
823 if (!mte_supported()) {
824 GTEST_SKIP() << "Requires MTE";
825 }
826
827 int intercept_result;
828 unique_fd output_fd;
829 StartProcess([&]() {
830 SetTagCheckingLevelSync();
831 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
832 p[0] = 0; // Untagged pointer, tagged memory.
833 });
834
835 StartIntercept(&output_fd);
836 FinishCrasher();
837 AssertDeath(SIGSEGV);
838 FinishIntercept(&intercept_result);
839
840 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
841
842 std::string result;
843 ConsumeFd(std::move(output_fd), &result);
844
845 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
846\s*=>0x[0-9a-f]+000:\[1\] 0 1 0)");
847#else
848 GTEST_SKIP() << "Requires aarch64";
849#endif
850}
851
852TEST_F(CrasherTest, mte_fault_tag_dump) {
853#if defined(__aarch64__)
854 if (!mte_supported()) {
855 GTEST_SKIP() << "Requires MTE";
856 }
857
858 int intercept_result;
859 unique_fd output_fd;
860 StartProcess([&]() {
861 SetTagCheckingLevelSync();
862 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
863 p[320] = 0; // Untagged pointer, tagged memory.
864 });
865
866 StartIntercept(&output_fd);
867 FinishCrasher();
868 AssertDeath(SIGSEGV);
869 FinishIntercept(&intercept_result);
870
871 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
872
873 std::string result;
874 ConsumeFd(std::move(output_fd), &result);
875
876 ASSERT_MATCH(result, R"(Memory tags around the fault address.*
877\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
878\s*=>0x[0-9a-f]+: 1 0 1 0 \[1\] 0 1 0 1 0 1 0 1 0 1 0
879\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
880)");
881#else
882 GTEST_SKIP() << "Requires aarch64";
883#endif
884}
885
886TEST_F(CrasherTest, mte_fault_tag_dump_rear_truncated) {
887#if defined(__aarch64__)
888 if (!mte_supported()) {
889 GTEST_SKIP() << "Requires MTE";
890 }
891
892 int intercept_result;
893 unique_fd output_fd;
894 StartProcess([&]() {
895 SetTagCheckingLevelSync();
896 size_t page_size = getpagesize();
897 volatile char* p = reinterpret_cast<char*>(CreateTagMapping());
898 p[page_size - kTagGranuleSize * 2] = 0; // Untagged pointer, tagged memory.
899 });
900
901 StartIntercept(&output_fd);
902 FinishCrasher();
903 AssertDeath(SIGSEGV);
904 FinishIntercept(&intercept_result);
905
906 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
907
908 std::string result;
909 ConsumeFd(std::move(output_fd), &result);
910
911 ASSERT_MATCH(result, R"(Memory tags around the fault address)");
912 ASSERT_MATCH(result,
913 R"(\s*0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
914\s*=>0x[0-9a-f]+: 1 0 1 0 1 0 1 0 1 0 1 0 1 0 \[1\] 0
915
916)"); // Ensure truncation happened and there's a newline after the tag fault.
917#else
918 GTEST_SKIP() << "Requires aarch64";
919#endif
920}
921
Josh Gaocdea7502017-11-01 15:00:40 -0700922TEST_F(CrasherTest, LD_PRELOAD) {
923 int intercept_result;
924 unique_fd output_fd;
925 StartProcess([]() {
926 setenv("LD_PRELOAD", "nonexistent.so", 1);
927 *reinterpret_cast<volatile char*>(0xdead) = '1';
928 });
929
930 StartIntercept(&output_fd);
931 FinishCrasher();
932 AssertDeath(SIGSEGV);
933 FinishIntercept(&intercept_result);
934
935 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
936
937 std::string result;
938 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -0800939 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
Josh Gaocdea7502017-11-01 15:00:40 -0700940}
941
Josh Gaocbe70cb2016-10-18 18:17:52 -0700942TEST_F(CrasherTest, abort) {
943 int intercept_result;
944 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800945 StartProcess([]() {
946 abort();
947 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700948 StartIntercept(&output_fd);
949 FinishCrasher();
950 AssertDeath(SIGABRT);
951 FinishIntercept(&intercept_result);
952
953 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
954
955 std::string result;
956 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -0700957 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700958}
959
960TEST_F(CrasherTest, signal) {
961 int intercept_result;
962 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800963 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700964 while (true) {
965 sleep(1);
966 }
Josh Gao502cfd22017-02-17 01:39:15 -0800967 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700968 StartIntercept(&output_fd);
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700969 FinishCrasher();
Josh Gaocbe70cb2016-10-18 18:17:52 -0700970 ASSERT_EQ(0, kill(crasher_pid, SIGSEGV));
971
972 AssertDeath(SIGSEGV);
973 FinishIntercept(&intercept_result);
974
975 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
976
977 std::string result;
978 ConsumeFd(std::move(output_fd), &result);
Elliott Hughes89722702018-05-02 10:47:00 -0700979 ASSERT_MATCH(
980 result,
981 R"(signal 11 \(SIGSEGV\), code 0 \(SI_USER from pid \d+, uid \d+\), fault addr --------)");
Josh Gaocbe70cb2016-10-18 18:17:52 -0700982 ASSERT_MATCH(result, R"(backtrace:)");
983}
984
985TEST_F(CrasherTest, abort_message) {
986 int intercept_result;
987 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -0800988 StartProcess([]() {
Josh Gao1cc7bd82018-02-13 13:16:17 -0800989 // Arrived at experimentally;
990 // logd truncates at 4062.
991 // strlen("Abort message: ''") is 17.
992 // That's 4045, but we also want a NUL.
993 char buf[4045 + 1];
994 memset(buf, 'x', sizeof(buf));
995 buf[sizeof(buf) - 1] = '\0';
996 android_set_abort_message(buf);
Josh Gao502cfd22017-02-17 01:39:15 -0800997 abort();
998 });
Josh Gaocbe70cb2016-10-18 18:17:52 -0700999 StartIntercept(&output_fd);
1000 FinishCrasher();
1001 AssertDeath(SIGABRT);
1002 FinishIntercept(&intercept_result);
1003
1004 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1005
1006 std::string result;
1007 ConsumeFd(std::move(output_fd), &result);
Josh Gao1cc7bd82018-02-13 13:16:17 -08001008 ASSERT_MATCH(result, R"(Abort message: 'x{4045}')");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001009}
1010
Christopher Ferrise8891452021-08-17 17:34:53 -07001011TEST_F(CrasherTest, abort_message_newline_trimmed) {
1012 int intercept_result;
1013 unique_fd output_fd;
1014 StartProcess([]() {
1015 android_set_abort_message("Message with a newline.\n");
1016 abort();
1017 });
1018 StartIntercept(&output_fd);
1019 FinishCrasher();
1020 AssertDeath(SIGABRT);
1021 FinishIntercept(&intercept_result);
1022
1023 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1024
1025 std::string result;
1026 ConsumeFd(std::move(output_fd), &result);
1027 ASSERT_MATCH(result, R"(Abort message: 'Message with a newline.')");
1028}
1029
1030TEST_F(CrasherTest, abort_message_multiple_newlines_trimmed) {
1031 int intercept_result;
1032 unique_fd output_fd;
1033 StartProcess([]() {
1034 android_set_abort_message("Message with multiple newlines.\n\n\n\n\n");
1035 abort();
1036 });
1037 StartIntercept(&output_fd);
1038 FinishCrasher();
1039 AssertDeath(SIGABRT);
1040 FinishIntercept(&intercept_result);
1041
1042 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1043
1044 std::string result;
1045 ConsumeFd(std::move(output_fd), &result);
1046 ASSERT_MATCH(result, R"(Abort message: 'Message with multiple newlines.')");
1047}
1048
Josh Gaoe06f2a42017-04-27 16:50:38 -07001049TEST_F(CrasherTest, abort_message_backtrace) {
1050 int intercept_result;
1051 unique_fd output_fd;
1052 StartProcess([]() {
1053 android_set_abort_message("not actually aborting");
Josh Gaoa48b41b2019-12-13 14:11:04 -08001054 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoe06f2a42017-04-27 16:50:38 -07001055 exit(0);
1056 });
1057 StartIntercept(&output_fd);
1058 FinishCrasher();
1059 AssertDeath(0);
1060 FinishIntercept(&intercept_result);
1061
1062 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1063
1064 std::string result;
1065 ConsumeFd(std::move(output_fd), &result);
1066 ASSERT_NOT_MATCH(result, R"(Abort message:)");
1067}
1068
Josh Gaocbe70cb2016-10-18 18:17:52 -07001069TEST_F(CrasherTest, intercept_timeout) {
1070 int intercept_result;
1071 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001072 StartProcess([]() {
1073 abort();
1074 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001075 StartIntercept(&output_fd);
1076
1077 // Don't let crasher finish until we timeout.
1078 FinishIntercept(&intercept_result);
1079
1080 ASSERT_NE(1, intercept_result) << "tombstoned reported success? (intercept_result = "
1081 << intercept_result << ")";
1082
1083 FinishCrasher();
1084 AssertDeath(SIGABRT);
1085}
1086
Elliott Hughese4781d52021-03-17 09:15:15 -07001087TEST_F(CrasherTest, wait_for_debugger) {
1088 if (!android::base::SetProperty(kWaitForDebuggerKey, "1")) {
1089 FAIL() << "failed to enable wait_for_debugger";
Josh Gaocbe70cb2016-10-18 18:17:52 -07001090 }
1091 sleep(1);
1092
Josh Gao502cfd22017-02-17 01:39:15 -08001093 StartProcess([]() {
1094 abort();
1095 });
Josh Gaocbe70cb2016-10-18 18:17:52 -07001096 FinishCrasher();
1097
1098 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001099 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
Josh Gaocbe70cb2016-10-18 18:17:52 -07001100 ASSERT_TRUE(WIFSTOPPED(status));
1101 ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
1102
1103 ASSERT_EQ(0, kill(crasher_pid, SIGCONT));
1104
1105 AssertDeath(SIGABRT);
1106}
1107
Josh Gaocbe70cb2016-10-18 18:17:52 -07001108TEST_F(CrasherTest, backtrace) {
1109 std::string result;
1110 int intercept_result;
1111 unique_fd output_fd;
Josh Gao502cfd22017-02-17 01:39:15 -08001112
1113 StartProcess([]() {
1114 abort();
1115 });
Narayan Kamatha73df602017-05-24 15:07:25 +01001116 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001117
1118 std::this_thread::sleep_for(500ms);
1119
1120 sigval val;
1121 val.sival_int = 1;
Josh Gaoa48b41b2019-12-13 14:11:04 -08001122 ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
Josh Gaocbe70cb2016-10-18 18:17:52 -07001123 FinishIntercept(&intercept_result);
1124 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1125 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001126 ASSERT_BACKTRACE_FRAME(result, "read");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001127
1128 int status;
1129 ASSERT_EQ(0, waitpid(crasher_pid, &status, WNOHANG | WUNTRACED));
1130
1131 StartIntercept(&output_fd);
1132 FinishCrasher();
1133 AssertDeath(SIGABRT);
1134 FinishIntercept(&intercept_result);
1135 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1136 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001137 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaocbe70cb2016-10-18 18:17:52 -07001138}
Josh Gaofca7ca32017-01-23 12:05:35 -08001139
1140TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
Josh Gao502cfd22017-02-17 01:39:15 -08001141 int intercept_result;
1142 unique_fd output_fd;
Josh Gaofca7ca32017-01-23 12:05:35 -08001143 StartProcess([]() {
1144 prctl(PR_SET_DUMPABLE, 0);
Josh Gao502cfd22017-02-17 01:39:15 -08001145 abort();
Josh Gaofca7ca32017-01-23 12:05:35 -08001146 });
Josh Gao502cfd22017-02-17 01:39:15 -08001147
1148 StartIntercept(&output_fd);
1149 FinishCrasher();
1150 AssertDeath(SIGABRT);
1151 FinishIntercept(&intercept_result);
1152
1153 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1154
1155 std::string result;
1156 ConsumeFd(std::move(output_fd), &result);
Andreas Gampe26cbafb2017-06-22 20:14:43 -07001157 ASSERT_BACKTRACE_FRAME(result, "abort");
Josh Gaofca7ca32017-01-23 12:05:35 -08001158}
1159
Josh Gao502cfd22017-02-17 01:39:15 -08001160TEST_F(CrasherTest, capabilities) {
1161 ASSERT_EQ(0U, getuid()) << "capability test requires root";
1162
Josh Gaofca7ca32017-01-23 12:05:35 -08001163 StartProcess([]() {
Josh Gao502cfd22017-02-17 01:39:15 -08001164 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
1165 err(1, "failed to set PR_SET_KEEPCAPS");
1166 }
1167
1168 if (setresuid(1, 1, 1) != 0) {
1169 err(1, "setresuid failed");
1170 }
1171
1172 __user_cap_header_struct capheader;
1173 __user_cap_data_struct capdata[2];
1174 memset(&capheader, 0, sizeof(capheader));
1175 memset(&capdata, 0, sizeof(capdata));
1176
1177 capheader.version = _LINUX_CAPABILITY_VERSION_3;
1178 capheader.pid = 0;
1179
1180 // Turn on every third capability.
1181 static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
1182 for (int i = 0; i < CAP_LAST_CAP; i += 3) {
1183 capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
1184 capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
1185 }
1186
1187 // Make sure CAP_SYS_PTRACE is off.
1188 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1189 capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
1190
1191 if (capset(&capheader, &capdata[0]) != 0) {
1192 err(1, "capset failed");
1193 }
1194
1195 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
1196 err(1, "failed to drop ambient capabilities");
1197 }
1198
Josh Gaoa5199a92017-04-03 13:18:34 -07001199 pthread_setname_np(pthread_self(), "thread_name");
Josh Gao502cfd22017-02-17 01:39:15 -08001200 raise(SIGSYS);
Josh Gaofca7ca32017-01-23 12:05:35 -08001201 });
Josh Gao502cfd22017-02-17 01:39:15 -08001202
1203 unique_fd output_fd;
1204 StartIntercept(&output_fd);
1205 FinishCrasher();
1206 AssertDeath(SIGSYS);
1207
1208 std::string result;
1209 int intercept_result;
1210 FinishIntercept(&intercept_result);
1211 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1212 ConsumeFd(std::move(output_fd), &result);
Josh Gaoa5199a92017-04-03 13:18:34 -07001213 ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
Jaesung Chung58778e12017-06-15 18:20:34 +09001214 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gaofca7ca32017-01-23 12:05:35 -08001215}
Josh Gaoc3c8c022017-02-13 16:36:18 -08001216
Josh Gao2e7b8e22017-05-04 17:12:57 -07001217TEST_F(CrasherTest, fake_pid) {
1218 int intercept_result;
1219 unique_fd output_fd;
1220
1221 // Prime the getpid/gettid caches.
1222 UNUSED(getpid());
1223 UNUSED(gettid());
1224
1225 std::function<pid_t()> clone_fn = []() {
1226 return syscall(__NR_clone, SIGCHLD, nullptr, nullptr, nullptr, nullptr);
1227 };
1228 StartProcess(
1229 []() {
1230 ASSERT_NE(getpid(), syscall(__NR_getpid));
1231 ASSERT_NE(gettid(), syscall(__NR_gettid));
1232 raise(SIGSEGV);
1233 },
1234 clone_fn);
1235
1236 StartIntercept(&output_fd);
1237 FinishCrasher();
1238 AssertDeath(SIGSEGV);
1239 FinishIntercept(&intercept_result);
1240
1241 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1242
1243 std::string result;
1244 ConsumeFd(std::move(output_fd), &result);
Jaesung Chung58778e12017-06-15 18:20:34 +09001245 ASSERT_BACKTRACE_FRAME(result, "tgkill");
Josh Gao2e7b8e22017-05-04 17:12:57 -07001246}
1247
Josh Gaoe04ca272018-01-16 15:38:17 -08001248static const char* const kDebuggerdSeccompPolicy =
1249 "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
1250
Josh Gao70adac62018-02-22 11:38:33 -08001251static pid_t seccomp_fork_impl(void (*prejail)()) {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001252 std::string policy;
1253 if (!android::base::ReadFileToString(kDebuggerdSeccompPolicy, &policy)) {
1254 PLOG(FATAL) << "failed to read policy file";
1255 }
1256
1257 // Allow a bunch of syscalls used by the tests.
1258 policy += "\nclone: 1";
1259 policy += "\nsigaltstack: 1";
1260 policy += "\nnanosleep: 1";
Christopher Ferrisab606682019-09-17 15:31:47 -07001261 policy += "\ngetrlimit: 1";
1262 policy += "\nugetrlimit: 1";
Josh Gao6f9eeec2018-09-12 13:55:47 -07001263
1264 FILE* tmp_file = tmpfile();
1265 if (!tmp_file) {
1266 PLOG(FATAL) << "tmpfile failed";
1267 }
1268
Christopher Ferris172b0a02019-09-18 17:48:30 -07001269 unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
Josh Gao6f9eeec2018-09-12 13:55:47 -07001270 if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
1271 PLOG(FATAL) << "failed to write policy to tmpfile";
1272 }
1273
1274 if (lseek(tmp_fd.get(), 0, SEEK_SET) != 0) {
1275 PLOG(FATAL) << "failed to seek tmp_fd";
Josh Gaoe04ca272018-01-16 15:38:17 -08001276 }
1277
1278 ScopedMinijail jail{minijail_new()};
1279 if (!jail) {
1280 LOG(FATAL) << "failed to create minijail";
1281 }
1282
1283 minijail_no_new_privs(jail.get());
1284 minijail_log_seccomp_filter_failures(jail.get());
1285 minijail_use_seccomp_filter(jail.get());
Josh Gao6f9eeec2018-09-12 13:55:47 -07001286 minijail_parse_seccomp_filters_from_fd(jail.get(), tmp_fd.release());
Josh Gaoe04ca272018-01-16 15:38:17 -08001287
1288 pid_t result = fork();
1289 if (result == -1) {
1290 return result;
1291 } else if (result != 0) {
1292 return result;
1293 }
1294
1295 // Spawn and detach a thread that spins forever.
1296 std::atomic<bool> thread_ready(false);
1297 std::thread thread([&jail, &thread_ready]() {
1298 minijail_enter(jail.get());
1299 thread_ready = true;
1300 for (;;)
1301 ;
1302 });
1303 thread.detach();
1304
1305 while (!thread_ready) {
1306 continue;
1307 }
1308
Josh Gao70adac62018-02-22 11:38:33 -08001309 if (prejail) {
1310 prejail();
1311 }
1312
Josh Gaoe04ca272018-01-16 15:38:17 -08001313 minijail_enter(jail.get());
1314 return result;
1315}
1316
Josh Gao70adac62018-02-22 11:38:33 -08001317static pid_t seccomp_fork() {
1318 return seccomp_fork_impl(nullptr);
1319}
1320
Josh Gaoe04ca272018-01-16 15:38:17 -08001321TEST_F(CrasherTest, seccomp_crash) {
1322 int intercept_result;
1323 unique_fd output_fd;
1324
1325 StartProcess([]() { abort(); }, &seccomp_fork);
1326
1327 StartIntercept(&output_fd);
1328 FinishCrasher();
1329 AssertDeath(SIGABRT);
1330 FinishIntercept(&intercept_result);
1331 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1332
1333 std::string result;
1334 ConsumeFd(std::move(output_fd), &result);
1335 ASSERT_BACKTRACE_FRAME(result, "abort");
1336}
1337
Josh Gao70adac62018-02-22 11:38:33 -08001338static pid_t seccomp_fork_rlimit() {
1339 return seccomp_fork_impl([]() {
1340 struct rlimit rlim = {
1341 .rlim_cur = 512 * 1024 * 1024,
1342 .rlim_max = 512 * 1024 * 1024,
1343 };
1344
1345 if (setrlimit(RLIMIT_AS, &rlim) != 0) {
1346 raise(SIGINT);
1347 }
1348 });
1349}
1350
1351TEST_F(CrasherTest, seccomp_crash_oom) {
1352 int intercept_result;
1353 unique_fd output_fd;
1354
1355 StartProcess(
1356 []() {
1357 std::vector<void*> vec;
1358 for (int i = 0; i < 512; ++i) {
1359 char* buf = static_cast<char*>(malloc(1024 * 1024));
1360 if (!buf) {
1361 abort();
1362 }
1363 memset(buf, 0xff, 1024 * 1024);
1364 vec.push_back(buf);
1365 }
1366 },
1367 &seccomp_fork_rlimit);
1368
1369 StartIntercept(&output_fd);
1370 FinishCrasher();
1371 AssertDeath(SIGABRT);
1372 FinishIntercept(&intercept_result);
1373 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1374
1375 // We can't actually generate a backtrace, just make sure that the process terminates.
1376}
1377
Josh Gaoe04ca272018-01-16 15:38:17 -08001378__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
1379 siginfo_t siginfo;
1380 siginfo.si_code = SI_QUEUE;
1381 siginfo.si_pid = getpid();
1382 siginfo.si_uid = getuid();
1383
1384 if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
1385 PLOG(FATAL) << "invalid dump type";
1386 }
1387
1388 siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
1389
Josh Gaoa48b41b2019-12-13 14:11:04 -08001390 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
Josh Gaoe04ca272018-01-16 15:38:17 -08001391 PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
1392 return false;
1393 }
1394
1395 return true;
1396}
1397
1398TEST_F(CrasherTest, seccomp_tombstone) {
1399 int intercept_result;
1400 unique_fd output_fd;
1401
1402 static const auto dump_type = kDebuggerdTombstone;
1403 StartProcess(
1404 []() {
1405 raise_debugger_signal(dump_type);
1406 _exit(0);
1407 },
1408 &seccomp_fork);
1409
1410 StartIntercept(&output_fd, dump_type);
1411 FinishCrasher();
1412 AssertDeath(0);
1413 FinishIntercept(&intercept_result);
1414 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1415
1416 std::string result;
1417 ConsumeFd(std::move(output_fd), &result);
1418 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1419}
1420
Josh Gao6f9eeec2018-09-12 13:55:47 -07001421extern "C" void foo() {
1422 LOG(INFO) << "foo";
1423 std::this_thread::sleep_for(1s);
1424}
1425
1426extern "C" void bar() {
1427 LOG(INFO) << "bar";
1428 std::this_thread::sleep_for(1s);
1429}
1430
Josh Gaoe04ca272018-01-16 15:38:17 -08001431TEST_F(CrasherTest, seccomp_backtrace) {
1432 int intercept_result;
1433 unique_fd output_fd;
1434
1435 static const auto dump_type = kDebuggerdNativeBacktrace;
1436 StartProcess(
1437 []() {
Josh Gao6f9eeec2018-09-12 13:55:47 -07001438 std::thread a(foo);
1439 std::thread b(bar);
1440
1441 std::this_thread::sleep_for(100ms);
1442
Josh Gaoe04ca272018-01-16 15:38:17 -08001443 raise_debugger_signal(dump_type);
1444 _exit(0);
1445 },
1446 &seccomp_fork);
1447
1448 StartIntercept(&output_fd, dump_type);
1449 FinishCrasher();
1450 AssertDeath(0);
1451 FinishIntercept(&intercept_result);
1452 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1453
1454 std::string result;
1455 ConsumeFd(std::move(output_fd), &result);
1456 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
Josh Gao6f9eeec2018-09-12 13:55:47 -07001457 ASSERT_BACKTRACE_FRAME(result, "foo");
1458 ASSERT_BACKTRACE_FRAME(result, "bar");
Josh Gaoe04ca272018-01-16 15:38:17 -08001459}
1460
1461TEST_F(CrasherTest, seccomp_crash_logcat) {
1462 StartProcess([]() { abort(); }, &seccomp_fork);
1463 FinishCrasher();
1464
1465 // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
1466 AssertDeath(SIGABRT);
1467}
1468
Josh Gaofd13bf02017-08-18 15:37:26 -07001469TEST_F(CrasherTest, competing_tracer) {
1470 int intercept_result;
1471 unique_fd output_fd;
1472 StartProcess([]() {
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001473 raise(SIGABRT);
Josh Gaofd13bf02017-08-18 15:37:26 -07001474 });
1475
1476 StartIntercept(&output_fd);
Josh Gaofd13bf02017-08-18 15:37:26 -07001477
1478 ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001479 FinishCrasher();
Josh Gaofd13bf02017-08-18 15:37:26 -07001480
1481 int status;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001482 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gaofd13bf02017-08-18 15:37:26 -07001483 ASSERT_TRUE(WIFSTOPPED(status));
1484 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1485
1486 ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
1487 FinishIntercept(&intercept_result);
1488 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1489
1490 std::string result;
1491 ConsumeFd(std::move(output_fd), &result);
1492 std::string regex = R"(failed to attach to thread \d+, already traced by )";
1493 regex += std::to_string(gettid());
1494 regex += R"( \(.+debuggerd_test)";
1495 ASSERT_MATCH(result, regex.c_str());
1496
Christopher Ferris172b0a02019-09-18 17:48:30 -07001497 ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
Josh Gao2b2ae0c2017-08-21 14:31:17 -07001498 ASSERT_TRUE(WIFSTOPPED(status));
1499 ASSERT_EQ(SIGABRT, WSTOPSIG(status));
1500
Josh Gaofd13bf02017-08-18 15:37:26 -07001501 ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
1502 AssertDeath(SIGABRT);
1503}
1504
Josh Gaobf06a402018-08-27 16:34:01 -07001505TEST_F(CrasherTest, fdsan_warning_abort_message) {
1506 int intercept_result;
1507 unique_fd output_fd;
1508
1509 StartProcess([]() {
1510 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
Christopher Ferris172b0a02019-09-18 17:48:30 -07001511 unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
Josh Gaobf06a402018-08-27 16:34:01 -07001512 if (fd == -1) {
1513 abort();
1514 }
1515 close(fd.get());
1516 _exit(0);
1517 });
1518
1519 StartIntercept(&output_fd);
1520 FinishCrasher();
1521 AssertDeath(0);
1522 FinishIntercept(&intercept_result);
1523 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1524
1525 std::string result;
1526 ConsumeFd(std::move(output_fd), &result);
1527 ASSERT_MATCH(result, "Abort message: 'attempted to close");
1528}
1529
Josh Gaoc3c8c022017-02-13 16:36:18 -08001530TEST(crash_dump, zombie) {
1531 pid_t forkpid = fork();
1532
Josh Gaoc3c8c022017-02-13 16:36:18 -08001533 pid_t rc;
1534 int status;
1535
1536 if (forkpid == 0) {
1537 errno = 0;
1538 rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
1539 if (rc != -1 || errno != ECHILD) {
1540 errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1541 }
1542
Josh Gaoa48b41b2019-12-13 14:11:04 -08001543 raise(BIONIC_SIGNAL_DEBUGGER);
Josh Gaoc3c8c022017-02-13 16:36:18 -08001544
1545 errno = 0;
Christopher Ferris172b0a02019-09-18 17:48:30 -07001546 rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001547 if (rc != -1 || errno != ECHILD) {
1548 errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
1549 }
1550 _exit(0);
1551 } else {
Christopher Ferris172b0a02019-09-18 17:48:30 -07001552 rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
Josh Gaoc3c8c022017-02-13 16:36:18 -08001553 ASSERT_EQ(forkpid, rc);
1554 ASSERT_TRUE(WIFEXITED(status));
1555 ASSERT_EQ(0, WEXITSTATUS(status));
1556 }
1557}
Josh Gao352a8452017-03-30 16:46:21 -07001558
1559TEST(tombstoned, no_notify) {
1560 // Do this a few times.
1561 for (int i = 0; i < 3; ++i) {
1562 pid_t pid = 123'456'789 + i;
1563
1564 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001565 InterceptStatus status;
1566 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1567 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001568
1569 {
1570 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001571 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001572 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1573 }
1574
1575 pid_t read_pid;
1576 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1577 ASSERT_EQ(read_pid, pid);
1578 }
1579}
1580
1581TEST(tombstoned, stress) {
1582 // Spawn threads to simultaneously do a bunch of failing dumps and a bunch of successful dumps.
1583 static constexpr int kDumpCount = 100;
1584
1585 std::atomic<bool> start(false);
1586 std::vector<std::thread> threads;
1587 threads.emplace_back([&start]() {
1588 while (!start) {
1589 continue;
1590 }
1591
1592 // Use a way out of range pid, to avoid stomping on an actual process.
1593 pid_t pid_base = 1'000'000;
1594
1595 for (int dump = 0; dump < kDumpCount; ++dump) {
1596 pid_t pid = pid_base + dump;
1597
1598 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001599 InterceptStatus status;
1600 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1601 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001602
1603 // Pretend to crash, and then immediately close the socket.
1604 unique_fd sockfd(socket_local_client(kTombstonedCrashSocketName,
1605 ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
1606 if (sockfd == -1) {
1607 FAIL() << "failed to connect to tombstoned: " << strerror(errno);
1608 }
1609 TombstonedCrashPacket packet = {};
1610 packet.packet_type = CrashPacketType::kDumpRequest;
1611 packet.packet.dump_request.pid = pid;
1612 if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
1613 FAIL() << "failed to write to tombstoned: " << strerror(errno);
1614 }
1615
1616 continue;
1617 }
1618 });
1619
1620 threads.emplace_back([&start]() {
1621 while (!start) {
1622 continue;
1623 }
1624
1625 // Use a way out of range pid, to avoid stomping on an actual process.
1626 pid_t pid_base = 2'000'000;
1627
1628 for (int dump = 0; dump < kDumpCount; ++dump) {
1629 pid_t pid = pid_base + dump;
1630
1631 unique_fd intercept_fd, output_fd;
Narayan Kamathca5e9082017-06-02 15:42:06 +01001632 InterceptStatus status;
1633 tombstoned_intercept(pid, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1634 ASSERT_EQ(InterceptStatus::kRegistered, status);
Josh Gao352a8452017-03-30 16:46:21 -07001635
1636 {
1637 unique_fd tombstoned_socket, input_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +01001638 ASSERT_TRUE(tombstoned_connect(pid, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Josh Gao352a8452017-03-30 16:46:21 -07001639 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), &pid, sizeof(pid)));
1640 tombstoned_notify_completion(tombstoned_socket.get());
1641 }
1642
1643 // TODO: Fix the race that requires this sleep.
1644 std::this_thread::sleep_for(50ms);
1645
1646 pid_t read_pid;
1647 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), &read_pid, sizeof(read_pid)));
1648 ASSERT_EQ(read_pid, pid);
1649 }
1650 });
1651
1652 start = true;
1653
1654 for (std::thread& thread : threads) {
1655 thread.join();
1656 }
1657}
Narayan Kamathca5e9082017-06-02 15:42:06 +01001658
1659TEST(tombstoned, java_trace_intercept_smoke) {
1660 // Using a "real" PID is a little dangerous here - if the test fails
1661 // or crashes, we might end up getting a bogus / unreliable stack
1662 // trace.
1663 const pid_t self = getpid();
1664
1665 unique_fd intercept_fd, output_fd;
1666 InterceptStatus status;
1667 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1668 ASSERT_EQ(InterceptStatus::kRegistered, status);
1669
Josh Gao76e1e302021-01-26 15:53:11 -08001670 // First connect to tombstoned requesting a native tombstone. This
Narayan Kamathca5e9082017-06-02 15:42:06 +01001671 // should result in a "regular" FD and not the installed intercept.
1672 const char native[] = "native";
1673 unique_fd tombstoned_socket, input_fd;
Josh Gao76e1e302021-01-26 15:53:11 -08001674 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdTombstone));
Narayan Kamathca5e9082017-06-02 15:42:06 +01001675 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), native, sizeof(native)));
1676 tombstoned_notify_completion(tombstoned_socket.get());
1677
1678 // Then, connect to tombstoned asking for a java backtrace. This *should*
1679 // trigger the intercept.
1680 const char java[] = "java";
1681 ASSERT_TRUE(tombstoned_connect(self, &tombstoned_socket, &input_fd, kDebuggerdJavaBacktrace));
1682 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), java, sizeof(java)));
1683 tombstoned_notify_completion(tombstoned_socket.get());
1684
1685 char outbuf[sizeof(java)];
1686 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1687 ASSERT_STREQ("java", outbuf);
1688}
1689
1690TEST(tombstoned, multiple_intercepts) {
1691 const pid_t fake_pid = 1'234'567;
1692 unique_fd intercept_fd, output_fd;
1693 InterceptStatus status;
1694 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdJavaBacktrace);
1695 ASSERT_EQ(InterceptStatus::kRegistered, status);
1696
1697 unique_fd intercept_fd_2, output_fd_2;
1698 tombstoned_intercept(fake_pid, &intercept_fd_2, &output_fd_2, &status, kDebuggerdNativeBacktrace);
1699 ASSERT_EQ(InterceptStatus::kFailedAlreadyRegistered, status);
1700}
1701
1702TEST(tombstoned, intercept_any) {
1703 const pid_t fake_pid = 1'234'567;
1704
1705 unique_fd intercept_fd, output_fd;
1706 InterceptStatus status;
1707 tombstoned_intercept(fake_pid, &intercept_fd, &output_fd, &status, kDebuggerdNativeBacktrace);
1708 ASSERT_EQ(InterceptStatus::kRegistered, status);
1709
1710 const char any[] = "any";
1711 unique_fd tombstoned_socket, input_fd;
1712 ASSERT_TRUE(tombstoned_connect(fake_pid, &tombstoned_socket, &input_fd, kDebuggerdAnyIntercept));
1713 ASSERT_TRUE(android::base::WriteFully(input_fd.get(), any, sizeof(any)));
1714 tombstoned_notify_completion(tombstoned_socket.get());
1715
1716 char outbuf[sizeof(any)];
1717 ASSERT_TRUE(android::base::ReadFully(output_fd.get(), outbuf, sizeof(outbuf)));
1718 ASSERT_STREQ("any", outbuf);
1719}
Josh Gao2b22ae12018-09-12 14:51:03 -07001720
1721TEST(tombstoned, interceptless_backtrace) {
1722 // Generate 50 backtraces, and then check to see that we haven't created 50 new tombstones.
1723 auto get_tombstone_timestamps = []() -> std::map<int, time_t> {
1724 std::map<int, time_t> result;
1725 for (int i = 0; i < 99; ++i) {
1726 std::string path = android::base::StringPrintf("/data/tombstones/tombstone_%02d", i);
1727 struct stat st;
1728 if (stat(path.c_str(), &st) == 0) {
1729 result[i] = st.st_mtim.tv_sec;
1730 }
1731 }
1732 return result;
1733 };
1734
1735 auto before = get_tombstone_timestamps();
1736 for (int i = 0; i < 50; ++i) {
1737 raise_debugger_signal(kDebuggerdNativeBacktrace);
1738 }
1739 auto after = get_tombstone_timestamps();
1740
1741 int diff = 0;
1742 for (int i = 0; i < 99; ++i) {
1743 if (after.count(i) == 0) {
1744 continue;
1745 }
1746 if (before.count(i) == 0) {
1747 ++diff;
1748 continue;
1749 }
1750 if (before[i] != after[i]) {
1751 ++diff;
1752 }
1753 }
1754
1755 // We can't be sure that nothing's crash looping in the background.
1756 // This should be good enough, though...
1757 ASSERT_LT(diff, 10) << "too many new tombstones; is something crashing in the background?";
1758}
Christopher Ferris481e8372019-07-15 17:13:24 -07001759
1760static __attribute__((__noinline__)) void overflow_stack(void* p) {
1761 void* buf[1];
1762 buf[0] = p;
1763 static volatile void* global = buf;
1764 if (global) {
1765 global = buf;
1766 overflow_stack(&buf);
1767 }
1768}
1769
1770TEST_F(CrasherTest, stack_overflow) {
1771 int intercept_result;
1772 unique_fd output_fd;
1773 StartProcess([]() { overflow_stack(nullptr); });
1774
1775 StartIntercept(&output_fd);
1776 FinishCrasher();
1777 AssertDeath(SIGSEGV);
1778 FinishIntercept(&intercept_result);
1779
1780 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1781
1782 std::string result;
1783 ConsumeFd(std::move(output_fd), &result);
1784 ASSERT_MATCH(result, R"(Cause: stack pointer[^\n]*stack overflow.\n)");
1785}
Josh Gao76e1e302021-01-26 15:53:11 -08001786
Christopher Ferrisfe751c52021-04-16 09:40:40 -07001787static bool CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
1788 std::string test_lib(testing::internal::GetArgvs()[0]);
1789 auto const value = test_lib.find_last_of('/');
1790 if (value == std::string::npos) {
1791 test_lib = "./";
1792 } else {
1793 test_lib = test_lib.substr(0, value + 1) + "./";
1794 }
1795 test_lib += "libcrash_test.so";
1796
1797 *tmp_so_name = std::string(tmp_dir) + "/libcrash_test.so";
1798 std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
1799
1800 // Copy the shared so to a tempory directory.
1801 return system(cp_cmd.c_str()) == 0;
1802}
1803
1804TEST_F(CrasherTest, unreadable_elf) {
1805 int intercept_result;
1806 unique_fd output_fd;
1807 StartProcess([]() {
1808 TemporaryDir td;
1809 std::string tmp_so_name;
1810 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
1811 _exit(1);
1812 }
1813 void* handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
1814 if (handle == nullptr) {
1815 _exit(1);
1816 }
1817 // Delete the original shared library so that we get the warning
1818 // about unreadable elf files.
1819 if (unlink(tmp_so_name.c_str()) == -1) {
1820 _exit(1);
1821 }
1822 void (*crash_func)() = reinterpret_cast<void (*)()>(dlsym(handle, "crash"));
1823 if (crash_func == nullptr) {
1824 _exit(1);
1825 }
1826 crash_func();
1827 });
1828
1829 StartIntercept(&output_fd);
1830 FinishCrasher();
1831 AssertDeath(SIGSEGV);
1832 FinishIntercept(&intercept_result);
1833
1834 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1835
1836 std::string result;
1837 ConsumeFd(std::move(output_fd), &result);
1838 ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
1839}
1840
Josh Gao76e1e302021-01-26 15:53:11 -08001841TEST(tombstoned, proto) {
1842 const pid_t self = getpid();
1843 unique_fd tombstoned_socket, text_fd, proto_fd;
1844 ASSERT_TRUE(
1845 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1846
1847 tombstoned_notify_completion(tombstoned_socket.get());
1848
1849 ASSERT_NE(-1, text_fd.get());
1850 ASSERT_NE(-1, proto_fd.get());
1851
1852 struct stat text_st;
1853 ASSERT_EQ(0, fstat(text_fd.get(), &text_st));
1854
1855 // Give tombstoned some time to link the files into place.
1856 std::this_thread::sleep_for(100ms);
1857
1858 // Find the tombstone.
Christopher Ferris35da2882021-02-17 15:39:06 -08001859 std::optional<std::string> tombstone_file;
1860 std::unique_ptr<DIR, decltype(&closedir)> dir_h(opendir("/data/tombstones"), closedir);
1861 ASSERT_TRUE(dir_h != nullptr);
1862 std::regex tombstone_re("tombstone_\\d+");
1863 dirent* entry;
1864 while ((entry = readdir(dir_h.get())) != nullptr) {
1865 if (!std::regex_match(entry->d_name, tombstone_re)) {
1866 continue;
1867 }
1868 std::string path = android::base::StringPrintf("/data/tombstones/%s", entry->d_name);
Josh Gao76e1e302021-01-26 15:53:11 -08001869
1870 struct stat st;
1871 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) != 0) {
1872 continue;
1873 }
1874
1875 if (st.st_dev == text_st.st_dev && st.st_ino == text_st.st_ino) {
Christopher Ferris35da2882021-02-17 15:39:06 -08001876 tombstone_file = path;
Josh Gao76e1e302021-01-26 15:53:11 -08001877 break;
1878 }
1879 }
1880
Christopher Ferris35da2882021-02-17 15:39:06 -08001881 ASSERT_TRUE(tombstone_file);
1882 std::string proto_path = tombstone_file.value() + ".pb";
Josh Gao76e1e302021-01-26 15:53:11 -08001883
1884 struct stat proto_fd_st;
1885 struct stat proto_file_st;
1886 ASSERT_EQ(0, fstat(proto_fd.get(), &proto_fd_st));
1887 ASSERT_EQ(0, stat(proto_path.c_str(), &proto_file_st));
1888
1889 ASSERT_EQ(proto_fd_st.st_dev, proto_file_st.st_dev);
1890 ASSERT_EQ(proto_fd_st.st_ino, proto_file_st.st_ino);
1891}
1892
1893TEST(tombstoned, proto_intercept) {
1894 const pid_t self = getpid();
1895 unique_fd intercept_fd, output_fd;
1896 InterceptStatus status;
1897
1898 tombstoned_intercept(self, &intercept_fd, &output_fd, &status, kDebuggerdTombstone);
1899 ASSERT_EQ(InterceptStatus::kRegistered, status);
1900
1901 unique_fd tombstoned_socket, text_fd, proto_fd;
1902 ASSERT_TRUE(
1903 tombstoned_connect(self, &tombstoned_socket, &text_fd, &proto_fd, kDebuggerdTombstoneProto));
1904 ASSERT_TRUE(android::base::WriteStringToFd("foo", text_fd.get()));
1905 tombstoned_notify_completion(tombstoned_socket.get());
1906
1907 text_fd.reset();
1908
1909 std::string output;
1910 ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
1911 ASSERT_EQ("foo", output);
1912}
Christopher Ferrisa3e9a0b2021-07-29 12:38:07 -07001913
1914// Verify that when an intercept is present for the main thread, and the signal
1915// is received on a different thread, the intercept still works.
1916TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
1917 StartProcess([]() {
1918 std::thread thread([]() {
1919 // Raise the signal on the side thread.
1920 raise_debugger_signal(kDebuggerdNativeBacktrace);
1921 });
1922 thread.join();
1923 _exit(0);
1924 });
1925
1926 unique_fd output_fd;
1927 StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
1928 FinishCrasher();
1929 AssertDeath(0);
1930
1931 int intercept_result;
1932 FinishIntercept(&intercept_result);
1933 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1934
1935 std::string result;
1936 ConsumeFd(std::move(output_fd), &result);
1937 ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
1938}
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001939
1940static std::string format_pointer(uintptr_t ptr) {
1941#if defined(__LP64__)
1942 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
1943 static_cast<uint32_t>(ptr & 0xffffffff));
1944#else
1945 return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
1946#endif
1947}
1948
1949static std::string format_pointer(void* ptr) {
1950 return format_pointer(reinterpret_cast<uintptr_t>(ptr));
1951}
1952
1953static std::string format_full_pointer(uintptr_t ptr) {
1954#if defined(__LP64__)
1955 return android::base::StringPrintf("%016" PRIx64, ptr);
1956#else
1957 return android::base::StringPrintf("%08x", ptr);
1958#endif
1959}
1960
1961static std::string format_full_pointer(void* ptr) {
1962 return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
1963}
1964
1965__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
1966 int* crash_ptr = reinterpret_cast<int*>(ptr);
1967 *crash_ptr = 1;
1968 return *crash_ptr;
1969}
1970
1971// Verify that a fault address before the first map is properly handled.
1972TEST_F(CrasherTest, fault_address_before_first_map) {
1973 StartProcess([]() {
1974 ASSERT_EQ(0, crash_call(0x1024));
1975 _exit(0);
1976 });
1977
1978 unique_fd output_fd;
1979 StartIntercept(&output_fd);
1980 FinishCrasher();
1981 AssertDeath(SIGSEGV);
1982
1983 int intercept_result;
1984 FinishIntercept(&intercept_result);
1985 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
1986
1987 std::string result;
1988 ConsumeFd(std::move(output_fd), &result);
Peter Collingbourne773acaa2021-11-10 16:29:23 -08001989 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+1024)");
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07001990
1991 ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
1992
1993 std::string match_str = android::base::StringPrintf(
1994 R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
1995 format_pointer(0x1024).c_str());
1996 ASSERT_MATCH(result, match_str);
1997}
1998
1999// Verify that a fault address after the last map is properly handled.
2000TEST_F(CrasherTest, fault_address_after_last_map) {
2001 uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
2002 StartProcess([crash_uptr]() {
2003 ASSERT_EQ(0, crash_call(crash_uptr));
2004 _exit(0);
2005 });
2006
2007 unique_fd output_fd;
2008 StartIntercept(&output_fd);
2009 FinishCrasher();
2010 AssertDeath(SIGSEGV);
2011
2012 int intercept_result;
2013 FinishIntercept(&intercept_result);
2014 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2015
2016 std::string result;
2017 ConsumeFd(std::move(output_fd), &result);
2018
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002019 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2020 match_str += format_full_pointer(crash_uptr);
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002021 ASSERT_MATCH(result, match_str);
2022
2023 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2024
2025 // Assumes that the open files section comes after the map section.
2026 // If that assumption changes, the regex below needs to change.
2027 match_str = android::base::StringPrintf(
2028 R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
2029 format_pointer(crash_uptr).c_str());
2030 ASSERT_MATCH(result, match_str);
2031}
2032
2033// Verify that a fault address between maps is properly handled.
2034TEST_F(CrasherTest, fault_address_between_maps) {
2035 // Create a map before the fork so it will be present in the child.
2036 void* start_ptr =
2037 mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2038 ASSERT_NE(MAP_FAILED, start_ptr);
2039 // Unmap the page in the middle.
2040 void* middle_ptr =
2041 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
2042 ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
2043
2044 StartProcess([middle_ptr]() {
2045 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
2046 _exit(0);
2047 });
2048
2049 // Unmap the two maps.
2050 ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
2051 void* end_ptr =
2052 reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
2053 ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
2054
2055 unique_fd output_fd;
2056 StartIntercept(&output_fd);
2057 FinishCrasher();
2058 AssertDeath(SIGSEGV);
2059
2060 int intercept_result;
2061 FinishIntercept(&intercept_result);
2062 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2063
2064 std::string result;
2065 ConsumeFd(std::move(output_fd), &result);
2066
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002067 std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x)";
2068 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(middle_ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002069 ASSERT_MATCH(result, match_str);
2070
2071 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2072
2073 match_str = android::base::StringPrintf(
2074 R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
2075 format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
2076 format_pointer(end_ptr).c_str());
2077 ASSERT_MATCH(result, match_str);
2078}
2079
2080// Verify that a fault address happens in the correct map.
2081TEST_F(CrasherTest, fault_address_in_map) {
2082 // Create a map before the fork so it will be present in the child.
2083 void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2084 ASSERT_NE(MAP_FAILED, ptr);
2085
2086 StartProcess([ptr]() {
2087 ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
2088 _exit(0);
2089 });
2090
2091 ASSERT_EQ(0, munmap(ptr, getpagesize()));
2092
2093 unique_fd output_fd;
2094 StartIntercept(&output_fd);
2095 FinishCrasher();
2096 AssertDeath(SIGSEGV);
2097
2098 int intercept_result;
2099 FinishIntercept(&intercept_result);
2100 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2101
2102 std::string result;
2103 ConsumeFd(std::move(output_fd), &result);
2104
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002105 std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr 0x)";
2106 match_str += format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
Christopher Ferris7e4c2a82021-08-20 17:45:09 -07002107 ASSERT_MATCH(result, match_str);
2108
2109 ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
2110
2111 match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
2112 ASSERT_MATCH(result, match_str);
2113}
Christopher Ferris2038cc72021-09-15 03:57:10 +00002114
2115static constexpr uint32_t kDexData[] = {
2116 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
2117 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
2118 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
2119 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
2120 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
2121 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
2122 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
2123 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
2124 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
2125 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
2126 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
2127 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
2128 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
2129 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
2130 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
2131 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
2132 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
2133};
2134
2135TEST_F(CrasherTest, verify_dex_pc_with_function_name) {
2136 StartProcess([]() {
2137 TemporaryDir td;
2138 std::string tmp_so_name;
2139 if (!CopySharedLibrary(td.path, &tmp_so_name)) {
2140 _exit(1);
2141 }
2142
2143 // In order to cause libunwindstack to look for this __dex_debug_descriptor
2144 // move the library to which has a basename of libart.so.
2145 std::string art_so_name = android::base::Dirname(tmp_so_name) + "/libart.so";
2146 ASSERT_EQ(0, rename(tmp_so_name.c_str(), art_so_name.c_str()));
2147 void* handle = dlopen(art_so_name.c_str(), RTLD_NOW | RTLD_LOCAL);
2148 if (handle == nullptr) {
2149 _exit(1);
2150 }
2151
2152 void* ptr =
2153 mmap(nullptr, sizeof(kDexData), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2154 ASSERT_TRUE(ptr != MAP_FAILED);
2155 memcpy(ptr, kDexData, sizeof(kDexData));
2156 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, sizeof(kDexData), "dex");
2157
2158 JITCodeEntry dex_entry = {.symfile_addr = reinterpret_cast<uintptr_t>(ptr),
2159 .symfile_size = sizeof(kDexData)};
2160
2161 JITDescriptor* dex_debug =
2162 reinterpret_cast<JITDescriptor*>(dlsym(handle, "__dex_debug_descriptor"));
2163 ASSERT_TRUE(dex_debug != nullptr);
2164 dex_debug->version = 1;
2165 dex_debug->action_flag = 0;
2166 dex_debug->relevant_entry = 0;
2167 dex_debug->first_entry = reinterpret_cast<uintptr_t>(&dex_entry);
2168
2169 // This sets the magic dex pc value for register 0, using the value
2170 // of register 1 + 0x102.
2171 asm(".cfi_escape "
2172 "0x16 /* DW_CFA_val_expression */, 0, 0x0a /* size */,"
2173 "0x0c /* DW_OP_const4u */, 0x44, 0x45, 0x58, 0x31, /* magic = 'DEX1' */"
2174 "0x13 /* DW_OP_drop */,"
2175 "0x92 /* DW_OP_bregx */, 1, 0x82, 0x02 /* 2-byte SLEB128 */");
2176
2177 // For each different architecture, set register one to the dex ptr mmap
2178 // created above. Then do a nullptr dereference to force a crash.
2179#if defined(__arm__)
2180 asm volatile(
2181 "mov r1, %[base]\n"
2182 "mov r2, 0\n"
2183 "str r3, [r2]\n"
2184 : [base] "+r"(ptr)
2185 :
2186 : "r1", "r2", "r3", "memory");
2187#elif defined(__aarch64__)
2188 asm volatile(
2189 "mov x1, %[base]\n"
2190 "mov x2, 0\n"
2191 "str x3, [x2]\n"
2192 : [base] "+r"(ptr)
2193 :
2194 : "x1", "x2", "x3", "memory");
2195#elif defined(__i386__)
2196 asm volatile(
2197 "mov %[base], %%ecx\n"
2198 "movl $0, %%edi\n"
2199 "movl 0(%%edi), %%edx\n"
2200 : [base] "+r"(ptr)
2201 :
2202 : "edi", "ecx", "edx", "memory");
2203#elif defined(__x86_64__)
2204 asm volatile(
2205 "mov %[base], %%rdx\n"
2206 "movq 0, %%rdi\n"
2207 "movq 0(%%rdi), %%rcx\n"
2208 : [base] "+r"(ptr)
2209 :
2210 : "rcx", "rdx", "rdi", "memory");
2211#else
2212#error "Unsupported architecture"
2213#endif
2214 _exit(0);
2215 });
2216
2217 unique_fd output_fd;
2218 StartIntercept(&output_fd);
2219 FinishCrasher();
2220 AssertDeath(SIGSEGV);
2221
2222 int intercept_result;
2223 FinishIntercept(&intercept_result);
2224 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2225
2226 std::string result;
2227 ConsumeFd(std::move(output_fd), &result);
2228
2229 // Verify the process crashed properly.
Peter Collingbourne773acaa2021-11-10 16:29:23 -08002230 ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0*)");
Christopher Ferris2038cc72021-09-15 03:57:10 +00002231
2232 // Now verify that the dex_pc frame includes a proper function name.
2233 ASSERT_MATCH(result, R"( \[anon:dex\] \(Main\.\<init\>\+2)");
2234}
Christopher Ferrisbdea3bb2021-11-17 01:09:22 +00002235
2236static std::string format_map_pointer(uintptr_t ptr) {
2237#if defined(__LP64__)
2238 return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
2239 static_cast<uint32_t>(ptr & 0xffffffff));
2240#else
2241 return android::base::StringPrintf("%08x", ptr);
2242#endif
2243}
2244
2245// Verify that map data is properly formatted.
2246TEST_F(CrasherTest, verify_map_format) {
2247 // Create multiple maps to make sure that the map data is formatted properly.
2248 void* none_map = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2249 ASSERT_NE(MAP_FAILED, none_map);
2250 void* r_map = mmap(nullptr, getpagesize(), PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2251 ASSERT_NE(MAP_FAILED, r_map);
2252 void* w_map = mmap(nullptr, getpagesize(), PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2253 ASSERT_NE(MAP_FAILED, w_map);
2254 void* x_map = mmap(nullptr, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2255 ASSERT_NE(MAP_FAILED, x_map);
2256
2257 TemporaryFile tf;
2258 ASSERT_EQ(0x2000, lseek(tf.fd, 0x2000, SEEK_SET));
2259 char c = 'f';
2260 ASSERT_EQ(1, write(tf.fd, &c, 1));
2261 ASSERT_EQ(0x5000, lseek(tf.fd, 0x5000, SEEK_SET));
2262 ASSERT_EQ(1, write(tf.fd, &c, 1));
2263 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
2264 void* file_map = mmap(nullptr, 0x3001, PROT_READ, MAP_PRIVATE, tf.fd, 0x2000);
2265 ASSERT_NE(MAP_FAILED, file_map);
2266
2267 StartProcess([]() { abort(); });
2268
2269 ASSERT_EQ(0, munmap(none_map, getpagesize()));
2270 ASSERT_EQ(0, munmap(r_map, getpagesize()));
2271 ASSERT_EQ(0, munmap(w_map, getpagesize()));
2272 ASSERT_EQ(0, munmap(x_map, getpagesize()));
2273 ASSERT_EQ(0, munmap(file_map, 0x3001));
2274
2275 unique_fd output_fd;
2276 StartIntercept(&output_fd);
2277 FinishCrasher();
2278 AssertDeath(SIGABRT);
2279 int intercept_result;
2280 FinishIntercept(&intercept_result);
2281
2282 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2283
2284 std::string result;
2285 ConsumeFd(std::move(output_fd), &result);
2286
2287 std::string match_str;
2288 // Verify none.
2289 match_str = android::base::StringPrintf(
2290 " %s-%s --- 0 1000\\n",
2291 format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
2292 format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
2293 ASSERT_MATCH(result, match_str);
2294
2295 // Verify read-only.
2296 match_str = android::base::StringPrintf(
2297 " %s-%s r-- 0 1000\\n",
2298 format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
2299 format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
2300 ASSERT_MATCH(result, match_str);
2301
2302 // Verify write-only.
2303 match_str = android::base::StringPrintf(
2304 " %s-%s -w- 0 1000\\n",
2305 format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
2306 format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
2307 ASSERT_MATCH(result, match_str);
2308
2309 // Verify exec-only.
2310 match_str = android::base::StringPrintf(
2311 " %s-%s --x 0 1000\\n",
2312 format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
2313 format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
2314 ASSERT_MATCH(result, match_str);
2315
2316 // Verify file map with non-zero offset and a name.
2317 match_str = android::base::StringPrintf(
2318 " %s-%s r-- 2000 4000 %s\\n",
2319 format_map_pointer(reinterpret_cast<uintptr_t>(file_map)).c_str(),
2320 format_map_pointer(reinterpret_cast<uintptr_t>(file_map) + 0x3fff).c_str(), tf.path);
2321 ASSERT_MATCH(result, match_str);
2322}
2323
2324// Verify that the tombstone map data is correct.
2325TEST_F(CrasherTest, verify_header) {
2326 StartProcess([]() { abort(); });
2327
2328 unique_fd output_fd;
2329 StartIntercept(&output_fd);
2330 FinishCrasher();
2331 AssertDeath(SIGABRT);
2332 int intercept_result;
2333 FinishIntercept(&intercept_result);
2334
2335 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2336
2337 std::string result;
2338 ConsumeFd(std::move(output_fd), &result);
2339
2340 std::string match_str = android::base::StringPrintf(
2341 "Build fingerprint: '%s'\\nRevision: '%s'\\n",
2342 android::base::GetProperty("ro.build.fingerprint", "unknown").c_str(),
2343 android::base::GetProperty("ro.revision", "unknown").c_str());
2344 match_str += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
2345 ASSERT_MATCH(result, match_str);
2346}
2347
2348// Verify that the thread header is formatted properly.
2349TEST_F(CrasherTest, verify_thread_header) {
2350 void* shared_map =
2351 mmap(nullptr, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2352 ASSERT_NE(MAP_FAILED, shared_map);
2353 memset(shared_map, 0, sizeof(pid_t));
2354
2355 StartProcess([&shared_map]() {
2356 std::atomic_bool tid_written;
2357 std::thread thread([&tid_written, &shared_map]() {
2358 pid_t tid = gettid();
2359 memcpy(shared_map, &tid, sizeof(pid_t));
2360 tid_written = true;
2361 volatile bool done = false;
2362 while (!done)
2363 ;
2364 });
2365 thread.detach();
2366 while (!tid_written.load(std::memory_order_acquire))
2367 ;
2368 abort();
2369 });
2370
2371 pid_t primary_pid = crasher_pid;
2372
2373 unique_fd output_fd;
2374 StartIntercept(&output_fd);
2375 FinishCrasher();
2376 AssertDeath(SIGABRT);
2377 int intercept_result;
2378 FinishIntercept(&intercept_result);
2379 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2380
2381 // Read the tid data out.
2382 pid_t tid;
2383 memcpy(&tid, shared_map, sizeof(pid_t));
2384 ASSERT_NE(0, tid);
2385
2386 ASSERT_EQ(0, munmap(shared_map, sizeof(pid_t)));
2387
2388 std::string result;
2389 ConsumeFd(std::move(output_fd), &result);
2390
2391 // Verify that there are two headers, one where the tid is "primary_pid"
2392 // and the other where the tid is "tid".
2393 std::string match_str = android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n",
2394 primary_pid, primary_pid);
2395 ASSERT_MATCH(result, match_str);
2396
2397 match_str =
2398 android::base::StringPrintf("pid: %d, tid: %d, name: .* >>> .* <<<\\n", primary_pid, tid);
2399 ASSERT_MATCH(result, match_str);
2400}
2401
2402// Verify that there is a BuildID present in the map section and set properly.
2403TEST_F(CrasherTest, verify_build_id) {
2404 StartProcess([]() { abort(); });
2405
2406 unique_fd output_fd;
2407 StartIntercept(&output_fd);
2408 FinishCrasher();
2409 AssertDeath(SIGABRT);
2410 int intercept_result;
2411 FinishIntercept(&intercept_result);
2412 ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
2413
2414 std::string result;
2415 ConsumeFd(std::move(output_fd), &result);
2416
2417 // Find every /system or /apex lib and verify the BuildID is displayed
2418 // properly.
2419 bool found_valid_elf = false;
2420 std::smatch match;
2421 std::regex build_id_regex(R"( ((/system/|/apex/)\S+) \(BuildId: ([^\)]+)\))");
2422 for (std::string prev_file; std::regex_search(result, match, build_id_regex);
2423 result = match.suffix()) {
2424 if (prev_file == match[1]) {
2425 // Already checked this file.
2426 continue;
2427 }
2428
2429 prev_file = match[1];
2430 unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(prev_file, 0).release());
2431 if (!elf.Init() || !elf.valid()) {
2432 // Skipping invalid elf files.
2433 continue;
2434 }
2435 ASSERT_EQ(match[3], elf.GetPrintableBuildID());
2436
2437 found_valid_elf = true;
2438 }
2439 ASSERT_TRUE(found_valid_elf) << "Did not find any elf files with valid BuildIDs to check.";
2440}