Miscellaneous futex fixes:

- Tighten up the sys_futex_requeue() ABI a bit, to disallow
    dissimilar futex flags and potential UaF access. (Peter Zijlstra)
 
  - Fix UaF between futex_key_to_node_opt() and vma_replace_policy()
    (Hao-Yu Yang)
 
  - Clear stale exiting pointer in futex_lock_pi() retry path,
    which bug triggered a warning (and potential misbehavior)
    in stress-testing. (Davidlohr Bueso)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmnItYsRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1h0Ow/+O4JG+XMdmTn2OLZQBFVqlt40RG+UAudW
 tLyop+xovbLXk0FbZZen233yrYLnD8Qea9+LSIi1KPOKdklT4fimgDrVhSdZVMcY
 mPJxkZ1NTRDpl3qpjgaT3yXslgpQQlzDLjAkyyC6SWQh7RHlZ9JB4UICei9sOeE8
 WgwBrCfDMJXgjG5sAvkIhQFJaNEb/5HBHJu2Nxldlkl0of+le1e0mGUdY7H0ntxx
 kJ4jCsrpCw+tzhZw7RmGe8ouEDkbt2f7EBT10pjZ1cEP22Rogn1AzgdD7pkbhcU3
 WxbBGjSfm3ziPADELf0IhVYE/s+UXKTK9LfKDt4Q5W7paTV+o4Fllr+sraBmOoxp
 Ova5RZzSdq5NCGAcmFJWg/rxEyZf+uC7GjwPx/80huzgJvBthdjOagdVKm/3BNv8
 4d4H9KX67zWXE/XQHMt3g/7KYlVD9tzcp+v+h/rs8fiwkCkElwbljLISEr1StyOv
 CDaCouu6FQE8MoVTNPPbH1DfEyIgNKHdXfkQbt/OkGVB9/dX71zFmxEXRCYAGMb1
 wZXJ0j/oZZYcapmcb/xk5YjcZEfEU9QnMHHtCdR+dDL56xbsT5cDIzrb09LF6H/9
 WiMxhx2V3RNBNUwbOKGX6vdqa2kXG+Pjp6sq9Af7VB9oy+nbWpfcVFqWbWwKAP1N
 7e/EmnoxPTs=
 =85AU
 -----END PGP SIGNATURE-----

Merge tag 'locking-urgent-2026-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull futex fixes from Ingo Molnar:

 - Tighten up the sys_futex_requeue() ABI a bit, to disallow dissimilar
   futex flags and potential UaF access (Peter Zijlstra)

 - Fix UaF between futex_key_to_node_opt() and vma_replace_policy()
   (Hao-Yu Yang)

 - Clear stale exiting pointer in futex_lock_pi() retry path, which
   triggered a warning (and potential misbehavior) in stress-testing
   (Davidlohr Bueso)

* tag 'locking-urgent-2026-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  futex: Clear stale exiting pointer in futex_lock_pi() retry path
  futex: Fix UaF between futex_key_to_node_opt() and vma_replace_policy()
  futex: Require sys_futex_requeue() to have identical flags
This commit is contained in:
Linus Torvalds 2026-03-29 09:59:46 -07:00
commit f087b0bad4
5 changed files with 20 additions and 4 deletions

View File

@ -55,6 +55,7 @@ struct mempolicy {
nodemask_t cpuset_mems_allowed; /* relative to these nodes */ nodemask_t cpuset_mems_allowed; /* relative to these nodes */
nodemask_t user_nodemask; /* nodemask passed by user */ nodemask_t user_nodemask; /* nodemask passed by user */
} w; } w;
struct rcu_head rcu;
}; };
/* /*

View File

@ -342,7 +342,7 @@ static int __futex_key_to_node(struct mm_struct *mm, unsigned long addr)
if (!vma) if (!vma)
return FUTEX_NO_NODE; return FUTEX_NO_NODE;
mpol = vma_policy(vma); mpol = READ_ONCE(vma->vm_policy);
if (!mpol) if (!mpol)
return FUTEX_NO_NODE; return FUTEX_NO_NODE;

View File

@ -918,7 +918,7 @@ int fixup_pi_owner(u32 __user *uaddr, struct futex_q *q, int locked)
int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylock) int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylock)
{ {
struct hrtimer_sleeper timeout, *to; struct hrtimer_sleeper timeout, *to;
struct task_struct *exiting = NULL; struct task_struct *exiting;
struct rt_mutex_waiter rt_waiter; struct rt_mutex_waiter rt_waiter;
struct futex_q q = futex_q_init; struct futex_q q = futex_q_init;
DEFINE_WAKE_Q(wake_q); DEFINE_WAKE_Q(wake_q);
@ -933,6 +933,7 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
to = futex_setup_timer(time, &timeout, flags, 0); to = futex_setup_timer(time, &timeout, flags, 0);
retry: retry:
exiting = NULL;
ret = get_futex_key(uaddr, flags, &q.key, FUTEX_WRITE); ret = get_futex_key(uaddr, flags, &q.key, FUTEX_WRITE);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;

View File

@ -459,6 +459,14 @@ SYSCALL_DEFINE4(futex_requeue,
if (ret) if (ret)
return ret; return ret;
/*
* For now mandate both flags are identical, like the sys_futex()
* interface has. If/when we merge the variable sized futex support,
* that patch can modify this test to allow a difference in size.
*/
if (futexes[0].w.flags != futexes[1].w.flags)
return -EINVAL;
cmpval = futexes[0].w.val; cmpval = futexes[0].w.val;
return futex_requeue(u64_to_user_ptr(futexes[0].w.uaddr), futexes[0].w.flags, return futex_requeue(u64_to_user_ptr(futexes[0].w.uaddr), futexes[0].w.flags,

View File

@ -487,7 +487,13 @@ void __mpol_put(struct mempolicy *pol)
{ {
if (!atomic_dec_and_test(&pol->refcnt)) if (!atomic_dec_and_test(&pol->refcnt))
return; return;
kmem_cache_free(policy_cache, pol); /*
* Required to allow mmap_lock_speculative*() access, see for example
* futex_key_to_node_opt(). All accesses are serialized by mmap_lock,
* however the speculative lock section unbound by the normal lock
* boundaries, requiring RCU freeing.
*/
kfree_rcu(pol, rcu);
} }
EXPORT_SYMBOL_FOR_MODULES(__mpol_put, "kvm"); EXPORT_SYMBOL_FOR_MODULES(__mpol_put, "kvm");
@ -1020,7 +1026,7 @@ static int vma_replace_policy(struct vm_area_struct *vma,
} }
old = vma->vm_policy; old = vma->vm_policy;
vma->vm_policy = new; /* protected by mmap_lock */ WRITE_ONCE(vma->vm_policy, new); /* protected by mmap_lock */
mpol_put(old); mpol_put(old);
return 0; return 0;