aboutsummaryrefslogtreecommitdiff
path: root/kernel/sys.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-04-30 00:54:29 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 08:29:49 -0700
commit12a3de0a965826096d8adc593bcf4392a7d5b459 (patch)
tree764d69c2973e67cb3ae58bec02e29cd616c40f90 /kernel/sys.c
parent1dd768c0815334d2319d6377f0750ace075b6142 (diff)
pids: sys_getpgid: fix unsafe *pid usage, s/tasklist/rcu/
1. sys_getpgid() needs rcu_read_lock() to derive the pgrp _nr, even if the task is current, otherwise we can race with another thread which does sys_setpgid(). 2. Use rcu_read_lock() instead of tasklist_lock when pid != 0, make sure that we don't use the NULL pid if the task exits right after successful find_task_by_vpid(). 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>
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index ddd28e261f3..895d2d4c949 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -991,31 +991,37 @@ out:
asmlinkage long sys_getpgid(pid_t pid)
{
+ struct task_struct *p;
+ struct pid *grp;
+ int retval;
+
+ rcu_read_lock();
if (!pid)
- return task_pgrp_vnr(current);
+ grp = task_pgrp(current);
else {
- int retval;
- struct task_struct *p;
-
- read_lock(&tasklist_lock);
- p = find_task_by_vpid(pid);
retval = -ESRCH;
- if (p) {
- retval = security_task_getpgid(p);
- if (!retval)
- retval = task_pgrp_vnr(p);
- }
- read_unlock(&tasklist_lock);
- return retval;
+ p = find_task_by_vpid(pid);
+ if (!p)
+ goto out;
+ grp = task_pgrp(p);
+ if (!grp)
+ goto out;
+
+ retval = security_task_getpgid(p);
+ if (retval)
+ goto out;
}
+ retval = pid_vnr(grp);
+out:
+ rcu_read_unlock();
+ return retval;
}
#ifdef __ARCH_WANT_SYS_GETPGRP
asmlinkage long sys_getpgrp(void)
{
- /* SMP - assuming writes are word atomic this is fine */
- return task_pgrp_vnr(current);
+ return sys_getpgid(0);
}
#endif