[PATCH] mm/hugetlb: fix null ptr defer in hugetlb_vma_lock_write

Edward Adam Davis
2023-11-02T13:11:25Z

When obtaining resv_map from vma, it is necessary to simultaneously determine
the flag HPAGE_RESV_OWNER of vm_private_data.
Only when they are met simultaneously, resv_map is valid.

Reported-and-tested-by: syzbot+6ada951e7c0f7bc8a71e@syzkaller.appspotmail.com
Fixes: bf4916922c60 ("hugetlbfs: extend hugetlb_vma_lock to private VMAs")
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
---
include/linux/hugetlb.h | 5 ++++-
mm/hugetlb.c | 1 -
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 47d25a5e1933..14babc602f14 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -179,6 +179,7 @@ struct address_space *hugetlb_page_mapping_lock_write(struct page *hpage);

extern int sysctl_hugetlb_shm_group;
extern struct list_head huge_boot_pages;
+static int is_vma_resv_set(struct vm_area_struct *vma, unsigned long flag);

/* arch callbacks */

@@ -1265,9 +1266,11 @@ static inline bool __vma_shareable_lock(struct vm_area_struct *vma)
return (vma->vm_flags & VM_MAYSHARE) && vma->vm_private_data;
}

+#define HPAGE_RESV_OWNER (1UL << 0)
static inline bool __vma_private_lock(struct vm_area_struct *vma)
{
- return (!(vma->vm_flags & VM_MAYSHARE)) && vma->vm_private_data;
+ return (!(vma->vm_flags & VM_MAYSHARE)) && vma->vm_private_data &&
+ is_vma_resv_set(vma, HPAGE_RESV_OWNER);
}

/*
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 1301ba7b2c9a..97ea782dfba6 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1033,7 +1033,6 @@ __weak unsigned long vma_mmu_pagesize(struct vm_area_struct *vma)
* bits of the reservation map pointer, which are always clear due to
* alignment.
*/
-#define HPAGE_RESV_OWNER (1UL << 0)
#define HPAGE_RESV_UNMAPPED (1UL << 1)
#define HPAGE_RESV_MASK (HPAGE_RESV_OWNER | HPAGE_RESV_UNMAPPED)

--
2.25.1