minijail: Avoid setting PR_SET_KEEPCAPS if that bit is locked

This change avoids setting PR_SET_KEEPCAPS if the bit is locked and we
are using ambient capabilities. This allows using minijail from an
already-minijailed process.

Bug: 112030238
Test: make tests
Change-Id: Iafd5d2409dcb526048b84edfc8b8f29f30d0dd4c
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);