[PATCH] freevxfs: bound immediate inode folio reads
From: Samuel Moelius
Date: Mon Jun 08 2026 - 20:43:46 EST
FreeVxFS immediate inodes store at most VXFS_NIMMED bytes in the inode.
vxfs_immed_read_folio() copied a full folio from that inline array,
regardless of the inode size or remaining immediate data.
A crafted filesystem with an immediate directory inode can therefore
make directory iteration read past the inline-data field while filling
the page-cache folio.
Copy only the bytes that exist in the immediate-data array and zero the
rest of the folio, matching normal short-read page-cache behavior.
Assisted-by: Codex:gpt-5.5-cyber-preview
Signed-off-by: Samuel Moelius <sam.moelius@xxxxxxxxxxxxxxx>
---
fs/freevxfs/vxfs_immed.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c
index ed51fcd34757..c01cb4015203 100644
--- a/fs/freevxfs/vxfs_immed.c
+++ b/fs/freevxfs/vxfs_immed.c
@@ -30,15 +30,22 @@
*/
static int vxfs_immed_read_folio(struct file *fp, struct folio *folio)
{
+ struct inode *inode = folio->mapping->host;
+ size_t offset = folio_pos(folio);
struct vxfs_inode_info *vip = VXFS_INO(folio->mapping->host);
- void *src = vip->vii_immed.vi_immed + folio_pos(folio);
- unsigned long i;
+ size_t size = min_t(loff_t, inode->i_size,
+ sizeof(vip->vii_immed.vi_immed));
+ size_t len = 0;
- for (i = 0; i < folio_nr_pages(folio); i++) {
- memcpy_to_page(folio_page(folio, i), 0, src, PAGE_SIZE);
- src += PAGE_SIZE;
+ if (offset < size) {
+ len = min_t(size_t, size - offset, folio_size(folio));
+ memcpy_to_folio(folio, 0, vip->vii_immed.vi_immed + offset,
+ len);
}
+ if (len < folio_size(folio))
+ folio_zero_segment(folio, len, folio_size(folio));
+
folio_mark_uptodate(folio);
folio_unlock(folio);
--
2.43.0