aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-01-16 22:04:09 -0500
committerDarrick J. Wong <darrick.wong@oracle.com>2018-01-18 00:00:47 -0500
commit4bb73d014785cc55225686f9f46e7192fb59d26b (patch)
treec5b2139794cd13ae841dd3b2d04848a35748438c
parentbe78ff0e72778eb4df4aac66edb9e97462bfe00d (diff)
xfs: check sb_agblocks and sb_agblklog when validating superblock
Currently, we don't check sb_agblocks or sb_agblklog when we validate the superblock, which means that we can fuzz garbage values into those values and the mount succeeds. This leads to all sorts of UBSAN warnings in xfs/350 since we can then coerce other parts of xfs into shifting by ridiculously large values. Once we've validated agblocks, make sure the agcount makes sense. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
-rw-r--r--fs/xfs/libxfs/xfs_fs.h7
-rw-r--r--fs/xfs/libxfs/xfs_sb.c14
2 files changed, 21 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index b90924104596..faf1a4edd618 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -233,6 +233,13 @@ typedef struct xfs_fsop_resblks {
233#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) 233#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL)
234#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) 234#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL)
235 235
236/*
237 * Limits on sb_agblocks/sb_agblklog -- mkfs won't format AGs smaller than
238 * 16MB or larger than 1TB.
239 */
240#define XFS_MIN_AG_BYTES (1ULL << 24) /* 16 MB */
241#define XFS_MAX_AG_BYTES (1ULL << 40) /* 1 TB */
242
236/* keep the maximum size under 2^31 by a small amount */ 243/* keep the maximum size under 2^31 by a small amount */
237#define XFS_MAX_LOG_BYTES \ 244#define XFS_MAX_LOG_BYTES \
238 ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) 245 ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 869a2f3f0375..e0c826403c6a 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -118,6 +118,9 @@ xfs_mount_validate_sb(
118 bool check_inprogress, 118 bool check_inprogress,
119 bool check_version) 119 bool check_version)
120{ 120{
121 u32 agcount = 0;
122 u32 rem;
123
121 if (sbp->sb_magicnum != XFS_SB_MAGIC) { 124 if (sbp->sb_magicnum != XFS_SB_MAGIC) {
122 xfs_warn(mp, "bad magic number"); 125 xfs_warn(mp, "bad magic number");
123 return -EWRONGFS; 126 return -EWRONGFS;
@@ -228,6 +231,13 @@ xfs_mount_validate_sb(
228 return -EINVAL; 231 return -EINVAL;
229 } 232 }
230 233
234 /* Compute agcount for this number of dblocks and agblocks */
235 if (sbp->sb_agblocks) {
236 agcount = div_u64_rem(sbp->sb_dblocks, sbp->sb_agblocks, &rem);
237 if (rem)
238 agcount++;
239 }
240
231 /* 241 /*
232 * More sanity checking. Most of these were stolen directly from 242 * More sanity checking. Most of these were stolen directly from
233 * xfs_repair. 243 * xfs_repair.
@@ -252,6 +262,10 @@ xfs_mount_validate_sb(
252 sbp->sb_inodesize != (1 << sbp->sb_inodelog) || 262 sbp->sb_inodesize != (1 << sbp->sb_inodelog) ||
253 sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE || 263 sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE ||
254 sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) || 264 sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
265 XFS_FSB_TO_B(mp, sbp->sb_agblocks) < XFS_MIN_AG_BYTES ||
266 XFS_FSB_TO_B(mp, sbp->sb_agblocks) > XFS_MAX_AG_BYTES ||
267 sbp->sb_agblklog != xfs_highbit32(sbp->sb_agblocks - 1) + 1 ||
268 agcount == 0 || agcount != sbp->sb_agcount ||
255 (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || 269 (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) ||
256 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || 270 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||
257 (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || 271 (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) ||