| From eb31e5d060cbd93b36f6998f8f3b7b5ad75599de Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 7 Oct 2020 12:30:58 +0100 |
| Subject: gfs2: Fix NULL pointer dereference in gfs2_rgrp_dump |
| |
| From: Andrew Price <anprice@redhat.com> |
| |
| [ Upstream commit 0e539ca1bbbe85a86549c97a30a765ada4a09df9 ] |
| |
| When an rindex entry is found to be corrupt, compute_bitstructs() calls |
| gfs2_consist_rgrpd() which calls gfs2_rgrp_dump() like this: |
| |
| gfs2_rgrp_dump(NULL, rgd->rd_gl, fs_id_buf); |
| |
| gfs2_rgrp_dump then dereferences the gl without checking it and we get |
| |
| BUG: KASAN: null-ptr-deref in gfs2_rgrp_dump+0x28/0x280 |
| |
| because there's no rgrp glock involved while reading the rindex on mount. |
| |
| Fix this by changing gfs2_rgrp_dump to take an rgrp argument. |
| |
| Reported-by: syzbot+43fa87986bdd31df9de6@syzkaller.appspotmail.com |
| Signed-off-by: Andrew Price <anprice@redhat.com> |
| Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/gfs2/glops.c | 11 ++++++++++- |
| fs/gfs2/rgrp.c | 9 +++------ |
| fs/gfs2/rgrp.h | 2 +- |
| fs/gfs2/util.c | 2 +- |
| 4 files changed, 15 insertions(+), 9 deletions(-) |
| |
| diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c |
| index de1d5f1d9ff85..c2c90747d79b5 100644 |
| --- a/fs/gfs2/glops.c |
| +++ b/fs/gfs2/glops.c |
| @@ -227,6 +227,15 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags) |
| rgd->rd_flags &= ~GFS2_RDF_UPTODATE; |
| } |
| |
| +static void gfs2_rgrp_go_dump(struct seq_file *seq, struct gfs2_glock *gl, |
| + const char *fs_id_buf) |
| +{ |
| + struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl); |
| + |
| + if (rgd) |
| + gfs2_rgrp_dump(seq, rgd, fs_id_buf); |
| +} |
| + |
| static struct gfs2_inode *gfs2_glock2inode(struct gfs2_glock *gl) |
| { |
| struct gfs2_inode *ip; |
| @@ -712,7 +721,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { |
| .go_sync = rgrp_go_sync, |
| .go_inval = rgrp_go_inval, |
| .go_lock = gfs2_rgrp_go_lock, |
| - .go_dump = gfs2_rgrp_dump, |
| + .go_dump = gfs2_rgrp_go_dump, |
| .go_type = LM_TYPE_RGRP, |
| .go_flags = GLOF_LVB, |
| }; |
| diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c |
| index 074f228ea8390..1bba5a9d45fa3 100644 |
| --- a/fs/gfs2/rgrp.c |
| +++ b/fs/gfs2/rgrp.c |
| @@ -2209,20 +2209,17 @@ static void rgblk_free(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd, |
| /** |
| * gfs2_rgrp_dump - print out an rgrp |
| * @seq: The iterator |
| - * @gl: The glock in question |
| + * @rgd: The rgrp in question |
| * @fs_id_buf: pointer to file system id (if requested) |
| * |
| */ |
| |
| -void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_glock *gl, |
| +void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd, |
| const char *fs_id_buf) |
| { |
| - struct gfs2_rgrpd *rgd = gl->gl_object; |
| struct gfs2_blkreserv *trs; |
| const struct rb_node *n; |
| |
| - if (rgd == NULL) |
| - return; |
| gfs2_print_dbg(seq, "%s R: n:%llu f:%02x b:%u/%u i:%u r:%u e:%u\n", |
| fs_id_buf, |
| (unsigned long long)rgd->rd_addr, rgd->rd_flags, |
| @@ -2253,7 +2250,7 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) |
| (unsigned long long)rgd->rd_addr); |
| fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n"); |
| sprintf(fs_id_buf, "fsid=%s: ", sdp->sd_fsname); |
| - gfs2_rgrp_dump(NULL, rgd->rd_gl, fs_id_buf); |
| + gfs2_rgrp_dump(NULL, rgd, fs_id_buf); |
| rgd->rd_flags |= GFS2_RDF_ERROR; |
| } |
| |
| diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h |
| index a1d7e14fc55b9..9a587ada51eda 100644 |
| --- a/fs/gfs2/rgrp.h |
| +++ b/fs/gfs2/rgrp.h |
| @@ -67,7 +67,7 @@ extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, |
| extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist); |
| extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); |
| extern u64 gfs2_ri_total(struct gfs2_sbd *sdp); |
| -extern void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_glock *gl, |
| +extern void gfs2_rgrp_dump(struct seq_file *seq, struct gfs2_rgrpd *rgd, |
| const char *fs_id_buf); |
| extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, |
| struct buffer_head *bh, |
| diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c |
| index 1cd0328cae20a..0fba3bf641890 100644 |
| --- a/fs/gfs2/util.c |
| +++ b/fs/gfs2/util.c |
| @@ -419,7 +419,7 @@ void gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, |
| char fs_id_buf[sizeof(sdp->sd_fsname) + 7]; |
| |
| sprintf(fs_id_buf, "fsid=%s: ", sdp->sd_fsname); |
| - gfs2_rgrp_dump(NULL, rgd->rd_gl, fs_id_buf); |
| + gfs2_rgrp_dump(NULL, rgd, fs_id_buf); |
| gfs2_lm(sdp, |
| "fatal: filesystem consistency error\n" |
| " RG = %llu\n" |
| -- |
| 2.27.0 |
| |