CRED: Neuter sys_capset()

Take away the ability for sys_capset() to affect processes other than current.

This means that current will not need to lock its own credentials when reading
them against interference by other processes.

This has effectively been the case for a while anyway, since:

 (1) Without LSM enabled, sys_capset() is disallowed.

 (2) With file-based capabilities, sys_capset() is neutered.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Acked-by: Andrew G. Morgan <morgan@kernel.org>
Acked-by: James Morris <jmorris@namei.org>
Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
David Howells 2008-11-14 10:39:14 +11:00 committed by James Morris
parent 8bbf4976b5
commit 1cdcbec1a3
6 changed files with 63 additions and 285 deletions

View File

@ -441,17 +441,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
current->fsgid = current->gid; current->fsgid = current->gid;
if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/* /* Clear the capabilities if we switch to a non-root user */
* Clear the capabilities if we switch to a non-root user
*/
#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
/*
* FIXME: There is a race here against sys_capset. The
* capabilities can change yet we will restore the old
* value below. We should hold task_capabilities_lock,
* but we cannot because user_path_at can sleep.
*/
#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
if (current->uid) if (current->uid)
old_cap = cap_set_effective(__cap_empty_set); old_cap = cap_set_effective(__cap_empty_set);
else else

View File

@ -53,8 +53,8 @@ extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent); extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_capset_check(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern void cap_capset_set(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_bprm_set_security(struct linux_binprm *bprm); extern int cap_bprm_set_security(struct linux_binprm *bprm);
extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe); extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm); extern int cap_bprm_secureexec(struct linux_binprm *bprm);
@ -1191,24 +1191,14 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return 0 if the capability sets were successfully obtained. * Return 0 if the capability sets were successfully obtained.
* @capset_check: * @capset_check:
* Check permission before setting the @effective, @inheritable, and * Check permission before setting the @effective, @inheritable, and
* @permitted capability sets for the @target process. * @permitted capability sets for the current process.
* Caveat: @target is also set to current if a set of processes is
* specified (i.e. all processes other than current and init or a
* particular process group). Hence, the capset_set hook may need to
* revalidate permission to the actual target process.
* @target contains the task_struct structure for target process.
* @effective contains the effective capability set. * @effective contains the effective capability set.
* @inheritable contains the inheritable capability set. * @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set. * @permitted contains the permitted capability set.
* Return 0 if permission is granted. * Return 0 if permission is granted.
* @capset_set: * @capset_set:
* Set the @effective, @inheritable, and @permitted capability sets for * Set the @effective, @inheritable, and @permitted capability sets for
* the @target process. Since capset_check cannot always check permission * the current process.
* to the real @target process, this hook may also perform permission
* checking to determine if the current process is allowed to set the
* capability sets of the @target process. However, this hook has no way
* of returning an error due to the structure of the sys_capset code.
* @target contains the task_struct structure for target process.
* @effective contains the effective capability set. * @effective contains the effective capability set.
* @inheritable contains the inheritable capability set. * @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set. * @permitted contains the permitted capability set.
@ -1303,12 +1293,10 @@ struct security_operations {
int (*capget) (struct task_struct *target, int (*capget) (struct task_struct *target,
kernel_cap_t *effective, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted); kernel_cap_t *inheritable, kernel_cap_t *permitted);
int (*capset_check) (struct task_struct *target, int (*capset_check) (kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted); kernel_cap_t *permitted);
void (*capset_set) (struct task_struct *target, void (*capset_set) (kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted); kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, int cap, int audit); int (*capable) (struct task_struct *tsk, int cap, int audit);
@ -1572,12 +1560,10 @@ int security_capget(struct task_struct *target,
kernel_cap_t *effective, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted); kernel_cap_t *permitted);
int security_capset_check(struct task_struct *target, int security_capset_check(kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted); kernel_cap_t *permitted);
void security_capset_set(struct task_struct *target, void security_capset_set(kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted); kernel_cap_t *permitted);
int security_capable(struct task_struct *tsk, int cap); int security_capable(struct task_struct *tsk, int cap);
@ -1769,20 +1755,18 @@ static inline int security_capget(struct task_struct *target,
return cap_capget(target, effective, inheritable, permitted); return cap_capget(target, effective, inheritable, permitted);
} }
static inline int security_capset_check(struct task_struct *target, static inline int security_capset_check(kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted) kernel_cap_t *permitted)
{ {
return cap_capset_check(target, effective, inheritable, permitted); return cap_capset_check(effective, inheritable, permitted);
} }
static inline void security_capset_set(struct task_struct *target, static inline void security_capset_set(kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted) kernel_cap_t *permitted)
{ {
cap_capset_set(target, effective, inheritable, permitted); cap_capset_set(effective, inheritable, permitted);
} }
static inline int security_capable(struct task_struct *tsk, int cap) static inline int security_capable(struct task_struct *tsk, int cap)

