aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:23 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:23 -0500
commitd84f4f992cbd76e8f39c488cf0c5d123843923b1 (patch)
treefc4a0349c42995715b93d0f7a3c78e9ea9b3f36e /kernel
parent745ca2475a6ac596e3d8d37c2759c0fbe2586227 (diff)
CRED: Inaugurate COW credentials
Inaugurate copy-on-write credentials management. This uses RCU to manage the credentials pointer in the task_struct with respect to accesses by other tasks. A process may only modify its own credentials, and so does not need locking to access or modify its own credentials. A mutex (cred_replace_mutex) is added to the task_struct to control the effect of PTRACE_ATTACHED on credential calculations, particularly with respect to execve(). With this patch, the contents of an active credentials struct may not be changed directly; rather a new set of credentials must be prepared, modified and committed using something like the following sequence of events: struct cred *new = prepare_creds(); int ret = blah(new); if (ret < 0) { abort_creds(new); return ret; } return commit_creds(new); There are some exceptions to this rule: the keyrings pointed to by the active credentials may be instantiated - keyrings violate the COW rule as managing COW keyrings is tricky, given that it is possible for a task to directly alter the keys in a keyring in use by another task. To help enforce this, various pointers to sets of credentials, such as those in the task_struct, are declared const. The purpose of this is compile-time discouragement of altering credentials through those pointers. Once a set of credentials has been made public through one of these pointers, it may not be modified, except under special circumstances: (1) Its reference count may incremented and decremented. (2) The keyrings to which it points may be modified, but not replaced. The only safe way to modify anything else is to create a replacement and commit using the functions described in Documentation/credentials.txt (which will be added by a later patch). This patch and the preceding patches have been tested with the LTP SELinux testsuite. This patch makes several logical sets of alteration: (1) execve(). This now prepares and commits credentials in various places in the security code rather than altering the current creds directly. (2) Temporary credential overrides. do_coredump() and sys_faccessat() now prepare their own credentials and temporarily override the ones currently on the acting thread, whilst preventing interference from other threads by holding cred_replace_mutex on the thread being dumped. This will be replaced in a future patch by something that hands down the credentials directly to the functions being called, rather than altering the task's objective credentials. (3) LSM interface. A number of functions have been changed, added or removed: (*) security_capset_check(), ->capset_check() (*) security_capset_set(), ->capset_set() Removed in favour of security_capset(). (*) security_capset(), ->capset() New. This is passed a pointer to the new creds, a pointer to the old creds and the proposed capability sets. It should fill in the new creds or return an error. All pointers, barring the pointer to the new creds, are now const. (*) security_bprm_apply_creds(), ->bprm_apply_creds() Changed; now returns a value, which will cause the process to be killed if it's an error. (*) security_task_alloc(), ->task_alloc_security() Removed in favour of security_prepare_creds(). (*) security_cred_free(), ->cred_free() New. Free security data attached to cred->security. (*) security_prepare_creds(), ->cred_prepare() New. Duplicate any security data attached to cred->security. (*) security_commit_creds(), ->cred_commit() New. Apply any security effects for the upcoming installation of new security by commit_creds(). (*) security_task_post_setuid(), ->task_post_setuid() Removed in favour of security_task_fix_setuid(). (*) security_task_fix_setuid(), ->task_fix_setuid() Fix up the proposed new credentials for setuid(). This is used by cap_set_fix_setuid() to implicitly adjust capabilities in line with setuid() changes. Changes are made to the new credentials, rather than the task itself as in security_task_post_setuid(). (*) security_task_reparent_to_init(), ->task_reparent_to_init() Removed. Instead the task being reparented to init is referred directly to init's credentials. NOTE! This results in the loss of some state: SELinux's osid no longer records the sid of the thread that forked it. (*) security_key_alloc(), ->key_alloc() (*) security_key_permission(), ->key_permission() Changed. These now take cred pointers rather than task pointers to refer to the security context. (4) sys_capset(). This has been simplified and uses less locking. The LSM functions it calls have been merged. (5) reparent_to_kthreadd(). This gives the current thread the same credentials as init by simply using commit_thread() to point that way. (6) __sigqueue_alloc() and switch_uid() __sigqueue_alloc() can't stop the target task from changing its creds beneath it, so this function gets a reference to the currently applicable user_struct which it then passes into the sigqueue struct it returns if successful. switch_uid() is now called from commit_creds(), and possibly should be folded into that. commit_creds() should take care of protecting __sigqueue_alloc(). (7) [sg]et[ug]id() and co and [sg]et_current_groups. The set functions now all use prepare_creds(), commit_creds() and abort_creds() to build and check a new set of credentials before applying it. security_task_set[ug]id() is called inside the prepared section. This guarantees that nothing else will affect the creds until we've finished. The calling of set_dumpable() has been moved into commit_creds(). Much of the functionality of set_user() has been moved into commit_creds(). The get functions all simply access the data directly. (8) security_task_prctl() and cap_task_prctl(). security_task_prctl() has been modified to return -ENOSYS if it doesn't want to handle a function, or otherwise return the return value directly rather than through an argument. Additionally, cap_task_prctl() now prepares a new set of credentials, even if it doesn't end up using it. (9) Keyrings. A number of changes have been made to the keyrings code: (a) switch_uid_keyring(), copy_keys(), exit_keys() and suid_keys() have all been dropped and built in to the credentials functions directly. They may want separating out again later. (b) key_alloc() and search_process_keyrings() now take a cred pointer rather than a task pointer to specify the security context. (c) copy_creds() gives a new thread within the same thread group a new thread keyring if its parent had one, otherwise it discards the thread keyring. (d) The authorisation key now points directly to the credentials to extend the search into rather pointing to the task that carries them. (e) Installing thread, process or session keyrings causes a new set of credentials to be created, even though it's not strictly necessary for process or session keyrings (they're shared). (10) Usermode helper. The usermode helper code now carries a cred struct pointer in its subprocess_info struct instead of a new session keyring pointer. This set of credentials is derived from init_cred and installed on the new process after it has been cloned. call_usermodehelper_setup() allocates the new credentials and call_usermodehelper_freeinfo() discards them if they haven't been used. A special cred function (prepare_usermodeinfo_creds()) is provided specifically for call_usermodehelper_setup() to call. call_usermodehelper_setkeys() adjusts the credentials to sport the supplied keyring as the new session keyring. (11) SELinux. SELinux has a number of changes, in addition to those to support the LSM interface changes mentioned above: (a) selinux_setprocattr() no longer does its check for whether the current ptracer can access processes with the new SID inside the lock that covers getting the ptracer's SID. Whilst this lock ensures that the check is done with the ptracer pinned, the result is only valid until the lock is released, so there's no point doing it inside the lock. (12) is_single_threaded(). This function has been extracted from selinux_setprocattr() and put into a file of its own in the lib/ directory as join_session_keyring() now wants to use it too. The code in SELinux just checked to see whether a task shared mm_structs with other tasks (CLONE_VM), but that isn't good enough. We really want to know if they're part of the same thread group (CLONE_THREAD). (13) nfsd. The NFS server daemon now has to use the COW credentials to set the credentials it is going to use. It really needs to pass the credentials down to the functions it calls, but it can't do that until other patches in this series have been applied. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/auditsc.c42
-rw-r--r--kernel/capability.c78
-rw-r--r--kernel/cred-internals.h21
-rw-r--r--kernel/cred.c321
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/fork.c7
-rw-r--r--kernel/kmod.c30
-rw-r--r--kernel/ptrace.c9
-rw-r--r--kernel/signal.c10
-rw-r--r--kernel/sys.c450
-rw-r--r--kernel/user.c37
-rw-r--r--kernel/user_namespace.c12
12 files changed, 652 insertions, 374 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ae8ef88ade3f..bc1e2d854bf6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2546,18 +2546,17 @@ int __audit_signal_info(int sig, struct task_struct *t)
2546 2546
2547/** 2547/**
2548 * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps 2548 * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps
2549 * @bprm pointer to the bprm being processed 2549 * @bprm: pointer to the bprm being processed
2550 * @caps the caps read from the disk 2550 * @new: the proposed new credentials
2551 * @old: the old credentials
2551 * 2552 *
2552 * Simply check if the proc already has the caps given by the file and if not 2553 * Simply check if the proc already has the caps given by the file and if not
2553 * store the priv escalation info for later auditing at the end of the syscall 2554 * store the priv escalation info for later auditing at the end of the syscall
2554 * 2555 *
2555 * this can fail and we don't care. See the note in audit.h for
2556 * audit_log_bprm_fcaps() for my explaination....
2557 *
2558 * -Eric 2556 * -Eric
2559 */ 2557 */
2560void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE) 2558int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
2559 const struct cred *new, const struct cred *old)
2561{ 2560{
2562 struct audit_aux_data_bprm_fcaps *ax; 2561 struct audit_aux_data_bprm_fcaps *ax;
2563 struct audit_context *context = current->audit_context; 2562 struct audit_context *context = current->audit_context;
@@ -2566,7 +2565,7 @@ void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_
2566 2565
2567 ax = kmalloc(sizeof(*ax), GFP_KERNEL); 2566 ax = kmalloc(sizeof(*ax), GFP_KERNEL);
2568 if (!ax) 2567 if (!ax)
2569 return; 2568 return -ENOMEM;
2570 2569
2571 ax->d.type = AUDIT_BPRM_FCAPS; 2570 ax->d.type = AUDIT_BPRM_FCAPS;
2572 ax->d.next = context->aux; 2571 ax->d.next = context->aux;
@@ -2581,26 +2580,27 @@ void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_
2581 ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); 2580 ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
2582 ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; 2581 ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
2583 2582
2584 ax->old_pcap.permitted = *pP; 2583 ax->old_pcap.permitted = old->cap_permitted;
2585 ax->old_pcap.inheritable = current->cred->cap_inheritable; 2584 ax->old_pcap.inheritable = old->cap_inheritable;
2586 ax->old_pcap.effective = *pE; 2585 ax->old_pcap.effective = old->cap_effective;
2587 2586
2588 ax->new_pcap.permitted = current->cred->cap_permitted; 2587 ax->new_pcap.permitted = new->cap_permitted;
2589 ax->new_pcap.inheritable = current->cred->cap_inheritable; 2588 ax->new_pcap.inheritable = new->cap_inheritable;
2590 ax->new_pcap.effective = current->cred->cap_effective; 2589 ax->new_pcap.effective = new->cap_effective;
2590 return 0;
2591} 2591}
2592 2592
2593/** 2593/**
2594 * __audit_log_capset - store information about the arguments to the capset syscall 2594 * __audit_log_capset - store information about the arguments to the capset syscall
2595 * @pid target pid of the capset call 2595 * @pid: target pid of the capset call
2596 * @eff effective cap set 2596 * @new: the new credentials
2597 * @inh inheritible cap set 2597 * @old: the old (current) credentials
2598 * @perm permited cap set
2599 * 2598 *
2600 * Record the aguments userspace sent to sys_capset for later printing by the 2599 * Record the aguments userspace sent to sys_capset for later printing by the
2601 * audit system if applicable 2600 * audit system if applicable
2602 */ 2601 */
2603int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm) 2602int __audit_log_capset(pid_t pid,
2603 const struct cred *new, const struct cred *old)
2604{ 2604{
2605 struct audit_aux_data_capset *ax; 2605 struct audit_aux_data_capset *ax;
2606 struct audit_context *context = current->audit_context; 2606 struct audit_context *context = current->audit_context;
@@ -2617,9 +2617,9 @@ int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_c
2617 context->aux = (void *)ax; 2617 context->aux = (void *)ax;
2618 2618
2619 ax->pid = pid; 2619 ax->pid = pid;
2620 ax->cap.effective = *eff; 2620 ax->cap.effective = new->cap_effective;
2621 ax->cap.inheritable = *eff; 2621 ax->cap.inheritable = new->cap_effective;
2622 ax->cap.permitted = *perm; 2622 ax->cap.permitted = new->cap_permitted;
2623 2623
2624 return 0; 2624 return 0;
2625} 2625}
diff --git a/kernel/capability.c b/kernel/capability.c
index a404b980b1bd..36b4b4daebec 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -15,12 +15,7 @@
15#include <linux/syscalls.h> 15#include <linux/syscalls.h>
16#include <linux/pid_namespace.h> 16#include <linux/pid_namespace.h>
17#include <asm/uaccess.h> 17#include <asm/uaccess.h>
18 18#include "cred-internals.h"
19/*
20 * This lock protects task->cap_* for all tasks including current.
21 * Locking rule: acquire this prior to tasklist_lock.
22 */
23static DEFINE_SPINLOCK(task_capability_lock);
24 19
25/* 20/*
26 * Leveraged for setting/resetting capabilities 21 * Leveraged for setting/resetting capabilities
@@ -128,12 +123,11 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
128} 123}
129 124
130/* 125/*
131 * If we have configured with filesystem capability support, then the 126 * The only thing that can change the capabilities of the current
132 * only thing that can change the capabilities of the current process 127 * process is the current process. As such, we can't be in this code
133 * is the current process. As such, we can't be in this code at the 128 * at the same time as we are in the process of setting capabilities
134 * same time as we are in the process of setting capabilities in this 129 * in this process. The net result is that we can limit our use of
135 * process. The net result is that we can limit our use of locks to 130 * locks to when we are reading the caps of another process.
136 * when we are reading the caps of another process.
137 */ 131 */
138static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, 132static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
139 kernel_cap_t *pIp, kernel_cap_t *pPp) 133 kernel_cap_t *pIp, kernel_cap_t *pPp)
@@ -143,7 +137,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
143 if (pid && (pid != task_pid_vnr(current))) { 137 if (pid && (pid != task_pid_vnr(current))) {
144 struct task_struct *target; 138 struct task_struct *target;
145 139
146 spin_lock(&task_capability_lock);
147 read_lock(&tasklist_lock); 140 read_lock(&tasklist_lock);
148 141
149 target = find_task_by_vpid(pid); 142 target = find_task_by_vpid(pid);
@@ -153,34 +146,12 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
153 ret = security_capget(target, pEp, pIp, pPp); 146 ret = security_capget(target, pEp, pIp, pPp);
154 147
155 read_unlock(&tasklist_lock); 148 read_unlock(&tasklist_lock);
156 spin_unlock(&task_capability_lock);
157 } else 149 } else
158 ret = security_capget(current, pEp, pIp, pPp); 150 ret = security_capget(current, pEp, pIp, pPp);
159 151
160 return ret; 152 return ret;
161} 153}
162 154
163/*
164 * Atomically modify the effective capabilities returning the original
165 * value. No permission check is performed here - it is assumed that the
166 * caller is permitted to set the desired effective capabilities.
167 */
168kernel_cap_t cap_set_effective(const kernel_cap_t pE_new)
169{
170 kernel_cap_t pE_old;
171
172 spin_lock(&task_capability_lock);
173
174 pE_old = current->cred->cap_effective;
175 current->cred->cap_effective = pE_new;
176
177 spin_unlock(&task_capability_lock);
178
179 return pE_old;
180}
181
182EXPORT_SYMBOL(cap_set_effective);
183
184/** 155/**
185 * sys_capget - get the capabilities of a given process. 156 * sys_capget - get the capabilities of a given process.
186 * @header: pointer to struct that contains capability version and 157 * @header: pointer to struct that contains capability version and
@@ -208,7 +179,6 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
208 return -EINVAL; 179 return -EINVAL;
209 180
210 ret = cap_get_target_pid(pid, &pE, &pI, &pP); 181 ret = cap_get_target_pid(pid, &pE, &pI, &pP);
211
212 if (!ret) { 182 if (!ret) {
213 struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; 183 struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
214 unsigned i; 184 unsigned i;
@@ -270,6 +240,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
270 struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; 240 struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
271 unsigned i, tocopy; 241 unsigned i, tocopy;
272 kernel_cap_t inheritable, permitted, effective; 242 kernel_cap_t inheritable, permitted, effective;
243 struct cred *new;
273 int ret; 244 int ret;
274 pid_t pid; 245 pid_t pid;
275 246
@@ -284,8 +255,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
284 if (pid != 0 && pid != task_pid_vnr(current)) 255 if (pid != 0 && pid != task_pid_vnr(current))
285 return -EPERM; 256 return -EPERM;
286 257
287 if (copy_from_user(&kdata, data, tocopy 258 if (copy_from_user(&kdata, data,
288 * sizeof(struct __user_cap_data_struct))) 259 tocopy * sizeof(struct __user_cap_data_struct)))
289 return -EFAULT; 260 return -EFAULT;
290 261
291 for (i = 0; i < tocopy; i++) { 262 for (i = 0; i < tocopy; i++) {
@@ -300,24 +271,23 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
300 i++; 271 i++;
301 } 272 }
302 273
303 ret = audit_log_capset(pid, &effective, &inheritable, &permitted); 274 new = prepare_creds();
304 if (ret) 275 if (!new)
276 return -ENOMEM;
277
278 ret = security_capset(new, current_cred(),
279 &effective, &inheritable, &permitted);
280 if (ret < 0)
281 goto error;
282
283 ret = audit_log_capset(pid, new, current_cred());
284 if (ret < 0)
305 return ret; 285 return ret;
306 286
307 /* This lock is required even when filesystem capability support is 287 return commit_creds(new);
308 * configured - it protects the sys_capget() call from returning 288
309 * incorrect data in the case that the targeted process is not the 289error:
310 * current one. 290 abort_creds(new);
311 */
312 spin_lock(&task_capability_lock);
313
314 ret = security_capset_check(&effective, &inheritable, &permitted);
315 /* Having verified that the proposed changes are legal, we now put them
316 * into effect.
317 */
318 if (!ret)
319 security_capset_set(&effective, &inheritable, &permitted);
320 spin_unlock(&task_capability_lock);
321 return ret; 291 return ret;
322} 292}
323 293
diff --git a/kernel/cred-internals.h b/kernel/cred-internals.h
new file mode 100644
index 000000000000..2dc4fc2d0bf1
--- /dev/null
+++ b/kernel/cred-internals.h
@@ -0,0 +1,21 @@
1/* Internal credentials stuff
2 *
3 * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12/*
13 * user.c
14 */
15static inline void sched_switch_user(struct task_struct *p)
16{
17#ifdef CONFIG_USER_SCHED
18 sched_move_task(p);
19#endif /* CONFIG_USER_SCHED */
20}
21
diff --git a/kernel/cred.c b/kernel/cred.c
index ac73e3617684..cb6b5eda978d 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -15,6 +15,10 @@
15#include <linux/keyctl.h> 15#include <linux/keyctl.h>
16#include <linux/init_task.h> 16#include <linux/init_task.h>
17#include <linux/security.h> 17#include <linux/security.h>
18#include <linux/cn_proc.h>
19#include "cred-internals.h"
20
21static struct kmem_cache *cred_jar;
18 22
19/* 23/*
20 * The common credentials for the initial task's thread group 24 * The common credentials for the initial task's thread group
@@ -64,7 +68,7 @@ static void release_tgcred_rcu(struct rcu_head *rcu)
64/* 68/*
65 * Release a set of thread group credentials. 69 * Release a set of thread group credentials.
66 */ 70 */
67static void release_tgcred(struct cred *cred) 71void release_tgcred(struct cred *cred)
68{ 72{
69#ifdef CONFIG_KEYS 73#ifdef CONFIG_KEYS
70 struct thread_group_cred *tgcred = cred->tgcred; 74 struct thread_group_cred *tgcred = cred->tgcred;
@@ -81,79 +85,322 @@ static void put_cred_rcu(struct rcu_head *rcu)
81{ 85{
82 struct cred *cred = container_of(rcu, struct cred, rcu); 86 struct cred *cred = container_of(rcu, struct cred, rcu);
83 87
84 BUG_ON(atomic_read(&cred->usage) != 0); 88 if (atomic_read(&cred->usage) != 0)
89 panic("CRED: put_cred_rcu() sees %p with usage %d\n",
90 cred, atomic_read(&cred->usage));
85 91
92 security_cred_free(cred);
86 key_put(cred->thread_keyring); 93 key_put(cred->thread_keyring);
87 key_put(cred->request_key_auth); 94 key_put(cred->request_key_auth);
88 release_tgcred(cred); 95 release_tgcred(cred);
89 put_group_info(cred->group_info); 96 put_group_info(cred->group_info);
90 free_uid(cred->user); 97 free_uid(cred->user);
91 security_cred_free(cred); 98 kmem_cache_free(cred_jar, cred);
92 kfree(cred);
93} 99}
94 100
95/** 101/**
96 * __put_cred - Destroy a set of credentials 102 * __put_cred - Destroy a set of credentials
97 * @sec: The record to release 103 * @cred: The record to release
98 * 104 *
99 * Destroy a set of credentials on which no references remain. 105 * Destroy a set of credentials on which no references remain.
100 */ 106 */
101void __put_cred(struct cred *cred) 107void __put_cred(struct cred *cred)
102{ 108{
109 BUG_ON(atomic_read(&cred->usage) != 0);
110
103 call_rcu(&cred->rcu, put_cred_rcu); 111 call_rcu(&cred->rcu, put_cred_rcu);
104} 112}
105EXPORT_SYMBOL(__put_cred); 113EXPORT_SYMBOL(__put_cred);
106 114
115/**
116 * prepare_creds - Prepare a new set of credentials for modification
117 *
118 * Prepare a new set of task credentials for modification. A task's creds
119 * shouldn't generally be modified directly, therefore this function is used to
120 * prepare a new copy, which the caller then modifies and then commits by
121 * calling commit_creds().
122 *
123 * Returns a pointer to the new creds-to-be if successful, NULL otherwise.
124 *
125 * Call commit_creds() or abort_creds() to clean up.
126 */
127struct cred *prepare_creds(void)
128{
129 struct task_struct *task = current;
130 const struct cred *old;
131 struct cred *new;
132
133 BUG_ON(atomic_read(&task->cred->usage) < 1);
134
135 new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
136 if (!new)
137 return NULL;
138
139 old = task->cred;
140 memcpy(new, old, sizeof(struct cred));
141
142 atomic_set(&new->usage, 1);
143 get_group_info(new->group_info);
144 get_uid(new->user);
145
146#ifdef CONFIG_KEYS
147 key_get(new->thread_keyring);
148 key_get(new->request_key_auth);
149 atomic_inc(&new->tgcred->usage);
150#endif
151
152#ifdef CONFIG_SECURITY
153 new->security = NULL;
154#endif
155
156 if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
157 goto error;
158 return new;
159
160error:
161 abort_creds(new);
162 return NULL;
163}
164EXPORT_SYMBOL(prepare_creds);
165
166/*
167 * prepare new credentials for the usermode helper dispatcher
168 */
169struct cred *prepare_usermodehelper_creds(void)
170{
171#ifdef CONFIG_KEYS
172 struct thread_group_cred *tgcred = NULL;
173#endif
174 struct cred *new;
175
176#ifdef CONFIG_KEYS
177 tgcred = kzalloc(sizeof(*new->tgcred), GFP_ATOMIC);
178 if (!tgcred)
179 return NULL;
180#endif
181
182 new = kmem_cache_alloc(cred_jar, GFP_ATOMIC);
183 if (!new)
184 return NULL;
185
186 memcpy(new, &init_cred, sizeof(struct cred));
187
188 atomic_set(&new->usage, 1);
189 get_group_info(new->group_info);
190 get_uid(new->user);
191
192#ifdef CONFIG_KEYS
193 new->thread_keyring = NULL;
194 new->request_key_auth = NULL;
195 new->jit_keyring = KEY_REQKEY_DEFL_DEFAULT;
196
197 atomic_set(&tgcred->usage, 1);
198 spin_lock_init(&tgcred->lock);
199 new->tgcred = tgcred;
200#endif
201
202#ifdef CONFIG_SECURITY
203 new->security = NULL;
204#endif
205 if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
206 goto error;
207
208 BUG_ON(atomic_read(&new->usage) != 1);
209 return new;
210
211error:
212 put_cred(new);
213 return NULL;
214}
215
107/* 216/*
108 * Copy credentials for the new process created by fork() 217 * Copy credentials for the new process created by fork()
218 *
219 * We share if we can, but under some circumstances we have to generate a new
220 * set.
109 */ 221 */
110int copy_creds(struct task_struct *p, unsigned long clone_flags) 222int copy_creds(struct task_struct *p, unsigned long clone_flags)
111{ 223{
112 struct cred *pcred; 224#ifdef CONFIG_KEYS
113 int ret; 225 struct thread_group_cred *tgcred;
226#endif
227 struct cred *new;
228
229 mutex_init(&p->cred_exec_mutex);
114 230
115 pcred = kmemdup(p->cred, sizeof(*p->cred), GFP_KERNEL); 231 if (
116 if (!pcred) 232#ifdef CONFIG_KEYS
233 !p->cred->thread_keyring &&
234#endif
235 clone_flags & CLONE_THREAD
236 ) {
237 get_cred(p->cred);
238 atomic_inc(&p->cred->user->processes);
239 return 0;
240 }
241
242 new = prepare_creds();
243 if (!new)
117 return -ENOMEM; 244 return -ENOMEM;
118 245
119#ifdef CONFIG_KEYS 246#ifdef CONFIG_KEYS
120 if (clone_flags & CLONE_THREAD) { 247 /* new threads get their own thread keyrings if their parent already
121 atomic_inc(&pcred->tgcred->usage); 248 * had one */
122 } else { 249 if (new->thread_keyring) {
123 pcred->tgcred = kmalloc(sizeof(struct cred), GFP_KERNEL); 250 key_put(new->thread_keyring);
124 if (!pcred->tgcred) { 251 new->thread_keyring = NULL;
125 kfree(pcred); 252 if (clone_flags & CLONE_THREAD)
253 install_thread_keyring_to_cred(new);
254 }
255
256 /* we share the process and session keyrings between all the threads in
257 * a process - this is slightly icky as we violate COW credentials a
258 * bit */
259 if (!(clone_flags & CLONE_THREAD)) {
260 tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
261 if (!tgcred) {
262 put_cred(new);
126 return -ENOMEM; 263 return -ENOMEM;
127 } 264 }
128 atomic_set(&pcred->tgcred->usage, 1); 265 atomic_set(&tgcred->usage, 1);
129 spin_lock_init(&pcred->tgcred->lock); 266 spin_lock_init(&tgcred->lock);
130 pcred->tgcred->process_keyring = NULL; 267 tgcred->process_keyring = NULL;
131 pcred->tgcred->session_keyring = 268 tgcred->session_keyring = key_get(new->tgcred->session_keyring);
132 key_get(p->cred->tgcred->session_keyring); 269
270 release_tgcred(new);
271 new->tgcred = tgcred;
133 } 272 }
134#endif 273#endif
135 274
136#ifdef CONFIG_SECURITY 275 atomic_inc(&new->user->processes);
137 pcred->security = NULL; 276 p->cred = new;
138#endif 277 return 0;
278}
139 279
140 ret = security_cred_alloc(pcred); 280/**
141 if (ret < 0) { 281 * commit_creds - Install new credentials upon the current task
142 release_tgcred(pcred); 282 * @new: The credentials to be assigned
143 kfree(pcred); 283 *
144 return ret; 284 * Install a new set of credentials to the current task, using RCU to replace
285 * the old set.
286 *
287 * This function eats the caller's reference to the new credentials.
288 *
289 * Always returns 0 thus allowing this function to be tail-called at the end
290 * of, say, sys_setgid().
291 */
292int commit_creds(struct cred *new)
293{
294 struct task_struct *task = current;
295 const struct cred *old;
296
297 BUG_ON(atomic_read(&new->usage) < 1);
298 BUG_ON(atomic_read(&task->cred->usage) < 1);
299
300 old = task->cred;
301 security_commit_creds(new, old);
302
303 /* dumpability changes */
304 if (old->euid != new->euid ||
305 old->egid != new->egid ||
306 old->fsuid != new->fsuid ||
307 old->fsgid != new->fsgid ||
308 !cap_issubset(new->cap_permitted, old->cap_permitted)) {
309 set_dumpable(task->mm, suid_dumpable);
310 task->pdeath_signal = 0;
311 smp_wmb();
145 } 312 }
146 313
147 atomic_set(&pcred->usage, 1); 314 /* alter the thread keyring */
148 get_group_info(pcred->group_info); 315 if (new->fsuid != old->fsuid)
149 get_uid(pcred->user); 316 key_fsuid_changed(task);
150 key_get(pcred->thread_keyring); 317 if (new->fsgid != old->fsgid)
151 key_get(pcred->request_key_auth); 318 key_fsgid_changed(task);
319
320 /* do it
321 * - What if a process setreuid()'s and this brings the
322 * new uid over his NPROC rlimit? We can check this now
323 * cheaply with the new uid cache, so if it matters
324 * we should be checking for it. -DaveM
325 */
326 if (new->user != old->user)
327 atomic_inc(&new->user->processes);
328 rcu_assign_pointer(task->cred, new);
329 if (new->user != old->user)
330 atomic_dec(&old->user->processes);
331
332 sched_switch_user(task);
333
334 /* send notifications */
335 if (new->uid != old->uid ||
336 new->euid != old->euid ||
337 new->suid != old->suid ||
338 new->fsuid != old->fsuid)
339 proc_id_connector(task, PROC_EVENT_UID);
152 340
153 atomic_inc(&pcred->user->processes); 341 if (new->gid != old->gid ||
342 new->egid != old->egid ||
343 new->sgid != old->sgid ||
344 new->fsgid != old->fsgid)
345 proc_id_connector(task, PROC_EVENT_GID);
154 346
155 /* RCU assignment is unneeded here as no-one can have accessed this 347 put_cred(old);
156 * pointer yet, barring us */
157 p->cred = pcred;
158 return 0; 348 return 0;
159} 349}
350EXPORT_SYMBOL(commit_creds);
351
352/**
353 * abort_creds - Discard a set of credentials and unlock the current task
354 * @new: The credentials that were going to be applied
355 *
356 * Discard a set of credentials that were under construction and unlock the
357 * current task.
358 */
359void abort_creds(struct cred *new)
360{
361 BUG_ON(atomic_read(&new->usage) < 1);
362 put_cred(new);
363}
364EXPORT_SYMBOL(abort_creds);
365
366/**
367 * override_creds - Temporarily override the current process's credentials
368 * @new: The credentials to be assigned
369 *
370 * Install a set of temporary override credentials on the current process,
371 * returning the old set for later reversion.
372 */
373const struct cred *override_creds(const struct cred *new)
374{
375 const struct cred *old = current->cred;
376
377 rcu_assign_pointer(current->cred, get_cred(new));
378 return old;
379}
380EXPORT_SYMBOL(override_creds);
381
382/**
383 * revert_creds - Revert a temporary credentials override
384 * @old: The credentials to be restored
385 *
386 * Revert a temporary set of override credentials to an old set, discarding the
387 * override set.
388 */
389void revert_creds(const struct cred *old)
390{
391 const struct cred *override = current->cred;
392
393 rcu_assign_pointer(current->cred, old);
394 put_cred(override);
395}
396EXPORT_SYMBOL(revert_creds);
397
398/*
399 * initialise the credentials stuff
400 */
401void __init cred_init(void)
402{
403 /* allocate a slab in which we can store credentials */
404 cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred),
405 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
406}
diff --git a/kernel/exit.c b/kernel/exit.c
index bbc22530f2c1..c0711da15486 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -47,12 +47,14 @@
47#include <linux/blkdev.h> 47#include <linux/blkdev.h>
48#include <linux/task_io_accounting_ops.h> 48#include <linux/task_io_accounting_ops.h>
49#include <linux/tracehook.h> 49#include <linux/tracehook.h>
50#include <linux/init_task.h>
50#include <trace/sched.h> 51#include <trace/sched.h>
51 52
52#include <asm/uaccess.h> 53#include <asm/uaccess.h>
53#include <asm/unistd.h> 54#include <asm/unistd.h>
54#include <asm/pgtable.h> 55#include <asm/pgtable.h>
55#include <asm/mmu_context.h> 56#include <asm/mmu_context.h>
57#include "cred-internals.h"
56 58
57static void exit_mm(struct task_struct * tsk); 59static void exit_mm(struct task_struct * tsk);
58 60
@@ -338,12 +340,12 @@ static void reparent_to_kthreadd(void)
338 /* cpus_allowed? */ 340 /* cpus_allowed? */
339 /* rt_priority? */ 341 /* rt_priority? */
340 /* signals? */ 342 /* signals? */
341 security_task_reparent_to_init(current);
342 memcpy(current->signal->rlim, init_task.signal->rlim, 343 memcpy(current->signal->rlim, init_task.signal->rlim,
343 sizeof(current->signal->rlim)); 344 sizeof(current->signal->rlim));
344 atomic_inc(&(INIT_USER->__count)); 345
346 atomic_inc(&init_cred.usage);
347 commit_creds(&init_cred);
345 write_unlock_irq(&tasklist_lock); 348 write_unlock_irq(&tasklist_lock);
346 switch_uid(INIT_USER);
347} 349}
348 350
349void __set_special_pids(struct pid *pid) 351void __set_special_pids(struct pid *pid)
@@ -1085,7 +1087,6 @@ NORET_TYPE void do_exit(long code)
1085 check_stack_usage(); 1087 check_stack_usage();
1086 exit_thread(); 1088 exit_thread();
1087 cgroup_exit(tsk, 1); 1089 cgroup_exit(tsk, 1);
1088 exit_keys(tsk);
1089 1090
1090 if (group_dead && tsk->signal->leader) 1091 if (group_dead && tsk->signal->leader)
1091 disassociate_ctty(1); 1092 disassociate_ctty(1);
diff --git a/kernel/fork.c b/kernel/fork.c
index ded1972672a3..82a7948a664e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1084,10 +1084,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1084 goto bad_fork_cleanup_sighand; 1084 goto bad_fork_cleanup_sighand;
1085 if ((retval = copy_mm(clone_flags, p))) 1085 if ((retval = copy_mm(clone_flags, p)))
1086 goto bad_fork_cleanup_signal; 1086 goto bad_fork_cleanup_signal;
1087 if ((retval = copy_keys(clone_flags, p)))
1088 goto bad_fork_cleanup_mm;
1089 if ((retval = copy_namespaces(clone_flags, p))) 1087 if ((retval = copy_namespaces(clone_flags, p)))
1090 goto bad_fork_cleanup_keys; 1088 goto bad_fork_cleanup_mm;
1091 if ((retval = copy_io(clone_flags, p))) 1089 if ((retval = copy_io(clone_flags, p)))
1092 goto bad_fork_cleanup_namespaces; 1090 goto bad_fork_cleanup_namespaces;
1093 retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); 1091 retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
@@ -1252,8 +1250,6 @@ bad_fork_cleanup_io:
1252 put_io_context(p->io_context); 1250 put_io_context(p->io_context);
1253bad_fork_cleanup_namespaces: 1251bad_fork_cleanup_namespaces:
1254 exit_task_namespaces(p); 1252 exit_task_namespaces(p);
1255bad_fork_cleanup_keys:
1256 exit_keys(p);
1257bad_fork_cleanup_mm: 1253bad_fork_cleanup_mm:
1258 if (p->mm) 1254 if (p->mm)
1259 mmput(p->mm); 1255 mmput(p->mm);
@@ -1281,6 +1277,7 @@ bad_fork_cleanup_cgroup:
1281bad_fork_cleanup_put_domain: 1277bad_fork_cleanup_put_domain:
1282 module_put(task_thread_info(p)->exec_domain->module); 1278 module_put(task_thread_info(p)->exec_domain->module);
1283bad_fork_cleanup_count: 1279bad_fork_cleanup_count:
1280 atomic_dec(&p->cred->user->processes);
1284 put_cred(p->cred); 1281 put_cred(p->cred);
1285bad_fork_free: 1282bad_fork_free:
1286 free_task(p); 1283 free_task(p);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index f044f8f57703..b46dbb908669 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -118,10 +118,10 @@ EXPORT_SYMBOL(request_module);
118struct subprocess_info { 118struct subprocess_info {
119 struct work_struct work; 119 struct work_struct work;
120 struct completion *complete; 120 struct completion *complete;
121 struct cred *cred;
121 char *path; 122 char *path;
122 char **argv; 123 char **argv;
123 char **envp; 124 char **envp;
124 struct key *ring;
125 enum umh_wait wait; 125 enum umh_wait wait;
126 int retval; 126 int retval;
127 struct file *stdin; 127 struct file *stdin;
@@ -134,19 +134,20 @@ struct subprocess_info {
134static int ____call_usermodehelper(void *data) 134static int ____call_usermodehelper(void *data)
135{ 135{
136 struct subprocess_info *sub_info = data; 136 struct subprocess_info *sub_info = data;
137 struct key *new_session, *old_session;
138 int retval; 137 int retval;
139 138
140 /* Unblock all signals and set the session keyring. */ 139 BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
141 new_session = key_get(sub_info->ring); 140
141 /* Unblock all signals */
142 spin_lock_irq(&current->sighand->siglock); 142 spin_lock_irq(&current->sighand->siglock);
143 old_session = __install_session_keyring(new_session);
144 flush_signal_handlers(current, 1); 143 flush_signal_handlers(current, 1);
145 sigemptyset(&current->blocked); 144 sigemptyset(&current->blocked);
146 recalc_sigpending(); 145 recalc_sigpending();
147 spin_unlock_irq(&current->sighand->siglock); 146 spin_unlock_irq(&current->sighand->siglock);
148 147
149 key_put(old_session); 148 /* Install the credentials */
149 commit_creds(sub_info->cred);
150 sub_info->cred = NULL;
150 151
151 /* Install input pipe when needed */ 152 /* Install input pipe when needed */
152 if (sub_info->stdin) { 153 if (sub_info->stdin) {
@@ -185,6 +186,8 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info)
185{ 186{
186 if (info->cleanup) 187 if (info->cleanup)
187 (*info->cleanup)(info->argv, info->envp); 188 (*info->cleanup)(info->argv, info->envp);
189 if (info->cred)
190 put_cred(info->cred);
188 kfree(info); 191 kfree(info);
189} 192}
190EXPORT_SYMBOL(call_usermodehelper_freeinfo); 193EXPORT_SYMBOL(call_usermodehelper_freeinfo);
@@ -240,6 +243,8 @@ static void __call_usermodehelper(struct work_struct *work)
240 pid_t pid; 243 pid_t pid;
241 enum umh_wait wait = sub_info->wait; 244 enum umh_wait wait = sub_info->wait;
242 245
246 BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
247
243 /* CLONE_VFORK: wait until the usermode helper has execve'd 248 /* CLONE_VFORK: wait until the usermode helper has execve'd
244 * successfully We need the data structures to stay around 249 * successfully We need the data structures to stay around
245 * until that is done. */ 250 * until that is done. */
@@ -362,6 +367,9 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
362 sub_info->path = path; 367 sub_info->path = path;
363 sub_info->argv = argv; 368 sub_info->argv = argv;
364 sub_info->envp = envp; 369 sub_info->envp = envp;
370 sub_info->cred = prepare_usermodehelper_creds();
371 if (!sub_info->cred)
372 return NULL;
365 373
366 out: 374 out:
367 return sub_info; 375 return sub_info;
@@ -376,7 +384,13 @@ EXPORT_SYMBOL(call_usermodehelper_setup);
376void call_usermodehelper_setkeys(struct subprocess_info *info, 384void call_usermodehelper_setkeys(struct subprocess_info *info,
377 struct key *session_keyring) 385 struct key *session_keyring)
378{ 386{
379 info->ring = session_keyring; 387#ifdef CONFIG_KEYS
388 struct thread_group_cred *tgcred = info->cred->tgcred;
389 key_put(tgcred->session_keyring);
390 tgcred->session_keyring = key_get(session_keyring);
391#else
392 BUG();
393#endif
380} 394}
381EXPORT_SYMBOL(call_usermodehelper_setkeys); 395EXPORT_SYMBOL(call_usermodehelper_setkeys);
382 396
@@ -444,6 +458,8 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
444 DECLARE_COMPLETION_ONSTACK(done); 458 DECLARE_COMPLETION_ONSTACK(done);
445 int retval = 0; 459 int retval = 0;
446 460
461 BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
462
447 helper_lock(); 463 helper_lock();
448 if (sub_info->path[0] == '\0') 464 if (sub_info->path[0] == '\0')
449 goto out; 465 goto out;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b9d5f4e4f6a4..f764b8806955 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -171,6 +171,14 @@ int ptrace_attach(struct task_struct *task)
171 if (same_thread_group(task, current)) 171 if (same_thread_group(task, current))
172 goto out; 172 goto out;
173 173
174 /* Protect exec's credential calculations against our interference;
175 * SUID, SGID and LSM creds get determined differently under ptrace.
176 */
177 retval = mutex_lock_interruptible(&current->cred_exec_mutex);
178 if (retval < 0)
179 goto out;
180
181 retval = -EPERM;
174repeat: 182repeat:
175 /* 183 /*
176 * Nasty, nasty. 184 * Nasty, nasty.
@@ -210,6 +218,7 @@ repeat:
210bad: 218bad:
211 write_unlock_irqrestore(&tasklist_lock, flags); 219 write_unlock_irqrestore(&tasklist_lock, flags);
212 task_unlock(task); 220 task_unlock(task);
221 mutex_unlock(&current->cred_exec_mutex);
213out: 222out:
214 return retval; 223 return retval;
215} 224}
diff --git a/kernel/signal.c b/kernel/signal.c
index 84989124bafb..2a64304ed54b 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -180,7 +180,7 @@ int next_signal(struct sigpending *pending, sigset_t *mask)
180/* 180/*
181 * allocate a new signal queue record 181 * allocate a new signal queue record
182 * - this may be called without locks if and only if t == current, otherwise an 182 * - this may be called without locks if and only if t == current, otherwise an
183 * appopriate lock must be held to protect t's user_struct 183 * appopriate lock must be held to stop the target task from exiting
184 */ 184 */
185static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, 185static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
186 int override_rlimit) 186 int override_rlimit)
@@ -194,7 +194,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
194 * caller must be holding the RCU readlock (by way of a spinlock) and 194 * caller must be holding the RCU readlock (by way of a spinlock) and
195 * we use RCU protection here 195 * we use RCU protection here
196 */ 196 */
197 user = __task_cred(t)->user; 197 user = get_uid(__task_cred(t)->user);
198 atomic_inc(&user->sigpending); 198 atomic_inc(&user->sigpending);
199 if (override_rlimit || 199 if (override_rlimit ||
200 atomic_read(&user->sigpending) <= 200 atomic_read(&user->sigpending) <=
@@ -202,12 +202,14 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
202 q = kmem_cache_alloc(sigqueue_cachep, flags); 202 q = kmem_cache_alloc(sigqueue_cachep, flags);
203 if (unlikely(q == NULL)) { 203 if (unlikely(q == NULL)) {
204 atomic_dec(&user->sigpending); 204 atomic_dec(&user->sigpending);
205 free_uid(user);
205 } else { 206 } else {
206 INIT_LIST_HEAD(&q->list); 207 INIT_LIST_HEAD(&q->list);
207 q->flags = 0; 208 q->flags = 0;
208 q->user = get_uid(user); 209 q->user = user;
209 } 210 }
210 return(q); 211
212 return q;
211} 213}
212 214
213static void __sigqueue_free(struct sigqueue *q) 215static void __sigqueue_free(struct sigqueue *q)
diff --git a/kernel/sys.c b/kernel/sys.c
index ccc9eb736d35..ab735040468a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -180,7 +180,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
180 } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); 180 } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
181 break; 181 break;
182 case PRIO_USER: 182 case PRIO_USER:
183 user = cred->user; 183 user = (struct user_struct *) cred->user;
184 if (!who) 184 if (!who)
185 who = cred->uid; 185 who = cred->uid;
186 else if ((who != cred->uid) && 186 else if ((who != cred->uid) &&
@@ -479,47 +479,48 @@ void ctrl_alt_del(void)
479 */ 479 */
480asmlinkage long sys_setregid(gid_t rgid, gid_t egid) 480asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
481{ 481{
482 struct cred *cred = current->cred; 482 const struct cred *old;
483 int old_rgid = cred->gid; 483 struct cred *new;
484 int old_egid = cred->egid;
485 int new_rgid = old_rgid;
486 int new_egid = old_egid;
487 int retval; 484 int retval;
488 485
486 new = prepare_creds();
487 if (!new)
488 return -ENOMEM;
489 old = current_cred();
490
489 retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); 491 retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
490 if (retval) 492 if (retval)
491 return retval; 493 goto error;
492 494
495 retval = -EPERM;
493 if (rgid != (gid_t) -1) { 496 if (rgid != (gid_t) -1) {
494 if ((old_rgid == rgid) || 497 if (old->gid == rgid ||
495 (cred->egid == rgid) || 498 old->egid == rgid ||
496 capable(CAP_SETGID)) 499 capable(CAP_SETGID))
497 new_rgid = rgid; 500 new->gid = rgid;
498 else 501 else
499 return -EPERM; 502 goto error;
500 } 503 }
501 if (egid != (gid_t) -1) { 504 if (egid != (gid_t) -1) {
502 if ((old_rgid == egid) || 505 if (old->gid == egid ||
503 (cred->egid == egid) || 506 old->egid == egid ||
504 (cred->sgid == egid) || 507 old->sgid == egid ||
505 capable(CAP_SETGID)) 508 capable(CAP_SETGID))
506 new_egid = egid; 509 new->egid = egid;
507 else 510 else
508 return -EPERM; 511 goto error;
509 }
510 if (new_egid != old_egid) {
511 set_dumpable(current->mm, suid_dumpable);
512 smp_wmb();
513 } 512 }
513
514 if (rgid != (gid_t) -1 || 514 if (rgid != (gid_t) -1 ||
515 (egid != (gid_t) -1 && egid != old_rgid)) 515 (egid != (gid_t) -1 && egid != old->gid))
516 cred->sgid = new_egid; 516 new->sgid = new->egid;
517 cred->fsgid = new_egid; 517 new->fsgid = new->egid;
518 cred->egid = new_egid; 518
519 cred->gid = new_rgid; 519 return commit_creds(new);
520 key_fsgid_changed(current); 520
521 proc_id_connector(current, PROC_EVENT_GID); 521error:
522 return 0; 522 abort_creds(new);
523 return retval;
523} 524}
524 525
525/* 526/*
@@ -529,40 +530,42 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
529 */ 530 */
530asmlinkage long sys_setgid(gid_t gid) 531asmlinkage long sys_setgid(gid_t gid)
531{ 532{
532 struct cred *cred = current->cred; 533 const struct cred *old;
533 int old_egid = cred->egid; 534 struct cred *new;
534 int retval; 535 int retval;
535 536
537 new = prepare_creds();
538 if (!new)
539 return -ENOMEM;
540 old = current_cred();
541
536 retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); 542 retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
537 if (retval) 543 if (retval)
538 return retval; 544 goto error;
539 545
540 if (capable(CAP_SETGID)) { 546 retval = -EPERM;
541 if (old_egid != gid) { 547 if (capable(CAP_SETGID))
542 set_dumpable(current->mm, suid_dumpable); 548 new->gid = new->egid = new->sgid = new->fsgid = gid;
543 smp_wmb(); 549 else if (gid == old->gid || gid == old->sgid)
544 } 550 new->egid = new->fsgid = gid;
545 cred->gid = cred->egid = cred->sgid = cred->fsgid = gid;
546 } else if ((gid == cred->gid) || (gid == cred->sgid)) {
547 if (old_egid != gid) {
548 set_dumpable(current->mm, suid_dumpable);
549 smp_wmb();
550 }
551 cred->egid = cred->fsgid = gid;
552 }
553 else 551 else
554 return -EPERM; 552 goto error;
555 553
556 key_fsgid_changed(current); 554 return commit_creds(new);
557 proc_id_connector(current, PROC_EVENT_GID); 555
558 return 0; 556error:
557 abort_creds(new);
558 return retval;
559} 559}
560 560
561static int set_user(uid_t new_ruid, int dumpclear) 561/*
562 * change the user struct in a credentials set to match the new UID
563 */
564static int set_user(struct cred *new)
562{ 565{
563 struct user_struct *new_user; 566 struct user_struct *new_user;
564 567
565 new_user = alloc_uid(current->nsproxy->user_ns, new_ruid); 568 new_user = alloc_uid(current->nsproxy->user_ns, new->uid);
566 if (!new_user) 569 if (!new_user)
567 return -EAGAIN; 570 return -EAGAIN;
568 571
@@ -573,13 +576,8 @@ static int set_user(uid_t new_ruid, int dumpclear)
573 return -EAGAIN; 576 return -EAGAIN;
574 } 577 }
575 578
576 switch_uid(new_user); 579 free_uid(new->user);
577 580 new->user = new_user;
578 if (dumpclear) {
579 set_dumpable(current->mm, suid_dumpable);
580 smp_wmb();
581 }
582 current->cred->uid = new_ruid;
583 return 0; 581 return 0;
584} 582}
585 583
@@ -600,55 +598,56 @@ static int set_user(uid_t new_ruid, int dumpclear)
600 */ 598 */
601asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) 599asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
602{ 600{
603 struct cred *cred = current->cred; 601 const struct cred *old;
604 int old_ruid, old_euid, old_suid, new_ruid, new_euid; 602 struct cred *new;
605 int retval; 603 int retval;
606 604
605 new = prepare_creds();
606 if (!new)
607 return -ENOMEM;
608 old = current_cred();
609
607 retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); 610 retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
608 if (retval) 611 if (retval)
609 return retval; 612 goto error;
610
611 new_ruid = old_ruid = cred->uid;
612 new_euid = old_euid = cred->euid;
613 old_suid = cred->suid;
614 613
614 retval = -EPERM;
615 if (ruid != (uid_t) -1) { 615 if (ruid != (uid_t) -1) {
616 new_ruid = ruid; 616 new->uid = ruid;
617 if ((old_ruid != ruid) && 617 if (old->uid != ruid &&
618 (cred->euid != ruid) && 618 old->euid != ruid &&
619 !capable(CAP_SETUID)) 619 !capable(CAP_SETUID))
620 return -EPERM; 620 goto error;
621 } 621 }
622 622
623 if (euid != (uid_t) -1) { 623 if (euid != (uid_t) -1) {
624 new_euid = euid; 624 new->euid = euid;
625 if ((old_ruid != euid) && 625 if (old->uid != euid &&
626 (cred->euid != euid) && 626 old->euid != euid &&
627 (cred->suid != euid) && 627 old->suid != euid &&
628 !capable(CAP_SETUID)) 628 !capable(CAP_SETUID))
629 return -EPERM; 629 goto error;
630 } 630 }
631 631
632 if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) 632 retval = -EAGAIN;
633 return -EAGAIN; 633 if (new->uid != old->uid && set_user(new) < 0)
634 goto error;
634 635
635 if (new_euid != old_euid) {
636 set_dumpable(current->mm, suid_dumpable);
637 smp_wmb();
638 }
639 cred->fsuid = cred->euid = new_euid;
640 if (ruid != (uid_t) -1 || 636 if (ruid != (uid_t) -1 ||
641 (euid != (uid_t) -1 && euid != old_ruid)) 637 (euid != (uid_t) -1 && euid != old->uid))
642 cred->suid = cred->euid; 638 new->suid = new->euid;
643 cred->fsuid = cred->euid; 639 new->fsuid = new->euid;
644
645 key_fsuid_changed(current);
646 proc_id_connector(current, PROC_EVENT_UID);
647 640
648 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); 641 retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
649} 642 if (retval < 0)
643 goto error;
650 644
645 return commit_creds(new);
651 646
647error:
648 abort_creds(new);
649 return retval;
650}
652 651
653/* 652/*
654 * setuid() is implemented like SysV with SAVED_IDS 653 * setuid() is implemented like SysV with SAVED_IDS
@@ -663,37 +662,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
663 */ 662 */
664asmlinkage long sys_setuid(uid_t uid) 663asmlinkage long sys_setuid(uid_t uid)
665{ 664{
666 struct cred *cred = current->cred; 665 const struct cred *old;
667 int old_euid = cred->euid; 666 struct cred *new;
668 int old_ruid, old_suid, new_suid;
669 int retval; 667 int retval;
670 668
669 new = prepare_creds();
670 if (!new)
671 return -ENOMEM;
672 old = current_cred();
673
671 retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); 674 retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
672 if (retval) 675 if (retval)
673 return retval; 676 goto error;
674 677
675 old_ruid = cred->uid; 678 retval = -EPERM;
676 old_suid = cred->suid;
677 new_suid = old_suid;
678
679 if (capable(CAP_SETUID)) { 679 if (capable(CAP_SETUID)) {
680 if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) 680 new->suid = new->uid = uid;
681 return -EAGAIN; 681 if (uid != old->uid && set_user(new) < 0) {
682 new_suid = uid; 682 retval = -EAGAIN;
683 } else if ((uid != cred->uid) && (uid != new_suid)) 683 goto error;
684 return -EPERM; 684 }
685 685 } else if (uid != old->uid && uid != new->suid) {
686 if (old_euid != uid) { 686 goto error;
687 set_dumpable(current->mm, suid_dumpable);
688 smp_wmb();
689 } 687 }
690 cred->fsuid = cred->euid = uid;
691 cred->suid = new_suid;
692 688
693 key_fsuid_changed(current); 689 new->fsuid = new->euid = uid;
694 proc_id_connector(current, PROC_EVENT_UID); 690
691 retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
692 if (retval < 0)
693 goto error;
694
695 return commit_creds(new);
695 696
696 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); 697error:
698 abort_creds(new);
699 return retval;
697} 700}
698 701
699 702
@@ -703,47 +706,53 @@ asmlinkage long sys_setuid(uid_t uid)
703 */ 706 */
704asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) 707asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
705{ 708{
706 struct cred *cred = current->cred; 709 const struct cred *old;
707 int old_ruid = cred->uid; 710 struct cred *new;
708 int old_euid = cred->euid;
709 int old_suid = cred->suid;
710 int retval; 711 int retval;
711 712
713 new = prepare_creds();
714 if (!new)
715 return -ENOMEM;
716
712 retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); 717 retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
713 if (retval) 718 if (retval)
714 return retval; 719 goto error;
720 old = current_cred();
715 721
722 retval = -EPERM;
716 if (!capable(CAP_SETUID)) { 723 if (!capable(CAP_SETUID)) {
717 if ((ruid != (uid_t) -1) && (ruid != cred->uid) && 724 if (ruid != (uid_t) -1 && ruid != old->uid &&
718 (ruid != cred->euid) && (ruid != cred->suid)) 725 ruid != old->euid && ruid != old->suid)
719 return -EPERM; 726 goto error;
720 if ((euid != (uid_t) -1) && (euid != cred->uid) && 727 if (euid != (uid_t) -1 && euid != old->uid &&
721 (euid != cred->euid) && (euid != cred->suid)) 728 euid != old->euid && euid != old->suid)
722 return -EPERM; 729 goto error;
723 if ((suid != (uid_t) -1) && (suid != cred->uid) && 730 if (suid != (uid_t) -1 && suid != old->uid &&
724 (suid != cred->euid) && (suid != cred->suid)) 731 suid != old->euid && suid != old->suid)
725 return -EPERM; 732 goto error;
726 } 733 }
734
735 retval = -EAGAIN;
727 if (ruid != (uid_t) -1) { 736 if (ruid != (uid_t) -1) {
728 if (ruid != cred->uid && 737 new->uid = ruid;
729 set_user(ruid, euid != cred->euid) < 0) 738 if (ruid != old->uid && set_user(new) < 0)
730 return -EAGAIN; 739 goto error;
731 } 740 }
732 if (euid != (uid_t) -1) { 741 if (euid != (uid_t) -1)
733 if (euid != cred->euid) { 742 new->euid = euid;
734 set_dumpable(current->mm, suid_dumpable);
735 smp_wmb();
736 }
737 cred->euid = euid;
738 }
739 cred->fsuid = cred->euid;
740 if (suid != (uid_t) -1) 743 if (suid != (uid_t) -1)
741 cred->suid = suid; 744 new->suid = suid;
745 new->fsuid = new->euid;
742 746
743 key_fsuid_changed(current); 747 retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
744 proc_id_connector(current, PROC_EVENT_UID); 748 if (retval < 0)
749 goto error;
745 750
746 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); 751 return commit_creds(new);
752
753error:
754 abort_creds(new);
755 return retval;
747} 756}
748 757
749asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) 758asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
@@ -763,40 +772,45 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us
763 */ 772 */
764asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) 773asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
765{ 774{
766 struct cred *cred = current->cred; 775 const struct cred *old;
776 struct cred *new;
767 int retval; 777 int retval;
768 778
779 new = prepare_creds();
780 if (!new)
781 return -ENOMEM;
782 old = current_cred();
783
769 retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); 784 retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
770 if (retval) 785 if (retval)
771 return retval; 786 goto error;
772 787
788 retval = -EPERM;
773 if (!capable(CAP_SETGID)) { 789 if (!capable(CAP_SETGID)) {
774 if ((rgid != (gid_t) -1) && (rgid != cred->gid) && 790 if (rgid != (gid_t) -1 && rgid != old->gid &&
775 (rgid != cred->egid) && (rgid != cred->sgid)) 791 rgid != old->egid && rgid != old->sgid)
776 return -EPERM; 792 goto error;
777 if ((egid != (gid_t) -1) && (egid != cred->gid) && 793 if (egid != (gid_t) -1 && egid != old->gid &&
778 (egid != cred->egid) && (egid != cred->sgid)) 794 egid != old->egid && egid != old->sgid)
779 return -EPERM; 795 goto error;
780 if ((sgid != (gid_t) -1) && (sgid != cred->gid) && 796 if (sgid != (gid_t) -1 && sgid != old->gid &&
781 (sgid != cred->egid) && (sgid != cred->sgid)) 797 sgid != old->egid && sgid != old->sgid)
782 return -EPERM; 798 goto error;
783 } 799 }
784 if (egid != (gid_t) -1) { 800
785 if (egid != cred->egid) {
786 set_dumpable(current->mm, suid_dumpable);
787 smp_wmb();
788 }
789 cred->egid = egid;
790 }
791 cred->fsgid = cred->egid;
792 if (rgid != (gid_t) -1) 801 if (rgid != (gid_t) -1)
793 cred->gid = rgid; 802 new->gid = rgid;
803 if (egid != (gid_t) -1)
804 new->egid = egid;
794 if (sgid != (gid_t) -1) 805 if (sgid != (gid_t) -1)
795 cred->sgid = sgid; 806 new->sgid = sgid;
807 new->fsgid = new->egid;
796 808
797 key_fsgid_changed(current); 809 return commit_creds(new);
798 proc_id_connector(current, PROC_EVENT_GID); 810
799 return 0; 811error:
812 abort_creds(new);
813 return retval;
800} 814}
801 815
802asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) 816asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid)
@@ -820,28 +834,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us
820 */ 834 */
821asmlinkage long sys_setfsuid(uid_t uid) 835asmlinkage long sys_setfsuid(uid_t uid)
822{ 836{
823 struct cred *cred = current->cred; 837 const struct cred *old;
824 int old_fsuid; 838 struct cred *new;
839 uid_t old_fsuid;
840
841 new = prepare_creds();
842 if (!new)
843 return current_fsuid();
844 old = current_cred();
845 old_fsuid = old->fsuid;
825 846
826 old_fsuid = cred->fsuid; 847 if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
827 if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) 848 goto error;
828 return old_fsuid;
829 849
830 if (uid == cred->uid || uid == cred->euid || 850 if (uid == old->uid || uid == old->euid ||
831 uid == cred->suid || uid == cred->fsuid || 851 uid == old->suid || uid == old->fsuid ||
832 capable(CAP_SETUID)) { 852 capable(CAP_SETUID)) {
833 if (uid != old_fsuid) { 853 if (uid != old_fsuid) {
834 set_dumpable(current->mm, suid_dumpable); 854 new->fsuid = uid;
835 smp_wmb(); 855 if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
856 goto change_okay;
836 } 857 }
837 cred->fsuid = uid;
838 } 858 }
839 859
840 key_fsuid_changed(current); 860error:
841 proc_id_connector(current, PROC_EVENT_UID); 861 abort_creds(new);
842 862 return old_fsuid;
843 security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
844 863
864change_okay:
865 commit_creds(new);
845 return old_fsuid; 866 return old_fsuid;
846} 867}
847 868
@@ -850,24 +871,34 @@ asmlinkage long sys_setfsuid(uid_t uid)
850 */ 871 */
851asmlinkage long sys_setfsgid(gid_t gid) 872asmlinkage long sys_setfsgid(gid_t gid)
852{ 873{
853 struct cred *cred = current->cred; 874 const struct cred *old;
854 int old_fsgid; 875 struct cred *new;
876 gid_t old_fsgid;
877
878 new = prepare_creds();
879 if (!new)
880 return current_fsgid();
881 old = current_cred();
882 old_fsgid = old->fsgid;
855 883
856 old_fsgid = cred->fsgid;
857 if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) 884 if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
858 return old_fsgid; 885 goto error;
859 886
860 if (gid == cred->gid || gid == cred->egid || 887 if (gid == old->gid || gid == old->egid ||
861 gid == cred->sgid || gid == cred->fsgid || 888 gid == old->sgid || gid == old->fsgid ||
862 capable(CAP_SETGID)) { 889 capable(CAP_SETGID)) {
863 if (gid != old_fsgid) { 890 if (gid != old_fsgid) {
864 set_dumpable(current->mm, suid_dumpable); 891 new->fsgid = gid;
865 smp_wmb(); 892 goto change_okay;
866 } 893 }
867 cred->fsgid = gid;
868 key_fsgid_changed(current);
869 proc_id_connector(current, PROC_EVENT_GID);
870 } 894 }
895
896error:
897 abort_creds(new);
898 return old_fsgid;
899
900change_okay:
901 commit_creds(new);
871 return old_fsgid; 902 return old_fsgid;
872} 903}
873 904
@@ -1136,7 +1167,7 @@ EXPORT_SYMBOL(groups_free);
1136 1167
1137/* export the group_info to a user-space array */ 1168/* export the group_info to a user-space array */
1138static int groups_to_user(gid_t __user *grouplist, 1169static int groups_to_user(gid_t __user *grouplist,
1139 struct group_info *group_info) 1170 const struct group_info *group_info)
1140{ 1171{
1141 int i; 1172 int i;
1142 unsigned int count = group_info->ngroups; 1173 unsigned int count = group_info->ngroups;
@@ -1227,31 +1258,25 @@ int groups_search(const struct group_info *group_info, gid_t grp)
1227} 1258}
1228 1259
1229/** 1260/**
1230 * set_groups - Change a group subscription in a security record 1261 * set_groups - Change a group subscription in a set of credentials
1231 * @sec: The security record to alter 1262 * @new: The newly prepared set of credentials to alter
1232 * @group_info: The group list to impose 1263 * @group_info: The group list to install
1233 * 1264 *
1234 * Validate a group subscription and, if valid, impose it upon a task security 1265 * Validate a group subscription and, if valid, insert it into a set
1235 * record. 1266 * of credentials.
1236 */ 1267 */
1237int set_groups(struct cred *cred, struct group_info *group_info) 1268int set_groups(struct cred *new, struct group_info *group_info)
1238{ 1269{
1239 int retval; 1270 int retval;
1240 struct group_info *old_info;
1241 1271
1242 retval = security_task_setgroups(group_info); 1272 retval = security_task_setgroups(group_info);
1243 if (retval) 1273 if (retval)
1244 return retval; 1274 return retval;
1245 1275
1276 put_group_info(new->group_info);
1246 groups_sort(group_info); 1277 groups_sort(group_info);
1247 get_group_info(group_info); 1278 get_group_info(group_info);
1248 1279 new->group_info = group_info;
1249 spin_lock(&cred->lock);
1250 old_info = cred->group_info;
1251 cred->group_info = group_info;
1252 spin_unlock(&cred->lock);
1253
1254 put_group_info(old_info);
1255 return 0; 1280 return 0;
1256} 1281}
1257 1282
@@ -1266,7 +1291,20 @@ EXPORT_SYMBOL(set_groups);
1266 */ 1291 */
1267int set_current_groups(struct group_info *group_info) 1292int set_current_groups(struct group_info *group_info)
1268{ 1293{
1269 return set_groups(current->cred, group_info); 1294 struct cred *new;
1295 int ret;
1296
1297 new = prepare_creds();
1298 if (!new)
1299 return -ENOMEM;
1300
1301 ret = set_groups(new, group_info);
1302 if (ret < 0) {
1303 abort_creds(new);
1304 return ret;
1305 }
1306
1307 return commit_creds(new);
1270} 1308}
1271 1309
1272EXPORT_SYMBOL(set_current_groups); 1310EXPORT_SYMBOL(set_current_groups);
@@ -1666,9 +1704,11 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
1666 unsigned char comm[sizeof(me->comm)]; 1704 unsigned char comm[sizeof(me->comm)];
1667 long error; 1705 long error;
1668 1706
1669 if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) 1707 error = security_task_prctl(option, arg2, arg3, arg4, arg5);
1708 if (error != -ENOSYS)
1670 return error; 1709 return error;
1671 1710
1711 error = 0;
1672 switch (option) { 1712 switch (option) {
1673 case PR_SET_PDEATHSIG: 1713 case PR_SET_PDEATHSIG:
1674 if (!valid_signal(arg2)) { 1714 if (!valid_signal(arg2)) {
diff --git a/kernel/user.c b/kernel/user.c
index 104d22ac84d5..d476307dd4b0 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -16,6 +16,7 @@
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/user_namespace.h> 18#include <linux/user_namespace.h>
19#include "cred-internals.h"
19 20
20struct user_namespace init_user_ns = { 21struct user_namespace init_user_ns = {
21 .kref = { 22 .kref = {
@@ -104,16 +105,10 @@ static int sched_create_user(struct user_struct *up)
104 return rc; 105 return rc;
105} 106}
106 107
107static void sched_switch_user(struct task_struct *p)
108{
109 sched_move_task(p);
110}
111
112#else /* CONFIG_USER_SCHED */ 108#else /* CONFIG_USER_SCHED */
113 109
114static void sched_destroy_user(struct user_struct *up) { } 110static void sched_destroy_user(struct user_struct *up) { }
115static int sched_create_user(struct user_struct *up) { return 0; } 111static int sched_create_user(struct user_struct *up) { return 0; }
116static void sched_switch_user(struct task_struct *p) { }
117 112
118#endif /* CONFIG_USER_SCHED */ 113#endif /* CONFIG_USER_SCHED */
119 114
@@ -448,36 +443,6 @@ out_unlock:
448 return NULL; 443 return NULL;
449} 444}
450 445
451void switch_uid(struct user_struct *new_user)
452{
453 struct user_struct *old_user;
454
455 /* What if a process setreuid()'s and this brings the
456 * new uid over his NPROC rlimit? We can check this now
457 * cheaply with the new uid cache, so if it matters
458 * we should be checking for it. -DaveM
459 */
460 old_user = current->cred->user;
461 atomic_inc(&new_user->processes);
462 atomic_dec(&old_user->processes);
463 switch_uid_keyring(new_user);
464 current->cred->user = new_user;
465 sched_switch_user(current);
466
467 /*
468 * We need to synchronize with __sigqueue_alloc()
469 * doing a get_uid(p->user).. If that saw the old
470 * user value, we need to wait until it has exited
471 * its critical region before we can free the old
472 * structure.
473 */
474 smp_mb();
475 spin_unlock_wait(&current->sighand->siglock);
476
477 free_uid(old_user);
478 suid_keys(current);
479}
480
481#ifdef CONFIG_USER_NS 446#ifdef CONFIG_USER_NS
482void release_uids(struct user_namespace *ns) 447void release_uids(struct user_namespace *ns)
483{ 448{
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index f82730adea00..0d9c51d67333 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -19,6 +19,7 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
19{ 19{
20 struct user_namespace *ns; 20 struct user_namespace *ns;
21 struct user_struct *new_user; 21 struct user_struct *new_user;
22 struct cred *new;
22 int n; 23 int n;
23 24
24 ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); 25 ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
@@ -45,7 +46,16 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
45 return ERR_PTR(-ENOMEM); 46 return ERR_PTR(-ENOMEM);
46 } 47 }
47 48
48 switch_uid(new_user); 49 /* Install the new user */
50 new = prepare_creds();
51 if (!new) {
52 free_uid(new_user);
53 free_uid(ns->root_user);
54 kfree(ns);
55 }
56 free_uid(new->user);
57 new->user = new_user;
58 commit_creds(new);
49 return ns; 59 return ns;
50} 60}
51 61