Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

futex: Clear stale exiting pointer in futex_lock_pi() retry path

Fuzzying/stressing futexes triggered:

WARNING: kernel/futex/core.c:825 at wait_for_owner_exiting+0x7a/0x80, CPU#11: futex_lock_pi_s/524

When futex_lock_pi_atomic() sees the owner is exiting, it returns -EBUSY
and stores a refcounted task pointer in 'exiting'.

After wait_for_owner_exiting() consumes that reference, the local pointer
is never reset to nil. Upon a retry, if futex_lock_pi_atomic() returns a
different error, the bogus pointer is passed to wait_for_owner_exiting().

CPU0 CPU1 CPU2
futex_lock_pi(uaddr)
// acquires the PI futex
exit()
futex_cleanup_begin()
futex_state = EXITING;
futex_lock_pi(uaddr)
futex_lock_pi_atomic()
attach_to_pi_owner()
// observes EXITING
*exiting = owner; // takes ref
return -EBUSY
wait_for_owner_exiting(-EBUSY, owner)
put_task_struct(); // drops ref
// exiting still points to owner
goto retry;
futex_lock_pi_atomic()
lock_pi_update_atomic()
cmpxchg(uaddr)
*uaddr ^= WAITERS // whatever
// value changed
return -EAGAIN;
wait_for_owner_exiting(-EAGAIN, exiting) // stale
WARN_ON_ONCE(exiting)

Fix this by resetting upon retry, essentially aligning it with requeue_pi.

Fixes: 3ef240eaff36 ("futex: Prevent exit livelock")
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260326001759.4129680-1-dave@stgolabs.net

authored by

Davidlohr Bueso and committed by
Thomas Gleixner
210d36d8 190a8c48

+2 -1
+2 -1
kernel/futex/pi.c
··· 918 918 int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylock) 919 919 { 920 920 struct hrtimer_sleeper timeout, *to; 921 - struct task_struct *exiting = NULL; 921 + struct task_struct *exiting; 922 922 struct rt_mutex_waiter rt_waiter; 923 923 struct futex_q q = futex_q_init; 924 924 DEFINE_WAKE_Q(wake_q); ··· 933 933 to = futex_setup_timer(time, &timeout, flags, 0); 934 934 935 935 retry: 936 + exiting = NULL; 936 937 ret = get_futex_key(uaddr, flags, &q.key, FUTEX_WRITE); 937 938 if (unlikely(ret != 0)) 938 939 goto out;