diff options
author | David Meybohm <dmeybohmlkml@bellsouth.net> | 2005-08-22 22:11:08 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-23 20:44:29 +0200 |
commit | 4c5640cb5f5a6fd780d99397eca028b575cb1206 (patch) | |
tree | 3f5eb4b4390ea71031eb2c93261052e6698cbdc1 /kernel/timer.c | |
parent | Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6 (diff) | |
download | linux-4c5640cb5f5a6fd780d99397eca028b575cb1206.tar.xz linux-4c5640cb5f5a6fd780d99397eca028b575cb1206.zip |
[PATCH] preempt race in getppid
With CONFIG_PREEMPT && !CONFIG_SMP, it's possible for sys_getppid to
return a bogus value if the parent's task_struct gets reallocated after
current->group_leader->real_parent is read:
asmlinkage long sys_getppid(void)
{
int pid;
struct task_struct *me = current;
struct task_struct *parent;
parent = me->group_leader->real_parent;
RACE HERE => for (;;) {
pid = parent->tgid;
#ifdef CONFIG_SMP
{
struct task_struct *old = parent;
/*
* Make sure we read the pid before re-reading the
* parent pointer:
*/
smp_rmb();
parent = me->group_leader->real_parent;
if (old != parent)
continue;
}
#endif
break;
}
return pid;
}
If the process gets preempted at the indicated point, the parent process
can go ahead and call exit() and then get wait()'d on to reap its
task_struct. When the preempted process gets resumed, it will not do any
further checks of the parent pointer on !CONFIG_SMP: it will read the
bad pid and return.
So, the same algorithm used when SMP is enabled should be used when
preempt is enabled, which will recheck ->real_parent in this case.
Signed-off-by: David Meybohm <dmeybohmlkml@bellsouth.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to '')
-rw-r--r-- | kernel/timer.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index f2a11887a726..5377f40723ff 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1023,7 +1023,7 @@ asmlinkage long sys_getppid(void) parent = me->group_leader->real_parent; for (;;) { pid = parent->tgid; -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) { struct task_struct *old = parent; |