[PATCH] jfs: validate lv bounds in diWrite to prevent slab-out-of-bounds
From: Tristan Madani
Date: Fri May 01 2026 - 07:03:57 EST
From: Tristan Madani <tristan@xxxxxxxxxxxxxxxxxxx>
diWrite() copies btree root data from the in-memory inode to the
on-disk dinode using lv->offset and lv->length from the transaction
lock without bounds checking. When a corrupted JFS filesystem image
provides inconsistent dtree or xtree metadata, the transaction log
entries can reference slots beyond the root node boundaries
(DTROOTMAXSLOT or XTROOTMAXSLOT), causing a slab-out-of-bounds write
in the subsequent memcpy.
For example, with a crafted directory inode where the dtree metadata
produces lv->offset + lv->length > DTROOTMAXSLOT (9), the memcpy in
the dtree copy loop writes 32 bytes past the dinode boundary into
adjacent slab memory.
Add bounds validation before each memcpy in both the xtree and dtree
copy loops to ensure lv->offset + lv->length does not exceed
XTROOTMAXSLOT (18) or DTROOTMAXSLOT (9) respectively.
Reported-by: syzbot+aa6df9d3b383bf5f047f@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=aa6df9d3b383bf5f047f
Tested-by: syzbot+aa6df9d3b383bf5f047f@xxxxxxxxxxxxxxxxxxxxxxxxx
Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Tristan Madani <tristan@xxxxxxxxxxxxxxxxxxx>
---
fs/jfs/jfs_imap.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index b84ba4d7dfb44..70d6a33597273 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -726,6 +726,11 @@ int diWrite(tid_t tid, struct inode *ip)
xp = &dp->di_xtroot;
lv = ilinelock->lv;
for (n = 0; n < ilinelock->index; n++, lv++) {
+ if (lv->offset + lv->length > XTROOTMAXSLOT) {
+ jfs_err("diWrite: xtree lv out of bounds");
+ release_metapage(mp);
+ return -EIO;
+ }
memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
lv->length << L2XTSLOTSIZE);
}
@@ -750,6 +755,11 @@ int diWrite(tid_t tid, struct inode *ip)
xp = (dtpage_t *) & dp->di_dtroot;
lv = ilinelock->lv;
for (n = 0; n < ilinelock->index; n++, lv++) {
+ if (lv->offset + lv->length > DTROOTMAXSLOT) {
+ jfs_err("diWrite: dtree lv out of bounds");
+ release_metapage(mp);
+ return -EIO;
+ }
memcpy(&xp->slot[lv->offset], &p->slot[lv->offset],
lv->length << L2DTSLOTSIZE);
}
--
2.47.3