pid: make setpgid() system call use RCU read-side critical section
RFC PATCH 1/1 pid: make setpgid() system call use RCU read-side critical section
[ 23.584719]
[ 23.584720] ===================================================
[ 23.585059] [ INFO: suspicious rcu_dereference_check() usage. ]
[ 23.585176] ---------------------------------------------------
[ 23.585176] kernel/pid.c:419 invoked rcu_dereference_check() without protection!
[ 23.585176]
[ 23.585176] other info that might help us debug this:
[ 23.585176]
[ 23.585176]
[ 23.585176] rcu_scheduler_active = 1, debug_locks = 1
[ 23.585176] 1 lock held by rc.sysinit/728:
[ 23.585176] #0: (tasklist_lock){.+.+..}, at: [<ffffffff8104771f>] sys_setpgid+0x5f/0x193
[ 23.585176]
[ 23.585176] stack backtrace:
[ 23.585176] Pid: 728, comm: rc.sysinit Not tainted 2.6.36-rc2 #2
[ 23.585176] Call Trace:
[ 23.585176] [<ffffffff8105b436>] lockdep_rcu_dereference+0x99/0xa2
[ 23.585176] [<ffffffff8104c324>] find_task_by_pid_ns+0x50/0x6a
[ 23.585176] [<ffffffff8104c35b>] find_task_by_vpid+0x1d/0x1f
[ 23.585176] [<ffffffff81047727>] sys_setpgid+0x67/0x193
[ 23.585176] [<ffffffff810029eb>] system_call_fastpath+0x16/0x1b
[ 24.959669] type=1400 audit(1282938522.956:4): avc: denied { module_request } for pid=766 comm="hwclock" kmod="char-major-10-135" scontext=system_u:system_r:hwclock_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclasIt turns out that the setpgid() system call fails to enter an RCU read-side critical section before doing a PID-to-task_struct translation. This commit therefore does rcu_read_lock() before the translation, and also does rcu_read_unlock() after the last use of the returned pointer.
---
sys.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/sys.c +2 -0
@@ -938,6 +938,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)write_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid);if (!p) goto out;
@@ -983,6 +984,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) err =0 ; out:/* All paths lead to here, thus we are safe. -DaveM */ +rcu_read_unlock ();write_unlock_irq (&tasklist_lock);return err; }
Ccing Oleg.
Quoted 39 lines · Paul E. McKenney
[ 23.584720] =================================================== [ 23.585059] [ INFO: suspicious rcu_dereference_check() usage. ] [ 23.585176] --------------------------------------------------- [ 23.585176] kernel/pid.c:419 invoked rcu_dereference_check() without protection! [ 23.585176] [ 23.585176] other info that might help us debug this: [ 23.585176] [ 23.585176] [ 23.585176] rcu_scheduler_active = 1, debug_locks = 1 [ 23.585176] 1 lock held by rc.sysinit/728: [ 23.585176] #0: (tasklist_lock){.+.+..}, at: [<ffffffff8104771f>] sys_setpgid+0x5f/0x193 [ 23.585176] [ 23.585176] stack backtrace: [ 23.585176] Pid: 728, comm: rc.sysinit Not tainted 2.6.36-rc2 #2 [ 23.585176] Call Trace: [ 23.585176] [<ffffffff8105b436>] lockdep_rcu_dereference+0x99/0xa2 [ 23.585176] [<ffffffff8104c324>] find_task_by_pid_ns+0x50/0x6a [ 23.585176] [<ffffffff8104c35b>] find_task_by_vpid+0x1d/0x1f [ 23.585176] [<ffffffff81047727>] sys_setpgid+0x67/0x193 [ 23.585176] [<ffffffff810029eb>] system_call_fastpath+0x16/0x1b [ 24.959669] type=1400 audit(1282938522.956:4): avc: denied { module_request } for pid=766 comm="hwclock" kmod="char-major-10-135" scontext=system_u:system_r:hwclock_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclasIt turns out that the
setpgid()system call fails to enter an RCU read-side critical section before doing a PID-to-task_struct translation. This commit therefore doesrcu_read_lock()before the translation, and also doesrcu_read_unlock()after the last use of the returned pointer.Located-by Andrew Morton <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>---
sys.c | 2 ++ 1 file changed, 2 insertions(+)kernel/sys.c +0
-0
kernel/sys.c SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) · line 942
Quoted 5 lines
kernel/sys.c +1
-0@@ -938,6 +938,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)write_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid);
AFAICT the missing lock doesn't harm due to the write_lock of tasklist above. But is probably a good thing to do anyway.
regards,
Signature · 2 lines
js suse labs
Quoted 44 lines · Jiri Slaby
Ccing Oleg.
Quoted 41 lines · Paul E. McKenney
[ 23.584720] =================================================== [ 23.585059] [ INFO: suspicious rcu_dereference_check() usage. ] [ 23.585176] --------------------------------------------------- [ 23.585176] kernel/pid.c:419 invoked rcu_dereference_check() without protection! [ 23.585176] [ 23.585176] other info that might help us debug this: [ 23.585176] [ 23.585176] [ 23.585176] rcu_scheduler_active = 1, debug_locks = 1 [ 23.585176] 1 lock held by rc.sysinit/728: [ 23.585176] #0: (tasklist_lock){.+.+..}, at: [<ffffffff8104771f>] sys_setpgid+0x5f/0x193 [ 23.585176] [ 23.585176] stack backtrace: [ 23.585176] Pid: 728, comm: rc.sysinit Not tainted 2.6.36-rc2 #2 [ 23.585176] Call Trace: [ 23.585176] [<ffffffff8105b436>] lockdep_rcu_dereference+0x99/0xa2 [ 23.585176] [<ffffffff8104c324>] find_task_by_pid_ns+0x50/0x6a [ 23.585176] [<ffffffff8104c35b>] find_task_by_vpid+0x1d/0x1f [ 23.585176] [<ffffffff81047727>] sys_setpgid+0x67/0x193 [ 23.585176] [<ffffffff810029eb>] system_call_fastpath+0x16/0x1b [ 24.959669] type=1400 audit(1282938522.956:4): avc: denied { module_request } for pid=766 comm="hwclock" kmod="char-major-10-135" scontext=system_u:system_r:hwclock_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclasIt turns out that the
setpgid()system call fails to enter an RCU read-side critical section before doing a PID-to-task_struct translation. This commit therefore doesrcu_read_lock()before the translation, and also doesrcu_read_unlock()after the last use of the returned pointer.Located-by Andrew Morton <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>---
sys.c | 2 ++ 1 file changed, 2 insertions(+)kernel/sys.c +0
-0@@ -938,6 +938,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)write_lock_irq (&tasklist_lock);
Quoted 6 lines
kernel/sys.c SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) · line 942
Quoted 3 lines
kernel/sys.c +1
-0err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid);AFAICT the missing lock doesn't harm due to the
write_lockof tasklist above. But is probably a good thing to do anyway.
Or we can add the tasklist lock to the rcu_dereference_check() condition.
Thanx, Paul
Quoted 9 lines
regards,
Signature · 7 lines
js suse labs -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
kernel/sys.c SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)
Quoted 7 lines · Paul E. McKenney
kernel/sys.c +2
-0write_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); +rcu_read_unlock ();write_unlock_irq (&tasklist_lock);
I would generally put the rcu lock outside the IRQ disabled section on the basis that it's better to keep the amount of time we have interrupts disabled shortest.
Quoted 1 line
Located-by Andrew Morton <[email protected]>
'Reported-by' might be more consistent with what others use.
David
Quoted 14 lines · David Howells
Review
Quoted 7 lines · Paul E. McKenney
(quoted diff) +2
-0write_lock_irq(&tasklist_lock); err = -ESRCH; + rcu_read_lock(); + rcu_read_unlock(); write_unlock_irq(&tasklist_lock);I would generally put the rcu lock outside the IRQ disabled section on the basis that it's better to keep the amount of time we have interrupts disabled shortest.
Quoted 5 lines
Quoted 1 line
Located-by Andrew Morton <[email protected]>'Reported-by' might be more consistent with what others use.
David
Good points, how about the following?
Thanx, Paul
------------------------------------------------------------------------
pid: make setpgid() system call use RCU read-side critical section
[ 23.584719]
[ 23.584720] ===================================================
[ 23.585059] [ INFO: suspicious rcu_dereference_check() usage. ]
[ 23.585176] ---------------------------------------------------
[ 23.585176] kernel/pid.c:419 invoked rcu_dereference_check() without protection!
[ 23.585176]
[ 23.585176] other info that might help us debug this:
[ 23.585176]
[ 23.585176]
[ 23.585176] rcu_scheduler_active = 1, debug_locks = 1
[ 23.585176] 1 lock held by rc.sysinit/728:
[ 23.585176] #0: (tasklist_lock){.+.+..}, at: [<ffffffff8104771f>] sys_setpgid+0x5f/0x193
[ 23.585176]
[ 23.585176] stack backtrace:
[ 23.585176] Pid: 728, comm: rc.sysinit Not tainted 2.6.36-rc2 #2
[ 23.585176] Call Trace:
[ 23.585176] [<ffffffff8105b436>] lockdep_rcu_dereference+0x99/0xa2
[ 23.585176] [<ffffffff8104c324>] find_task_by_pid_ns+0x50/0x6a
[ 23.585176] [<ffffffff8104c35b>] find_task_by_vpid+0x1d/0x1f
[ 23.585176] [<ffffffff81047727>] sys_setpgid+0x67/0x193
[ 23.585176] [<ffffffff810029eb>] system_call_fastpath+0x16/0x1b
[ 24.959669] type=1400 audit(1282938522.956:4): avc: denied { module_request } for pid=766 comm="hwclock" kmod="char-major-10-135" scontext=system_u:system_r:hwclock_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclasIt turns out that the setpgid() system call fails to enter an RCU read-side critical section before doing a PID-to-task_struct translation. This commit therefore does rcu_read_lock() before the translation, and also does rcu_read_unlock() after the last use of the returned pointer.
kernel/sys.c +2 -0
@@ -931,6 +931,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) pgid = pid;if (pgid <0 )return -EINVAL ; +rcu_read_lock ();/* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM
@@ -984,6 +985,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) out:/* All paths lead to here, thus we are safe. -DaveM */ write_unlock_irq (&tasklist_lock); +rcu_read_unlock ();return err; }
David Howells
Acked-byQuoted 7 lines · Paul E. McKenney
It turns out that the
setpgid()system call fails to enter an RCU read-side critical section before doing a PID-to-task_struct translation. This commit therefore doesrcu_read_lock()before the translation, and also doesrcu_read_unlock()after the last use of the returned pointer.Reported-by Andrew Morton <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>
Quoted 2 lines · Jiri Slaby
Ccing Oleg.
Sorry for delay...
Quoted 11 lines
kernel/sys.c SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) · line 942
Quoted 8 lines
kernel/sys.c +1
-0@@ -938,6 +938,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)write_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid);AFAICT the missing lock doesn't harm due to the
write_lockof tasklist above. But is probably a good thing to do anyway.
The problem is, find_task_by_vpid() is not safe without RCU. It is not that the returned task_struct can't go away, find_pid_ns() itself is not safe. This is because the failing copy_process() calls free_pid() without tasklist_lock and modifies pid_hash[] list.
Oleg.
Quoted 13 lines · Oleg Nesterov
Quoted 11 lines · Jiri Slaby
kernel/sys.c SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) · line 942
Quoted 8 lines
kernel/sys.c +1
-0@@ -938,6 +938,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)write_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid);AFAICT the missing lock doesn't harm due to the
write_lockof tasklist above. But is probably a good thing to do anyway.
Quoted 4 lines
The problem is,
find_task_by_vpid()is not safe without RCU. It is not that the returnedtask_structcan't go away,find_pid_ns()itself is not safe. This is because the failingcopy_process()callsfree_pid()withouttasklist_lockand modifies pid_hash[] list.
That said, it (950eaaca681c4) should probably go into stable. (Apply to all 32-35 whichever are maintained currently.)
thanks,
Signature · 2 lines
js suse labs
Quoted 15 lines · Jiri Slaby
Quoted 13 lines · Oleg Nesterov
Quoted 11 lines · Jiri Slaby
kernel/sys.c SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) · line 942
Quoted 8 lines
kernel/sys.c +1
-0@@ -938,6 +938,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)write_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid);AFAICT the missing lock doesn't harm due to the
write_lockof tasklist above. But is probably a good thing to do anyway.
Quoted 7 lines
Quoted 4 lines
The problem is,
find_task_by_vpid()is not safe without RCU. It is not that the returnedtask_structcan't go away,find_pid_ns()itself is not safe. This is because the failingcopy_process()callsfree_pid()withouttasklist_lockand modifies pid_hash[] list.That said, it (
950eaaca681c4) should probably go into stable. (Apply to all 32-35 whichever are maintained currently.)
Perhaps, but the race is mostly theoretical.
To be honest, I think 950eaaca681c4 needs a comment to explain what rcu_read_lock() protects, or perhaps we can make it more explicit.
Oleg.
kernel/sys.c +4 -2
@@ -931,7 +931,6 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid pgid = pid;if (pgid <0 )return -EINVAL ; -rcu_read_lock ();/* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM
@@ -939,7 +938,9 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pidwrite_lock_irq (&tasklist_lock); err = -ESRCH ; +rcu_read_lock (); p =find_task_by_vpid (pid); +rcu_read_unlock ();if (!p) goto out;
@@ -968,7 +969,9 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pidif (pgid != pid) {struct task_struct *g; +rcu_read_lock (); pgrp =find_vpid (pgid); +rcu_read_unlock (); g =pid_task (pgrp,PIDTYPE_PGID );if (!g ||task_session (g) !=task_session (group_leader)) goto out;
@@ -985,7 +988,6 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid out:/* All paths lead to here, thus we are safe. -DaveM */ write_unlock_irq (&tasklist_lock); -rcu_read_unlock ();return err; }