minijail: Avoid setting PR_SET_KEEPCAPS if that bit is locked
am: 89cbc32f00

Change-Id: Ia17af21dd531cf61aaf47fe3c985217a5ffc346d
diff --git a/libminijail.c b/libminijail.c
index 6804ebb..144e5da 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -2056,15 +2056,22 @@
 		drop_capbset(j->cap_bset, last_valid_cap);
 	}
 
+	/*
+	 * POSIX capabilities are a bit tricky. If we drop our capability to
+	 * change uids, our attempt to use drop_ugid() below will fail. Hang on
+	 * to root caps across drop_ugid(), then lock securebits.
+	 */
 	if (j->flags.use_caps) {
 		/*
-		 * POSIX capabilities are a bit tricky. If we drop our
-		 * capability to change uids, our attempt to use setuid()
-		 * below will fail. Hang on to root caps across setuid(), then
-		 * lock securebits.
+		 * Using ambient capabilities takes care of most of the cases
+		 * where PR_SET_KEEPCAPS would be needed, but still try to set
+		 * them unless it is locked (maybe due to running minijail
+		 * within an already-minijailed process).
 		 */
-		if (prctl(PR_SET_KEEPCAPS, 1))
-			pdie("prctl(PR_SET_KEEPCAPS) failed");
+		if (!j->flags.set_ambient_caps || !secure_keep_caps_locked()) {
+			if (prctl(PR_SET_KEEPCAPS, 1))
+				pdie("prctl(PR_SET_KEEPCAPS) failed");
+		}
 
 		if (lock_securebits(j->securebits_skip_mask) < 0) {
 			pdie("locking securebits failed");
diff --git a/system.c b/system.c
index 434980a..9852be7 100644
--- a/system.c
+++ b/system.c
@@ -44,6 +44,14 @@
 _Static_assert(SECURE_ALL_BITS == 0x55, "SECURE_ALL_BITS == 0x55.");
 #endif
 
+int secure_keep_caps_locked(void)
+{
+	int bits = prctl(PR_GET_SECUREBITS);
+	if (bits < 0)
+		return 0;
+	return bits & SECBIT_KEEP_CAPS_LOCKED;
+}
+
 int secure_noroot_set_and_locked(uint64_t mask)
 {
 	return (mask & (SECBIT_NOROOT | SECBIT_NOROOT_LOCKED)) ==
diff --git a/system.h b/system.h
index c21f7f3..5007981 100644
--- a/system.h
+++ b/system.h
@@ -38,6 +38,7 @@
 #define PR_CAP_AMBIENT_CLEAR_ALL 4
 #endif
 
+int secure_keep_caps_locked(void);
 int secure_noroot_set_and_locked(uint64_t mask);
 int lock_securebits(uint64_t skip_mask);