debuggerd_test: add capability test.

Also, remove the dependency on crasher.

Bug: http://b/35100921
Bug: http://b/35241370
Test: /data/nativetest/debuggerd_test/debuggerd_test32
Test: /data/nativetest64/debuggerd_test/debuggerd_test64
Change-Id: I318f6de764d435251417953bf175ba321b59981f
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index e22d6a9..1a27f3f 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -17,6 +17,7 @@
 #include <err.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/types.h>
 
@@ -24,6 +25,8 @@
 #include <regex>
 #include <thread>
 
+#include <android/set_abort_message.h>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
@@ -40,10 +43,8 @@
 using android::base::unique_fd;
 
 #if defined(__LP64__)
-#define CRASHER_PATH  "/system/bin/crasher64"
 #define ARCH_SUFFIX "64"
 #else
-#define CRASHER_PATH "/system/bin/crasher"
 #define ARCH_SUFFIX ""
 #endif
 
@@ -179,23 +180,14 @@
   if (crasher_pid == -1) {
     FAIL() << "fork failed: " << strerror(errno);
   } else if (crasher_pid == 0) {
-    unique_fd devnull(open("/dev/null", O_WRONLY));
-    dup2(crasher_read_pipe.get(), STDIN_FILENO);
-    dup2(devnull.get(), STDOUT_FILENO);
-    dup2(devnull.get(), STDERR_FILENO);
+    char dummy;
+    crasher_pipe.reset();
+    TEMP_FAILURE_RETRY(read(crasher_read_pipe.get(), &dummy, 1));
     function();
     _exit(0);
   }
 }
 
-void CrasherTest::StartCrasher(const std::string& crash_type) {
-  std::string type = "wait-" + crash_type;
-  StartProcess([type]() {
-    execl(CRASHER_PATH, CRASHER_PATH, type.c_str(), nullptr);
-    exit(errno);
-  });
-}
-
 void CrasherTest::FinishCrasher() {
   if (crasher_pipe == -1) {
     FAIL() << "crasher pipe uninitialized";
@@ -249,7 +241,10 @@
 TEST_F(CrasherTest, smoke) {
   int intercept_result;
   unique_fd output_fd;
-  StartCrasher("SIGSEGV");
+  StartProcess([]() {
+    *reinterpret_cast<volatile char*>(0xdead) = '1';
+  });
+
   StartIntercept(&output_fd);
   FinishCrasher();
   AssertDeath(SIGSEGV);
@@ -265,7 +260,9 @@
 TEST_F(CrasherTest, abort) {
   int intercept_result;
   unique_fd output_fd;
-  StartCrasher("abort");
+  StartProcess([]() {
+    abort();
+  });
   StartIntercept(&output_fd);
   FinishCrasher();
   AssertDeath(SIGABRT);
@@ -281,7 +278,9 @@
 TEST_F(CrasherTest, signal) {
   int intercept_result;
   unique_fd output_fd;
-  StartCrasher("abort");
+  StartProcess([]() {
+    abort();
+  });
   StartIntercept(&output_fd);
 
   // Wait for a bit, or we might end up killing the process before the signal
@@ -303,7 +302,10 @@
 TEST_F(CrasherTest, abort_message) {
   int intercept_result;
   unique_fd output_fd;
-  StartCrasher("smash-stack");
+  StartProcess([]() {
+    android_set_abort_message("abort message goes here");
+    abort();
+  });
   StartIntercept(&output_fd);
   FinishCrasher();
   AssertDeath(SIGABRT);
@@ -313,13 +315,15 @@
 
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
-  ASSERT_MATCH(result, R"(Abort message: 'stack corruption detected \(-fstack-protector\)')");
+  ASSERT_MATCH(result, R"(Abort message: 'abort message goes here')");
 }
 
 TEST_F(CrasherTest, intercept_timeout) {
   int intercept_result;
   unique_fd output_fd;
-  StartCrasher("abort");
+  StartProcess([]() {
+    abort();
+  });
   StartIntercept(&output_fd);
 
   // Don't let crasher finish until we timeout.
@@ -338,7 +342,9 @@
   }
   sleep(1);
 
-  StartCrasher("abort");
+  StartProcess([]() {
+    abort();
+  });
   FinishCrasher();
 
   int status;
@@ -357,7 +363,9 @@
     FAIL() << "failed to enable wait_for_gdb";
   }
 
-  StartCrasher("abort");
+  StartProcess([]() {
+    abort();
+  });
   ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
   AssertDeath(SIGSEGV);
 }
@@ -366,7 +374,10 @@
   std::string result;
   int intercept_result;
   unique_fd output_fd;
-  StartCrasher("abort");
+
+  StartProcess([]() {
+    abort();
+  });
   StartIntercept(&output_fd);
 
   std::this_thread::sleep_for(500ms);
@@ -392,20 +403,78 @@
 }
 
 TEST_F(CrasherTest, PR_SET_DUMPABLE_0_crash) {
+  int intercept_result;
+  unique_fd output_fd;
   StartProcess([]() {
     prctl(PR_SET_DUMPABLE, 0);
-    volatile char* null = static_cast<char*>(nullptr);
-    *null = '\0';
+    abort();
   });
-  AssertDeath(SIGSEGV);
+
+  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_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
 }
 
-TEST_F(CrasherTest, PR_SET_DUMPABLE_0_raise) {
+TEST_F(CrasherTest, capabilities) {
+  ASSERT_EQ(0U, getuid()) << "capability test requires root";
+
   StartProcess([]() {
-    prctl(PR_SET_DUMPABLE, 0);
-    raise(SIGUSR1);
+    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
+      err(1, "failed to set PR_SET_KEEPCAPS");
+    }
+
+    if (setresuid(1, 1, 1) != 0) {
+      err(1, "setresuid failed");
+    }
+
+    __user_cap_header_struct capheader;
+    __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    // Turn on every third capability.
+    static_assert(CAP_LAST_CAP > 33, "CAP_LAST_CAP <= 32");
+    for (int i = 0; i < CAP_LAST_CAP; i += 3) {
+      capdata[CAP_TO_INDEX(i)].permitted |= CAP_TO_MASK(i);
+      capdata[CAP_TO_INDEX(i)].effective |= CAP_TO_MASK(i);
+    }
+
+    // Make sure CAP_SYS_PTRACE is off.
+    capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].permitted &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
+    capdata[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective &= ~(CAP_TO_MASK(CAP_SYS_PTRACE));
+
+    if (capset(&capheader, &capdata[0]) != 0) {
+      err(1, "capset failed");
+    }
+
+    if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0) != 0) {
+      err(1, "failed to drop ambient capabilities");
+    }
+
+    raise(SIGSYS);
   });
-  AssertDeath(SIGUSR1);
+
+  unique_fd output_fd;
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGSYS);
+
+  std::string result;
+  int intercept_result;
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
 }
 
 TEST(crash_dump, zombie) {