[PATCH] gfs2: prevent corrupt data from entering jextent
From: Edward Adam Davis
Date: Wed Mar 25 2026 - 03:51:09 EST
During the mount process, when the journal recovery is executed, the
system blocks and waits for the recovery to complete. The issue reported
in [1] involves the kernel thread responsible for journal recovery
becoming blocked on a specific folio that had not yet been fully read.
This folio was submitted via a bio chain containing an excessively large
sector value; however, the submission failed during the process because
the end-of-file (EOF) check for the bio failed. Consequently, the folio
was never unlocked, which ultimately triggered the timeout issue reported
in [1].
To address this, a check for the blocknr value has been added during the
loading of journal extents from the disk. If the blocknr value exceeds
the maximum sector value supported by the disk, it indicates that the
data on the disk is corrupted; in such cases, the loading of the journal
extent is immediately terminated.
[1]
INFO: task kworker/0:3:5963 blocked in I/O wait for more than 143 seconds.
Workqueue: gfs2_recovery gfs2_recover_func
Call Trace:
folio_wait_locked include/linux/pagemap.h:1245 [inline]
gfs2_jhead_process_page+0x175/0x670 fs/gfs2/lops.c:470
gfs2_find_jhead+0xbd2/0xd30 fs/gfs2/lops.c:586
gfs2_recover_func+0x6cf/0x1f60 fs/gfs2/recovery.c:459
Fixes: b50f227bddf1 ("GFS2: Clean up journal extent mapping")
Reported-by: syzbot+9013411dc43f3582823a@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=9013411dc43f3582823a
Tested-by: syzbot+9013411dc43f3582823a@xxxxxxxxxxxxxxxxxxxxxxxxx
Signed-off-by: Edward Adam Davis <eadavis@xxxxxx>
---
fs/gfs2/bmap.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 1cd8ec0bce83..d42307ab0684 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -2266,6 +2266,9 @@ int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
u64 size;
int rc;
ktime_t start, end;
+ struct super_block *sb = sdp->sd_vfs;
+ sector_t maxsector = bdev_nr_sectors(sb->s_bdev);
+ u32 bshift = sdp->sd_fsb2bb_shift;
start = ktime_get();
lblock_stop = i_size_read(jd->jd_inode) >> shift;
@@ -2280,6 +2283,10 @@ int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
rc = gfs2_block_map(jd->jd_inode, lblock, &bh, 0);
if (rc || !buffer_mapped(&bh))
goto fail;
+ if (bh.b_blocknr << bshift > maxsector) {
+ rc = -EIO;
+ goto fail;
+ }
rc = gfs2_add_jextent(jd, lblock, bh.b_blocknr, bh.b_size >> shift);
if (rc)
goto fail;
--
2.43.0