Forwarded: [PATCH] jfs: validate budmin from dmapctl to prevent shift-out-of-bounds
From: syzbot
Date: Fri Apr 17 2026 - 06:15:40 EST
For archival purposes, forwarding an incoming command email to
linux-kernel@xxxxxxxxxxxxxxx, syzkaller-bugs@xxxxxxxxxxxxxxxx.
***
Subject: [PATCH] jfs: validate budmin from dmapctl to prevent shift-out-of-bounds
Author: tristmd@xxxxxxxxx
From: Tristan Madani <tristan@xxxxxxxxxxxxxxxxxxx>
#syz test: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
dbAllocAG() reads budmin directly from an on-disk dmapctl page and uses
it as a shift amount:
blkno += ((s64)(ti - le32_to_cpu(dcp->leafidx))) << budmin;
When the filesystem image is corrupted, budmin (an s8) can be negative,
causing a UBSAN shift-out-of-bounds splat with "shift exponent -1 is
negative".
The existing mount-time validation in dbMount() (commit 7c4af96b24a6)
covers db_agheight/db_agwidth/db_agstart but not budmin in individual
dmapctl pages, since those are read at allocation time, not at mount.
Fix this by validating budmin immediately after reading it from the
dmapctl page. A valid budmin for a dmapctl page must be in the range
[L2BPERDMAP, L2MAXL2SIZE] (i.e. [13, 43]). Reject pages outside this
range as corrupt.
The same pattern exists in dbFindCtl() which also reads budmin from
dmapctl pages and uses it as a shift; add the validation there too.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+4b717071f1eecb2972df@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=4b717071f1eecb2972df
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Tristan Madani <tristan@xxxxxxxxxxxxxxxxxxx>
---
fs/jfs/jfs_dmap.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 35e063c9f3a4..a1b2c3d4e5f6 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -1373,6 +1373,13 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
dcp = (struct dmapctl *) mp->data;
budmin = dcp->budmin;
+ if (budmin < L2BPERDMAP || budmin > L2MAXL2SIZE) {
+ jfs_error(bmp->db_ipbmap->i_sb,
+ "Corrupt dmapctl budmin %d\n", budmin);
+ release_metapage(mp);
+ return -EIO;
+ }
+
if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n");
release_metapage(mp);
@@ -1703,6 +1710,13 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
dcp = (struct dmapctl *) mp->data;
budmin = dcp->budmin;
+ if (budmin < L2BPERDMAP || budmin > L2MAXL2SIZE) {
+ jfs_error(bmp->db_ipbmap->i_sb,
+ "Corrupt dmapctl budmin %d\n", budmin);
+ release_metapage(mp);
+ return -EIO;
+ }
+
if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
jfs_error(bmp->db_ipbmap->i_sb,
"Corrupt dmapctl page\n");
--
2.39.2