]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64: remove redundant concurrent ptdump UAF mitigation
authorLorenzo Stoakes (ARM) <ljs@kernel.org>
Thu, 23 Jul 2026 15:16:35 +0000 (16:16 +0100)
committerAndrew Morton <akpm@linux-foundation.org>
Wed, 5 Aug 2026 03:02:00 +0000 (20:02 -0700)
This partially reverts commit fa93b45fd397 ("arm64: Enable vmalloc-huge
with ptdump"), retaining vmalloc-huge support but eliminating the now
redundant mitigation against a race between huge vmap page table freeing
and ptdump, as this issue has now been fixed at core.

We also simultaneously remove the arm64 if-deffery when acquiring the mmap
read lock upon vmap huge page table promotion as it is no longer required.

Note that this patch relies on the preceding vmalloc patch, and should not
be backported alone.

Link: https://lore.kernel.org/20260723-series-vmap-race-fix-v6-5-8cc77dcc0018@kernel.org
Fixes: fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Acked-by: Will Deacon <will@kernel.org>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: "Borah, Chaitanya Kumar" <chaitanya.kumar.borah@intel.com>
Cc: "Borislav Petkov (AMD)" <bp@alien8.de>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Carlier <devnexen@gmail.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Toshi Kani <toshi.kani@hpe.com>
Cc: "Uladzislau Rezki (Sony)" <urezki@gmail.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
arch/arm64/include/asm/ptdump.h
arch/arm64/mm/mmu.c
arch/arm64/mm/ptdump.c
mm/vmalloc.c

index 5b374a6ab34a4e433f5c09ee091f0d5af1bbb266..50a195eda8ed228c42af91ec917f66d5c16955d2 100644 (file)
@@ -7,8 +7,6 @@
 
 #include <linux/ptdump.h>
 
-DECLARE_STATIC_KEY_FALSE(arm64_ptdump_lock_key);
-
 #ifdef CONFIG_PTDUMP
 
 #include <linux/mm_types.h>
index 18a8b0d3714ee5c8f8ffa2efd5042e87e6648631..d4de88770ecfea98a2eef2205661a5adbbbff38c 100644 (file)
@@ -49,8 +49,6 @@
 #define NO_CONT_MAPPINGS       BIT(1)
 #define NO_EXEC_MAPPINGS       BIT(2)  /* assumes FEAT_HPDS is not used */
 
-DEFINE_STATIC_KEY_FALSE(arm64_ptdump_lock_key);
-
 u64 kimage_voffset __ro_after_init;
 EXPORT_SYMBOL(kimage_voffset);
 
@@ -1864,8 +1862,7 @@ int pmd_clear_huge(pmd_t *pmdp)
        return 1;
 }
 
-static int __pmd_free_pte_page(pmd_t *pmdp, unsigned long addr,
-                              bool acquire_mmap_lock)
+int pmd_free_pte_page(pmd_t *pmdp, unsigned long addr)
 {
        pte_t *table;
        pmd_t pmd;
@@ -1877,25 +1874,13 @@ static int __pmd_free_pte_page(pmd_t *pmdp, unsigned long addr,
                return 1;
        }
 
-       /* See comment in pud_free_pmd_page for static key logic */
        table = pte_offset_kernel(pmdp, addr);
        pmd_clear(pmdp);
        __flush_tlb_kernel_pgtable(addr);
-       if (static_branch_unlikely(&arm64_ptdump_lock_key) && acquire_mmap_lock) {
-               mmap_read_lock(&init_mm);
-               mmap_read_unlock(&init_mm);
-       }
-
        pte_free_kernel(NULL, table);
        return 1;
 }
 
-int pmd_free_pte_page(pmd_t *pmdp, unsigned long addr)
-{
-       /* If ptdump is walking the pagetables, acquire init_mm.mmap_lock */
-       return __pmd_free_pte_page(pmdp, addr, /* acquire_mmap_lock = */ true);
-}
-
 int pud_free_pmd_page(pud_t *pudp, unsigned long addr)
 {
        pmd_t *table;
@@ -1911,36 +1896,16 @@ int pud_free_pmd_page(pud_t *pudp, unsigned long addr)
        }
 
        table = pmd_offset(pudp, addr);