View File

@ -127,160 +127,6 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
return 0; return 0;
} }
#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
/*
* Without filesystem capability support, we nominally support one process
* setting the capabilities of another
*/
static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
kernel_cap_t *pIp, kernel_cap_t *pPp)
{
struct task_struct *target;
int ret;
spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);
if (pid && pid != task_pid_vnr(current)) {
target = find_task_by_vpid(pid);
if (!target) {
ret = -ESRCH;
goto out;
}
} else
target = current;
ret = security_capget(target, pEp, pIp, pPp);
out:
read_unlock(&tasklist_lock);
spin_unlock(&task_capability_lock);
return ret;
}
/*
* cap_set_pg - set capabilities for all processes in a given process
* group. We call this holding task_capability_lock and tasklist_lock.
*/
static inline int cap_set_pg(int pgrp_nr, kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
struct task_struct *g, *target;
int ret = -EPERM;
int found = 0;
struct pid *pgrp;
spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);
pgrp = find_vpid(pgrp_nr);
do_each_pid_task(pgrp, PIDTYPE_PGID, g) {
target = g;
while_each_thread(g, target) {
if (!security_capset_check(target, effective,
inheritable, permitted)) {
security_capset_set(target, effective,
inheritable, permitted);
ret = 0;
}
found = 1;
}
} while_each_pid_task(pgrp, PIDTYPE_PGID, g);
read_unlock(&tasklist_lock);
spin_unlock(&task_capability_lock);
if (!found)
ret = 0;
return ret;
}
/*
* cap_set_all - set capabilities for all processes other than init
* and self. We call this holding task_capability_lock and tasklist_lock.
*/
static inline int cap_set_all(kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
struct task_struct *g, *target;
int ret = -EPERM;
int found = 0;
spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);
do_each_thread(g, target) {
if (target == current
|| is_container_init(target->group_leader))
continue;
found = 1;
if (security_capset_check(target, effective, inheritable,
permitted))
continue;
ret = 0;
security_capset_set(target, effective, inheritable, permitted);
} while_each_thread(g, target);
read_unlock(&tasklist_lock);
spin_unlock(&task_capability_lock);
if (!found)
ret = 0;
return ret;
}
/*
* Given the target pid does not refer to the current process we
* need more elaborate support... (This support is not present when
* filesystem capabilities are configured.)
*/
static inline int do_sys_capset_other_tasks(pid_t pid, kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
struct task_struct *target;
int ret;
if (!capable(CAP_SETPCAP))
return -EPERM;
if (pid == -1) /* all procs other than current and init */
return cap_set_all(effective, inheritable, permitted);
else if (pid < 0) /* all procs in process group */
return cap_set_pg(-pid, effective, inheritable, permitted);
/* target != current */
spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);
target = find_task_by_vpid(pid);
if (!target)
ret = -ESRCH;
else {
ret = security_capset_check(target, effective, inheritable,
permitted);
/* having verified that the proposed changes are legal,
we now put them into effect. */
if (!ret)
security_capset_set(target, effective, inheritable,
permitted);
}
read_unlock(&tasklist_lock);
spin_unlock(&task_capability_lock);
return ret;
}
#else /* ie., def CONFIG_SECURITY_FILE_CAPABILITIES */
/* /*
* If we have configured with filesystem capability support, then the * If we have configured with filesystem capability support, then the
* only thing that can change the capabilities of the current process * only thing that can change the capabilities of the current process
@ -314,22 +160,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
return ret; return ret;
} }
/*
* With filesystem capability support configured, the kernel does not
* permit the changing of capabilities in one process by another
* process. (CAP_SETPCAP has much less broad semantics when configured
* this way.)
*/
static inline int do_sys_capset_other_tasks(pid_t pid,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
return -EPERM;
}
#endif /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
/* /*
* Atomically modify the effective capabilities returning the original * Atomically modify the effective capabilities returning the original
* value. No permission check is performed here - it is assumed that the * value. No permission check is performed here - it is assumed that the
@ -424,16 +254,14 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
* @data: pointer to struct that contains the effective, permitted, * @data: pointer to struct that contains the effective, permitted,
* and inheritable capabilities * and inheritable capabilities
* *
* Set capabilities for a given process, all processes, or all * Set capabilities for the current process only. The ability to any other
* processes in a given process group. * process(es) has been deprecated and removed.
* *
* The restrictions on setting capabilities are specified as: * The restrictions on setting capabilities are specified as:
* *
* [pid is for the 'target' task. 'current' is the calling task.] * I: any raised capabilities must be a subset of the old permitted
* * P: any raised capabilities must be a subset of the old permitted
* I: any raised capabilities must be a subset of the (old current) permitted * E: must be set to a subset of new permitted
* P: any raised capabilities must be a subset of the (old current) permitted
* E: must be set to a subset of (new target) permitted
* *
* Returns 0 on success and < 0 on error. * Returns 0 on success and < 0 on error.
*/ */
@ -452,10 +280,13 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
if (get_user(pid, &header->pid)) if (get_user(pid, &header->pid))
return -EFAULT; return -EFAULT;
/* may only affect current now */
if (pid != 0 && pid != task_pid_vnr(current))
return -EPERM;
if (copy_from_user(&kdata, data, tocopy if (copy_from_user(&kdata, data, tocopy
* sizeof(struct __user_cap_data_struct))) { * sizeof(struct __user_cap_data_struct)))
return -EFAULT; return -EFAULT;
}
for (i = 0; i < tocopy; i++) { for (i = 0; i < tocopy; i++) {
effective.cap[i] = kdata[i].effective; effective.cap[i] = kdata[i].effective;
@ -473,32 +304,20 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
if (ret) if (ret)
return ret; return ret;
if (pid && (pid != task_pid_vnr(current))) /* This lock is required even when filesystem capability support is
ret = do_sys_capset_other_tasks(pid, &effective, &inheritable, * configured - it protects the sys_capget() call from returning
&permitted); * incorrect data in the case that the targeted process is not the
else {
/*
* This lock is required even when filesystem
* capability support is configured - it protects the
* sys_capget() call from returning incorrect data in
* the case that the targeted process is not the
* current one. * current one.
*/ */
spin_lock(&task_capability_lock); spin_lock(&task_capability_lock);
ret = security_capset_check(current, &effective, &inheritable, ret = security_capset_check(&effective, &inheritable, &permitted);
&permitted); /* Having verified that the proposed changes are legal, we now put them
/* * into effect.
* Having verified that the proposed changes are
* legal, we now put them into effect.
*/ */
if (!ret) if (!ret)
security_capset_set(current, &effective, &inheritable, security_capset_set(&effective, &inheritable, &permitted);
&permitted);
spin_unlock(&task_capability_lock); spin_unlock(&task_capability_lock);
}
return ret; return ret;
} }

