Andrew, James, Stephen, Chris,

The following is all-but-untested (just compiles with relevant config
combinations).  But is each of you ok with the following approach for
handling unknown capabilities?

KaiGai,  the following does not require any immediate change from
libcap, but does dictate how 64-bit capabilities would be formed.
Please let me know if you have an objection.

thanks,
-serge

>From 64284b5cff82a713d31247f37c2e8b393faa30d3 Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <[EMAIL PROTECTED]>
Date: Mon, 6 Aug 2007 17:45:05 -0400
Subject: [PATCH 1/1] file capabilities: don't ensure we break with 64-bit caps

We are currently using all 32 capability bits, so it seems
all but certain that we will be using 64-bit capabilities
soon.

Meanwhile there is disagreement about whether the kernel
should load binaries which have file capabilities for unknown
kernels or not.

This patch introduces a config variable, as well as a
64-bit file capability format.  If
SECURITY_FILE_CAPABILITIES_STRICTXATTR=y then any file
with 64-bit capabilities will refuse to load.  If
SECURITY_FILE_CAPABILITIES_STRICTXATTR=n, then any file
with 64-bit capabilities will load, ignoring unknown
capabilities.

The introduction of a 64-bit file capability format for
the extended attributes must happen now to ensure that
those who wish to use STRICTXATTR=n aren't foiled when
the 33d capability bit is introduced.

Signed-off-by: Serge E. Hallyn <[EMAIL PROTECTED]>
---
 include/linux/capability.h |   15 ++++++++++++++-
 security/Kconfig           |   10 ++++++++++
 security/commoncap.c       |   42 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/include/linux/capability.h b/include/linux/capability.h
index 8961e7f..390443a 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -46,8 +46,10 @@ typedef struct __user_cap_data_struct {
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
 #define XATTR_CAPS_SZ (3*sizeof(__le32))
+#define XATTR_CAPS_SZ_64 (5*sizeof(__le32))
 #define VFS_CAP_REVISION_MASK  0xFF000000
-#define VFS_CAP_REVISION_1     0x01000000
+#define VFS_CAP_REVISION_1     0x01000000  /* 32-bit caps */
+#define VFS_CAP_REVISION_2     0x02000000  /* 64-bit caps */
 
 #define VFS_CAP_REVISION       VFS_CAP_REVISION_1
 
@@ -62,6 +64,17 @@ struct vfs_cap_data {
        } data[1];
 };
 
+#define VFS_CAP_HIBIT_MASK 0xFFFFFFFF
+struct vfs_cap_data_v2 {
+       __u32 magic_etc;  /* Little endian */
+       struct {
+               __u32 permitted_lo;    /* Little endian */
+               __u32 permitted_hi;    /* Little endian */
+               __u32 inheritable_lo;  /* Little endian */
+               __u32 inheritable_hi;  /* Little endian */
+       } data[1];
+};
+
 #ifdef __KERNEL__
 
 /* #define STRICT_CAP_T_TYPECHECKS */
diff --git a/security/Kconfig b/security/Kconfig
index 8086e61..77e34de 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -90,6 +90,16 @@ config SECURITY_FILE_CAPABILITIES
 
          If in doubt, answer N.
 
+config SECURITYFILE_CAPS_STRICT
+       bool "Refuse to run files with unknown capabilities"
+       depends on SECURITY_FILE_CAPABILITIES
+       default y
+       help
+         Refuse to run files which have unknown capabilities set
+         in the security.capability xattr.  This could prevent
+         running important binaries from an updated distribution
+         on an older kernel.
+
 config SECURITY_ROOTPLUG
        bool "Root Plug Support"
        depends on USB=y && SECURITY
diff --git a/security/commoncap.c b/security/commoncap.c
index aa6d929..25ac8ec 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -119,18 +119,50 @@ static inline void bprm_clear_caps(struct linux_binprm 
*bprm)
 
 #ifdef CONFIG_SECURITY_FILE_CAPABILITIES
 
+#ifdef CONFIG_SECURITYFILE_CAPS_STRICT
+static inline int read_v2_caps(__le32 *caps, struct linux_binprm *bprm)
+{
+       if ((le32_to_cpu(caps[2]) & VFS_CAP_HIBIT_MASK) ||
+                       (le32_to_cpu(caps[4]) & VFS_CAP_HIBIT_MASK))
+               return -EINVAL;
+
+       bprm->cap_permitted = to_cap_t( le32_to_cpu(caps[1]) );
+       bprm->cap_inheritable = to_cap_t( le32_to_cpu(caps[3]) );
+       return 0;
+}
+#else
+static inline int read_v2_caps(__le32 *caps, struct linux_binprm *bprm)
+{
+       bprm->cap_permitted = to_cap_t( le32_to_cpu(caps[1]) );
+       bprm->cap_inheritable = to_cap_t( le32_to_cpu(caps[3]) );
+       return 0;
+}
+#endif
+
+static inline int cap_size_valid(int size)
+{
+       if (size == XATTR_CAPS_SZ)
+               return 1;
+#ifndef CONFIG_SECURITYFILE_CAPS_STRICT
+       if (size == XATTR_CAPS_SZ)
+               return 1;
+#endif
+       return 0;
+
+}
+
 static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm,
                                int size)
 {
        __u32 magic_etc;
 
-       if (size != XATTR_CAPS_SZ)
+       if (!cap_size_valid(size))
                return -EINVAL;
 
        magic_etc = le32_to_cpu(caps[0]);
 
        switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
-       case VFS_CAP_REVISION:
+       case VFS_CAP_REVISION_1:
                if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
                        bprm->cap_effective = true;
                else
@@ -138,6 +170,12 @@ static inline int cap_from_disk(__le32 *caps, struct 
linux_binprm *bprm,
                bprm->cap_permitted = to_cap_t( le32_to_cpu(caps[1]) );
                bprm->cap_inheritable = to_cap_t( le32_to_cpu(caps[2]) );
                return 0;
+       case VFS_CAP_REVISION_2:
+               if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
+                       bprm->cap_effective = true;
+               else
+                       bprm->cap_effective = false;
+               return read_v2_caps(caps, bprm);
        default:
                return -EINVAL;
        }
-- 
1.5.1.1.GIT

-
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to