Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfs: add a few more verifier tests

These were exposed by fsfuzzer runs; without them we fail
in various exciting and sometimes convoluted ways when we
encounter disk corruption.

Without the MAXLEVELS tests we tend to walk off the end of
an array in a loop like this:

for (i = 0; i < cur->bc_nlevels; i++) {
if (cur->bc_bufs[i])

Without the dirblklog test we try to allocate more memory
than we could possibly hope for and loop forever:

xfs_dabuf_map()
nfsb = mp->m_dir_geo->fsbcount;
irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP...

As for the logbsize check, that's the convoluted one.

If logbsize is specified at mount time, it's sanitized
in xfs_parseargs; in particular it makes sure that it's
not > XLOG_MAX_RECORD_BSIZE.

If not specified at mount time, it comes from the superblock
via sb_logsunit; this is limited to 256k at mkfs time as well;
it's copied into m_logbsize in xfs_finish_flags().

However, if for some reason the on-disk value is corrupt and
too large, nothing catches it. It's a circuitous path, but
that size eventually finds its way to places that make the kernel
very unhappy, leading to oopses in xlog_pack_data() because we
use the size as an index into iclog->ic_data, but the array
is not necessarily that big.

Anyway - bounds checking when we read from disk is a good thing!

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>

authored by

Eric Sandeen and committed by
Dave Chinner
e1b05723 8018ec08

+8
+4
fs/xfs/libxfs/xfs_alloc.c
··· 2209 2209 be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) 2210 2210 return false; 2211 2211 2212 + if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS || 2213 + be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS) 2214 + return false; 2215 + 2212 2216 /* 2213 2217 * during growfs operations, the perag is not fully initialised, 2214 2218 * so we can't use it for any useful checking. growfs ensures we can't
+2
fs/xfs/libxfs/xfs_ialloc.c
··· 2051 2051 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) 2052 2052 return false; 2053 2053 2054 + if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS) 2055 + return false; 2054 2056 /* 2055 2057 * during growfs operations, the perag is not fully initialised, 2056 2058 * so we can't use it for any useful checking. growfs ensures we can't
+2
fs/xfs/libxfs/xfs_sb.c
··· 279 279 sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || 280 280 sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || 281 281 sbp->sb_blocksize != (1 << sbp->sb_blocklog) || 282 + sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG || 282 283 sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || 283 284 sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || 284 285 sbp->sb_inodelog < XFS_DINODE_MIN_LOG || 285 286 sbp->sb_inodelog > XFS_DINODE_MAX_LOG || 286 287 sbp->sb_inodesize != (1 << sbp->sb_inodelog) || 288 + sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE || 287 289 sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) || 288 290 (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || 289 291 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||