From b15ba33299d7e24ccead3baf1d331b321ec2cf5e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 1 May 2020 23:33:23 -0400 Subject: [PATCH] xfs: validate the realtime geometry in xfs_validate_sb_common Source kernel commit: f8e566c0f5e1fd8de33ccec6eb1ff815cd4b0dc3 Validate the geometry of the realtime geometry when we mount the filesystem, so that we don't abruptly shut down the filesystem later on. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Signed-off-by: Eric Sandeen --- libxfs/libxfs_priv.h | 23 +++++++++++++++++++++++ libxfs/xfs_sb.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 46de4ea84..8d717d91d 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -252,6 +252,21 @@ div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder) return dividend / divisor; } +/** + * div_u64 - unsigned 64bit divide with 32bit divisor + * @dividend: unsigned 64bit dividend + * @divisor: unsigned 32bit divisor + * + * This is the most common 64bit divide and should be used if possible, + * as many 32bit archs can optimize this variant better than a full 64bit + * divide. + */ +static inline uint64_t div_u64(uint64_t dividend, uint32_t divisor) +{ + uint32_t remainder; + return div_u64_rem(dividend, divisor, &remainder); +} + /** * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder * @dividend: unsigned 64bit dividend @@ -380,6 +395,14 @@ roundup_64(uint64_t x, uint32_t y) return x * y; } +static inline uint64_t +howmany_64(uint64_t x, uint32_t y) +{ + x += y - 1; + do_div(x, y); + return x; +} + /* buffer management */ #define XBF_TRYLOCK 0 #define XBF_UNMAPPED 0 diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index e26b90166..d37d60b39 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -325,6 +325,38 @@ xfs_validate_sb_common( return -EFSCORRUPTED; } + /* Validate the realtime geometry; stolen from xfs_repair */ + if (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE || + sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) { + xfs_notice(mp, + "realtime extent sanity check failed"); + return -EFSCORRUPTED; + } + + if (sbp->sb_rblocks == 0) { + if (sbp->sb_rextents != 0 || sbp->sb_rbmblocks != 0 || + sbp->sb_rextslog != 0 || sbp->sb_frextents != 0) { + xfs_notice(mp, + "realtime zeroed geometry check failed"); + return -EFSCORRUPTED; + } + } else { + uint64_t rexts; + uint64_t rbmblocks; + + rexts = div_u64(sbp->sb_rblocks, sbp->sb_rextsize); + rbmblocks = howmany_64(sbp->sb_rextents, + NBBY * sbp->sb_blocksize); + + if (sbp->sb_rextents != rexts || + sbp->sb_rextslog != xfs_highbit32(sbp->sb_rextents) || + sbp->sb_rbmblocks != rbmblocks) { + xfs_notice(mp, + "realtime geometry sanity check failed"); + return -EFSCORRUPTED; + } + } + if (sbp->sb_unit) { if (!xfs_sb_version_hasdalign(sbp) || sbp->sb_unit > sbp->sb_width || -- 2.50.1