From: Darrick J. Wong Date: Fri, 17 Nov 2017 04:11:33 +0000 (-0600) Subject: xfs: abort dir/attr btree operation if btree is obviously weird X-Git-Tag: v4.15.0-rc1~143^2~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9473ee32e1d700c002543245c2fb4a49cdf8a685;p=thirdparty%2Fxfsprogs-dev.git xfs: abort dir/attr btree operation if btree is obviously weird Source kernel commit: 8210f4dda2d7642cb7c882db55e53d899cced401 Abort an dir/attr btree operation if the attr btree has obvious problems like loops back to the root or pointers don't point down the tree. Found by fuzzing btree[0].before to zero in xfs/402, which livelocks on the cycle in the attr btree. Apply the same checks to xfs_da3_node_lookup_int. Signed-off-by: Darrick J. Wong Reviewed-by: Brian Foster Signed-off-by: Eric Sandeen --- diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c index 347bf4821..b2457fdc5 100644 --- a/libxfs/xfs_da_btree.c +++ b/libxfs/xfs_da_btree.c @@ -1461,6 +1461,7 @@ xfs_da3_node_lookup_int( int max; int error; int retval; + unsigned int expected_level = 0; struct xfs_inode *dp = state->args->dp; args = state->args; @@ -1469,7 +1470,7 @@ xfs_da3_node_lookup_int( * Descend thru the B-tree searching each level for the right * node to use, until the right hashval is found. */ - blkno = (args->whichfork == XFS_DATA_FORK)? args->geo->leafblk : 0; + blkno = args->geo->leafblk; for (blk = &state->path.blk[0], state->path.active = 1; state->path.active <= XFS_DA_NODE_MAXDEPTH; blk++, state->path.active++) { @@ -1512,6 +1513,18 @@ xfs_da3_node_lookup_int( dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); + /* Tree taller than we can handle; bail out! */ + if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) + return -EFSCORRUPTED; + + /* Check the level from the root. */ + if (blkno == args->geo->leafblk) + expected_level = nodehdr.level - 1; + else if (expected_level != nodehdr.level) + return -EFSCORRUPTED; + else + expected_level--; + max = nodehdr.count; blk->hashval = be32_to_cpu(btree[max - 1].hashval); @@ -1557,8 +1570,15 @@ xfs_da3_node_lookup_int( blk->index = probe; blkno = be32_to_cpu(btree[probe].before); } + + /* We can't point back to the root. */ + if (blkno == args->geo->leafblk) + return -EFSCORRUPTED; } + if (expected_level != 0) + return -EFSCORRUPTED; + /* * A leaf block that ends in the hashval that we are interested in * (final hashval == search hashval) means that the next block may