summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDev Jain <dev.jain@arm.com>2026-07-03 11:41:54 +0000
committerWill Deacon <will@kernel.org>2026-07-22 11:44:47 +0000
commitf73a8edc2ccc6ec72c37d5c578e7592d2e1f9922 (patch)
treedefdeaae8fc38e515021ce93aed0eb3857ea7a75
parent285f90a4d1141c7594f2368e19cbb307388eff30 (diff)
downloadlinux-f73a8edc2ccc6ec72c37d5c578e7592d2e1f9922.tar.gz
linux-f73a8edc2ccc6ec72c37d5c578e7592d2e1f9922.tar.bz2
linux-f73a8edc2ccc6ec72c37d5c578e7592d2e1f9922.zip
arm64: make huge_ptep_get handled unaligned addresses
huge_ptep_get() can be handed a virtual address pointing to the middle of a contpmd/contpte mapped hugetlb folio (examples of callers are pagemap_hugetlb_range, page_mapped_in_vma). The arm64 helper rewalks the pgtables in find_num_contig to answer whether the huge pte we have maps a contpmd or a contpte hugetlb folio, and returns CONT_PMDS or CONT_PTES, so that it can collect a/d bits over the contiguous ptes. We can falsely return CONT_PTES instead of CONT_PMDS if the addr is not aligned. On systems where CONT_PTES != CONT_PMDS (meaning page size is 16K), we could collect excess A/D bit state, meaning extra work for the kernel. Even worse, we may iterate beyond the PTE table and dereference a garbage ptep pointer to access physical memory we don't own. Since the ptep pointer is a linear map address, we may run off the end of the linear map or into a hole, dereference a VA not mapped into the kernel pgtables and cause kernel panic. Fix this by aligning the pmdp pointer down to a contpmd base before checking equality with the passed huge pte pointer, to correctly answer whether the huge pte is the base of a contpmd block. Fixes: 29cb80519689 ("arm64: hugetlb: Cleanup huge_pte size discovery mechanisms") Cc: stable@vger.kernel.org Acked-by: David Hildenbrand (Arm) <david@kernel.org> Signed-off-by: Dev Jain <dev.jain@arm.com> Acked-by: Muchun Song <muchun.song@linux.dev> Signed-off-by: Will Deacon <will@kernel.org>
-rw-r--r--arch/arm64/mm/hugetlbpage.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 30772a909aea..8e799c1fe0aa 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -87,7 +87,7 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,
p4dp = p4d_offset(pgdp, addr);
pudp = pud_offset(p4dp, addr);
pmdp = pmd_offset(pudp, addr);
- if ((pte_t *)pmdp == ptep) {
+ if ((pte_t *)PTR_ALIGN_DOWN(pmdp, sizeof(*pmdp) * CONT_PMDS) == ptep) {
*pgsize = PMD_SIZE;
return CONT_PMDS;
}