Re: [PATCH 01/15] hugetlbfs: fix integer overflow in fallocate()
From: Ackerley Tng
Date: Thu Oct 29 2026 - 16:54:05 EST
"David Hildenbrand (Arm)" <david@xxxxxxxxxx> writes:
> hugetlbfs_fallocate() rounds the range end up by adding hpage_size - 1
> to offset + len. vfs_fallocate()'s existing overflow check only makes
> sure that offset + len does not overflow.
>
> Once we overflow for valid endpoints near LLONG_MAX, we can get a
> negative temporary result that is then converted to a very large
> huge page index.
>
> A one-byte allocation ending at LLONG_MAX can therefore consume all
> available huge pages. Pages added beyond LLONG_MAX are skipped during
> inode eviction, leaking them and triggering the BUG_ON() in clear_inode().
>
> To fix it, calculate the end index in a simpler way that cannot
> overflow. This also fixes the signed overflow reported by luojiajun in
> 2019.
>
> Backporting notes: without commit a08c7193e4f18 ("mm/filemap: remove
> hugetlb special casing in filemap.c"), remove_inode_hugepages() must
> include the final huge page during truncate and eviction.
>
> Reported-by: luojiajun <luojiajun3@xxxxxxxxxx>
> Closes: https://lore.kernel.org/all/1554775226-67213-1-git-send-email-luojiajun3@xxxxxxxxxx/
> Reported-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
> Fixes: 70c3547e36f5 ("hugetlbfs: add hugetlbfs_fallocate()")
> Cc: stable@xxxxxxxxxx
> Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
> ---
> fs/hugetlbfs/inode.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 01c4d6f44ebe..5592cfc6cc8b 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -721,11 +721,13 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
>
> /*
> * Default preallocate case.
> - * For this range, start is rounded down and end is rounded up
> - * as well as being converted to page offsets.
> + * vfs_fallocate() guarantees that offset + len is positive and does
> + * not overflow. Avoid overflows when calculating the end huge page
> + * index: set it to one past the index of the huge page containing the
> + * last byte.
> */
> start = offset >> hpage_shift;
> - end = (offset + len + hpage_size - 1) >> hpage_shift;
> + end = ((offset + len - 1) >> hpage_shift) + 1;
Reviewed-by: Ackerley Tng <ackerleytng@xxxxxxxxxx>
>
> inode_lock(inode);
>
>
> --
> 2.43.0