From: Greg Kroah-Hartman Date: Fri, 4 Aug 2023 10:27:44 +0000 (+0200) Subject: 6.4-stable patches X-Git-Tag: v4.14.321~73 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc2a862732c8f4149d6152893a8981406936b78d;p=thirdparty%2Fkernel%2Fstable-queue.git 6.4-stable patches added patches: mm-lock_vma_under_rcu-must-check-vma-anon_vma-under-vma-lock.patch --- diff --git a/queue-6.4/mm-lock_vma_under_rcu-must-check-vma-anon_vma-under-vma-lock.patch b/queue-6.4/mm-lock_vma_under_rcu-must-check-vma-anon_vma-under-vma-lock.patch new file mode 100644 index 00000000000..fd531bc43a0 --- /dev/null +++ b/queue-6.4/mm-lock_vma_under_rcu-must-check-vma-anon_vma-under-vma-lock.patch @@ -0,0 +1,116 @@ +From 657b5146955eba331e01b9a6ae89ce2e716ba306 Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Wed, 26 Jul 2023 23:41:03 +0200 +Subject: mm: lock_vma_under_rcu() must check vma->anon_vma under vma lock + +From: Jann Horn + +commit 657b5146955eba331e01b9a6ae89ce2e716ba306 upstream. + +lock_vma_under_rcu() tries to guarantee that __anon_vma_prepare() can't +be called in the VMA-locked page fault path by ensuring that +vma->anon_vma is set. + +However, this check happens before the VMA is locked, which means a +concurrent move_vma() can concurrently call unlink_anon_vmas(), which +disassociates the VMA's anon_vma. + +This means we can get UAF in the following scenario: + + THREAD 1 THREAD 2 + ======== ======== + + lock_vma_under_rcu() + rcu_read_lock() + mas_walk() + check vma->anon_vma + + mremap() syscall + move_vma() + vma_start_write() + unlink_anon_vmas() + + + handle_mm_fault() + __handle_mm_fault() + handle_pte_fault() + do_pte_missing() + do_anonymous_page() + anon_vma_prepare() + __anon_vma_prepare() + find_mergeable_anon_vma() + mas_walk() [looks up VMA X] + + munmap() syscall (deletes VMA X) + + reusable_anon_vma() [called on freed VMA X] + +This is a security bug if you can hit it, although an attacker would +have to win two races at once where the first race window is only a few +instructions wide. + +This patch is based on some previous discussion with Linus Torvalds on +the security list. + +Cc: stable@vger.kernel.org +Fixes: 5e31275cc997 ("mm: add per-VMA lock and helper functions to control it") +Signed-off-by: Jann Horn +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -5410,27 +5410,28 @@ retry: + if (!vma_is_anonymous(vma)) + goto inval; + +- /* find_mergeable_anon_vma uses adjacent vmas which are not locked */ +- if (!vma->anon_vma) +- goto inval; +- + if (!vma_start_read(vma)) + goto inval; + + /* ++ * find_mergeable_anon_vma uses adjacent vmas which are not locked. ++ * This check must happen after vma_start_read(); otherwise, a ++ * concurrent mremap() with MREMAP_DONTUNMAP could dissociate the VMA ++ * from its anon_vma. ++ */ ++ if (unlikely(!vma->anon_vma)) ++ goto inval_end_read; ++ ++ /* + * Due to the possibility of userfault handler dropping mmap_lock, avoid + * it for now and fall back to page fault handling under mmap_lock. + */ +- if (userfaultfd_armed(vma)) { +- vma_end_read(vma); +- goto inval; +- } ++ if (userfaultfd_armed(vma)) ++ goto inval_end_read; + + /* Check since vm_start/vm_end might change before we lock the VMA */ +- if (unlikely(address < vma->vm_start || address >= vma->vm_end)) { +- vma_end_read(vma); +- goto inval; +- } ++ if (unlikely(address < vma->vm_start || address >= vma->vm_end)) ++ goto inval_end_read; + + /* Check if the VMA got isolated after we found it */ + if (vma->detached) { +@@ -5442,6 +5443,9 @@ retry: + + rcu_read_unlock(); + return vma; ++ ++inval_end_read: ++ vma_end_read(vma); + inval: + rcu_read_unlock(); + count_vm_vma_lock_event(VMA_LOCK_ABORT); diff --git a/queue-6.4/series b/queue-6.4/series index e69de29bb2d..4d1f0c015e4 100644 --- a/queue-6.4/series +++ b/queue-6.4/series @@ -0,0 +1 @@ +mm-lock_vma_under_rcu-must-check-vma-anon_vma-under-vma-lock.patch