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);