Merge changes I32567010,I400d5991 am: 1d26b40ed5 am: 1e4efdaeac am: 2e0997bccd
am: 2a80862300

Change-Id: I7f836dea2e4976896d68ea9c382ed07144862b9d
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 64a38dd..cd45bbb 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 
 // We test both kinds of logging.
@@ -189,6 +190,8 @@
     fprintf(stderr, "  readdir-NULL          pass a null pointer to readdir\n");
     fprintf(stderr, "  strlen-NULL           pass a null pointer to strlen\n");
     fprintf(stderr, "\n");
+    fprintf(stderr, "  no_new_privs          set PR_SET_NO_NEW_PRIVS and then abort\n");
+    fprintf(stderr, "\n");
     fprintf(stderr, "prefix any of the above with 'thread-' to run on a new thread\n");
     fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
     fprintf(stderr, "all available file descriptors before crashing.\n");
@@ -276,6 +279,12 @@
     } else if (!strcasecmp(arg, "kuser_cmpxchg64")) {
         return __kuser_cmpxchg64(0, 0, 0);
 #endif
+    } else if (!strcasecmp(arg, "no_new_privs")) {
+        if (prctl(PR_SET_NO_NEW_PRIVS, 1) != 0) {
+          fprintf(stderr, "prctl(PR_SET_NO_NEW_PRIVS, 1) failed: %s\n", strerror(errno));
+          return EXIT_SUCCESS;
+        }
+        abort();
     } else {
         return usage();
     }
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 353f642..cb8f017 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -174,6 +174,41 @@
   return (old_action.sa_flags & SA_SIGINFO) != 0;
 }
 
+static void raise_caps() {
+  // Raise CapInh to match CapPrm, so that we can set the ambient bits.
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  if (capget(&capheader, &capdata[0]) == -1) {
+    fatal_errno("capget failed");
+  }
+
+  if (capdata[0].permitted != capdata[0].inheritable ||
+      capdata[1].permitted != capdata[1].inheritable) {
+    capdata[0].inheritable = capdata[0].permitted;
+    capdata[1].inheritable = capdata[1].permitted;
+
+    if (capset(&capheader, &capdata[0]) == -1) {
+      __libc_format_log(ANDROID_LOG_ERROR, "libc", "capset failed: %s", strerror(errno));
+    }
+  }
+
+  // Set the ambient capability bits so that crash_dump gets all of our caps and can ptrace us.
+  uint64_t capmask = capdata[0].inheritable;
+  capmask |= static_cast<uint64_t>(capdata[1].inheritable) << 32;
+  for (unsigned long i = 0; i < 64; ++i) {
+    if (capmask & (1 << i)) {
+      if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) != 0) {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to raise ambient capability %lu: %s",
+                          i, strerror(errno));
+      }
+    }
+  }
+}
+
 struct debugger_thread_info {
   bool crash_dump_started;
   pid_t crashing_tid;
@@ -217,10 +252,7 @@
     close(pipefds[0]);
     close(pipefds[1]);
 
-    // Set all of the ambient capability bits we can, so that crash_dump can ptrace us.
-    for (unsigned long i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) != -1; ++i) {
-      prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
-    }
+    raise_caps();
 
     char buf[10];
     snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid);