diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /kernel/capability.c | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff) |
o Merge with Linux 2.1.116.
o New Newport console code.
o New G364 console code.
Diffstat (limited to 'kernel/capability.c')
-rw-r--r-- | kernel/capability.c | 129 |
1 files changed, 49 insertions, 80 deletions
diff --git a/kernel/capability.c b/kernel/capability.c index ddbfaa87b..60d4ed6b5 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -5,7 +5,6 @@ * Integrated into 2.1.97+, Andrew G. Morgan <morgan@transmeta.com> */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/capability.h> @@ -15,20 +14,8 @@ #include <asm/uaccess.h> -static inline void cap_fromuser(kernel_cap_t *k, __u32 *u) -{ - copy_from_user(k, u, sizeof(*k)); -} - - -static inline void cap_touser(__u32 *u, const kernel_cap_t *k) -{ - copy_to_user(u, k, sizeof(*k)); -} - -#ifdef __SMP__ -static spinlock_t task_capability_lock; -#endif +/* Note: never hold tasklist_lock while spinning for this one */ +spinlock_t task_capability_lock; /* * For sys_getproccap() and sys_setproccap(), any of the three @@ -36,65 +23,58 @@ static spinlock_t task_capability_lock; * uninteresting and/or not to be changed. */ -asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t data) +asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t dataptr) { - int error = -EINVAL, pid; + int error, pid; __u32 version; struct task_struct *target; + struct __user_cap_data_struct data; - if (!access_ok(VERIFY_WRITE, &header->version, sizeof(*header))) { - /* not large enough for current header so indicate error */ - if (access_ok(VERIFY_WRITE, &header->version, - sizeof(header->version))) { - return error; - } - goto all_done; - } - - copy_from_user(&version, &header->version, sizeof(header->version)); + if (get_user(version, &header->version)) + return -EFAULT; + + error = -EINVAL; if (version != _LINUX_CAPABILITY_VERSION) { - /* if enough space for kernel version, write that */ - - all_done: version = _LINUX_CAPABILITY_VERSION; - copy_to_user(&header->version, &version, - sizeof(header->version)); + if (put_user(version, &header->version)) + error = -EFAULT; return error; } - if (!access_ok(VERIFY_WRITE, data, sizeof(*data))) { - return error; - } + if (get_user(pid, &header->pid)) + return -EFAULT; - copy_from_user(&pid, &header->pid, sizeof(header->pid)); - if (pid < 0) { - return error; - } + if (pid < 0) + return -EINVAL; + + error = 0; spin_lock(&task_capability_lock); if (pid && pid != current->pid) { - read_lock(&tasklist_lock); + read_lock(&tasklist_lock); target = find_task_by_pid(pid); /* identify target of query */ - if (!target) { + if (!target) error = -ESRCH; - goto out; - } } else { target = current; } - cap_touser(&data->permitted, &target->cap_permitted); - cap_touser(&data->inheritable, &target->cap_inheritable); - cap_touser(&data->effective, &target->cap_effective); + if (!error) { + data.permitted = target->cap_permitted.cap; + data.inheritable = target->cap_inheritable.cap; + data.effective = target->cap_effective.cap; + } - error = 0; + if (target != current) + read_unlock(&tasklist_lock); + spin_unlock(&task_capability_lock); -out: - if (target != current) { - read_unlock(&tasklist_lock); + if (!error) { + if (copy_to_user(dataptr, &data, sizeof data)) + return -EFAULT; } - spin_unlock(&task_capability_lock); + return error; } @@ -155,38 +135,31 @@ asmlinkage int sys_capset(cap_user_header_t header, const cap_user_data_t data) kernel_cap_t inheritable, permitted, effective; __u32 version; struct task_struct *target; - int error = -EINVAL, pid; - - if (!access_ok(VERIFY_WRITE, &header->version, sizeof(*header))) { - /* not large enough for current header so indicate error */ - if (!access_ok(VERIFY_WRITE, &header->version, - sizeof(header->version))) { - return error; - } - goto all_done; - } + int error, pid; - copy_from_user(&version, &header->version, sizeof(header->version)); - if (version != _LINUX_CAPABILITY_VERSION) { + if (get_user(version, &header->version)) + return -EFAULT; - all_done: + if (version != _LINUX_CAPABILITY_VERSION) { version = _LINUX_CAPABILITY_VERSION; - copy_to_user(&header->version, &version, - sizeof(header->version)); - return error; - } - - if (!access_ok(VERIFY_READ, data, sizeof(*data))) { - return error; + if (put_user(version, &header->version)) + return -EFAULT; + return -EINVAL; } /* may want to set other processes at some point -- for now demand 0 */ - copy_from_user(&pid, &header->pid, sizeof(pid)); + if (get_user(pid, &header->pid)) + return -EFAULT; - error = -EPERM; if (pid && !capable(CAP_SETPCAP)) - return error; + return -EPERM; + if (copy_from_user(&effective, &data->effective, sizeof(effective)) || + copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) || + copy_from_user(&permitted, &data->permitted, sizeof(permitted))) + return -EFAULT; + + error = -EPERM; spin_lock(&task_capability_lock); if (pid > 0 && pid != current->pid) { @@ -194,16 +167,12 @@ asmlinkage int sys_capset(cap_user_header_t header, const cap_user_data_t data) target = find_task_by_pid(pid); /* identify target of query */ if (!target) { error = -ESRCH; - goto out; - } + goto out; + } } else { target = current; } - /* copy from userspace */ - cap_fromuser(&effective, &data->effective); - cap_fromuser(&inheritable, &data->inheritable); - cap_fromuser(&permitted, &data->permitted); /* verify restrictions on target's new Inheritable set */ if (!cap_issubset(inheritable, |