From: Allison Collins <allison.henderson@oracle.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>, sandeen@sandeen.net
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 4/4] xfs_repair: don't corrupt a attr fork da3 node when clearing forw/back
Date: Tue, 4 Feb 2020 22:29:26 -0700 [thread overview]
Message-ID: <7baaea32-91dc-353d-6de2-ccae5bd79a52@oracle.com> (raw)
In-Reply-To: <158086359417.2079557.4428155306169446299.stgit@magnolia>
On 2/4/20 5:46 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> In process_longform_attr, we enforce that the root block of the
> attribute index must have both forw or back pointers set to zero.
> Unfortunately, the code that nulls out the pointers is not aware that
> the root block could be in da3 node format.
>
> This leads to corruption of da3 root node blocks because the functions
> that convert attr3 leaf headers to and from the ondisk structures
> perform some interpretation of firstused on what they think is an attr1
> leaf block.
>
> Found by using xfs/402 to fuzz hdr.info.hdr.forw.
>
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> repair/attr_repair.c | 181 ++++++++++++++++++++++++++++++++------------------
> 1 file changed, 117 insertions(+), 64 deletions(-)
>
>
> diff --git a/repair/attr_repair.c b/repair/attr_repair.c
> index 7b26df33..535fcfbb 100644
> --- a/repair/attr_repair.c
> +++ b/repair/attr_repair.c
> @@ -952,6 +952,106 @@ _("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"),
> return 0;
> }
>
> +static int
> +process_longform_leaf_root(
> + struct xfs_mount *mp,
> + xfs_ino_t ino,
> + struct xfs_dinode *dip,
> + struct blkmap *blkmap,
> + int *repair,
> + struct xfs_buf *bp)
> +{
> + struct xfs_attr3_icleaf_hdr leafhdr;
> + xfs_dahash_t next_hashval;
> + int badness;
"badness" pretty much just looks like "error" here? Or is it different
in some way?
> + int repairlinks = 0;
> +
> + /*
> + * check sibling pointers in leaf block or root block 0 before
> + * we have to release the btree block
> + */
> + xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, bp->b_addr);
> + if (leafhdr.forw != 0 || leafhdr.back != 0) {
> + if (!no_modify) {
> + do_warn(
> +_("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
> + ino);
> + repairlinks = 1;
> + leafhdr.forw = 0;
> + leafhdr.back = 0;
> + xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, bp->b_addr,
> + &leafhdr);
> + } else {
> + do_warn(
> +_("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
> + }
> + }
> +
> + badness = process_leaf_attr_block(mp, bp->b_addr, 0, ino, blkmap, 0,
> + &next_hashval, repair);
> + if (badness) {
> + *repair = 0;
> + /* the block is bad. lose the attribute fork. */
> + libxfs_putbuf(bp);
> + return 1;
> + }
> +
> + *repair = *repair || repairlinks;
> +
> + if (*repair && !no_modify)
> + libxfs_writebuf(bp, 0);
> + else
> + libxfs_putbuf(bp);
> +
> + return 0;
> +}
> +
> +static int
> +process_longform_da_root(
> + struct xfs_mount *mp,
> + xfs_ino_t ino,
> + struct xfs_dinode *dip,
> + struct blkmap *blkmap,
> + int *repair,
> + struct xfs_buf *bp)
> +{
> + struct xfs_da3_icnode_hdr da3_hdr;
> + int repairlinks = 0;
> + int error;
> +
> + libxfs_da3_node_hdr_from_disk(mp, &da3_hdr, bp->b_addr);
> + /*
> + * check sibling pointers in leaf block or root block 0 before
> + * we have to release the btree block
> + */
> + if (da3_hdr.forw != 0 || da3_hdr.back != 0) {
> + if (!no_modify) {
> + do_warn(
> +_("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
> + ino);
> +
> + repairlinks = 1;
> + da3_hdr.forw = 0;
> + da3_hdr.back = 0;
> + xfs_da3_node_hdr_to_disk(mp, bp->b_addr, &da3_hdr);
> + } else {
> + do_warn(
> +_("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
> + }
> + }
> +
> + /* must do this now, to release block 0 before the traversal */
Did you mean to reference *repair here without setting it? I guess it
was like that from the code it was taken from, but it makes it looks
like repair is both an in and an out. I wonder if it's really needed in
the check below?
Allison
> + if ((*repair || repairlinks) && !no_modify) {
> + *repair = 1;
> + libxfs_writebuf(bp, 0);
> + } else
> + libxfs_putbuf(bp);
> + error = process_node_attr(mp, ino, dip, blkmap); /* + repair */
> + if (error)
> + *repair = 0;
> + return error;
> +}
> +
> /*
> * Start processing for a leaf or fuller btree.
> * A leaf directory is one where the attribute fork is too big for
> @@ -963,19 +1063,15 @@ _("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"),
> */
> static int
> process_longform_attr(
> - xfs_mount_t *mp,
> - xfs_ino_t ino,
> - xfs_dinode_t *dip,
> - blkmap_t *blkmap,
> - int *repair) /* out - 1 if something was fixed */
> + struct xfs_mount *mp,
> + xfs_ino_t ino,
> + struct xfs_dinode *dip,
> + struct blkmap *blkmap,
> + int *repair) /* out - 1 if something was fixed */
> {
> - xfs_attr_leafblock_t *leaf;
> - xfs_fsblock_t bno;
> - xfs_buf_t *bp;
> - xfs_dahash_t next_hashval;
> - int repairlinks = 0;
> - struct xfs_attr3_icleaf_hdr leafhdr;
> - int error;
> + xfs_fsblock_t bno;
> + struct xfs_buf *bp;
> + struct xfs_da_blkinfo *info;
>
> *repair = 0;
>
> @@ -1015,74 +1111,31 @@ process_longform_attr(
> return 1;
> }
>
> - /* verify leaf block */
> - leaf = bp->b_addr;
> - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
> -
> - /* check sibling pointers in leaf block or root block 0 before
> - * we have to release the btree block
> - */
> - if (leafhdr.forw != 0 || leafhdr.back != 0) {
> - if (!no_modify) {
> - do_warn(
> - _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
> - ino);
> - repairlinks = 1;
> - leafhdr.forw = 0;
> - leafhdr.back = 0;
> - xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo,
> - leaf, &leafhdr);
> - } else {
> - do_warn(
> - _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
> - }
> - }
> -
> /*
> * use magic number to tell us what type of attribute this is.
> * it's possible to have a node or leaf attribute in either an
> * extent format or btree format attribute fork.
> */
> - switch (leafhdr.magic) {
> + info = bp->b_addr;
> + switch (be16_to_cpu(info->magic)) {
> case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */
> case XFS_ATTR3_LEAF_MAGIC:
> - if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
> - 0, &next_hashval, repair)) {
> - *repair = 0;
> - /* the block is bad. lose the attribute fork. */
> - libxfs_putbuf(bp);
> - return(1);
> - }
> - *repair = *repair || repairlinks;
> - break;
> -
> + return process_longform_leaf_root(mp, ino, dip, blkmap, repair,
> + bp);
> case XFS_DA_NODE_MAGIC: /* btree-form attribute */
> case XFS_DA3_NODE_MAGIC:
> - /* must do this now, to release block 0 before the traversal */
> - if ((*repair || repairlinks) && !no_modify) {
> - *repair = 1;
> - libxfs_writebuf(bp, 0);
> - } else
> - libxfs_putbuf(bp);
> - error = process_node_attr(mp, ino, dip, blkmap); /* + repair */
> - if (error)
> - *repair = 0;
> - return error;
> + return process_longform_da_root(mp, ino, dip, blkmap, repair,
> + bp);
> default:
> do_warn(
> _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"),
> - be16_to_cpu(leaf->hdr.info.magic), ino);
> + be16_to_cpu(info->magic), ino);
> libxfs_putbuf(bp);
> *repair = 0;
> - return(1);
> + return 1;
> }
>
> - if (*repair && !no_modify)
> - libxfs_writebuf(bp, 0);
> - else
> - libxfs_putbuf(bp);
> -
> - return(0); /* repair may be set */
> + return 0; /* should never get here */
> }
>
>
>
next prev parent reply other threads:[~2020-02-05 5:29 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-05 0:46 [PATCH 0/4] xfsprogs: random fixes Darrick J. Wong
2020-02-05 0:46 ` [PATCH 1/4] libxfs: re-sort libxfs_api_defs.h defines Darrick J. Wong
2020-02-05 2:11 ` Chaitanya Kulkarni
2020-02-05 5:28 ` Allison Collins
2020-02-17 13:45 ` Christoph Hellwig
2020-02-05 0:46 ` [PATCH 2/4] libfrog: remove libxfs.h dependencies in fsgeom.c and linux.c Darrick J. Wong
2020-02-05 5:28 ` Allison Collins
2020-02-17 13:46 ` Christoph Hellwig
2020-02-05 0:46 ` [PATCH 3/4] xfs_repair: refactor attr root block pointer check Darrick J. Wong
2020-02-05 5:28 ` Allison Collins
2020-02-13 23:14 ` Eric Sandeen
2020-02-14 4:24 ` Darrick J. Wong
2020-02-17 13:47 ` Christoph Hellwig
2020-02-05 0:46 ` [PATCH 4/4] xfs_repair: don't corrupt a attr fork da3 node when clearing forw/back Darrick J. Wong
2020-02-05 5:29 ` Allison Collins [this message]
2020-02-05 5:59 ` Darrick J. Wong
2020-02-17 13:48 ` Christoph Hellwig
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=7baaea32-91dc-353d-6de2-ccae5bd79a52@oracle.com \
--to=allison.henderson@oracle.com \
--cc=darrick.wong@oracle.com \
--cc=linux-xfs@vger.kernel.org \
--cc=sandeen@sandeen.net \
/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).