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

xfs: strengthen btree pointer checks before use

Instead of ASSERTing on null btree pointers in xfs_btree_ptr_to_daddr,
use the new block number verifiers to ensure that the btree pointer
doesn't point to any sensitive areas (AG headers, past-EOFS) and return
-EFSCORRUPTED if this is the case.  Remove the ASSERT because on-disk
corruptions shouldn't trigger ASSERTs.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 4cbae4b8
...@@ -992,22 +992,30 @@ xfs_btree_readahead( ...@@ -992,22 +992,30 @@ xfs_btree_readahead(
return xfs_btree_readahead_sblock(cur, lr, block); return xfs_btree_readahead_sblock(cur, lr, block);
} }
STATIC xfs_daddr_t STATIC int
xfs_btree_ptr_to_daddr( xfs_btree_ptr_to_daddr(
struct xfs_btree_cur *cur, struct xfs_btree_cur *cur,
union xfs_btree_ptr *ptr) union xfs_btree_ptr *ptr,
xfs_daddr_t *daddr)
{ {
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { xfs_fsblock_t fsbno;
ASSERT(ptr->l != cpu_to_be64(NULLFSBLOCK)); xfs_agblock_t agbno;
int error;
return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l)); error = xfs_btree_check_ptr(cur, ptr, 0, 1);
} else { if (error)
ASSERT(cur->bc_private.a.agno != NULLAGNUMBER); return error;
ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK));
return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno, if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
be32_to_cpu(ptr->s)); fsbno = be64_to_cpu(ptr->l);
*daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno);
} else {
agbno = be32_to_cpu(ptr->s);
*daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
agbno);
} }
return 0;
} }
/* /*
...@@ -1022,8 +1030,11 @@ xfs_btree_readahead_ptr( ...@@ -1022,8 +1030,11 @@ xfs_btree_readahead_ptr(
union xfs_btree_ptr *ptr, union xfs_btree_ptr *ptr,
xfs_extlen_t count) xfs_extlen_t count)
{ {
xfs_buf_readahead(cur->bc_mp->m_ddev_targp, xfs_daddr_t daddr;
xfs_btree_ptr_to_daddr(cur, ptr),
if (xfs_btree_ptr_to_daddr(cur, ptr, &daddr))
return;
xfs_buf_readahead(cur->bc_mp->m_ddev_targp, daddr,
cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops); cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops);
} }
...@@ -1286,11 +1297,14 @@ xfs_btree_get_buf_block( ...@@ -1286,11 +1297,14 @@ xfs_btree_get_buf_block(
{ {
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
xfs_daddr_t d; xfs_daddr_t d;
int error;
/* need to sort out how callers deal with failures first */ /* need to sort out how callers deal with failures first */
ASSERT(!(flags & XBF_TRYLOCK)); ASSERT(!(flags & XBF_TRYLOCK));
d = xfs_btree_ptr_to_daddr(cur, ptr); error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
if (error)
return error;
*bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
mp->m_bsize, flags); mp->m_bsize, flags);
...@@ -1321,7 +1335,9 @@ xfs_btree_read_buf_block( ...@@ -1321,7 +1335,9 @@ xfs_btree_read_buf_block(
/* need to sort out how callers deal with failures first */ /* need to sort out how callers deal with failures first */
ASSERT(!(flags & XBF_TRYLOCK)); ASSERT(!(flags & XBF_TRYLOCK));
d = xfs_btree_ptr_to_daddr(cur, ptr); error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
if (error)
return error;
error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
mp->m_bsize, flags, bpp, mp->m_bsize, flags, bpp,
cur->bc_ops->buf_ops); cur->bc_ops->buf_ops);
...@@ -1768,6 +1784,7 @@ xfs_btree_lookup_get_block( ...@@ -1768,6 +1784,7 @@ xfs_btree_lookup_get_block(
struct xfs_btree_block **blkp) /* return btree block */ struct xfs_btree_block **blkp) /* return btree block */
{ {
struct xfs_buf *bp; /* buffer pointer for btree block */ struct xfs_buf *bp; /* buffer pointer for btree block */
xfs_daddr_t daddr;
int error = 0; int error = 0;
/* special case the root block if in an inode */ /* special case the root block if in an inode */
...@@ -1784,7 +1801,10 @@ xfs_btree_lookup_get_block( ...@@ -1784,7 +1801,10 @@ xfs_btree_lookup_get_block(
* Otherwise throw it away and get a new one. * Otherwise throw it away and get a new one.
*/ */
bp = cur->bc_bufs[level]; bp = cur->bc_bufs[level];
if (bp && XFS_BUF_ADDR(bp) == xfs_btree_ptr_to_daddr(cur, pp)) { error = xfs_btree_ptr_to_daddr(cur, pp, &daddr);
if (error)
return error;
if (bp && XFS_BUF_ADDR(bp) == daddr) {
*blkp = XFS_BUF_TO_BLOCK(bp); *blkp = XFS_BUF_TO_BLOCK(bp);
return 0; return 0;
} }
......
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