gfs2 filesystem and dlm development
 help / color / mirror / Atom feed
From: Andreas Gruenbacher <agruenba@redhat.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Andreas Gruenbacher <agruenba@redhat.com>,
	Edward Adam Davis <eadavis@qq.com>,
	gfs2@lists.linux.dev,
	syzbot <syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com>
Subject: Re: [syzbot] [mm?] [gfs2?] WARNING in read_rindex_entry
Date: Fri, 21 Aug 2026 14:49:43 +0200	[thread overview]
Message-ID: <20260821124944.1648686-1-agruenba@redhat.com> (raw)
In-Reply-To: <20260819171409.e30eed94c3f7eb44b38e5ec7@linux-foundation.org>

On Thu, Aug 20, 2026 at 2:24 AM Andrew Morton <akpm@linux-foundation.org> wrote:
> On Wed, 19 Aug 2026 15:49:42 -0700 syzbot <syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com> wrote:
> > Hello,
> >
> > syzbot found the following issue on:
> >
> > HEAD commit:    15ef2f78c49d Merge tag 'input-for-v7.2-rc7' of git://git.k..
> > git tree:       upstream
> > console+strace: https://syzkaller.appspot.com/x/log.txt?x=10871279580000
> > kernel config:  https://syzkaller.appspot.com/x/.config?x=a0fdc3b566746377
> > dashboard link: https://syzkaller.appspot.com/bug?extid=9d20c3ad7d29227de28d
> > compiler:       gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
> > syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=14871279580000
> > C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=100d2a25580000
> >
> > Downloadable assets:
> > disk image: https://storage.googleapis.com/syzbot-assets/c2a8c7d3a889/disk-15ef2f78.raw.xz
> > vmlinux: https://storage.googleapis.com/syzbot-assets/2da78afed345/vmlinux-15ef2f78.xz
> > kernel image: https://storage.googleapis.com/syzbot-assets/c4ffd97e4708/bzImage-15ef2f78.xz
> > mounted in repro: https://storage.googleapis.com/syzbot-assets/eaa4120812b6/mount_0.gz
> >   fsck result: failed (log: https://syzkaller.appspot.com/x/fsck.log?x=17f52a25580000)
> >
> > IMPORTANT: if you fix the issue, please add the following tag to the commit:
> > Reported-by: syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com
>
> Thanks.  Mounting an intentionally corrupted fs image, I assume.
>
> It appears that GFS2 forgot to validate the `ri_length' which it read
> from disk.  That gets used in compute_bitstructs()->kzalloc_objs() and
> the memory allocator didn't like the excessively-sized allocation
> attempt.

Thanks for looking into this.  This commit (attached below) from the
for-later branch should prevent that from happening:

https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/8684#note_3716004816

Thanks,
Andreas

--

gfs2: Improve resource group validation and error handling

Validate the resource group boundaries, check against the device size, simplify
the initialization logic, and check for resource group overlaps.

Reported-by: syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9d20c3ad7d29227de28d
Tested-by: syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/gfs2/rgrp.c | 123 ++++++++++++++++++++++++++-----------------------
 1 file changed, 65 insertions(+), 58 deletions(-)

diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index f6048a73e5c3..3ac751eea055 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -745,6 +745,7 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
 
 /**
  * compute_bitstructs - Compute the bitmap sizes
+ * @sb: The superblock
  * @rgd: The resource group descriptor
  *
  * Calculates bitmap descriptors, one for each block that contains bitmap data
@@ -752,84 +753,74 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
  * Returns: errno
  */
 
-static int compute_bitstructs(struct gfs2_rgrpd *rgd)
+static int compute_bitstructs(struct super_block *sb, struct gfs2_rgrpd *rgd)
 {
 	struct gfs2_sbd *sdp = rgd->rd_sbd;
 	struct gfs2_bitmap *bi;
-	u32 length = rgd->rd_length; /* # blocks in hdr & bitmap */
+	u32 expected_length;
 	u32 bytes_left, bytes;
+	u64 data_end;
 	int x;
 
-	if (!length)
-		return -EINVAL;
+	/*
+	 * The first resource group block has a gfs2_rgrp header; the remaining
+	 * blocks have a gfs2_meta_header header.  The rest of each block is
+	 * filled with bitmap data.
+	 */
+
+	if (rgd->rd_addr <= (GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift)) {
+		gfs2_consist_rgrpd(rgd);
+		return -EIO;
+	}
+	if (check_add_overflow(rgd->rd_data0, rgd->rd_data, &data_end) ||
+	    rgd->rd_data == 0 || data_end > sb_bdev_nr_blocks(sb)) {
+		gfs2_consist_rgrpd(rgd);
+		return -EIO;
+	}
+	if (rgd->rd_bitbytes != DIV_ROUND_UP(rgd->rd_data, GFS2_NBBY)) {
+		gfs2_consist_rgrpd(rgd);
+		return -EIO;
+	}
+	expected_length = DIV_ROUND_UP(rgd->rd_bitbytes +
+		sizeof(struct gfs2_rgrp) - sizeof(struct gfs2_meta_header),
+		sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header));
+	if (rgd->rd_length != expected_length) {
+		gfs2_consist_rgrpd(rgd);
+		return -EIO;
+	}
+	if (rgd->rd_data0 < rgd->rd_addr + rgd->rd_length) {
+		gfs2_consist_rgrpd(rgd);
+		return -EIO;
+	}
 
-	rgd->rd_bits = kzalloc_objs(struct gfs2_bitmap, length, GFP_NOFS);
+	rgd->rd_bits = kzalloc_objs(struct gfs2_bitmap, rgd->rd_length, GFP_NOFS);
 	if (!rgd->rd_bits)
 		return -ENOMEM;
 
 	bytes_left = rgd->rd_bitbytes;
 
-	for (x = 0; x < length; x++) {
+	for (x = 0; x < rgd->rd_length; x++) {
 		bi = rgd->rd_bits + x;
 
 		bi->bi_flags = 0;
-		/* small rgrp; bitmap stored completely in header block */
-		if (length == 1) {
-			bytes = bytes_left;
-			bi->bi_offset = sizeof(struct gfs2_rgrp);
+		if (x == 0) {
+			/* header block */
 			bi->bi_start = 0;
-			bi->bi_bytes = bytes;
-			bi->bi_blocks = bytes * GFS2_NBBY;
-		/* header block */
-		} else if (x == 0) {
-			bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp);
 			bi->bi_offset = sizeof(struct gfs2_rgrp);
-			bi->bi_start = 0;
-			bi->bi_bytes = bytes;
-			bi->bi_blocks = bytes * GFS2_NBBY;
-		/* last block */
-		} else if (x + 1 == length) {
-			bytes = bytes_left;
-			bi->bi_offset = sizeof(struct gfs2_meta_header);
-			bi->bi_start = rgd->rd_bitbytes - bytes_left;
-			bi->bi_bytes = bytes;
-			bi->bi_blocks = bytes * GFS2_NBBY;
-		/* other blocks */
 		} else {
-			bytes = sdp->sd_sb.sb_bsize -
-				sizeof(struct gfs2_meta_header);
+			/* bitmap-only block */
+			struct gfs2_bitmap *prev = bi - 1;
+
+			bi->bi_start = prev->bi_start + prev->bi_bytes;
 			bi->bi_offset = sizeof(struct gfs2_meta_header);
-			bi->bi_start = rgd->rd_bitbytes - bytes_left;
-			bi->bi_bytes = bytes;
-			bi->bi_blocks = bytes * GFS2_NBBY;
 		}
-
+		bytes = sdp->sd_sb.sb_bsize - bi->bi_offset;
+		if (bytes > bytes_left)
+			bytes = bytes_left;
+		bi->bi_bytes = bytes;
+		bi->bi_blocks = bytes * GFS2_NBBY;
 		bytes_left -= bytes;
 	}
-
-	if (bytes_left) {
-		gfs2_consist_rgrpd(rgd);
-		return -EIO;
-	}
-	bi = rgd->rd_bits + (length - 1);
-	if ((bi->bi_start + bi->bi_bytes) * GFS2_NBBY != rgd->rd_data) {
-		gfs2_lm(sdp,
-			"ri_addr=%llu "
-			"ri_length=%u "
-			"ri_data0=%llu "
-			"ri_data=%u "
-			"ri_bitbytes=%u "
-			"start=%u len=%u offset=%u\n",
-			(unsigned long long)rgd->rd_addr,
-			rgd->rd_length,
-			(unsigned long long)rgd->rd_data0,
-			rgd->rd_data,
-			rgd->rd_bitbytes,
-			bi->bi_start, bi->bi_bytes, bi->bi_offset);
-		gfs2_consist_rgrpd(rgd);
-		return -EIO;
-	}
-
 	return 0;
 }
 
@@ -864,6 +855,7 @@ static int rgd_insert(struct gfs2_rgrpd *rgd)
 {
 	struct gfs2_sbd *sdp = rgd->rd_sbd;
 	struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
+	struct rb_node *prevn;
 
 	/* Figure out where to put new node */
 	while (*newn) {
@@ -882,6 +874,19 @@ static int rgd_insert(struct gfs2_rgrpd *rgd)
 	rb_link_node(&rgd->rd_node, parent, newn);
 	rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
 	sdp->sd_rgrps++;
+
+	prevn = rb_prev(&rgd->rd_node);
+	if (prevn) {
+		struct gfs2_rgrpd *prev =
+			rb_entry(prevn, struct gfs2_rgrpd, rd_node);
+
+		if (prev->rd_data0 + prev->rd_data > rgd->rd_addr) {
+			fs_err(sdp, "overlapping resource groups.\n");
+			rb_erase(&rgd->rd_node, &sdp->sd_rindex_tree);
+			return -ENOENT;
+		}
+	}
+
 	return 0;
 }
 
@@ -928,7 +933,7 @@ static int read_rindex_entry(struct gfs2_inode *ip)
 	if (error)
 		goto fail;
 
-	error = compute_bitstructs(rgd);
+	error = compute_bitstructs(sdp->sd_vfs, rgd);
 	if (error)
 		goto fail_glock;
 
@@ -944,7 +949,9 @@ static int read_rindex_entry(struct gfs2_inode *ip)
 		return 0;
 	}
 
-	error = 0; /* someone else read in the rgrp; free it and ignore it */
+	/* If someone else read in the rgrp, free it and ignore it. */
+	if (error == -EEXIST)
+		error = 0;
 fail_glock:
 	gfs2_glock_put(rgd->rd_gl);
 
-- 
2.55.0


  parent reply	other threads:[~2026-08-21 12:49 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-19 22:49 [syzbot] [mm?] [gfs2?] WARNING in read_rindex_entry syzbot
2026-08-20  0:14 ` Andrew Morton
2026-08-20  1:35   ` Zi Yan
2026-08-21 12:49   ` Andreas Gruenbacher [this message]
2026-08-20  4:21 ` [PATCH] gfs2: valid the length of rgrp header Edward Adam Davis
2026-08-21 12:54   ` Andreas Gruenbacher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260821124944.1648686-1-agruenba@redhat.com \
    --to=agruenba@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=eadavis@qq.com \
    --cc=gfs2@lists.linux.dev \
    --cc=syzbot+9d20c3ad7d29227de28d@syzkaller.appspotmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox