On 26/10/26 1:33 pm, Hao Ge wrote:
> commit a739e6b557af ("mm: vmalloc: WARN_ON if mapping size is not
> PAGE_SIZE aligned") made vmap_pte_range() warn and bail out when the
> size is not a multiple of PAGE_SIZE. That loop steps in page
Why are we checking the alignment so late into vmap_pte_range? Why not
simply do
if (!IS_ALIGNED(addr, PAGE_SIZE) || !IS_ALIGNED(end, PAGE_SIZE))
return; (or return -EINVAL);
at the start of vmap_range_noflush and vunmap_range_noflush?
> multiples and stops only at addr == end; with an unaligned size addr
> never lands on end, so the loop cannot terminate and walks off the
> end of the page table.
>
> vunmap_pte_range() has the same loop without any guard, so an
> unaligned range would clear PTEs past end without ever stopping,
> walking off the end of the page table.
>
> Add the check there too. The range is clamped down to the last full
> page rather than dropped, and the loop is skipped when nothing is
> left, so a buggy caller still gets its PTEs cleared as far as they
> go.
>
> Reported-by: Sashiko <[email protected]>
> Signed-off-by: Hao Ge <[email protected]>
> ---
> mm/vmalloc.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index 44e0eb32708f..7131f60d1a8e 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -393,6 +393,11 @@ static void vunmap_pte_range(pmd_t *pmd, unsigned long
> addr, unsigned long end,
> pte_t ptent;
> unsigned long size = PAGE_SIZE;
>
> + if (WARN_ON_ONCE(!PAGE_ALIGNED(end - addr)))
> + end = addr + PAGE_ALIGN_DOWN(end - addr);
> + if (end == addr)
> + return;
> +
> pte = pte_offset_kernel(pmd, addr);
> lazy_mmu_mode_enable();
>