| From stable-bounces@linux.kernel.org Sun Aug 13 23:25:48 2006 |
| Message-Id: <200608140624.k7E6ONGE007003@shell0.pdx.osdl.net> |
| To: greg@kroah.com |
| From: akpm@osdl.org |
| Date: Sun, 13 Aug 2006 23:24:23 -0700 |
| Cc: akpm@osdl.org, dev@openvz.org, stable@kernel.org, haveblue@us.ibm.com, dev@sw.ru, torvalds@osdl.org, oleg@tv-sign.ru |
| Subject: sys_getppid oopses on debug kernel |
| |
| From: Kirill Korotaev <dev@sw.ru> |
| |
| sys_getppid() optimization can access a freed memory. On kernels with |
| DEBUG_SLAB turned ON, this results in Oops. As Dave Hansen noted, this |
| optimization is also unsafe for memory hotplug. |
| |
| So this patch always takes the lock to be safe. |
| |
| [oleg@tv-sign.ru: simplifications] |
| |
| Signed-off-by: Kirill Korotaev <dev@openvz.org> |
| Cc: Dave Hansen <haveblue@us.ibm.com> |
| Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> |
| Signed-off-by: Andrew Morton <akpm@osdl.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| kernel/timer.c | 41 +++++++---------------------------------- |
| 1 file changed, 7 insertions(+), 34 deletions(-) |
| |
| --- linux-2.6.17.9.orig/kernel/timer.c |
| +++ linux-2.6.17.9/kernel/timer.c |
| @@ -975,46 +975,19 @@ asmlinkage long sys_getpid(void) |
| } |
| |
| /* |
| - * Accessing ->group_leader->real_parent is not SMP-safe, it could |
| - * change from under us. However, rather than getting any lock |
| - * we can use an optimistic algorithm: get the parent |
| - * pid, and go back and check that the parent is still |
| - * the same. If it has changed (which is extremely unlikely |
| - * indeed), we just try again.. |
| - * |
| - * NOTE! This depends on the fact that even if we _do_ |
| - * get an old value of "parent", we can happily dereference |
| - * the pointer (it was and remains a dereferencable kernel pointer |
| - * no matter what): we just can't necessarily trust the result |
| - * until we know that the parent pointer is valid. |
| - * |
| - * NOTE2: ->group_leader never changes from under us. |
| + * Accessing ->real_parent is not SMP-safe, it could |
| + * change from under us. However, we can use a stale |
| + * value of ->real_parent under rcu_read_lock(), see |
| + * release_task()->call_rcu(delayed_put_task_struct). |
| */ |
| asmlinkage long sys_getppid(void) |
| { |
| int pid; |
| - struct task_struct *me = current; |
| - struct task_struct *parent; |
| |
| - parent = me->group_leader->real_parent; |
| - for (;;) { |
| - pid = parent->tgid; |
| -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) |
| -{ |
| - struct task_struct *old = parent; |
| + rcu_read_lock(); |
| + pid = rcu_dereference(current->real_parent)->tgid; |
| + rcu_read_unlock(); |
| |
| - /* |
| - * 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; |
| } |
| |