-
-       /*
-        * Our objective is to prevent ptdump from reading a PMD table which has
-        * been freed. In this race, if pud_free_pmd_page observes the key on
-        * (which got flipped by ptdump) then the mmap lock sequence here will,
-        * as a result of the mmap write lock/unlock sequence in ptdump, give
-        * us the correct synchronization. If not, this means that ptdump has
-        * yet not started walking the pagetables - the sequence of barriers
-        * issued by __flush_tlb_kernel_pgtable() guarantees that ptdump will
-        * observe an empty PUD.
-        */
-       pud_clear(pudp);
-       __flush_tlb_kernel_pgtable(addr);
-       if (static_branch_unlikely(&arm64_ptdump_lock_key)) {
-               mmap_read_lock(&init_mm);
-               mmap_read_unlock(&init_mm);
-       }
-
        pmdp = table;
        next = addr;
        end = addr + PUD_SIZE;
        do {
                if (pmd_present(pmdp_get(pmdp)))
-                       /*
-                        * PMD has been isolated, so ptdump won't see it. No
-                        * need to acquire init_mm.mmap_lock.
-                        */
-                       __pmd_free_pte_page(pmdp, next, /* acquire_mmap_lock = */ false);
+                       pmd_free_pte_page(pmdp, next);
        } while (pmdp++, next += PMD_SIZE, next != end);
 
+       pud_clear(pudp);
+       __flush_tlb_kernel_pgtable(addr);
        pmd_free(NULL, table);
        return 1;
 }
index 1c20144700d7d711f3442f1f33815b9b0c34000f..5a76c59b5ada555055388b615bacd678db670cfa 100644 (file)
@@ -283,13 +283,6 @@ void note_page_flush(struct ptdump_state *pt_st)
        note_page(pt_st, 0, -1, pte_val(pte_zero));
 }
 
-static void arm64_ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm)
-{
-       static_branch_inc(&arm64_ptdump_lock_key);
-       ptdump_walk_pgd(st, mm, NULL);
-       static_branch_dec(&arm64_ptdump_lock_key);
-}
-
 void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
 {
        unsigned long end = ~0UL;
@@ -318,7 +311,7 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
                }
        };
 
-       arm64_ptdump_walk_pgd(&st.ptdump, info->mm);
+       ptdump_walk_pgd(&st.ptdump, info->mm, NULL);
 }
 
 static void __init ptdump_initialize(void)
@@ -360,7 +353,7 @@ bool ptdump_check_wx(void)
                }
        };
 
-       arm64_ptdump_walk_pgd(&st.ptdump, &init_mm);
+       ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
 
        if (st.wx_pages || st.uxn_pages) {
                pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
index d5c4d2bb770bfbb427868b5b4e15368cfc7957b5..f4fa227a8d7f04dad567f48a2dd704597c26ad04 100644 (file)
@@ -169,10 +169,7 @@ static int vmap_try_huge_pmd(pmd_t *pmd, unsigned long addr, unsigned long end,
         * Concurrent read lock holders are safe: each exclusively owns
         * the range it operates on and cannot reach this page table.
         */
-#ifndef CONFIG_ARM64
-       scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm)
-#endif
-       {
+       scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm) {
                if (!pmd_free_pte_page(pmd, addr))
                        return 0;
                return pmd_set_huge(pmd, phys_addr, prot);
@@ -229,10 +226,7 @@ static int vmap_try_huge_pud(pud_t *pud, unsigned long addr, unsigned long end,
                return pud_set_huge(pud, phys_addr, prot);
 
        /* See comment in vmap_try_huge_pmd(). */
-#ifndef CONFIG_ARM64
-       scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm)
-#endif
-       {
+       scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm) {
                if (!pud_free_pmd_page(pud, addr))
                        return 0;
                return pud_set_huge(pud, phys_addr, prot);
@@ -289,10 +283,7 @@ static int vmap_try_huge_p4d(p4d_t *p4d, unsigned long addr, unsigned long end,
                return p4d_set_huge(p4d, phys_addr, prot);
 
        /* See comment in vmap_try_huge_pmd(). */
-#ifndef CONFIG_ARM64
-       scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm)
-#endif
-       {
+       scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm) {
                if (!p4d_free_pud_page(p4d, addr))
                        return 0;
                return p4d_set_huge(p4d, phys_addr, prot);