FAILED: patch "[PATCH] mm: hugetlb: fix UAF in hugetlb_handle_userfault" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
958f32ce832b ("mm: hugetlb: fix UAF in hugetlb_handle_userfault")40549ba8f8e0 ("hugetlb: use new vma_lock for pmd sharing synchronization")378397ccb8e5 ("hugetlb: create hugetlb_unmap_file_folio to unmap single file folio") 8d9bfb260814 ("hugetlb: add vma based lock for pmd sharing")12710fd69634 ("hugetlb: rename vma_shareable() and refactor code")c86272287bc6 ("hugetlb: create remove_inode_single_folio to remove single file folio") 7e1813d48dd3 ("hugetlb: rename remove_huge_page to hugetlb_delete_from_page_cache") 3a47c54f09c4 ("hugetlbfs: revert use i_mmap_rwsem for more pmd sharing synchronization") 188a39725ad7 ("hugetlbfs: revert use i_mmap_rwsem to address page fault/truncate race") 5e6b1bf1b5c3 ("hugetlb: remove meaningless BUG_ON(huge_pte_none())")3a5497a2dae3 ("mm/hugetlb: fix missing call to restore_reserve_on_error()")6614a3c3164a ("Merge tag 'mm-stable-2022-08-03' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 958f32ce832ba781ac20e11bb2d12a9352ea28fc Mon Sep 17 00:00:00 2001
From: Liu Shixin <[email protected]>
Date: Fri, 23 Sep 2022 12:21:13 +0800
Subject: [PATCH] mm: hugetlb: fix UAF in hugetlb_handle_userfault
The vma_lock and hugetlb_fault_mutex are dropped before handling userfault and reacquire them again after handle_userfault(), but reacquire the vma_lock could lead to UAF[1,2] due to the following race,
hugetlb_fault
hugetlb_no_page
/*unlock vma_lock */
hugetlb_handle_userfault
handle_userfault
/* unlock mm->mmap_lock*/
vm_mmap_pgoff
do_mmap
mmap_region
munmap_vma_range
/* clean old vma */
/* lock vma_lock again <--- UAF */
/* unlock vma_lock */Since the vma_lock will unlock immediately after hugetlb_handle_userfault(), let's drop the unneeded lock and unlock in hugetlb_handle_userfault() to fix the issue.
[1] https://lore.kernel.org/linux-mm/[email protected]/
[2] https://lore.kernel.org/linux-mm/[email protected]/
mm/hugetlb.c +17 -20
@@ -5489,7 +5489,6 @@ static inline vm_fault_t hugetlb_handle_userfault(struct vm_area_struct *vma, unsigned long addr, unsigned long reason) { -vm_fault_t ret;u32 hash;struct vm_fault vmf = { .vma = vma,
@@ -5507,18 +5506,14 @@ static inline vm_fault_t hugetlb_handle_userfault(struct vm_area_struct *vma, };/* -* vma_lock and hugetlb_fault_mutex must be -* dropped before handling userfault. Reacquire -* after handling fault to make calling code simpler. +* vma_lock and hugetlb_fault_mutex must be dropped before handling +* userfault. Also mmap_lock could be dropped due to handling +* userfault, any vma operation should be careful from here. */ hugetlb_vma_unlock_read (vma); hash =hugetlb_fault_mutex_hash (mapping, idx);mutex_unlock (&hugetlb_fault_mutex_table[hash]); - ret =handle_userfault (&vmf, reason); -mutex_lock (&hugetlb_fault_mutex_table[hash]); -hugetlb_vma_lock_read (vma); - -return ret; +return handle_userfault (&vmf, reason); } static vm_fault_t hugetlb_no_page(struct mm_struct *mm,
@@ -5536,6 +5531,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,spinlock_t *ptl;unsigned long haddr = address &huge_page_mask (h);bool new_page, new_pagecache_page = false; +u32 hash =hugetlb_fault_mutex_hash (mapping, idx);/* * Currently, we are forced to kill the process in the event the
@@ -5546,7 +5542,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,if (is_vma_resv_set (vma,HPAGE_RESV_UNMAPPED )) {pr_warn_ratelimited ("PID %d killed due to inadequate hugepage pool\n" , current->pid); -return ret; + goto out; }/*
@@ -5560,12 +5556,10 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,if (idx >= size) goto out;/* Check for page in userfault range */ -if (userfaultfd_missing (vma)) { - ret =hugetlb_handle_userfault (vma, mapping, idx, +if (userfaultfd_missing (vma)) +return hugetlb_handle_userfault (vma, mapping, idx, flags, haddr, address,VM_UFFD_MISSING ); - goto out; - } page =alloc_huge_page (vma, haddr,0 );if (IS_ERR (page)) {
@@ -5631,10 +5625,9 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,if (userfaultfd_minor (vma)) {unlock_page (page);put_page (page); - ret =hugetlb_handle_userfault (vma, mapping, idx, +return hugetlb_handle_userfault (vma, mapping, idx, flags, haddr, address,VM_UFFD_MINOR ); - goto out; } }
@@ -5692,6 +5685,8 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,unlock_page (page); out: +hugetlb_vma_unlock_read (vma); +mutex_unlock (&hugetlb_fault_mutex_table[hash]);return ret; backout:
@@ -5789,11 +5784,13 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, entry =huge_ptep_get (ptep);/* PTE markers should be handled the same way as none pte */ -if (huge_pte_none_mostly (entry)) { - ret =hugetlb_no_page (mm, vma, mapping, idx, address, ptep, +if (huge_pte_none_mostly (entry)) +/* +* hugetlb_no_page will drop vma lock and hugetlb fault +* mutex internally, which make us return immediately. +*/ +return hugetlb_no_page (mm, vma, mapping, idx, address, ptep, entry, flags); - goto out_mutex; - } ret =0 ;