Skip to content

Commit 7e19619

Browse files
Naupjjingregkh
authored andcommitted
futex: Fix UaF between futex_key_to_node_opt() and vma_replace_policy()
[ Upstream commit 190a8c4 ] During futex_key_to_node_opt() execution, vma->vm_policy is read under speculative mmap lock and RCU. Concurrently, mbind() may call vma_replace_policy() which frees the old mempolicy immediately via kmem_cache_free(). This creates a race where __futex_key_to_node() dereferences a freed mempolicy pointer, causing a use-after-free read of mpol->mode. [ 151.412631] BUG: KASAN: slab-use-after-free in __futex_key_to_node (kernel/futex/core.c:349) [ 151.414046] Read of size 2 at addr ffff888001c49634 by task e/87 [ 151.415969] Call Trace: [ 151.416732] __asan_load2 (mm/kasan/generic.c:271) [ 151.416777] __futex_key_to_node (kernel/futex/core.c:349) [ 151.416822] get_futex_key (kernel/futex/core.c:374 kernel/futex/core.c:386 kernel/futex/core.c:593) Fix by adding rcu to __mpol_put(). Fixes: c042c50 ("futex: Implement FUTEX2_MPOL") Reported-by: Hao-Yu Yang <naup96721@gmail.com> Suggested-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Hao-Yu Yang <naup96721@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Eric Dumazet <edumazet@google.com> Acked-by: David Hildenbrand (Arm) <david@kernel.org> Link: https://patch.msgid.link/20260324174418.GB1850007@noisy.programming.kicks-ass.net Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e2f78c7 commit 7e19619

3 files changed

Lines changed: 10 additions & 3 deletions

File tree

include/linux/mempolicy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct mempolicy {
5555
nodemask_t cpuset_mems_allowed; /* relative to these nodes */
5656
nodemask_t user_nodemask; /* nodemask passed by user */
5757
} w;
58+
struct rcu_head rcu;
5859
};
5960

6061
/*

kernel/futex/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ static int __futex_key_to_node(struct mm_struct *mm, unsigned long addr)
342342
if (!vma)
343343
return FUTEX_NO_NODE;
344344

345-
mpol = vma_policy(vma);
345+
mpol = READ_ONCE(vma->vm_policy);
346346
if (!mpol)
347347
return FUTEX_NO_NODE;
348348

mm/mempolicy.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,13 @@ void __mpol_put(struct mempolicy *pol)
488488
{
489489
if (!atomic_dec_and_test(&pol->refcnt))
490490
return;
491-
kmem_cache_free(policy_cache, pol);
491+
/*
492+
* Required to allow mmap_lock_speculative*() access, see for example
493+
* futex_key_to_node_opt(). All accesses are serialized by mmap_lock,
494+
* however the speculative lock section unbound by the normal lock
495+
* boundaries, requiring RCU freeing.
496+
*/
497+
kfree_rcu(pol, rcu);
492498
}
493499
EXPORT_SYMBOL_FOR_MODULES(__mpol_put, "kvm");
494500

@@ -1021,7 +1027,7 @@ static int vma_replace_policy(struct vm_area_struct *vma,
10211027
}
10221028

10231029
old = vma->vm_policy;
1024-
vma->vm_policy = new; /* protected by mmap_lock */
1030+
WRITE_ONCE(vma->vm_policy, new); /* protected by mmap_lock */
10251031
mpol_put(old);
10261032

10271033
return 0;

0 commit comments

Comments
 (0)