preempt race in getppid
PATCH 1/1 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 <[email protected]>
---
kernel/timer.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-)
kernel/timer.c +1 -1
@@ -999,7 +999,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;