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().
Unified · Split
| @@ -55,6 +55,7 @@ struct mempolicy { · 54 unmodified lines | |||
| 55 | nodemask_t cpuset_mems_allowed; /* relative to these nodes */ | 55 | nodemask_t cpuset_mems_allowed; /* relative to these nodes */ |
| 56 | nodemask_t user_nodemask; /* nodemask passed by user */ | 56 | nodemask_t user_nodemask; /* nodemask passed by user */ |
| 57 | } w; | 57 | } w; |
| 58 | struct rcu_head rcu; | ||
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| 60 | /* | 61 | /* |
| @@ -342,7 +342,7 @@ static int __futex_key_to_node(struct mm_struct *mm, unsigned long addr) · 341 unmodified lines | |||
| 342 | if (!vma) | 342 | if (!vma) |
| 343 | return FUTEX_NO_NODE; | 343 | return FUTEX_NO_NODE; |
| 344 | 344 | ||
| 345 | mpol = vma_policy(vma); | 345 | mpol = READ_ONCE(vma->vm_policy); |
| 346 | if (!mpol) | 346 | if (!mpol) |
| 347 | return FUTEX_NO_NODE; | 347 | return FUTEX_NO_NODE; |
| 348 | 348 | ||
| @@ -487,7 +487,13 @@ void __mpol_put(struct mempolicy *pol) · 486 unmodified lines | |||
| 487 | { | 487 | { |
| 488 | if (!atomic_dec_and_test(&pol->refcnt)) | 488 | if (!atomic_dec_and_test(&pol->refcnt)) |
| 489 | return; | 489 | return; |
| 490 | kmem_cache_free(policy_cache, pol); | 490 | /* |
| 491 | * Required to allow mmap_lock_speculative*() access, see for example | ||
| 492 | * futex_key_to_node_opt(). All accesses are serialized by mmap_lock, | ||
| 493 | * however the speculative lock section unbound by the normal lock | ||
| 494 | * boundaries, requiring RCU freeing. | ||
| 495 | */ | ||
| 496 | kfree_rcu(pol, rcu); | ||
| 491 | } | 497 | } |
| 492 | EXPORT_SYMBOL_FOR_MODULES(__mpol_put, "kvm"); | 498 | EXPORT_SYMBOL_FOR_MODULES(__mpol_put, "kvm"); |
| 493 | 499 | ||
| @@ -1020,7 +1026,7 @@ static int vma_replace_policy(struct vm_area_struct *vma, · 526 unmodified lines | |||
| 1020 | } | 1026 | } |
| 1021 | 1027 | ||
| 1022 | old = vma->vm_policy; | 1028 | old = vma->vm_policy; |
| 1023 | vma->vm_policy = new; /* protected by mmap_lock */ | 1029 | WRITE_ONCE(vma->vm_policy, new); /* protected by mmap_lock */ |
| 1024 | mpol_put(old); | 1030 | mpol_put(old); |
| 1025 | 1031 | ||
| 1026 | return 0; | 1032 | return 0; |