]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: don't crash on partially sparse inode clusters
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 28 Sep 2020 21:35:37 +0000 (17:35 -0400)
committerEric Sandeen <sandeen@sandeen.net>
Mon, 28 Sep 2020 21:35:37 +0000 (17:35 -0400)
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 <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
repair/dino_chunks.c

index 96e2c1708b9437679327a16418b2da4ad9a95a66..50a2003614dfd5d9ebfbbfe48b39af4c776ebd04 100644 (file)
@@ -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);