From: "Serge E. Hallyn" <serue@us.ibm.com>
To: "Serge E. Hallyn" <serue@us.ibm.com>
Cc: lkml <linux-kernel@vger.kernel.org>,
linux-fsdevel <linux-fsdevel@vger.kernel.org>,
James Morris <jmorris@namei.org>,
Stephen Smalley <sds@tycho.nsa.gov>,
Andrew Morton <akpm@linux-foundation.org>,
jeffschroeder@computer.org, Chris Wright <chrisw@sous-sol.org>,
Karl MacMillan <kmacmillan@mentalrootkit.com>,
KaiGai Kohei <kaigai@kaigai.gr.jp>
Subject: [PATCH 2/2] file capabilities: accomodate >32 bit capabilities
Date: Tue, 8 May 2007 14:17:04 -0500 [thread overview]
Message-ID: <20070508191704.GC29913@sergelap.austin.ibm.com> (raw)
In-Reply-To: <20070508191548.GA29913@sergelap.austin.ibm.com>
From: Serge E. Hallyn <serue@us.ibm.com>
Subject: [PATCH 2/2] file capabilities: accomodate >32 bit capabilities
(Changelog: fixed syntax error in dummy version of check_cap_sanity())
As the capability set changes and distributions start tagging
binaries with capabilities, we would like for running an older
kernel to not necessarily make those binaries unusable.
(0. Enable the CONFIG_SECURITY_FS_CAPABILITIES option
when CONFIG_SECURITY=n.)
(1. Rename CONFIG_SECURITY_FS_CAPABILITIES to
CONFIG_SECURITY_FILE_CAPABILITIES)
2. Introduce CONFIG_SECURITY_FILE_CAPABILITIES_STRICTXATTR
which, when set, prevents loading binaries with capabilities
set which the kernel doesn't know about. When not set,
such capabilities run, ignoring the unknown caps.
3. To accomodate 64-bit caps, specify that capabilities are
stored as
u32 version; u32 eff0; u32 perm0; u32 inh0;
u32 eff1; u32 perm1; u32 inh1; (etc)
Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: James Morris <jmorris@namei.org>
Cc: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/capability.h | 23 ++++-
security/Kconfig | 14 ++-
security/commoncap.c | 157 ++++++++++++++++++++++-------------
3 files changed, 132 insertions(+), 62 deletions(-)
diff -puN include/linux/capability.h~file-capabilities-accomodate-future-64-bit-caps include/linux/capability.h
--- a/include/linux/capability.h~file-capabilities-accomodate-future-64-bit-caps
+++ a/include/linux/capability.h
@@ -44,11 +44,28 @@ typedef struct __user_cap_data_struct {
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+
+/* size of caps that we work with */
+#define XATTR_CAPS_SZ (4*sizeof(__le32))
+
+/*
+ * data[] is organized as:
+ * effective[0]
+ * permitted[0]
+ * inheritable[0]
+ * effective[1]
+ * ...
+ * this way we can just read as much of the on-disk capability as
+ * we know should exist and know we'll get the data we'll need.
+ */
struct vfs_cap_data_disk {
__le32 version;
- __le32 effective;
- __le32 permitted;
- __le32 inheritable;
+ __le32 data[]; /* eff[0], perm[0], inh[0], eff[1], ... */
+};
+
+struct vfs_cap_data_disk_v1 {
+ __le32 version;
+ __le32 data[3]; /* eff[0], perm[0], inh[0] */
};
#ifdef __KERNEL__
diff -puN security/commoncap.c~file-capabilities-accomodate-future-64-bit-caps security/commoncap.c
--- a/security/commoncap.c~file-capabilities-accomodate-future-64-bit-caps
+++ a/security/commoncap.c
@@ -110,36 +110,73 @@ void cap_capset_set (struct task_struct
target->cap_permitted = *permitted;
}
-#ifdef CONFIG_SECURITY_FS_CAPABILITIES
-static inline void cap_from_disk(struct vfs_cap_data_disk *dcap,
- struct vfs_cap_data *cap)
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES_STRICTXATTR
+static int check_cap_sanity(struct vfs_cap_data_disk *dcap, int size)
{
- cap->version = le32_to_cpu(dcap->version);
- cap->effective = le32_to_cpu(dcap->effective);
- cap->permitted = le32_to_cpu(dcap->permitted);
- cap->inheritable = le32_to_cpu(dcap->inheritable);
+ int word, bit;
+ u32 eff, inh, perm;
+ int sz = (size-1)/3;
+
+ word = CAP_NUMCAPS / 32;
+ bit = CAP_NUMCAPS % 32;
+
+ eff = le32_to_cpu(dcap->data[3*word]);
+ perm = le32_to_cpu(dcap->data[3*word+1]);
+ inh = le32_to_cpu(dcap->data[3*word+2]);
+
+ while (word < sz) {
+ if (bit == 32) {
+ bit = 0;
+ word++;
+ if (word >= sz)
+ break;
+ eff = le32_to_cpu(dcap->data[3*word]);
+ perm = le32_to_cpu(dcap->data[3*word+1]);
+ inh = le32_to_cpu(dcap->data[3*word+2]);
+ continue;
+ }
+ if (eff & CAP_TO_MASK(bit))
+ return -EINVAL;
+ if (inh & CAP_TO_MASK(bit))
+ return -EINVAL;
+ if (perm & CAP_TO_MASK(bit))
+ return -EINVAL;
+ bit++;
+ }
+
+ return 0;
}
+#else
+static int check_cap_sanity(struct vfs_cap_data_disk *dcap, int sz)
+{ return 0; }
+#endif
-static int check_cap_sanity(struct vfs_cap_data *cap)
+static inline int cap_from_disk(struct vfs_cap_data_disk *dcap,
+ struct linux_binprm *bprm, int size)
{
- int i;
+ int rc, version;
- if (cap->version != _LINUX_CAPABILITY_VERSION)
- return -EPERM;
+ version = le32_to_cpu(dcap->version);
+ if (version != _LINUX_CAPABILITY_VERSION)
+ return -EINVAL;
- for (i = CAP_NUMCAPS; i < 8*sizeof(cap->effective); i++) {
- if (cap->effective & CAP_TO_MASK(i))
- return -EPERM;
- }
- for (i = CAP_NUMCAPS; i < 8*sizeof(cap->permitted); i++) {
- if (cap->permitted & CAP_TO_MASK(i))
- return -EPERM;
- }
- for (i = CAP_NUMCAPS; i < 8*sizeof(cap->inheritable); i++) {
- if (cap->inheritable & CAP_TO_MASK(i))
- return -EPERM;
+ size /= sizeof(u32);
+ if ((size-1)%3) {
+ printk(KERN_WARNING "%s: size is an invalid size (%d)\n",
+ __FUNCTION__, size);
+ return -EINVAL;
}
+ rc = check_cap_sanity(dcap, size);
+ if (rc)
+ return rc;
+
+ bprm->cap_effective = le32_to_cpu(dcap->data[0]);
+ bprm->cap_permitted = le32_to_cpu(dcap->data[1]);
+ bprm->cap_inheritable = le32_to_cpu(dcap->data[2]);
+
return 0;
}
@@ -147,52 +184,58 @@ static int check_cap_sanity(struct vfs_c
static int set_file_caps(struct linux_binprm *bprm)
{
struct dentry *dentry;
- ssize_t rc;
- struct vfs_cap_data_disk dcaps;
- struct vfs_cap_data caps;
+ int rc;
+ struct vfs_cap_data_disk_v1 v1caps;
+ struct vfs_cap_data_disk *dcaps;
struct inode *inode;
- int err;
+ dcaps = (struct vfs_cap_data_disk *)&v1caps;
if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
return 0;
dentry = dget(bprm->file->f_dentry);
inode = dentry->d_inode;
- if (!inode->i_op || !inode->i_op->getxattr) {
- dput(dentry);
- return 0;
- }
-
- rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &dcaps,
- sizeof(dcaps));
- dput(dentry);
-
- if (rc == -ENODATA)
- return 0;
-
- if (rc < 0) {
- printk(KERN_NOTICE "%s: Error (%zd) getting xattr\n",
- __FUNCTION__, rc);
- return rc;
+ rc = 0;
+ if (!inode->i_op || !inode->i_op->getxattr)
+ goto out;
+
+ rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, dcaps,
+ XATTR_CAPS_SZ);
+ if (rc == -ENODATA || rc == -EOPNOTSUPP) {
+ rc = 0;
+ goto out;
+ }
+ if (rc == -ERANGE) {
+ int size;
+ size = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
+ if (size <= 0) { /* shouldn't ever happen */
+ rc = -EINVAL;
+ goto out;
+ }
+ dcaps = kmalloc(size, GFP_KERNEL);
+ if (!dcaps) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, dcaps,
+ size);
}
-
- if (rc != sizeof(dcaps)) {
- printk(KERN_NOTICE "%s: got wrong size for getxattr (%zd)\n",
- __FUNCTION__, rc);
- return -EPERM;
+ if (rc < 0)
+ goto out;
+ if (rc < sizeof(struct vfs_cap_data_disk_v1)) {
+ rc = -EINVAL;
+ goto out;
}
- cap_from_disk(&dcaps, &caps);
- err = check_cap_sanity(&caps);
- if (err)
- return err;
-
- bprm->cap_effective = caps.effective;
- bprm->cap_permitted = caps.permitted;
- bprm->cap_inheritable = caps.inheritable;
+ rc = cap_from_disk(dcaps, bprm, rc);
- return 0;
+out:
+ dput(dentry);
+ if ((void *)dcaps != (void *)&v1caps)
+ kfree(dcaps);
+ return rc;
}
+
#else
static inline int set_file_caps(struct linux_binprm *bprm)
{
@@ -399,7 +442,7 @@ int cap_task_post_setuid (uid_t old_ruid
return 0;
}
-#ifdef CONFIG_SECURITY_FS_CAPABILITIES
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
/*
* Rationale: code calling task_setscheduler, task_setioprio, and
* task_setnice, assumes that
diff -puN security/Kconfig~file-capabilities-accomodate-future-64-bit-caps security/Kconfig
--- a/security/Kconfig~file-capabilities-accomodate-future-64-bit-caps
+++ a/security/Kconfig
@@ -80,9 +80,9 @@ config SECURITY_CAPABILITIES
This enables the "default" Linux capabilities functionality.
If you are unsure how to answer this question, answer Y.
-config SECURITY_FS_CAPABILITIES
+config SECURITY_FILE_CAPABILITIES
bool "File POSIX Capabilities"
- depends on SECURITY=n || SECURITY_CAPABILITIES=y
+ depends on SECURITY=n || SECURITY_CAPABILITIES!=n
default n
help
This enables filesystem capabilities, allowing you to give
@@ -90,6 +90,16 @@ config SECURITY_FS_CAPABILITIES
If in doubt, answer N.
+config SECURITY_FILE_CAPABILITIES_STRICTXATTR
+ bool "Refuse to run files with unknown caps"
+ 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
tristate "Root Plug Support"
depends on USB && SECURITY
_
next prev parent reply other threads:[~2007-05-08 19:17 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-08 19:15 [PATCH 0/2] file capabilities: Introduction Serge E. Hallyn
2007-05-08 19:16 ` [PATCH 1/2] file capabilities: implement file capabilities Serge E. Hallyn
2007-05-08 19:17 ` Serge E. Hallyn [this message]
2007-05-08 20:58 ` [PATCH 2/2] file capabilities: accomodate >32 bit capabilities Andreas Dilger
2007-05-08 21:49 ` Serge E. Hallyn
2007-05-10 20:01 ` Andreas Dilger
2007-05-11 6:09 ` Suparna Bhattacharya
2007-05-14 17:26 ` Serge E. Hallyn
2007-05-08 20:05 ` [PATCH 0/2] file capabilities: Introduction Andrew Morton
2007-05-14 20:00 ` Pavel Machek
2007-05-17 5:57 ` Suparna Bhattacharya
2007-05-17 12:51 ` Serge E. Hallyn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070508191704.GC29913@sergelap.austin.ibm.com \
--to=serue@us.ibm.com \
--cc=akpm@linux-foundation.org \
--cc=chrisw@sous-sol.org \
--cc=jeffschroeder@computer.org \
--cc=jmorris@namei.org \
--cc=kaigai@kaigai.gr.jp \
--cc=kmacmillan@mentalrootkit.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=sds@tycho.nsa.gov \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).