[RFC][PATCH 1/1] support optional non-VFS capability inheritance without disabling file caps

From: Will Drewry
Date: Fri Aug 14 2009 - 00:15:30 EST


Capabilities marked as inheritable (+i) are inaccessible when inherited
by a child process (after exec()) with CONFIG_SECURITY_FILE_CAPABILITIES
enabled unless the VFS entry of the child also provides the capability (or
cap_setpcap) in the permitted/effective sets.

This change adds a securebit, SECURE_INHERIT_CAPS, which enableÑ
inherited capabilities to be propagated to the permitted set of the
child process. If it doesn't conflict with VFS_CAP_FLAGS_EFFECTIVE, it
will also mark the capabilities effective. This bit and change only
take effect when SECURE_NOROOT is set.

The securebit guard is used because this change violates the following
constraint:
pP' = (X & fP) | (pI & fI)
With bit-6 enabled, the constraint becomes:
pP' = (X & fP) | (pI)
and pE' varying based on VFS bits and if there are any file-based capabilities.

This allows for a purely runtime capabilities-based environment without
requiring every file to be annotated with an extended attribute. This
also means that SECURE_NOROOT process trees using capabilities become
more accessible, especially for filesystems without extended attribute
support - or in mixed FS environments.

For example, a daemon like dhcpcd may be launched with cap_net_raw by a
more privileged daemon. Once dhcpcd drops the cap_net_raw privilege, it
will not be able to regain it. Even if a local user runs dhcpcd
manually, the capability will not be granted because the capability was
not derived from the filesystem. However, the calling capability
manager could either gain its permissions from init or by having a
file-based capability set.

Nb, I may be missing something obvious - any insights will be appreciated,
and there is a good bit of flexibility in what can be done here.

Signed-off-by: Will Drewry <redpig@xxxxxxxxxxxxx>
---
include/linux/securebits.h | 12 +++++++++++-
security/commoncap.c | 7 +++++++
2 files changed, 18 insertions(+), 1 deletions(-)

diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index d2c5ed8..ed50b80 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -27,6 +27,15 @@
#define SECURE_KEEP_CAPS 4
#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */

+/* When set, any capabilities inherited from a parent process will
+ start in the permitted, and possibly effective, capability set
+ if SECURE_NOROOT is set.
+ pP' = (X & fP) | (pI & fI)
+ becomes
+ pP' = (X & fP) | (pI) */
+#define SECURE_INHERIT_CAPS 6
+#define SECURE_INHERIT_CAPS_LOCKED 7 /* make bit-6 immutable */
+
/* Each securesetting is implemented using two bits. One bit specifies
whether the setting is on or off. The other bit specify whether the
setting is locked or not. A setting which is locked cannot be
@@ -36,7 +45,8 @@

#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
issecure_mask(SECURE_NO_SETUID_FIXUP) | \
- issecure_mask(SECURE_KEEP_CAPS))
+ issecure_mask(SECURE_KEEP_CAPS) | \
+ issecure_mask(SECURE_INHERIT_CAPS))
#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)

#endif /* !_LINUX_SECUREBITS_H */
diff --git a/security/commoncap.c b/security/commoncap.c
index 48b7e02..9b4590d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -508,6 +508,13 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
}
if (new->euid == 0)
effective = true;
+ } else if (issecure(SECURE_INHERIT_CAPS)) {
+ /* Only enable permitted-to-effective inheritance if it doesn't
+ * override VFS_CAP_FLAGS_EFFECTIVE behavior. */
+ if (!effective && cap_isclear(new->cap_permitted))
+ effective = true;
+ new->cap_permitted = cap_combine(new->cap_permitted,
+ new->cap_inheritable);
}
skip:
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/