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

xfs: validate dabtree node buffer owners

Check the owner field of dabtree node blocks.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 8c25dc72
...@@ -252,6 +252,26 @@ xfs_da3_node_verify( ...@@ -252,6 +252,26 @@ xfs_da3_node_verify(
return NULL; return NULL;
} }
xfs_failaddr_t
xfs_da3_node_header_check(
struct xfs_buf *bp,
xfs_ino_t owner)
{
struct xfs_mount *mp = bp->b_mount;
if (xfs_has_crc(mp)) {
struct xfs_da3_blkinfo *hdr3 = bp->b_addr;
if (hdr3->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->owner) != owner)
return __this_address;
}
return NULL;
}
xfs_failaddr_t xfs_failaddr_t
xfs_da3_header_check( xfs_da3_header_check(
struct xfs_buf *bp, struct xfs_buf *bp,
...@@ -266,6 +286,8 @@ xfs_da3_header_check( ...@@ -266,6 +286,8 @@ xfs_da3_header_check(
switch (hdr->magic) { switch (hdr->magic) {
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
return xfs_attr3_leaf_header_check(bp, owner); return xfs_attr3_leaf_header_check(bp, owner);
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
return xfs_da3_node_header_check(bp, owner);
} }
return NULL; return NULL;
...@@ -1218,6 +1240,7 @@ xfs_da3_root_join( ...@@ -1218,6 +1240,7 @@ xfs_da3_root_join(
struct xfs_da3_icnode_hdr oldroothdr; struct xfs_da3_icnode_hdr oldroothdr;
int error; int error;
struct xfs_inode *dp = state->args->dp; struct xfs_inode *dp = state->args->dp;
xfs_failaddr_t fa;
trace_xfs_da_root_join(state->args); trace_xfs_da_root_join(state->args);
...@@ -1244,6 +1267,13 @@ xfs_da3_root_join( ...@@ -1244,6 +1267,13 @@ xfs_da3_root_join(
error = xfs_da3_node_read(args->trans, dp, child, &bp, args->whichfork); error = xfs_da3_node_read(args->trans, dp, child, &bp, args->whichfork);
if (error) if (error)
return error; return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level); xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);
/* /*
...@@ -1278,6 +1308,7 @@ xfs_da3_node_toosmall( ...@@ -1278,6 +1308,7 @@ xfs_da3_node_toosmall(
struct xfs_da_blkinfo *info; struct xfs_da_blkinfo *info;
xfs_dablk_t blkno; xfs_dablk_t blkno;
struct xfs_buf *bp; struct xfs_buf *bp;
xfs_failaddr_t fa;
struct xfs_da3_icnode_hdr nodehdr; struct xfs_da3_icnode_hdr nodehdr;
int count; int count;
int forward; int forward;
...@@ -1352,6 +1383,13 @@ xfs_da3_node_toosmall( ...@@ -1352,6 +1383,13 @@ xfs_da3_node_toosmall(
state->args->whichfork); state->args->whichfork);
if (error) if (error)
return error; return error;
fa = xfs_da3_node_header_check(bp, state->args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(state->args->trans, bp);
xfs_da_mark_sick(state->args);
return -EFSCORRUPTED;
}
node = bp->b_addr; node = bp->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &thdr, node); xfs_da3_node_hdr_from_disk(dp->i_mount, &thdr, node);
...@@ -1674,6 +1712,13 @@ xfs_da3_node_lookup_int( ...@@ -1674,6 +1712,13 @@ xfs_da3_node_lookup_int(
return -EFSCORRUPTED; return -EFSCORRUPTED;
} }
fa = xfs_da3_node_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_DA_NODE_MAGIC; blk->magic = XFS_DA_NODE_MAGIC;
/* /*
...@@ -1846,6 +1891,7 @@ xfs_da3_blk_link( ...@@ -1846,6 +1891,7 @@ xfs_da3_blk_link(
struct xfs_da_blkinfo *tmp_info; struct xfs_da_blkinfo *tmp_info;
struct xfs_da_args *args; struct xfs_da_args *args;
struct xfs_buf *bp; struct xfs_buf *bp;
xfs_failaddr_t fa;
int before = 0; int before = 0;
int error; int error;
struct xfs_inode *dp = state->args->dp; struct xfs_inode *dp = state->args->dp;
...@@ -1889,6 +1935,13 @@ xfs_da3_blk_link( ...@@ -1889,6 +1935,13 @@ xfs_da3_blk_link(
&bp, args->whichfork); &bp, args->whichfork);
if (error) if (error)
return error; return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL); ASSERT(bp != NULL);
tmp_info = bp->b_addr; tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == old_info->magic); ASSERT(tmp_info->magic == old_info->magic);
...@@ -1910,6 +1963,13 @@ xfs_da3_blk_link( ...@@ -1910,6 +1963,13 @@ xfs_da3_blk_link(
&bp, args->whichfork); &bp, args->whichfork);
if (error) if (error)
return error; return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL); ASSERT(bp != NULL);
tmp_info = bp->b_addr; tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == old_info->magic); ASSERT(tmp_info->magic == old_info->magic);
...@@ -1939,6 +1999,7 @@ xfs_da3_blk_unlink( ...@@ -1939,6 +1999,7 @@ xfs_da3_blk_unlink(
struct xfs_da_blkinfo *tmp_info; struct xfs_da_blkinfo *tmp_info;
struct xfs_da_args *args; struct xfs_da_args *args;
struct xfs_buf *bp; struct xfs_buf *bp;
xfs_failaddr_t fa;
int error; int error;
/* /*
...@@ -1969,6 +2030,13 @@ xfs_da3_blk_unlink( ...@@ -1969,6 +2030,13 @@ xfs_da3_blk_unlink(
&bp, args->whichfork); &bp, args->whichfork);
if (error) if (error)
return error; return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL); ASSERT(bp != NULL);
tmp_info = bp->b_addr; tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == save_info->magic); ASSERT(tmp_info->magic == save_info->magic);
...@@ -1986,6 +2054,13 @@ xfs_da3_blk_unlink( ...@@ -1986,6 +2054,13 @@ xfs_da3_blk_unlink(
&bp, args->whichfork); &bp, args->whichfork);
if (error) if (error)
return error; return error;
fa = xfs_da3_header_check(bp, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_trans_brelse(args->trans, bp);
xfs_da_mark_sick(args);
return -EFSCORRUPTED;
}
ASSERT(bp != NULL); ASSERT(bp != NULL);
tmp_info = bp->b_addr; tmp_info = bp->b_addr;
ASSERT(tmp_info->magic == save_info->magic); ASSERT(tmp_info->magic == save_info->magic);
...@@ -2101,6 +2176,12 @@ xfs_da3_path_shift( ...@@ -2101,6 +2176,12 @@ xfs_da3_path_shift(
switch (be16_to_cpu(info->magic)) { switch (be16_to_cpu(info->magic)) {
case XFS_DA_NODE_MAGIC: case XFS_DA_NODE_MAGIC:
case XFS_DA3_NODE_MAGIC: case XFS_DA3_NODE_MAGIC:
fa = xfs_da3_node_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_DA_NODE_MAGIC; blk->magic = XFS_DA_NODE_MAGIC;
xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
bp->b_addr); bp->b_addr);
...@@ -2406,6 +2487,13 @@ xfs_da3_swap_lastblock( ...@@ -2406,6 +2487,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w); error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
if (error) if (error)
goto done; goto done;
fa = xfs_da3_header_check(sib_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(sib_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
sib_info = sib_buf->b_addr; sib_info = sib_buf->b_addr;
if (XFS_IS_CORRUPT(mp, if (XFS_IS_CORRUPT(mp,
be32_to_cpu(sib_info->forw) != last_blkno || be32_to_cpu(sib_info->forw) != last_blkno ||
...@@ -2427,6 +2515,13 @@ xfs_da3_swap_lastblock( ...@@ -2427,6 +2515,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w); error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
if (error) if (error)
goto done; goto done;
fa = xfs_da3_header_check(sib_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(sib_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
sib_info = sib_buf->b_addr; sib_info = sib_buf->b_addr;
if (XFS_IS_CORRUPT(mp, if (XFS_IS_CORRUPT(mp,
be32_to_cpu(sib_info->back) != last_blkno || be32_to_cpu(sib_info->back) != last_blkno ||
...@@ -2450,6 +2545,13 @@ xfs_da3_swap_lastblock( ...@@ -2450,6 +2545,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w); error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
if (error) if (error)
goto done; goto done;
fa = xfs_da3_node_header_check(par_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(par_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
par_node = par_buf->b_addr; par_node = par_buf->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node); xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
if (XFS_IS_CORRUPT(mp, if (XFS_IS_CORRUPT(mp,
...@@ -2499,6 +2601,13 @@ xfs_da3_swap_lastblock( ...@@ -2499,6 +2601,13 @@ xfs_da3_swap_lastblock(
error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w); error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
if (error) if (error)
goto done; goto done;
fa = xfs_da3_node_header_check(par_buf, args->owner);
if (fa) {
__xfs_buf_mark_corrupt(par_buf, fa);
xfs_da_mark_sick(args);
error = -EFSCORRUPTED;
goto done;
}
par_node = par_buf->b_addr; par_node = par_buf->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node); xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
if (XFS_IS_CORRUPT(mp, par_hdr.level != level)) { if (XFS_IS_CORRUPT(mp, par_hdr.level != level)) {
......
...@@ -237,6 +237,7 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp, ...@@ -237,6 +237,7 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
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); xfs_failaddr_t xfs_da3_header_check(struct xfs_buf *bp, xfs_ino_t owner);
xfs_failaddr_t xfs_da3_node_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;
......
...@@ -239,6 +239,10 @@ xfs_attr_node_list_lookup( ...@@ -239,6 +239,10 @@ xfs_attr_node_list_lookup(
goto out_corruptbuf; goto out_corruptbuf;
} }
fa = xfs_da3_node_header_check(bp, dp->i_ino);
if (fa)
goto out_corruptbuf;
xfs_da3_node_hdr_from_disk(mp, &nodehdr, node); xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
/* Tree taller than we can handle; bail out! */ /* Tree taller than we can handle; bail out! */
...@@ -335,6 +339,11 @@ xfs_attr_node_list( ...@@ -335,6 +339,11 @@ xfs_attr_node_list(
case XFS_DA_NODE_MAGIC: case XFS_DA_NODE_MAGIC:
case XFS_DA3_NODE_MAGIC: case XFS_DA3_NODE_MAGIC:
trace_xfs_attr_list_wrong_blk(context); trace_xfs_attr_list_wrong_blk(context);
fa = xfs_da3_node_header_check(bp, dp->i_ino);
if (fa) {
__xfs_buf_mark_corrupt(bp, fa);
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
}
xfs_trans_brelse(context->tp, bp); xfs_trans_brelse(context->tp, bp);
bp = NULL; bp = NULL;
break; break;
......
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