[PW_SID:1120365] [v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF#2202
[PW_SID:1120365] [v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF#2202linux-riscv-bot wants to merge 1 commit into
Conversation
ptdump_walk_pgd() walks the kernel page tables under get_online_mems(). That does not stop vmalloc from freeing a kernel PTE page underneath the walk. When vmap_try_huge_pmd() promotes a range to a huge PMD it collapses the existing PTE table and frees it via pmd_free_pte_page(). On x86, riscv and powerpc this runs without the init_mm mmap lock; only arm64 takes it, and not on the block-split path. So ptdump can dereference a just-freed PTE page, which is the use after free syzbot hit in ptdump_pte_entry(). The race is not new. ptdump walks the whole kernel address space, including ranges other code is actively mapping, so it reads page tables it does not own. 5ba2f0a ("mm: introduce deferred freeing for kernel page tables") only widened the window; the Fixes tag points there for that reason. Every other walker works on a range it owns and is the only one mutating it: set_memory() on arm64/riscv/loongarch, the arm64 block-split path, the openrisc DMA path and the hugetlb_vmemmap remap. Nothing frees those ranges concurrently, so they cannot race and do not need RCU. ptdump is the only walker that traverses ranges it does not own. Defer the free by an RCU grace period. pagetable_free_kernel() now frees via call_rcu() in both the async and non-async configs. The async path still flushes the TLB first, then queues the per-page RCU free. The page stays valid until any walk that may have observed it drops its RCU read lock. On the read side walk_page_range_debug() walks the init_mm range in bounded chunks, taking rcu_read_lock() around each chunk and calling cond_resched() between them. A walker either sees the cleared PMD and skips, or keeps the page alive until it drops the lock; chunking keeps the read section short on a large kernel address space instead of holding RCU across the whole walk. The owned-range walkers are unchanged. Drop the mmap_write_lock() in ptdump_walk_pgd(). It never guarded against this free -- most architectures free the collapsed PTE table without it -- and RCU now provides the synchronisation. ptdump callbacks run under RCU within a chunk, so they must not sleep. The arch note_page() and effective_prot() callbacks only format into the preallocated seq_file buffer; the only GFP_KERNEL marker setup runs before the walk, and cond_resched() happens between chunks, outside the read lock. Fixes: 5ba2f0a ("mm: introduce deferred freeing for kernel page tables") Reported-by: syzbot+fd95a72470f5a44e464c@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/6a287988.39669fcc.33b062.00a0.GAE@google.com/T/ Assisted-by: Claude:claude-opus-4-8 Signed-off-by: David Carlier <devnexen@gmail.com> Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
|
Patch 1: "[v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF" |
PR for series 1120365 applied to workflow__riscv__fixes
Name: [v7] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF
URL: https://patchwork.kernel.org/project/linux-riscv/list/?series=1120365
Version: 7