diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_rmap.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index c0644f1be8a8..220cc72754e4 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c @@ -39,6 +39,7 @@ #include "xfs_extent_busy.h" #include "xfs_bmap.h" #include "xfs_inode.h" +#include "xfs_ialloc.h" /* * Lookup the first record less than or equal to [bno, len, owner, offset] @@ -203,6 +204,8 @@ xfs_rmap_get_rec( struct xfs_rmap_irec *irec, int *stat) { + struct xfs_mount *mp = cur->bc_mp; + xfs_agnumber_t agno = cur->bc_private.a.agno; union xfs_btree_rec *rec; int error; @@ -210,7 +213,43 @@ xfs_rmap_get_rec( if (error || !*stat) return error; - return xfs_rmap_btrec_to_irec(rec, irec); + if (xfs_rmap_btrec_to_irec(rec, irec)) + goto out_bad_rec; + + if (irec->rm_blockcount == 0) + goto out_bad_rec; + if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) { + if (irec->rm_owner != XFS_RMAP_OWN_FS) + goto out_bad_rec; + if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1) + goto out_bad_rec; + } else { + /* check for valid extent range, including overflow */ + if (!xfs_verify_agbno(mp, agno, irec->rm_startblock)) + goto out_bad_rec; + if (irec->rm_startblock > + irec->rm_startblock + irec->rm_blockcount) + goto out_bad_rec; + if (!xfs_verify_agbno(mp, agno, + irec->rm_startblock + irec->rm_blockcount - 1)) + goto out_bad_rec; + } + + if (!(xfs_verify_ino(mp, irec->rm_owner) || + (irec->rm_owner <= XFS_RMAP_OWN_FS && + irec->rm_owner >= XFS_RMAP_OWN_MIN))) + goto out_bad_rec; + + return 0; +out_bad_rec: + xfs_warn(mp, + "Reverse Mapping BTree record corruption in AG %d detected!", + agno); + xfs_warn(mp, + "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x", + irec->rm_owner, irec->rm_flags, irec->rm_startblock, + irec->rm_blockcount); + return -EFSCORRUPTED; } struct xfs_find_left_neighbor_info { |