xfs: check owner of dir3 blocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 11 Mar 2020 17:37:57 +0000 (10:37 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Thu, 12 Mar 2020 14:58:13 +0000 (07:58 -0700)
Check the owner field of dir3 block headers.  If it's corrupt, release
the buffer and return EFSCORRUPTED.  All callers handle this properly.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/libxfs/xfs_dir2_block.c

index d6ced59..1dbf2f9 100644 (file)
@@ -114,6 +114,23 @@ const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
        .verify_struct = xfs_dir3_block_verify,
 };
 
+static xfs_failaddr_t
+xfs_dir3_block_header_check(
+       struct xfs_inode        *dp,
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = dp->i_mount;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
+
+               if (be64_to_cpu(hdr3->owner) != dp->i_ino)
+                       return __this_address;
+       }
+
+       return NULL;
+}
+
 int
 xfs_dir3_block_read(
        struct xfs_trans        *tp,
@@ -121,12 +138,24 @@ xfs_dir3_block_read(
        struct xfs_buf          **bpp)
 {
        struct xfs_mount        *mp = dp->i_mount;
+       xfs_failaddr_t          fa;
        int                     err;
 
        err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, 0, bpp,
                                XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
-       if (!err && tp && *bpp)
-               xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
+       if (err || !*bpp)
+               return err;
+
+       /* Check things that we can't do in the verifier. */
+       fa = xfs_dir3_block_header_check(dp, *bpp);
+       if (fa) {
+               __xfs_buf_mark_corrupt(*bpp, fa);
+               xfs_trans_brelse(tp, *bpp);
+               *bpp = NULL;
+               return -EFSCORRUPTED;
+       }
+
+       xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
        return err;
 }