Skip to content

Commit 648f575

Browse files
committed
Merge tag 'locking_urgent_for_v6.8_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking fix from Borislav Petkov: - Prevent an inconsistent futex operation leading to stale state exposure * tag 'locking_urgent_for_v6.8_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: futex: Prevent the reuse of stale pi_state
2 parents 0e4363a + e626cb0 commit 648f575

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

kernel/futex/core.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -627,12 +627,21 @@ int futex_unqueue(struct futex_q *q)
627627
}
628628

629629
/*
630-
* PI futexes can not be requeued and must remove themselves from the
631-
* hash bucket. The hash bucket lock (i.e. lock_ptr) is held.
630+
* PI futexes can not be requeued and must remove themselves from the hash
631+
* bucket. The hash bucket lock (i.e. lock_ptr) is held.
632632
*/
633633
void futex_unqueue_pi(struct futex_q *q)
634634
{
635-
__futex_unqueue(q);
635+
/*
636+
* If the lock was not acquired (due to timeout or signal) then the
637+
* rt_waiter is removed before futex_q is. If this is observed by
638+
* an unlocker after dropping the rtmutex wait lock and before
639+
* acquiring the hash bucket lock, then the unlocker dequeues the
640+
* futex_q from the hash bucket list to guarantee consistent state
641+
* vs. userspace. Therefore the dequeue here must be conditional.
642+
*/
643+
if (!plist_node_empty(&q->list))
644+
__futex_unqueue(q);
636645

637646
BUG_ON(!q->pi_state);
638647
put_pi_state(q->pi_state);

kernel/futex/pi.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
11351135

11361136
hb = futex_hash(&key);
11371137
spin_lock(&hb->lock);
1138+
retry_hb:
11381139

11391140
/*
11401141
* Check waiters first. We do not trust user space values at
@@ -1177,12 +1178,17 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
11771178
/*
11781179
* Futex vs rt_mutex waiter state -- if there are no rt_mutex
11791180
* waiters even though futex thinks there are, then the waiter
1180-
* is leaving and the uncontended path is safe to take.
1181+
* is leaving. The entry needs to be removed from the list so a
1182+
* new futex_lock_pi() is not using this stale PI-state while
1183+
* the futex is available in user space again.
1184+
* There can be more than one task on its way out so it needs
1185+
* to retry.
11811186
*/
11821187
rt_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex);
11831188
if (!rt_waiter) {
1189+
__futex_unqueue(top_waiter);
11841190
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
1185-
goto do_uncontended;
1191+
goto retry_hb;
11861192
}
11871193

11881194
get_pi_state(pi_state);
@@ -1217,7 +1223,6 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
12171223
return ret;
12181224
}
12191225

1220-
do_uncontended:
12211226
/*
12221227
* We have no kernel internal state, i.e. no waiters in the
12231228
* kernel. Waiters which are about to queue themselves are stuck

0 commit comments

Comments
 (0)