xfs: validate directory leaf buffer owners
Check the owner field of directory leaf blocks. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
d44bea9b41
commit
402eef10a1
@ -288,8 +288,12 @@ xfs_da3_header_check(
|
||||
return xfs_attr3_leaf_header_check(bp, owner);
|
||||
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
|
||||
return xfs_da3_node_header_check(bp, owner);
|
||||
case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC):
|
||||
case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC):
|
||||
return xfs_dir3_leaf_header_check(bp, owner);
|
||||
}
|
||||
|
||||
ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1700,6 +1704,12 @@ xfs_da3_node_lookup_int(
|
||||
|
||||
if (magic == XFS_DIR2_LEAFN_MAGIC ||
|
||||
magic == XFS_DIR3_LEAFN_MAGIC) {
|
||||
fa = xfs_dir3_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_DIR2_LEAFN_MAGIC;
|
||||
blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
|
||||
blk->bp, NULL);
|
||||
@ -2208,6 +2218,12 @@ xfs_da3_path_shift(
|
||||
break;
|
||||
case XFS_DIR2_LEAFN_MAGIC:
|
||||
case XFS_DIR3_LEAFN_MAGIC:
|
||||
fa = xfs_dir3_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_DIR2_LEAFN_MAGIC;
|
||||
ASSERT(level == path->active-1);
|
||||
blk->index = 0;
|
||||
|
@ -101,6 +101,8 @@ extern struct xfs_dir2_data_free *xfs_dir2_data_freefind(
|
||||
|
||||
extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
|
||||
|
||||
xfs_failaddr_t xfs_dir3_leaf_header_check(struct xfs_buf *bp, xfs_ino_t owner);
|
||||
|
||||
extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
|
||||
extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
|
||||
extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;
|
||||
|
@ -208,6 +208,29 @@ xfs_dir3_leaf_verify(
|
||||
return xfs_dir3_leaf_check_int(mp, &leafhdr, bp->b_addr, true);
|
||||
}
|
||||
|
||||
xfs_failaddr_t
|
||||
xfs_dir3_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_dir3_leaf *hdr3 = bp->b_addr;
|
||||
|
||||
if (hdr3->hdr.info.hdr.magic !=
|
||||
cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) &&
|
||||
hdr3->hdr.info.hdr.magic !=
|
||||
cpu_to_be16(XFS_DIR3_LEAFN_MAGIC))
|
||||
return __this_address;
|
||||
|
||||
if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
|
||||
return __this_address;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_dir3_leaf_read_verify(
|
||||
struct xfs_buf *bp)
|
||||
@ -271,32 +294,60 @@ int
|
||||
xfs_dir3_leaf_read(
|
||||
struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
xfs_ino_t owner,
|
||||
xfs_dablk_t fbno,
|
||||
struct xfs_buf **bpp)
|
||||
{
|
||||
xfs_failaddr_t fa;
|
||||
int err;
|
||||
|
||||
err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
|
||||
&xfs_dir3_leaf1_buf_ops);
|
||||
if (!err && tp && *bpp)
|
||||
if (err || !(*bpp))
|
||||
return err;
|
||||
|
||||
fa = xfs_dir3_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_DATA_FORK);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (tp)
|
||||
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_dir3_leafn_read(
|
||||
struct xfs_trans *tp,
|
||||
struct xfs_inode *dp,
|
||||
xfs_ino_t owner,
|
||||
xfs_dablk_t fbno,
|
||||
struct xfs_buf **bpp)
|
||||
{
|
||||
xfs_failaddr_t fa;
|
||||
int err;
|
||||
|
||||
err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
|
||||
&xfs_dir3_leafn_buf_ops);
|
||||
if (!err && tp && *bpp)
|
||||
if (err || !(*bpp))
|
||||
return err;
|
||||
|
||||
fa = xfs_dir3_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_DATA_FORK);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (tp)
|
||||
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -646,7 +697,8 @@ xfs_dir2_leaf_addname(
|
||||
|
||||
trace_xfs_dir2_leaf_addname(args);
|
||||
|
||||
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
|
||||
error = xfs_dir3_leaf_read(tp, dp, args->owner, args->geo->leafblk,
|
||||
&lbp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -1237,7 +1289,8 @@ xfs_dir2_leaf_lookup_int(
|
||||
tp = args->trans;
|
||||
mp = dp->i_mount;
|
||||
|
||||
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
|
||||
error = xfs_dir3_leaf_read(tp, dp, args->owner, args->geo->leafblk,
|
||||
&lbp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -1562,7 +1562,8 @@ xfs_dir2_leafn_toosmall(
|
||||
/*
|
||||
* Read the sibling leaf block.
|
||||
*/
|
||||
error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, &bp);
|
||||
error = xfs_dir3_leafn_read(state->args->trans, dp,
|
||||
state->args->owner, blkno, &bp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -95,9 +95,9 @@ void xfs_dir2_leaf_hdr_from_disk(struct xfs_mount *mp,
|
||||
void xfs_dir2_leaf_hdr_to_disk(struct xfs_mount *mp, struct xfs_dir2_leaf *to,
|
||||
struct xfs_dir3_icleaf_hdr *from);
|
||||
int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
xfs_dablk_t fbno, struct xfs_buf **bpp);
|
||||
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
|
||||
int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
xfs_dablk_t fbno, struct xfs_buf **bpp);
|
||||
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
|
||||
extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
|
||||
struct xfs_buf *dbp);
|
||||
extern int xfs_dir2_leaf_addname(struct xfs_da_args *args);
|
||||
|
@ -470,7 +470,7 @@ xchk_directory_leaf1_bestfree(
|
||||
int error;
|
||||
|
||||
/* Read the free space block. */
|
||||
error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, &bp);
|
||||
error = xfs_dir3_leaf_read(sc->tp, sc->ip, sc->ip->i_ino, lblk, &bp);
|
||||
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
|
||||
return error;
|
||||
xchk_buffer_recheck(sc, bp);
|
||||
|
Loading…
x
Reference in New Issue
Block a user