]> git.karo-electronics.de Git - linux-beck.git/commit
rtmutex: Plug slow unlock race
authorThomas Gleixner <tglx@linutronix.de>
Wed, 11 Jun 2014 18:44:04 +0000 (18:44 +0000)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 16 Jun 2014 08:03:09 +0000 (10:03 +0200)
commit27e35715df54cbc4f2d044f681802ae30479e7fb
treedeacb08195cf3cc2ea7480f103991bd4b3e4aa6b
parent82084984383babe728e6e3c9a8e5c46278091315
rtmutex: Plug slow unlock race

When the rtmutex fast path is enabled the slow unlock function can
create the following situation:

spin_lock(foo->m->wait_lock);
foo->m->owner = NULL;
     rt_mutex_lock(foo->m); <-- fast path
free = atomic_dec_and_test(foo->refcnt);
rt_mutex_unlock(foo->m); <-- fast path
if (free)
   kfree(foo);

spin_unlock(foo->m->wait_lock); <--- Use after free.

Plug the race by changing the slow unlock to the following scheme:

     while (!rt_mutex_has_waiters(m)) {
          /* Clear the waiters bit in m->owner */
    clear_rt_mutex_waiters(m);
           owner = rt_mutex_owner(m);
           spin_unlock(m->wait_lock);
           if (cmpxchg(m->owner, owner, 0) == owner)
              return;
           spin_lock(m->wait_lock);
     }

So in case of a new waiter incoming while the owner tries the slow
path unlock we have two situations:

 unlock(wait_lock);
lock(wait_lock);
 cmpxchg(p, owner, 0) == owner
           mark_rt_mutex_waiters(lock);
  acquire(lock);

Or:

 unlock(wait_lock);
lock(wait_lock);
  mark_rt_mutex_waiters(lock);
 cmpxchg(p, owner, 0) != owner
enqueue_waiter();
unlock(wait_lock);
 lock(wait_lock);
 wakeup_next waiter();
 unlock(wait_lock);
lock(wait_lock);
acquire(lock);

If the fast path is disabled, then the simple

   m->owner = NULL;
   unlock(m->wait_lock);

is sufficient as all access to m->owner is serialized via
m->wait_lock;

Also document and clarify the wakeup_next_waiter function as suggested
by Oleg Nesterov.

Reported-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140611183852.937945560@linutronix.de
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
kernel/locking/rtmutex.c