X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fcapability.c;h=6b3412f25c50694a50daeeb6b3aa3ffbbc976a94;hb=34a75f0025b9cf803b6a88db032e6ad6950c9313;hp=1c5c35718450572a4319ba637f125998f90359b1;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/kernel/capability.c b/kernel/capability.c index 1c5c35718..6b3412f25 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -7,9 +7,12 @@ * 30 May 2002: Cleanup, Robert M. Love */ +#include #include #include #include +#include +#include #include unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ @@ -19,10 +22,10 @@ EXPORT_SYMBOL(securebits); EXPORT_SYMBOL(cap_bset); /* - * This global lock protects task->cap_* for all tasks including current. + * This lock protects task->cap_* for all tasks including current. * Locking rule: acquire this prior to tasklist_lock. */ -spinlock_t task_capability_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(task_capability_lock); /* * For sys_getproccap() and sys_setproccap(), any of the three @@ -30,8 +33,14 @@ spinlock_t task_capability_lock = SPIN_LOCK_UNLOCKED; * uninteresting and/or not to be changed. */ -/* +/** * sys_capget - get the capabilities of a given process. + * @header: pointer to struct that contains capability version and + * target pid data + * @dataptr: pointer to struct that contains the effective, permitted, + * and inheritable capabilities that are returned + * + * Returns 0 on success and < 0 on error. */ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) { @@ -84,40 +93,70 @@ out: * 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 void cap_set_pg(int pgrp, kernel_cap_t *effective, +static inline int cap_set_pg(int pgrp, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { task_t *g, *target; - struct list_head *l; - struct pid *pid; + int ret = -EPERM; + int found = 0; - for_each_task_pid(pgrp, PIDTYPE_PGID, g, l, pid) { + do_each_task_pid(pgrp, PIDTYPE_PGID, g) { target = g; - while_each_thread(g, target) - security_capset_set(target, effective, inheritable, permitted); - } + 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_task_pid(pgrp, PIDTYPE_PGID, g); + + 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 void cap_set_all(kernel_cap_t *effective, +static inline int cap_set_all(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { task_t *g, *target; + int ret = -EPERM; + int found = 0; do_each_thread(g, target) { if (target == current || target->pid == 1) 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); + + if (!found) + ret = 0; + return ret; } -/* - * sys_capset - set capabilities for a given process, all processes, or all +/** + * sys_capset - set capabilities for a process or a group of processes + * @header: pointer to struct that contains capability version and + * target pid data + * @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. * * The restrictions on setting capabilities are specified as: @@ -127,6 +166,8 @@ static inline void cap_set_all(kernel_cap_t *effective, * 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 + * + * Returns 0 on success and < 0 on error. */ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) { @@ -148,7 +189,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) if (get_user(pid, &header->pid)) return -EFAULT; - if (pid && !capable(CAP_SETPCAP)) + if (pid && pid != current->pid && !capable(CAP_SETPCAP)) return -EPERM; if (copy_from_user(&effective, &data->effective, sizeof(effective)) || @@ -168,36 +209,23 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) } else target = current; - ret = -EPERM; - - if (security_capset_check(target, &effective, &inheritable, &permitted)) - goto out; - - if (!cap_issubset(inheritable, cap_combine(target->cap_inheritable, - current->cap_permitted))) - goto out; - - /* verify restrictions on target's new Permitted set */ - if (!cap_issubset(permitted, cap_combine(target->cap_permitted, - current->cap_permitted))) - goto out; - - /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ - if (!cap_issubset(effective, permitted)) - goto out; - ret = 0; /* having verified that the proposed changes are legal, we now put them into effect. */ if (pid < 0) { if (pid == -1) /* all procs other than current and init */ - cap_set_all(&effective, &inheritable, &permitted); + ret = cap_set_all(&effective, &inheritable, &permitted); else /* all procs in process group */ - cap_set_pg(-pid, &effective, &inheritable, &permitted); + ret = cap_set_pg(-pid, &effective, &inheritable, + &permitted); } else { - security_capset_set(target, &effective, &inheritable, &permitted); + ret = security_capset_check(target, &effective, &inheritable, + &permitted); + if (!ret) + security_capset_set(target, &effective, &inheritable, + &permitted); } out: @@ -206,3 +234,22 @@ out: return ret; } + +int __capable(struct task_struct *t, int cap) +{ + if (security_capable(t, cap) == 0) { + t->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} +EXPORT_SYMBOL(__capable); + +int capable(int cap) +{ + /* here for now so we don't require task locking */ + if (vx_check_bit(VXC_CAP_MASK, cap) && !vx_mcaps(1L << cap)) + return 0; + return __capable(current, cap); +} +EXPORT_SYMBOL(capable);