]> err.no Git - linux-2.6/commitdiff
[PATCH] ITIMER_REAL: fix possible deadlock and race
authorOleg Nesterov <oleg@tv-sign.ru>
Wed, 29 Jun 2005 03:44:47 +0000 (20:44 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 29 Jun 2005 04:20:30 +0000 (21:20 -0700)
As Steven Rostedt pointed out, there are 2 problems with ITIMER_REAL
timers.

1. do_setitimer() does not call del_timer_sync() in case
   when the timer is not pending (it_real_value() returns 0).
   This is wrong, the timer may still be running, and it can
   rearm itself.

2. It calls del_timer_sync() with tsk->sighand->siglock held.
   This is deadlockable, because timer's handler needs this
   lock too.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
kernel/itimer.c

index 1dc988e0d2c77e962063c776b7b035800f51b9be..a72cb0e5aa4b5d6f94764e128e4f376f0dc6591e 100644 (file)
@@ -153,11 +153,15 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 
        switch (which) {
        case ITIMER_REAL:
+again:
                spin_lock_irq(&tsk->sighand->siglock);
                interval = tsk->signal->it_real_incr;
                val = it_real_value(tsk->signal);
-               if (val)
-                       del_timer_sync(&tsk->signal->real_timer);
+               /* We are sharing ->siglock with it_real_fn() */
+               if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
+                       spin_unlock_irq(&tsk->sighand->siglock);
+                       goto again;
+               }
                tsk->signal->it_real_incr =
                        timeval_to_jiffies(&value->it_interval);
                it_real_arm(tsk, timeval_to_jiffies(&value->it_value));