From: Darrick J. Wong Date: Mon, 28 Sep 2020 21:35:37 +0000 (-0400) Subject: xfs_repair: don't crash on partially sparse inode clusters X-Git-Tag: xfsprogs-5.9-fixes2_2020-10-10~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f4ff8086586b16b07ddfc39fd6fb52aa4a25c3ae;p=thirdparty%2Fxfsprogs-dev.git xfs_repair: don't crash on partially sparse inode clusters While running xfs/364 to fuzz the middle bit of recs[2].holemask, I observed a crash in xfs_repair stemming from the fact that each sparse bit accounts for 4 inodes, but inode cluster buffers can map to more than four inodes. When the first inode in an inode cluster is marked sparse, process_inode_chunk won't try to load the inode cluster buffer. Unfortunately, if the holemask indicates that there are inodes present anywhere in the rest of the cluster buffer, repair will try to check the corresponding cluster buffer, even if we didn't load it. This leads to a null pointer dereference, which crashes repair. Avoid the null pointer dereference by marking the inode sparse and moving on to the next inode. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Eric Sandeen --- diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 96e2c1708..50a200361 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -792,6 +792,25 @@ next_readbuf: if (is_inode_sparse(ino_rec, irec_offset)) goto process_next; + /* + * Repair skips reading the cluster buffer if the first inode + * in the cluster is marked as sparse. If subsequent inodes in + * the cluster buffer are /not/ marked sparse, there won't be + * a buffer, so we need to avoid the null pointer dereference. + */ + if (bplist[bp_index] == NULL) { + do_warn( + _("imap claims inode %" PRIu64 " is present, but inode cluster is sparse, "), + ino); + if (verbose || !no_modify) + do_warn(_("correcting imap\n")); + else + do_warn(_("would correct imap\n")); + set_inode_sparse(ino_rec, irec_offset); + set_inode_free(ino_rec, irec_offset); + goto process_next; + } + /* make inode pointer */ dino = xfs_make_iptr(mp, bplist[bp_index], cluster_offset);