Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 120716
b: refs/heads/master
c: 1cdcbec
h: refs/heads/master
v: v3
  • Loading branch information
David Howells authored and James Morris committed Nov 13, 2008
1 parent d8107fc commit 5e7756a
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 284 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: 8bbf4976b59fc9fc2861e79cab7beb3f6d647640
refs/heads/master: 1cdcbec1a3372c0c49c59d292e708fd07b509f18
12 changes: 1 addition & 11 deletions trunk/fs/open.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,17 +441,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
current->fsgid = current->gid;

if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/*
* 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 */
/* Clear the capabilities if we switch to a non-root user */
if (current->uid)
old_cap = cap_set_effective(__cap_empty_set);
else
Expand Down
48 changes: 16 additions & 32 deletions trunk/include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_capset_check(struct task_struct *target, 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 int cap_capset_check(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 void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
Expand Down Expand Up @@ -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.
* @capset_check:
* Check permission before setting the @effective, @inheritable, and
* @permitted capability sets for the @target 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.
* @permitted capability sets for the current process.
* @effective contains the effective capability set.
* @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set.
* Return 0 if permission is granted.
* @capset_set:
* Set the @effective, @inheritable, and @permitted capability sets for
* the @target process. Since capset_check cannot always check permission
* 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.
* the current process.
* @effective contains the effective capability set.
* @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set.
Expand Down Expand Up @@ -1303,12 +1293,10 @@ struct security_operations {
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
int (*capset_check) (struct task_struct *target,
kernel_cap_t *effective,
int (*capset_check) (kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
void (*capset_set) (struct task_struct *target,
kernel_cap_t *effective,
void (*capset_set) (kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, int cap, int audit);
Expand Down Expand Up @@ -1572,12 +1560,10 @@ int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
int security_capset_check(struct task_struct *target,
kernel_cap_t *effective,
int security_capset_check(kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
void security_capset_set(struct task_struct *target,
kernel_cap_t *effective,
void security_capset_set(kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
int security_capable(struct task_struct *tsk, int cap);
Expand Down Expand Up @@ -1769,20 +1755,18 @@ static inline int security_capget(struct task_struct *target,
return cap_capget(target, effective, inheritable, permitted);
}

static inline int security_capset_check(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
static inline int security_capset_check(kernel_cap_t *effective,
kernel_cap_t *inheritable,
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,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
static inline void security_capset_set(kernel_cap_t *effective,
kernel_cap_t *inheritable,
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)
Expand Down
227 changes: 23 additions & 204 deletions trunk/kernel/capability.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,160 +127,6 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
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
* only thing that can change the capabilities of the current process
Expand Down Expand Up @@ -314,22 +160,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
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
* value. No permission check is performed here - it is assumed that the
Expand Down Expand Up @@ -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,
* and inheritable capabilities
*
* Set capabilities for a given process, all processes, or all
* processes in a given process group.
* Set capabilities for the current process only. The ability to any other
* process(es) has been deprecated and removed.
*
* 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 current) 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
* I: any raised capabilities must be a subset of the old permitted
* P: any raised capabilities must be a subset of the old permitted
* E: must be set to a subset of new permitted
*
* Returns 0 on success and < 0 on error.
*/
Expand All @@ -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))
return -EFAULT;

/* may only affect current now */
if (pid != 0 && pid != task_pid_vnr(current))
return -EPERM;

if (copy_from_user(&kdata, data, tocopy
* sizeof(struct __user_cap_data_struct))) {
* sizeof(struct __user_cap_data_struct)))
return -EFAULT;
}

for (i = 0; i < tocopy; i++) {
effective.cap[i] = kdata[i].effective;
Expand All @@ -473,32 +304,20 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
if (ret)
return ret;

if (pid && (pid != task_pid_vnr(current)))
ret = do_sys_capset_other_tasks(pid, &effective, &inheritable,
&permitted);
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.
*/
spin_lock(&task_capability_lock);

ret = security_capset_check(current, &effective, &inheritable,
&permitted);
/*
* Having verified that the proposed changes are
* legal, we now put them into effect.
*/
if (!ret)
security_capset_set(current, &effective, &inheritable,
&permitted);
spin_unlock(&task_capability_lock);
}

/* 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.
*/
spin_lock(&task_capability_lock);

ret = security_capset_check(&effective, &inheritable, &permitted);
/* Having verified that the proposed changes are legal, we now put them
* into effect.
*/
if (!ret)
security_capset_set(&effective, &inheritable, &permitted);
spin_unlock(&task_capability_lock);
return ret;
}

Expand Down
Loading

0 comments on commit 5e7756a

Please sign in to comment.