Re: [PATCH] futex: Prevent robust futex exit race more

From: Keno Fischer

Date: Sun Jul 26 2026 - 18:54:33 EST


On Sun, 26 Jul 2026 22:39:35 +0200, Thomas Gleixner <tglx@xxxxxxxxxx> wrote:
> Something like the compiled but completely untested below.

Two issues noted below. With those fixed, passed my local test cases.
However, I re-ran the full TLA+ analysis over this protocol and it doesn't
fully resolve the lost-wakeup issue (both your and my revised patch).
In particular, if we drop the hb lock for a pagefault,
the waiter(s) we collected could have died and run exit
processing before we perform the store (so exit handling wouldn't
have performed the extra wakeup). In that case, waiters behind are stranded.
I think the simplest fix would be to separate the count and waiter
collection and only ->wake the waiters *AFTER* the release store has
run successfully.

> +static int collect_waiters(struct futex_hash_bucket *hb, struct futex_wake_q_head *fwake_q,
> + union futex_key *key, unsigned int nr_wake, u32 bitset)
> +{
> + struct futex_q *this, *next;
> + unsigned int matches = 0;

`matches` cannot be local here - either needs to go into futex_wake_q_head or
needs to set `waiters_left` in `continue` path an the robust nr_wake path.

> +/*
> + * Wake up waiters matching bitset queued on this futex (uaddr).
> + */
> +int futex_wake(u32 __user *uaddr, unsigned int flags, void __user *pop, int nr_wake, u32 bitset)
> +{
> + bool robust_unlock = !!(flags & FUTEX_ROBUST_UNLOCK);

FLAGS_ROBUST_UNLOCK

> + if (!bitset || nr_wake < 0)
> + return -EINVAL;

Noting that this changes userspace ABI for `nr_wake < 0` (e.g. for userspace
accidentally passing UINT_MAX rather than INT_MAX), although the current
behavior is of course surprising and in a quick audit, I didn't see any public
userspace code that gets this wrong, so worth trying probably. It's certainly
better behavior.