Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd0e0db3 authored by Josh Gao's avatar Josh Gao Committed by Gerrit Code Review
Browse files

Merge "debuggerd: add seccomp policies and tests."

parents 658e4ddd e04ca279
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -195,6 +195,7 @@ cc_test {
        "libcutils",
        "libdebuggerd_client",
        "liblog",
        "libminijail",
        "libnativehelper"
    ],

debuggerd/Android.mk

0 → 100644
+23 −0
Original line number Diff line number Diff line
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := crash_dump.policy
LOCAL_MODULE_CLASS := ETC
LOCAL_MULTILIB := both

ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
LOCAL_MODULE_STEM_32 := crash_dump.arm.policy
LOCAL_MODULE_STEM_64 := crash_dump.arm64.policy
endif

ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64))
LOCAL_MODULE_STEM_32 := crash_dump.x86.policy
LOCAL_MODULE_STEM_64 := crash_dump.x86_64.policy
endif

LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
LOCAL_SRC_FILES_arm := seccomp_policy/crash_dump.arm.policy
LOCAL_SRC_FILES_arm64 := seccomp_policy/crash_dump.arm64.policy
LOCAL_SRC_FILES_x86 := seccomp_policy/crash_dump.x86.policy
LOCAL_SRC_FILES_x86_64 := seccomp_policy/crash_dump.x86_64.policy
include $(BUILD_PREBUILT)
+140 −3
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@
#include <cutils/sockets.h>
#include <gtest/gtest.h>

#include <libminijail.h>
#include <scoped_minijail.h>

#include "debuggerd/handler.h"
#include "protocol.h"
#include "tombstoned/tombstoned.h"
@@ -77,8 +80,7 @@ constexpr char kWaitForGdbKey[] = "debug.debuggerd.wait_for_gdb";
  }()

#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
  ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
                       R"(/libc.so \()" frame_name R"(\+)")
  ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");

static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
                                 InterceptStatus* status, DebuggerdDumpType intercept_type) {
@@ -565,6 +567,141 @@ TEST_F(CrasherTest, fake_pid) {
  ASSERT_BACKTRACE_FRAME(result, "tgkill");
}

static const char* const kDebuggerdSeccompPolicy =
    "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";

pid_t seccomp_fork() {
  unique_fd policy_fd(open(kDebuggerdSeccompPolicy, O_RDONLY | O_CLOEXEC));
  if (policy_fd == -1) {
    LOG(FATAL) << "failed to open policy " << kDebuggerdSeccompPolicy;
  }

  ScopedMinijail jail{minijail_new()};
  if (!jail) {
    LOG(FATAL) << "failed to create minijail";
  }

  minijail_no_new_privs(jail.get());
  minijail_log_seccomp_filter_failures(jail.get());
  minijail_use_seccomp_filter(jail.get());
  minijail_parse_seccomp_filters_from_fd(jail.get(), policy_fd.release());

  pid_t result = fork();
  if (result == -1) {
    return result;
  } else if (result != 0) {
    return result;
  }

  // Spawn and detach a thread that spins forever.
  std::atomic<bool> thread_ready(false);
  std::thread thread([&jail, &thread_ready]() {
    minijail_enter(jail.get());
    thread_ready = true;
    for (;;)
      ;
  });
  thread.detach();

  while (!thread_ready) {
    continue;
  }

  minijail_enter(jail.get());
  return result;
}

TEST_F(CrasherTest, seccomp_crash) {
  int intercept_result;
  unique_fd output_fd;

  StartProcess([]() { abort(); }, &seccomp_fork);

  StartIntercept(&output_fd);
  FinishCrasher();
  AssertDeath(SIGABRT);
  FinishIntercept(&intercept_result);
  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";

  std::string result;
  ConsumeFd(std::move(output_fd), &result);
  ASSERT_BACKTRACE_FRAME(result, "abort");
}

__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
  siginfo_t siginfo;
  siginfo.si_code = SI_QUEUE;
  siginfo.si_pid = getpid();
  siginfo.si_uid = getuid();

  if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
    PLOG(FATAL) << "invalid dump type";
  }

  siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;

  if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
    PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
    return false;
  }

  return true;
}

TEST_F(CrasherTest, seccomp_tombstone) {
  int intercept_result;
  unique_fd output_fd;

  static const auto dump_type = kDebuggerdTombstone;
  StartProcess(
      []() {
        raise_debugger_signal(dump_type);
        _exit(0);
      },
      &seccomp_fork);

  StartIntercept(&output_fd, dump_type);
  FinishCrasher();
  AssertDeath(0);
  FinishIntercept(&intercept_result);
  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";

  std::string result;
  ConsumeFd(std::move(output_fd), &result);
  ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
}

TEST_F(CrasherTest, seccomp_backtrace) {
  int intercept_result;
  unique_fd output_fd;

  static const auto dump_type = kDebuggerdNativeBacktrace;
  StartProcess(
      []() {
        raise_debugger_signal(dump_type);
        _exit(0);
      },
      &seccomp_fork);

  StartIntercept(&output_fd, dump_type);
  FinishCrasher();
  AssertDeath(0);
  FinishIntercept(&intercept_result);
  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";

  std::string result;
  ConsumeFd(std::move(output_fd), &result);
  ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
}

TEST_F(CrasherTest, seccomp_crash_logcat) {
  StartProcess([]() { abort(); }, &seccomp_fork);
  FinishCrasher();

  // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
  AssertDeath(SIGABRT);
}

TEST_F(CrasherTest, competing_tracer) {
  int intercept_result;
  unique_fd output_fd;
+37 −0
Original line number Diff line number Diff line
read: 1
write: 1
exit: 1
rt_sigreturn: 1
sigreturn: 1
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
sigaction: 1
geteuid32: 1
getgid32: 1
getegid32: 1
getgroups32: 1
+36 −0
Original line number Diff line number Diff line
read: 1
write: 1
exit: 1
rt_sigreturn: 1
exit_group: 1
clock_gettime: 1
gettimeofday: 1
futex: 1
getrandom: 1
getpid: 1
gettid: 1
ppoll: 1
pipe2: 1
openat: 1
dup: 1
close: 1
lseek: 1
getdents64: 1
faccessat: 1
recvmsg: 1
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
mprotect: arg2 in PROT_READ|PROT_WRITE
munmap: 1
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
rt_sigaction: 1
geteuid: 1
getgid: 1
getegid: 1
getgroups: 1
Loading