Skip to content

Commit 90d7588

Browse files
Alexey IzbyshevKAGA-KOKO
authored andcommitted
futex: Resend potentially swallowed owner death notification
Commit ca16d5b ("futex: Prevent robust futex exit race") addressed two cases when tasks waiting on a robust non-PI futex remained blocked despite the futex not being owned anymore: * if the owner died after writing zero to the futex word, but before waking up a waiter * if a task waiting on the futex was woken up, but died before updating the futex word (effectively swallowing the notification without acting on it) In the second case, the task could be woken up either by the previous owner (after the futex word was reset to zero) or by the kernel (after the OWNER_DIED bit was set and the TID part of the futex word was reset to zero) if the previous owner died without the resetting the futex. Because the referenced commit wakes up a potential waiter only if the whole futex word is zero, the latter subcase remains unaddressed. Fix this by looking only at the TID part of the futex when deciding whether a wake up is needed. Fixes: ca16d5b ("futex: Prevent robust futex exit race") Signed-off-by: Alexey Izbyshev <izbyshev@ispras.ru> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20221111215439.248185-1-izbyshev@ispras.ru
1 parent d0c0064 commit 90d7588

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

kernel/futex/core.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
638638
bool pi, bool pending_op)
639639
{
640640
u32 uval, nval, mval;
641+
pid_t owner;
641642
int err;
642643

643644
/* Futex address must be 32bit aligned */
@@ -659,6 +660,10 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
659660
* 2. A woken up waiter is killed before it can acquire the
660661
* futex in user space.
661662
*
663+
* In the second case, the wake up notification could be generated
664+
* by the unlock path in user space after setting the futex value
665+
* to zero or by the kernel after setting the OWNER_DIED bit below.
666+
*
662667
* In both cases the TID validation below prevents a wakeup of
663668
* potential waiters which can cause these waiters to block
664669
* forever.
@@ -667,24 +672,27 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
667672
*
668673
* 1) task->robust_list->list_op_pending != NULL
669674
* @pending_op == true
670-
* 2) User space futex value == 0
675+
* 2) The owner part of user space futex value == 0
671676
* 3) Regular futex: @pi == false
672677
*
673678
* If these conditions are met, it is safe to attempt waking up a
674679
* potential waiter without touching the user space futex value and
675-
* trying to set the OWNER_DIED bit. The user space futex value is
676-
* uncontended and the rest of the user space mutex state is
677-
* consistent, so a woken waiter will just take over the
678-
* uncontended futex. Setting the OWNER_DIED bit would create
679-
* inconsistent state and malfunction of the user space owner died
680-
* handling.
680+
* trying to set the OWNER_DIED bit. If the futex value is zero,
681+
* the rest of the user space mutex state is consistent, so a woken
682+
* waiter will just take over the uncontended futex. Setting the
683+
* OWNER_DIED bit would create inconsistent state and malfunction
684+
* of the user space owner died handling. Otherwise, the OWNER_DIED
685+
* bit is already set, and the woken waiter is expected to deal with
686+
* this.
681687
*/
682-
if (pending_op && !pi && !uval) {
688+
owner = uval & FUTEX_TID_MASK;
689+
690+
if (pending_op && !pi && !owner) {
683691
futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);
684692
return 0;
685693
}
686694

687-
if ((uval & FUTEX_TID_MASK) != task_pid_vnr(curr))
695+
if (owner != task_pid_vnr(curr))
688696
return 0;
689697

690698
/*

0 commit comments

Comments
 (0)