aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-02-08 07:19:07 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:26 -0500
commit3a515e4a62dbf7e4c213740268a5267faa69e5b2 (patch)
tree51f98e662c80ca5de628f09c5eb24d18f1794f6c
parentf2cc3eb133baa2e9dc8efd40f417106b2ee520f3 (diff)
wait_task_continued/zombie: don't use task_pid_nr_ns() lockless
Surprise, the other two wait_task_*() functions also abuse the task_pid_nr_ns() function, and may cause read-after-free or report nr == 0 in wait_task_continued(). wait_task_zombie() doesn't have this problem, but it is still better to cache pid_t rather than call task_pid_nr_ns() three times on the saved pid_namespace. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/exit.c15
1 files changed, 5 insertions, 10 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index ee607720ae58..dee8b4d63403 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1189,12 +1189,9 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
1189{ 1189{
1190 unsigned long state; 1190 unsigned long state;
1191 int retval, status, traced; 1191 int retval, status, traced;
1192 struct pid_namespace *ns; 1192 pid_t pid = task_pid_nr_ns(p, current->nsproxy->pid_ns);
1193
1194 ns = current->nsproxy->pid_ns;
1195 1193
1196 if (unlikely(noreap)) { 1194 if (unlikely(noreap)) {
1197 pid_t pid = task_pid_nr_ns(p, ns);
1198 uid_t uid = p->uid; 1195 uid_t uid = p->uid;
1199 int exit_code = p->exit_code; 1196 int exit_code = p->exit_code;
1200 int why, status; 1197 int why, status;
@@ -1313,11 +1310,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
1313 retval = put_user(status, &infop->si_status); 1310 retval = put_user(status, &infop->si_status);
1314 } 1311 }
1315 if (!retval && infop) 1312 if (!retval && infop)
1316 retval = put_user(task_pid_nr_ns(p, ns), &infop->si_pid); 1313 retval = put_user(pid, &infop->si_pid);
1317 if (!retval && infop) 1314 if (!retval && infop)
1318 retval = put_user(p->uid, &infop->si_uid); 1315 retval = put_user(p->uid, &infop->si_uid);
1319 if (!retval) 1316 if (!retval)
1320 retval = task_pid_nr_ns(p, ns); 1317 retval = pid;
1321 1318
1322 if (traced) { 1319 if (traced) {
1323 write_lock_irq(&tasklist_lock); 1320 write_lock_irq(&tasklist_lock);
@@ -1436,7 +1433,6 @@ static int wait_task_continued(struct task_struct *p, int noreap,
1436 int retval; 1433 int retval;
1437 pid_t pid; 1434 pid_t pid;
1438 uid_t uid; 1435 uid_t uid;
1439 struct pid_namespace *ns;
1440 1436
1441 if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) 1437 if (!(p->signal->flags & SIGNAL_STOP_CONTINUED))
1442 return 0; 1438 return 0;
@@ -1451,8 +1447,7 @@ static int wait_task_continued(struct task_struct *p, int noreap,
1451 p->signal->flags &= ~SIGNAL_STOP_CONTINUED; 1447 p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
1452 spin_unlock_irq(&p->sighand->siglock); 1448 spin_unlock_irq(&p->sighand->siglock);
1453 1449
1454 ns = current->nsproxy->pid_ns; 1450 pid = task_pid_nr_ns(p, current->nsproxy->pid_ns);
1455 pid = task_pid_nr_ns(p, ns);
1456 uid = p->uid; 1451 uid = p->uid;
1457 get_task_struct(p); 1452 get_task_struct(p);
1458 read_unlock(&tasklist_lock); 1453 read_unlock(&tasklist_lock);
@@ -1463,7 +1458,7 @@ static int wait_task_continued(struct task_struct *p, int noreap,
1463 if (!retval && stat_addr) 1458 if (!retval && stat_addr)
1464 retval = put_user(0xffff, stat_addr); 1459 retval = put_user(0xffff, stat_addr);
1465 if (!retval) 1460 if (!retval)
1466 retval = task_pid_nr_ns(p, ns); 1461 retval = pid;
1467 } else { 1462 } else {
1468 retval = wait_noreap_copyout(p, pid, uid, 1463 retval = wait_noreap_copyout(p, pid, uid,
1469 CLD_CONTINUED, SIGCONT, 1464 CLD_CONTINUED, SIGCONT,