Commit f4887fbc authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: validate attr leaf buffer owners

Create a leaf block header checking function to validate the owner field
of xattr leaf blocks.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 33c028ff
...@@ -649,8 +649,8 @@ xfs_attr_leaf_remove_attr( ...@@ -649,8 +649,8 @@ xfs_attr_leaf_remove_attr(
int forkoff; int forkoff;
int error; int error;
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
&bp); args->blkno, &bp);
if (error) if (error)
return error; return error;
...@@ -681,7 +681,7 @@ xfs_attr_leaf_shrink( ...@@ -681,7 +681,7 @@ xfs_attr_leaf_shrink(
if (!xfs_attr_is_leaf(dp)) if (!xfs_attr_is_leaf(dp))
return 0; return 0;
error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp); error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
if (error) if (error)
return error; return error;
...@@ -1158,7 +1158,7 @@ xfs_attr_leaf_try_add( ...@@ -1158,7 +1158,7 @@ xfs_attr_leaf_try_add(
struct xfs_buf *bp; struct xfs_buf *bp;
int error; int error;
error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp); error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
if (error) if (error)
return error; return error;
...@@ -1206,7 +1206,7 @@ xfs_attr_leaf_hasname( ...@@ -1206,7 +1206,7 @@ xfs_attr_leaf_hasname(
{ {
int error = 0; int error = 0;
error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp); error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, bp);
if (error) if (error)
return error; return error;
......
...@@ -388,6 +388,27 @@ xfs_attr3_leaf_verify( ...@@ -388,6 +388,27 @@ xfs_attr3_leaf_verify(
return NULL; return NULL;
} }
xfs_failaddr_t
xfs_attr3_leaf_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_attr3_leafblock *hdr3 = bp->b_addr;
if (hdr3->hdr.info.hdr.magic !=
cpu_to_be16(XFS_ATTR3_LEAF_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
return __this_address;
}
return NULL;
}
static void static void
xfs_attr3_leaf_write_verify( xfs_attr3_leaf_write_verify(
struct xfs_buf *bp) struct xfs_buf *bp)
...@@ -448,16 +469,30 @@ int ...@@ -448,16 +469,30 @@ int
xfs_attr3_leaf_read( xfs_attr3_leaf_read(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_inode *dp, struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t bno, xfs_dablk_t bno,
struct xfs_buf **bpp) struct xfs_buf **bpp)
{ {
xfs_failaddr_t fa;
int err; int err;
err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK, err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK,
&xfs_attr3_leaf_buf_ops); &xfs_attr3_leaf_buf_ops);
if (!err && tp && *bpp) if (err || !(*bpp))
return err;
fa = xfs_attr3_leaf_header_check(*bpp, owner);
if (fa) {
__xfs_buf_mark_corrupt(*bpp, fa);
xfs_trans_brelse(tp, *bpp);
*bpp = NULL;
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
return -EFSCORRUPTED;
}
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF); xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
return err; return 0;
} }
/*======================================================================== /*========================================================================
...@@ -1160,7 +1195,7 @@ xfs_attr3_leaf_to_node( ...@@ -1160,7 +1195,7 @@ xfs_attr3_leaf_to_node(
error = xfs_da_grow_inode(args, &blkno); error = xfs_da_grow_inode(args, &blkno);
if (error) if (error)
goto out; goto out;
error = xfs_attr3_leaf_read(args->trans, dp, 0, &bp1); error = xfs_attr3_leaf_read(args->trans, dp, args->owner, 0, &bp1);
if (error) if (error)
goto out; goto out;
...@@ -1995,7 +2030,7 @@ xfs_attr3_leaf_toosmall( ...@@ -1995,7 +2030,7 @@ xfs_attr3_leaf_toosmall(
if (blkno == 0) if (blkno == 0)
continue; continue;
error = xfs_attr3_leaf_read(state->args->trans, state->args->dp, error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
blkno, &bp); state->args->owner, blkno, &bp);
if (error) if (error)
return error; return error;
...@@ -2717,7 +2752,8 @@ xfs_attr3_leaf_clearflag( ...@@ -2717,7 +2752,8 @@ xfs_attr3_leaf_clearflag(
/* /*
* Set up the operation. * Set up the operation.
*/ */
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp); error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp);
if (error) if (error)
return error; return error;
...@@ -2781,7 +2817,8 @@ xfs_attr3_leaf_setflag( ...@@ -2781,7 +2817,8 @@ xfs_attr3_leaf_setflag(
/* /*
* Set up the operation. * Set up the operation.
*/ */
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp); error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp);
if (error) if (error)
return error; return error;
...@@ -2840,7 +2877,8 @@ xfs_attr3_leaf_flipflags( ...@@ -2840,7 +2877,8 @@ xfs_attr3_leaf_flipflags(
/* /*
* Read the block containing the "old" attr * Read the block containing the "old" attr
*/ */
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp1); error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
args->blkno, &bp1);
if (error) if (error)
return error; return error;
...@@ -2848,8 +2886,8 @@ xfs_attr3_leaf_flipflags( ...@@ -2848,8 +2886,8 @@ xfs_attr3_leaf_flipflags(
* Read the block containing the "new" attr, if it is different * Read the block containing the "new" attr, if it is different
*/ */
if (args->blkno2 != args->blkno) { if (args->blkno2 != args->blkno) {
error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2, error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
&bp2); args->blkno2, &bp2);
if (error) if (error)
return error; return error;
} else { } else {
......
...@@ -98,12 +98,14 @@ int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp, ...@@ -98,12 +98,14 @@ int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
struct xfs_buf *leaf2_bp); struct xfs_buf *leaf2_bp);
int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local); int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp, int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, struct xfs_buf **bpp); xfs_ino_t owner, xfs_dablk_t bno, struct xfs_buf **bpp);
void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo, void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo,
struct xfs_attr3_icleaf_hdr *to, struct xfs_attr3_icleaf_hdr *to,
struct xfs_attr_leafblock *from); struct xfs_attr_leafblock *from);
void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo, void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo,
struct xfs_attr_leafblock *to, struct xfs_attr_leafblock *to,
struct xfs_attr3_icleaf_hdr *from); struct xfs_attr3_icleaf_hdr *from);
xfs_failaddr_t xfs_attr3_leaf_header_check(struct xfs_buf *bp,
xfs_ino_t owner);
#endif /* __XFS_ATTR_LEAF_H__ */ #endif /* __XFS_ATTR_LEAF_H__ */
...@@ -252,6 +252,25 @@ xfs_da3_node_verify( ...@@ -252,6 +252,25 @@ xfs_da3_node_verify(
return NULL; return NULL;
} }
xfs_failaddr_t
xfs_da3_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
struct xfs_da_blkinfo *hdr = bp->b_addr;
if (!xfs_has_crc(mp))
return NULL;
switch (hdr->magic) {
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
return xfs_attr3_leaf_header_check(bp, owner);
}
return NULL;
}
static void static void
xfs_da3_node_write_verify( xfs_da3_node_write_verify(
struct xfs_buf *bp) struct xfs_buf *bp)
...@@ -1591,6 +1610,7 @@ xfs_da3_node_lookup_int( ...@@ -1591,6 +1610,7 @@ xfs_da3_node_lookup_int(
struct xfs_da_node_entry *btree; struct xfs_da_node_entry *btree;
struct xfs_da3_icnode_hdr nodehdr; struct xfs_da3_icnode_hdr nodehdr;
struct xfs_da_args *args; struct xfs_da_args *args;
xfs_failaddr_t fa;
xfs_dablk_t blkno; xfs_dablk_t blkno;
xfs_dahash_t hashval; xfs_dahash_t hashval;
xfs_dahash_t btreehashval; xfs_dahash_t btreehashval;
...@@ -1629,6 +1649,12 @@ xfs_da3_node_lookup_int( ...@@ -1629,6 +1649,12 @@ xfs_da3_node_lookup_int(
if (magic == XFS_ATTR_LEAF_MAGIC || if (magic == XFS_ATTR_LEAF_MAGIC ||
magic == XFS_ATTR3_LEAF_MAGIC) { magic == XFS_ATTR3_LEAF_MAGIC) {
fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_ATTR_LEAF_MAGIC; blk->magic = XFS_ATTR_LEAF_MAGIC;
blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
break; break;
...@@ -1996,6 +2022,7 @@ xfs_da3_path_shift( ...@@ -1996,6 +2022,7 @@ xfs_da3_path_shift(
struct xfs_da_node_entry *btree; struct xfs_da_node_entry *btree;
struct xfs_da3_icnode_hdr nodehdr; struct xfs_da3_icnode_hdr nodehdr;
struct xfs_buf *bp; struct xfs_buf *bp;
xfs_failaddr_t fa;
xfs_dablk_t blkno = 0; xfs_dablk_t blkno = 0;
int level; int level;
int error; int error;
...@@ -2087,6 +2114,12 @@ xfs_da3_path_shift( ...@@ -2087,6 +2114,12 @@ xfs_da3_path_shift(
break; break;
case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR_LEAF_MAGIC:
case XFS_ATTR3_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC:
fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(blk->bp, fa);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
blk->magic = XFS_ATTR_LEAF_MAGIC; blk->magic = XFS_ATTR_LEAF_MAGIC;
ASSERT(level == path->active-1); ASSERT(level == path->active-1);
blk->index = 0; blk->index = 0;
...@@ -2290,6 +2323,7 @@ xfs_da3_swap_lastblock( ...@@ -2290,6 +2323,7 @@ xfs_da3_swap_lastblock(
struct xfs_buf *last_buf; struct xfs_buf *last_buf;
struct xfs_buf *sib_buf; struct xfs_buf *sib_buf;
struct xfs_buf *par_buf; struct xfs_buf *par_buf;
xfs_failaddr_t fa;
xfs_dahash_t dead_hash; xfs_dahash_t dead_hash;
xfs_fileoff_t lastoff; xfs_fileoff_t lastoff;
xfs_dablk_t dead_blkno; xfs_dablk_t dead_blkno;
...@@ -2326,6 +2360,14 @@ xfs_da3_swap_lastblock( ...@@ -2326,6 +2360,14 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w); error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w);
if (error) if (error)
return error; return error;
fa = xfs_da3_header_check(last_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(last_buf, fa);
xfs_trans_brelse(tp, last_buf);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
/* /*
* Copy the last block into the dead buffer and log it. * Copy the last block into the dead buffer and log it.
*/ */
......
...@@ -236,6 +236,7 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp, ...@@ -236,6 +236,7 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from); struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from);
void xfs_da3_node_hdr_to_disk(struct xfs_mount *mp, void xfs_da3_node_hdr_to_disk(struct xfs_mount *mp,
struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from); struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from);
xfs_failaddr_t xfs_da3_header_check(struct xfs_buf *bp, xfs_ino_t owner);
extern struct kmem_cache *xfs_da_state_cache; extern struct kmem_cache *xfs_da_state_cache;
......
...@@ -438,7 +438,8 @@ xfs_exchmaps_attr_to_sf( ...@@ -438,7 +438,8 @@ xfs_exchmaps_attr_to_sf(
if (!xfs_attr_is_leaf(xmi->xmi_ip2)) if (!xfs_attr_is_leaf(xmi->xmi_ip2))
return 0; return 0;
error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, 0, &bp); error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, 0,
&bp);
if (error) if (error)
return error; return error;
......
...@@ -320,6 +320,7 @@ xchk_da_btree_block( ...@@ -320,6 +320,7 @@ xchk_da_btree_block(
struct xfs_da3_blkinfo *hdr3; struct xfs_da3_blkinfo *hdr3;
struct xfs_da_args *dargs = &ds->dargs; struct xfs_da_args *dargs = &ds->dargs;
struct xfs_inode *ip = ds->dargs.dp; struct xfs_inode *ip = ds->dargs.dp;
xfs_failaddr_t fa;
xfs_ino_t owner; xfs_ino_t owner;
int *pmaxrecs; int *pmaxrecs;
struct xfs_da3_icnode_hdr nodehdr; struct xfs_da3_icnode_hdr nodehdr;
...@@ -442,6 +443,12 @@ xchk_da_btree_block( ...@@ -442,6 +443,12 @@ xchk_da_btree_block(
goto out_freebp; goto out_freebp;
} }
fa = xfs_da3_header_check(blk->bp, dargs->owner);
if (fa) {
xchk_da_set_corrupt(ds, level);
goto out_freebp;
}
/* /*
* If we've been handed a block that is below the dabtree root, does * If we've been handed a block that is below the dabtree root, does
* its hashval match what the parent block expected to see? * its hashval match what the parent block expected to see?
......
...@@ -214,6 +214,7 @@ xfs_attr_node_list_lookup( ...@@ -214,6 +214,7 @@ xfs_attr_node_list_lookup(
struct xfs_mount *mp = dp->i_mount; struct xfs_mount *mp = dp->i_mount;
struct xfs_trans *tp = context->tp; struct xfs_trans *tp = context->tp;
struct xfs_buf *bp; struct xfs_buf *bp;
xfs_failaddr_t fa;
int i; int i;
int error = 0; int error = 0;
unsigned int expected_level = 0; unsigned int expected_level = 0;
...@@ -273,6 +274,12 @@ xfs_attr_node_list_lookup( ...@@ -273,6 +274,12 @@ xfs_attr_node_list_lookup(
} }
} }
fa = xfs_attr3_leaf_header_check(bp, dp->i_ino);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
goto out_releasebuf;
}
if (expected_level != 0) if (expected_level != 0)
goto out_corruptbuf; goto out_corruptbuf;
...@@ -281,6 +288,7 @@ xfs_attr_node_list_lookup( ...@@ -281,6 +288,7 @@ xfs_attr_node_list_lookup(
out_corruptbuf: out_corruptbuf:
xfs_buf_mark_corrupt(bp); xfs_buf_mark_corrupt(bp);
out_releasebuf:
xfs_trans_brelse(tp, bp); xfs_trans_brelse(tp, bp);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK); xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
return -EFSCORRUPTED; return -EFSCORRUPTED;
...@@ -297,6 +305,7 @@ xfs_attr_node_list( ...@@ -297,6 +305,7 @@ xfs_attr_node_list(
struct xfs_buf *bp; struct xfs_buf *bp;
struct xfs_inode *dp = context->dp; struct xfs_inode *dp = context->dp;
struct xfs_mount *mp = dp->i_mount; struct xfs_mount *mp = dp->i_mount;
xfs_failaddr_t fa;
int error = 0; int error = 0;
trace_xfs_attr_node_list(context); trace_xfs_attr_node_list(context);
...@@ -332,6 +341,14 @@ xfs_attr_node_list( ...@@ -332,6 +341,14 @@ xfs_attr_node_list(
case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR_LEAF_MAGIC:
case XFS_ATTR3_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC:
leaf = bp->b_addr; leaf = bp->b_addr;
fa = xfs_attr3_leaf_header_check(bp, dp->i_ino);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(context->tp, bp);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
bp = NULL;
break;
}
xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
&leafhdr, leaf); &leafhdr, leaf);
entries = xfs_attr3_leaf_entryp(leaf); entries = xfs_attr3_leaf_entryp(leaf);
...@@ -382,8 +399,8 @@ xfs_attr_node_list( ...@@ -382,8 +399,8 @@ xfs_attr_node_list(
break; break;
cursor->blkno = leafhdr.forw; cursor->blkno = leafhdr.forw;
xfs_trans_brelse(context->tp, bp); xfs_trans_brelse(context->tp, bp);
error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, error = xfs_attr3_leaf_read(context->tp, dp, dp->i_ino,
&bp); cursor->blkno, &bp);
if (error) if (error)
return error; return error;
} }
...@@ -503,7 +520,8 @@ xfs_attr_leaf_list( ...@@ -503,7 +520,8 @@ xfs_attr_leaf_list(
trace_xfs_attr_leaf_list(context); trace_xfs_attr_leaf_list(context);
context->cursor.blkno = 0; context->cursor.blkno = 0;
error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp); error = xfs_attr3_leaf_read(context->tp, context->dp,
context->dp->i_ino, 0, &bp);
if (error) if (error)
return error; return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment