gfs2: Fix NULL pointer dereference in gfs2_rgrp_dump
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>
			
			
This commit is contained in:
		
							parent
							
								
									2164f9b918
								
							
						
					
					
						commit
						0e539ca1bb
					
				| @ -227,6 +227,15 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags) | |||||||
| 		rgd->rd_flags &= ~GFS2_RDF_UPTODATE; | 		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) | static struct gfs2_inode *gfs2_glock2inode(struct gfs2_glock *gl) | ||||||
| { | { | ||||||
| 	struct gfs2_inode *ip; | 	struct gfs2_inode *ip; | ||||||
| @ -712,7 +721,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { | |||||||
| 	.go_sync = rgrp_go_sync, | 	.go_sync = rgrp_go_sync, | ||||||
| 	.go_inval = rgrp_go_inval, | 	.go_inval = rgrp_go_inval, | ||||||
| 	.go_lock = gfs2_rgrp_go_lock, | 	.go_lock = gfs2_rgrp_go_lock, | ||||||
| 	.go_dump = gfs2_rgrp_dump, | 	.go_dump = gfs2_rgrp_go_dump, | ||||||
| 	.go_type = LM_TYPE_RGRP, | 	.go_type = LM_TYPE_RGRP, | ||||||
| 	.go_flags = GLOF_LVB, | 	.go_flags = GLOF_LVB, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -2209,20 +2209,17 @@ static void rgblk_free(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd, | |||||||
| /**
 | /**
 | ||||||
|  * gfs2_rgrp_dump - print out an rgrp |  * gfs2_rgrp_dump - print out an rgrp | ||||||
|  * @seq: The iterator |  * @seq: The iterator | ||||||
|  * @gl: The glock in question |  * @rgd: The rgrp in question | ||||||
|  * @fs_id_buf: pointer to file system id (if requested) |  * @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) | 		    const char *fs_id_buf) | ||||||
| { | { | ||||||
| 	struct gfs2_rgrpd *rgd = gl->gl_object; |  | ||||||
| 	struct gfs2_blkreserv *trs; | 	struct gfs2_blkreserv *trs; | ||||||
| 	const struct rb_node *n; | 	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", | 	gfs2_print_dbg(seq, "%s R: n:%llu f:%02x b:%u/%u i:%u r:%u e:%u\n", | ||||||
| 		       fs_id_buf, | 		       fs_id_buf, | ||||||
| 		       (unsigned long long)rgd->rd_addr, rgd->rd_flags, | 		       (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); | 		(unsigned long long)rgd->rd_addr); | ||||||
| 	fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n"); | 	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); | 	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; | 	rgd->rd_flags |= GFS2_RDF_ERROR; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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_alloc(struct gfs2_rgrp_list *rlist); | ||||||
| extern void gfs2_rlist_free(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 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); | 			   const char *fs_id_buf); | ||||||
| extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, | extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, | ||||||
| 				   struct buffer_head *bh, | 				   struct buffer_head *bh, | ||||||
|  | |||||||
| @ -419,7 +419,7 @@ void gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, | |||||||
| 	char fs_id_buf[sizeof(sdp->sd_fsname) + 7]; | 	char fs_id_buf[sizeof(sdp->sd_fsname) + 7]; | ||||||
| 
 | 
 | ||||||
| 	sprintf(fs_id_buf, "fsid=%s: ", sdp->sd_fsname); | 	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, | 	gfs2_lm(sdp, | ||||||
| 		"fatal: filesystem consistency error\n" | 		"fatal: filesystem consistency error\n" | ||||||
| 		"  RG = %llu\n" | 		"  RG = %llu\n" | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user