View File

@ -96,15 +96,6 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,
#ifdef CONFIG_SECURITY_FILE_CAPABILITIES #ifdef CONFIG_SECURITY_FILE_CAPABILITIES
static inline int cap_block_setpcap(struct task_struct *target)
{
/*
* No support for remote process capability manipulation with
* filesystem capability support.
*/
return (target != current);
}
static inline int cap_inh_is_capped(void) static inline int cap_inh_is_capped(void)
{ {
/* /*
@ -119,7 +110,6 @@ static inline int cap_limit_ptraced_target(void) { return 1; }
#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */ #else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
static inline int cap_block_setpcap(struct task_struct *t) { return 0; }
static inline int cap_inh_is_capped(void) { return 1; } static inline int cap_inh_is_capped(void) { return 1; }
static inline int cap_limit_ptraced_target(void) static inline int cap_limit_ptraced_target(void)
{ {
@ -128,21 +118,18 @@ static inline int cap_limit_ptraced_target(void)
#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, int cap_capset_check (kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
if (cap_block_setpcap(target)) {
return -EPERM;
}
if (cap_inh_is_capped() if (cap_inh_is_capped()
&& !cap_issubset(*inheritable, && !cap_issubset(*inheritable,
cap_combine(target->cap_inheritable, cap_combine(current->cap_inheritable,
current->cap_permitted))) { current->cap_permitted))) {
/* incapable of using this inheritable set */ /* incapable of using this inheritable set */
return -EPERM; return -EPERM;
} }
if (!cap_issubset(*inheritable, if (!cap_issubset(*inheritable,
cap_combine(target->cap_inheritable, cap_combine(current->cap_inheritable,
current->cap_bset))) { current->cap_bset))) {
/* no new pI capabilities outside bounding set */ /* no new pI capabilities outside bounding set */
return -EPERM; return -EPERM;
@ -150,7 +137,7 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
/* verify restrictions on target's new Permitted set */ /* verify restrictions on target's new Permitted set */
if (!cap_issubset (*permitted, if (!cap_issubset (*permitted,
cap_combine (target->cap_permitted, cap_combine (current->cap_permitted,
current->cap_permitted))) { current->cap_permitted))) {
return -EPERM; return -EPERM;
} }
@ -163,12 +150,12 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
return 0; return 0;
} }
void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, void cap_capset_set (kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
target->cap_effective = *effective; current->cap_effective = *effective;
target->cap_inheritable = *inheritable; current->cap_inheritable = *inheritable;
target->cap_permitted = *permitted; current->cap_permitted = *permitted;
} }
static inline void bprm_clear_caps(struct linux_binprm *bprm) static inline void bprm_clear_caps(struct linux_binprm *bprm)

View File

@ -145,20 +145,18 @@ int security_capget(struct task_struct *target,
return security_ops->capget(target, effective, inheritable, permitted); return security_ops->capget(target, effective, inheritable, permitted);
} }
int security_capset_check(struct task_struct *target, int security_capset_check(kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted) kernel_cap_t *permitted)
{ {
return security_ops->capset_check(target, effective, inheritable, permitted); return security_ops->capset_check(effective, inheritable, permitted);
} }
void security_capset_set(struct task_struct *target, void security_capset_set(kernel_cap_t *effective,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *inheritable,
kernel_cap_t *permitted) kernel_cap_t *permitted)
{ {
security_ops->capset_set(target, effective, inheritable, permitted); security_ops->capset_set(effective, inheritable, permitted);
} }
int security_capable(struct task_struct *tsk, int cap) int security_capable(struct task_struct *tsk, int cap)

View File

@ -1790,22 +1790,22 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
return secondary_ops->capget(target, effective, inheritable, permitted); return secondary_ops->capget(target, effective, inheritable, permitted);
} }
static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective, static int selinux_capset_check(kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
int error; int error;
error = secondary_ops->capset_check(target, effective, inheritable, permitted); error = secondary_ops->capset_check(effective, inheritable, permitted);
if (error) if (error)
return error; return error;
return task_has_perm(current, target, PROCESS__SETCAP); return task_has_perm(current, current, PROCESS__SETCAP);
} }
static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective, static void selinux_capset_set(kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
secondary_ops->capset_set(target, effective, inheritable, permitted); secondary_ops->capset_set(effective, inheritable, permitted);
} }
static int selinux_capable(struct task_struct *tsk, int cap, int audit) static int selinux_capable(struct task_struct *tsk, int cap, int audit)