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>
This commit is contained in:
parent
1dd768c081
commit
12a3de0a96
1 changed files with 22 additions and 16 deletions
38
kernel/sys.c
38
kernel/sys.c
|
@ -991,31 +991,37 @@ out:
|
|||
|
||||
asmlinkage long sys_getpgid(pid_t pid)
|
||||
{
|
||||
if (!pid)
|
||||
return task_pgrp_vnr(current);
|
||||
else {
|
||||
int retval;
|
||||
struct task_struct *p;
|
||||
struct task_struct *p;
|
||||
struct pid *grp;
|
||||
int retval;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
p = find_task_by_vpid(pid);
|
||||
rcu_read_lock();
|
||||
if (!pid)
|
||||
grp = task_pgrp(current);
|
||||
else {
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue