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:
commit
f087b0bad4
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue