xfs: refactor file range validation
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 4 Dec 2020 21:28:35 +0000 (13:28 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 9 Dec 2020 17:49:38 +0000 (09:49 -0800)
Refactor all the open-coded validation of file block ranges into a
single helper, and teach the bmap scrubber to check the ranges.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_types.c
fs/xfs/libxfs/xfs_types.h
fs/xfs/scrub/bmap.c
fs/xfs/xfs_bmap_item.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_rmap_item.c
fs/xfs/xfs_super.c

index 7bcf498ef6b2412392f061e5187e7c7152a45298..dcf56bcafb8f126c86fd51eb1af586f5b7ab3ba2 100644 (file)
@@ -6227,7 +6227,7 @@ xfs_bmap_validate_extent(
 {
        struct xfs_mount        *mp = ip->i_mount;
 
-       if (irec->br_startoff + irec->br_blockcount <= irec->br_startoff)
+       if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
                return __this_address;
 
        if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {
index 7b310eb296b7da48d57f55ed2750a0603df5f8c4..b254fbeaaa501edee0b389c2b05fbfbf4852d16b 100644 (file)
@@ -258,3 +258,28 @@ xfs_verify_dablk(
 
        return dabno <= max_dablk;
 }
+
+/* Check that a file block offset does not exceed the maximum. */
+bool
+xfs_verify_fileoff(
+       struct xfs_mount        *mp,
+       xfs_fileoff_t           off)
+{
+       return off <= XFS_MAX_FILEOFF;
+}
+
+/* Check that a range of file block offsets do not exceed the maximum. */
+bool
+xfs_verify_fileext(
+       struct xfs_mount        *mp,
+       xfs_fileoff_t           off,
+       xfs_fileoff_t           len)
+{
+       if (off + len <= off)
+               return false;
+
+       if (!xfs_verify_fileoff(mp, off))
+               return false;
+
+       return xfs_verify_fileoff(mp, off + len - 1);
+}
index 18e83ce465681513c0f92bb6ac9aef82ed0fa620..064bd6e8c922f74836b5eafba805e6ab6a472df6 100644 (file)
@@ -203,5 +203,8 @@ bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount);
 bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off);
 void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min,
                unsigned long long *max);
+bool xfs_verify_fileoff(struct xfs_mount *mp, xfs_fileoff_t off);
+bool xfs_verify_fileext(struct xfs_mount *mp, xfs_fileoff_t off,
+               xfs_fileoff_t len);
 
 #endif /* __XFS_TYPES_H__ */
index cce8ac7d3973c528c888eb13df866406b04f4ab4..bce4421acdb999ff922ed70cb76bdf86b8fb5478 100644 (file)
@@ -329,6 +329,10 @@ xchk_bmap_iextent(
                xchk_fblock_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
 
+       if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
+               xchk_fblock_set_corrupt(info->sc, info->whichfork,
+                               irec->br_startoff);
+
        xchk_bmap_dirattr_extent(ip, info, irec);
 
        /* There should never be a "hole" extent in either extent list. */
index 659bde22c505c9f1d6cfc997ea5d97d4c47dc1f7..93e4d8ae6e92b6d2b91ed7eb89717cda8dde487c 100644 (file)
@@ -445,7 +445,7 @@ xfs_bui_validate(
        if (!xfs_verify_ino(mp, bmap->me_owner))
                return false;
 
-       if (bmap->me_startoff + bmap->me_len <= bmap->me_startoff)
+       if (!xfs_verify_fileext(mp, bmap->me_startoff, bmap->me_len))
                return false;
 
        return xfs_verify_fsbext(mp, bmap->me_startblock, bmap->me_len);
index 2bfbcf28b1bd282613ad1a803cb7fda596170cd5..004fce3646aeface1d3789a959052f0d34337b78 100644 (file)
@@ -1521,7 +1521,7 @@ xfs_itruncate_extents_flags(
         * the page cache can't scale that far.
         */
        first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
-       if (first_unmap_block >= XFS_MAX_FILEOFF) {
+       if (!xfs_verify_fileoff(mp, first_unmap_block)) {
                WARN_ON_ONCE(first_unmap_block > XFS_MAX_FILEOFF);
                return 0;
        }
index 4fa875237422cfefe394dbfcdef70261e2a9661e..49cebd68b6727b7eb378e7c8c6111308a78771ee 100644 (file)
@@ -490,7 +490,7 @@ xfs_rui_validate_map(
            !xfs_verify_ino(mp, rmap->me_owner))
                return false;
 
-       if (rmap->me_startoff + rmap->me_len <= rmap->me_startoff)
+       if (!xfs_verify_fileext(mp, rmap->me_startoff, rmap->me_len))
                return false;
 
        return xfs_verify_fsbext(mp, rmap->me_startblock, rmap->me_len);
index 36002f460d7cd0ebda15bf779671938b71dffd67..e1668491cee79c653ec91ded010939ac7330990d 100644 (file)
@@ -1517,7 +1517,7 @@ xfs_fc_fill_super(
         * Avoid integer overflow by comparing the maximum bmbt offset to the
         * maximum pagecache offset in units of fs blocks.
         */
-       if (XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE) > XFS_MAX_FILEOFF) {
+       if (!xfs_verify_fileoff(mp, XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE))) {
                xfs_warn(mp,
 "MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!",
                         XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE),