Commit 648f575d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 0e4363ac e626cb02
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -627,11 +627,20 @@ int futex_unqueue(struct futex_q *q)
}

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

	BUG_ON(!q->pi_state);
+8 −3
Original line number Diff line number Diff line
@@ -1135,6 +1135,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)

	hb = futex_hash(&key);
	spin_lock(&hb->lock);
retry_hb:

	/*
	 * 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)
		/*
		 * Futex vs rt_mutex waiter state -- if there are no rt_mutex
		 * waiters even though futex thinks there are, then the waiter
		 * is leaving and the uncontended path is safe to take.
		 * is leaving. The entry needs to be removed from the list so a
		 * new futex_lock_pi() is not using this stale PI-state while
		 * the futex is available in user space again.
		 * There can be more than one task on its way out so it needs
		 * to retry.
		 */
		rt_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex);
		if (!rt_waiter) {
			__futex_unqueue(top_waiter);
			raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
			goto do_uncontended;
			goto retry_hb;
		}

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

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