aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/exit.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:19 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:19 -0500
commitc69e8d9c01db2adc503464993c358901c9af9de4 (patch)
treebed94aaa9aeb7a7834d1c880f72b62a11a752c78 /kernel/exit.c
parent86a264abe542cfececb4df129bc45a0338d8cdb9 (diff)
CRED: Use RCU to access another task's creds and to release a task's own creds
Use RCU to access another task's creds and to release a task's own creds. This means that it will be possible for the credentials of a task to be replaced without another task (a) requiring a full lock to read them, and (b) seeing deallocated memory. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel/exit.c')
-rw-r--r--kernel/exit.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index e0f6e1892fb9..bbc22530f2c1 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -160,7 +160,10 @@ void release_task(struct task_struct * p)
160 int zap_leader; 160 int zap_leader;
161repeat: 161repeat:
162 tracehook_prepare_release_task(p); 162 tracehook_prepare_release_task(p);
163 atomic_dec(&p->cred->user->processes); 163 /* don't need to get the RCU readlock here - the process is dead and
164 * can't be modifying its own credentials */
165 atomic_dec(&__task_cred(p)->user->processes);
166
164 proc_flush_task(p); 167 proc_flush_task(p);
165 write_lock_irq(&tasklist_lock); 168 write_lock_irq(&tasklist_lock);
166 tracehook_finish_release_task(p); 169 tracehook_finish_release_task(p);
@@ -1267,12 +1270,12 @@ static int wait_task_zombie(struct task_struct *p, int options,
1267 unsigned long state; 1270 unsigned long state;
1268 int retval, status, traced; 1271 int retval, status, traced;
1269 pid_t pid = task_pid_vnr(p); 1272 pid_t pid = task_pid_vnr(p);
1273 uid_t uid = __task_cred(p)->uid;
1270 1274
1271 if (!likely(options & WEXITED)) 1275 if (!likely(options & WEXITED))
1272 return 0; 1276 return 0;
1273 1277
1274 if (unlikely(options & WNOWAIT)) { 1278 if (unlikely(options & WNOWAIT)) {
1275 uid_t uid = p->cred->uid;
1276 int exit_code = p->exit_code; 1279 int exit_code = p->exit_code;
1277 int why, status; 1280 int why, status;
1278 1281
@@ -1393,7 +1396,7 @@ static int wait_task_zombie(struct task_struct *p, int options,
1393 if (!retval && infop) 1396 if (!retval && infop)
1394 retval = put_user(pid, &infop->si_pid); 1397 retval = put_user(pid, &infop->si_pid);
1395 if (!retval && infop) 1398 if (!retval && infop)
1396 retval = put_user(p->cred->uid, &infop->si_uid); 1399 retval = put_user(uid, &infop->si_uid);
1397 if (!retval) 1400 if (!retval)
1398 retval = pid; 1401 retval = pid;
1399 1402
@@ -1458,7 +1461,8 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
1458 if (!unlikely(options & WNOWAIT)) 1461 if (!unlikely(options & WNOWAIT))
1459 p->exit_code = 0; 1462 p->exit_code = 0;
1460 1463
1461 uid = p->cred->uid; 1464 /* don't need the RCU readlock here as we're holding a spinlock */
1465 uid = __task_cred(p)->uid;
1462unlock_sig: 1466unlock_sig:
1463 spin_unlock_irq(&p->sighand->siglock); 1467 spin_unlock_irq(&p->sighand->siglock);
1464 if (!exit_code) 1468 if (!exit_code)
@@ -1532,10 +1536,10 @@ static int wait_task_continued(struct task_struct *p, int options,
1532 } 1536 }
1533 if (!unlikely(options & WNOWAIT)) 1537 if (!unlikely(options & WNOWAIT))
1534 p->signal->flags &= ~SIGNAL_STOP_CONTINUED; 1538 p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
1539 uid = __task_cred(p)->uid;
1535 spin_unlock_irq(&p->sighand->siglock); 1540 spin_unlock_irq(&p->sighand->siglock);
1536 1541
1537 pid = task_pid_vnr(p); 1542 pid = task_pid_vnr(p);
1538 uid = p->cred->uid;
1539 get_task_struct(p); 1543 get_task_struct(p);
1540 read_unlock(&tasklist_lock); 1544 read_unlock(&tasklist_lock);
1541 1545