From: Brian Foster <bfoster@redhat.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: sandeen@redhat.com, linux-xfs@vger.kernel.org
Subject: Re: [PATCH v3 4/5] xfs_db: sanitize geometry on load
Date: Fri, 13 Jan 2017 08:35:43 -0500 [thread overview]
Message-ID: <20170113133542.GB22013@bfoster.bfoster> (raw)
In-Reply-To: <20170113003201.GC14038@birch.djwong.org>
On Thu, Jan 12, 2017 at 04:32:01PM -0800, Darrick J. Wong wrote:
> xfs_db doesn't check the filesystem geometry when it's mounting, which
> means that garbage agcount values can cause OOMs when we try to allocate
> all the per-AG incore metadata. If we see geometry that looks
> suspicious, try to derive the actual AG geometry to avoid crashing the
> system. This should help with xfs/1301 fuzzing.
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> v2: Only modify sb_ag{blocks,count} if they seem insane -- use local
> variables to avoid screwing up the rest of the metadata.
> v3: Suggest a possible agcount value, but always restrict to 1 AG.
> ---
> db/init.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 85 insertions(+), 10 deletions(-)
>
> diff --git a/db/init.c b/db/init.c
> index ec1e274..43a9409 100644
> --- a/db/init.c
> +++ b/db/init.c
> @@ -51,13 +51,94 @@ usage(void)
> exit(1);
> }
>
> +/* Try to load a superblock for the given agno, no verifiers. */
> +static bool
> +load_sb(
> + struct xfs_mount *mp,
> + xfs_agnumber_t agno,
> + struct xfs_sb *sbp)
> +{
> + struct xfs_buf *bp;
> +
> + bp = libxfs_readbuf(mp->m_ddev_targp,
> + XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
> + 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
> +
> + if (!bp || bp->b_error)
> + return false;
> +
> + /* copy SB from buffer to in-core, converting architecture as we go */
> + libxfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
> + libxfs_putbuf(bp);
> + libxfs_purgebuf(bp);
> +
> + return true;
> +}
> +
> +/*
> + * If the agcount doesn't look sane, suggest a real agcount to the user,
> + * and pretend agcount = 1 to avoid OOMing libxfs_initialize_perag.
> + */
> +static void
> +sanitize_geometry(
> + struct xfs_mount *mp,
> + struct xfs_sb *sbp)
> +{
> + struct xfs_sb sb;
> + unsigned int blocklog;
> + unsigned int blocksize;
> + unsigned int agblocks;
> + unsigned long long dblocks;
> +
> + /* If the geometry looks ok, we're done. */
> + if (sbp->sb_blocklog >= XFS_MIN_BLOCKSIZE_LOG &&
> + sbp->sb_blocklog <= XFS_MAX_BLOCKSIZE_LOG &&
> + sbp->sb_blocksize == (1 << sbp->sb_blocklog) &&
> + sbp->sb_dblocks * sbp->sb_blocksize <= x.dsize * x.dbsize &&
> + sbp->sb_dblocks <= XFS_MAX_DBLOCKS(sbp) &&
> + sbp->sb_dblocks >= XFS_MIN_DBLOCKS(sbp))
> + return;
> +
> + /* Check blocklog and blocksize */
> + blocklog = sbp->sb_blocklog;
> + blocksize = sbp->sb_blocksize;
> + if (blocklog < XFS_MIN_BLOCKSIZE_LOG ||
> + blocklog > XFS_MAX_BLOCKSIZE_LOG)
> + blocklog = libxfs_log2_roundup(blocksize);
> + if (blocksize != (1 << blocklog))
> + blocksize = (1 << blocksize);
> +
Same questions as before with regard to the above hunk.
> + /* Clamp dblocks to the size of the device. */
> + dblocks = sbp->sb_dblocks;
> + if (dblocks > x.dsize * x.dbsize / blocksize)
> + dblocks = x.dsize * x.dbsize / blocksize;
> +
> + /*
> + * See if agblocks helps us find a superblock.
> + * blkbb_log is later (re)set by libxfs_mount.
> + */
> + mp->m_blkbb_log = blocklog - BBSHIFT;
> + if (sbp->sb_agblocks > 0 && sbp->sb_agblocks <= MAXEXTNUM &&
> + load_sb(mp, 1, &sb) && sb.sb_magicnum == XFS_SB_MAGIC) {
If agblocks is bogus, this can effectively point anywhere in the fs,
correct? If so, I wonder how robust this magic number check is... for
example, what prevents us from pointing at a file data block with a
valid XFS superblock? IOW, perhaps we'd also need to validate sb_uuid.
> + fprintf(stderr,
> +_("%s: device %s AG count is insane, but could be %u. Limiting reads to AG 0.\n"),
> + progname, fsdevice, dblocks / sbp->sb_agblocks);
> + } else {
> + fprintf(stderr,
> +_("%s: device %s AG count is insane. Limiting reads to AG 0.\n"),
> + progname, fsdevice);
> + }
For reasons like the above, I think xfs_db shouldn't be in the business
of repair like validation (xfs_check notwithstanding). That said,
dropping into a fixed single AG mode seems less risky than trying to
surmise a valid geometry. I'd get rid of the "this might be your
agcount" messaging entirely though and just replace it with something
that explicitly states the filesystem is corrupted, the runtime geometry
is invalid and that the user should probably run xfs_repair before doing
anything.
I still like the idea of the single AG mode thing as a command line flag
rather than default behavior because it requires user acknowledgement,
but this is a debug tool after all, so I'll defer to Eric on that. I do
think that if we create this kind of invalid runtime mode, this should
be split into two patches. First, a bugfix patch for the core OOM
problem (i.e., detect a wacky superblock and exit). Second, replace the
exit with the single AG runtime mode thing.
Brian
> +
> + /* Assume 1 AG to avoid OOM. */
> + sbp->sb_agcount = 1;
> +}
> +
> void
> init(
> int argc,
> char **argv)
> {
> struct xfs_sb *sbp;
> - struct xfs_buf *bp;
> int c;
>
> setlocale(LC_ALL, "");
> @@ -124,20 +205,12 @@ init(
> */
> memset(&xmount, 0, sizeof(struct xfs_mount));
> libxfs_buftarg_init(&xmount, x.ddev, x.logdev, x.rtdev);
> - bp = libxfs_readbuf(xmount.m_ddev_targp, XFS_SB_DADDR,
> - 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
> -
> - if (!bp || bp->b_error) {
> + if (!load_sb(&xmount, 0, &xmount.m_sb)) {
> fprintf(stderr, _("%s: %s is invalid (cannot read first 512 "
> "bytes)\n"), progname, fsdevice);
> exit(1);
> }
>
> - /* copy SB from buffer to in-core, converting architecture as we go */
> - libxfs_sb_from_disk(&xmount.m_sb, XFS_BUF_TO_SBP(bp));
> - libxfs_putbuf(bp);
> - libxfs_purgebuf(bp);
> -
> sbp = &xmount.m_sb;
> if (sbp->sb_magicnum != XFS_SB_MAGIC) {
> fprintf(stderr, _("%s: %s is not a valid XFS filesystem (unexpected SB magic number 0x%08x)\n"),
> @@ -148,6 +221,8 @@ init(
> }
> }
>
> + sanitize_geometry(&xmount, sbp);
> +
> mp = libxfs_mount(&xmount, sbp, x.ddev, x.logdev, x.rtdev,
> LIBXFS_MOUNT_DEBUGGER);
> if (!mp) {
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2017-01-13 13:35 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-12 3:06 [PATCH 0/5] xfsprogs: misc fixes Darrick J. Wong
2017-01-12 3:06 ` [PATCH 1/5] xfs_io: fix the minimum arguments to the reflink command Darrick J. Wong
2017-01-12 13:53 ` Christoph Hellwig
2017-01-12 3:06 ` [PATCH 2/5] xfs_io: fix some documentation problems Darrick J. Wong
2017-01-12 13:53 ` Christoph Hellwig
2017-01-12 3:06 ` [PATCH 3/5] xfs_io: prefix dedupe command error messages consistently Darrick J. Wong
2017-01-12 13:53 ` Christoph Hellwig
2017-01-12 3:06 ` [PATCH 4/5] xfs_db: sanitize geometry on load Darrick J. Wong
2017-01-12 14:34 ` Eric Sandeen
2017-01-12 15:09 ` Brian Foster
2017-01-12 20:41 ` Darrick J. Wong
2017-01-12 20:41 ` [PATCH v2 " Darrick J. Wong
2017-01-12 23:20 ` Eric Sandeen
2017-01-13 0:23 ` Darrick J. Wong
2017-01-13 0:32 ` [PATCH v3 " Darrick J. Wong
2017-01-13 13:35 ` Brian Foster [this message]
2017-01-14 2:25 ` Eric Sandeen
2017-01-14 3:44 ` Brian Foster
2017-01-14 3:51 ` Eric Sandeen
2017-01-14 12:53 ` Brian Foster
2017-01-14 14:59 ` Eric Sandeen
2017-01-15 14:10 ` Brian Foster
2017-01-12 3:06 ` [PATCH 5/5] xfs_repair: strengthen geometry checks Darrick J. Wong
2017-01-14 2:13 ` Eric Sandeen
2017-01-20 20:06 ` Darrick J. Wong
2017-01-12 19:27 ` [PATCH 6/5] xfs_db: fix the 'source' command when passed as a -c option Darrick J. Wong
2017-01-12 19:34 ` [PATCH 7/5] xfs_repair.8: document dirty log conditions Darrick J. Wong
2017-01-12 19:41 ` Eric Sandeen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170113133542.GB22013@bfoster.bfoster \
--to=bfoster@redhat.com \
--cc=darrick.wong@oracle.com \
--cc=linux-xfs@vger.kernel.org \
--cc=sandeen@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).