[PATCH 01/15] hugetlbfs: fix integer overflow in fallocate()
From: David Hildenbrand (Arm)
Date: Wed Oct 28 2026 - 16:15:52 EST
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;
inode_lock(inode);
--
2.43.0