Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 120649
b: refs/heads/master
c: c0b0044
h: refs/heads/master
i:
  120647: 058f5ee
v: v3
  • Loading branch information
Eric Paris authored and James Morris committed Nov 11, 2008
1 parent 2872717 commit a4cf63f
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 59 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9d36be76c55ad2c2bb29683b752b0d9ad2e4eeef
refs/heads/master: c0b004413a46a0a5744e6d2b85220fe9d2c33d48
7 changes: 7 additions & 0 deletions trunk/include/linux/capability.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ typedef struct kernel_cap_struct {
__u32 cap[_KERNEL_CAPABILITY_U32S];
} kernel_cap_t;

/* exact same as vfs_cap_data but in cpu endian and always filled completely */
struct cpu_vfs_cap_data {
__u32 magic_etc;
kernel_cap_t permitted;
kernel_cap_t inheritable;
};

#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))

Expand Down
129 changes: 71 additions & 58 deletions trunk/security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,17 +202,70 @@ int cap_inode_killpriv(struct dentry *dentry)
return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
}

static inline int cap_from_disk(struct vfs_cap_data *caps,
struct linux_binprm *bprm, unsigned size)
static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
struct linux_binprm *bprm)
{
unsigned i;
int ret = 0;

if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
bprm->cap_effective = true;
else
bprm->cap_effective = false;

CAP_FOR_EACH_U32(i) {
__u32 permitted = caps->permitted.cap[i];
__u32 inheritable = caps->inheritable.cap[i];

/*
* pP' = (X & fP) | (pI & fI)
*/
bprm->cap_post_exec_permitted.cap[i] =
(current->cap_bset.cap[i] & permitted) |
(current->cap_inheritable.cap[i] & inheritable);

if (permitted & ~bprm->cap_post_exec_permitted.cap[i]) {
/*
* insufficient to execute correctly
*/
ret = -EPERM;
}
}

/*
* For legacy apps, with no internal support for recognizing they
* do not have enough capabilities, we return an error if they are
* missing some "forced" (aka file-permitted) capabilities.
*/
return bprm->cap_effective ? ret : 0;
}

int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
{
struct inode *inode = dentry->d_inode;
__u32 magic_etc;
unsigned tocopy, i;
int ret;
int size;
struct vfs_cap_data caps;

memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));

if (!inode || !inode->i_op || !inode->i_op->getxattr)
return -ENODATA;

size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
XATTR_CAPS_SZ);
if (size == -ENODATA || size == -EOPNOTSUPP) {
/* no data, that's ok */
return -ENODATA;
}
if (size < 0)
return size;

if (size < sizeof(magic_etc))
return -EINVAL;

magic_etc = le32_to_cpu(caps->magic_etc);
cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);

switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
case VFS_CAP_REVISION_1:
Expand All @@ -229,55 +282,21 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
return -EINVAL;
}

if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
bprm->cap_effective = true;
} else {
bprm->cap_effective = false;
}

ret = 0;

CAP_FOR_EACH_U32(i) {
__u32 value_cpu;

if (i >= tocopy) {
/*
* Legacy capability sets have no upper bits
*/
bprm->cap_post_exec_permitted.cap[i] = 0;
continue;
}
/*
* pP' = (X & fP) | (pI & fI)
*/
value_cpu = le32_to_cpu(caps->data[i].permitted);
bprm->cap_post_exec_permitted.cap[i] =
(current->cap_bset.cap[i] & value_cpu) |
(current->cap_inheritable.cap[i] &
le32_to_cpu(caps->data[i].inheritable));
if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
/*
* insufficient to execute correctly
*/
ret = -EPERM;
}
if (i >= tocopy)
break;
cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
}

/*
* For legacy apps, with no internal support for recognizing they
* do not have enough capabilities, we return an error if they are
* missing some "forced" (aka file-permitted) capabilities.
*/
return bprm->cap_effective ? ret : 0;
return 0;
}

/* Locate any VFS capabilities: */
static int get_file_caps(struct linux_binprm *bprm)
{
struct dentry *dentry;
int rc = 0;
struct vfs_cap_data vcaps;
struct inode *inode;
struct cpu_vfs_cap_data vcaps;

bprm_clear_caps(bprm);

Expand All @@ -288,24 +307,18 @@ static int get_file_caps(struct linux_binprm *bprm)
return 0;

dentry = dget(bprm->file->f_dentry);
inode = dentry->d_inode;
if (!inode->i_op || !inode->i_op->getxattr)
goto out;

rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
XATTR_CAPS_SZ);
if (rc == -ENODATA || rc == -EOPNOTSUPP) {
/* no data, that's ok */
rc = 0;
rc = get_vfs_caps_from_disk(dentry, &vcaps);
if (rc < 0) {
if (rc == -EINVAL)
printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n",
__func__, rc, bprm->filename);
else if (rc == -ENODATA)
rc = 0;
goto out;
}
if (rc < 0)
goto out;

rc = cap_from_disk(&vcaps, bprm, rc);
if (rc == -EINVAL)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
__func__, rc, bprm->filename);
rc = bprm_caps_from_vfs_caps(&vcaps, bprm);

out:
dput(dentry);
Expand Down

0 comments on commit a4cf63f

Please sign in to comment.