summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_attr_list.c
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2017-10-25 16:59:43 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2017-10-27 09:20:31 -0700
commit8210f4dda2d7642cb7c882db55e53d899cced401 (patch)
treebcc197df6ce3248726b89fe63fb0aa7ae204e1a8 /fs/xfs/xfs_attr_list.c
parentbdaac93f80b84aad2dd9316a3ffb6626b86c13e0 (diff)
xfs: abort dir/attr btree operation if btree is obviously weird
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 <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
Diffstat (limited to 'fs/xfs/xfs_attr_list.c')
-rw-r--r--fs/xfs/xfs_attr_list.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index 021ec5a0e070..a3603101e5f0 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -223,6 +223,7 @@ xfs_attr_node_list_lookup(
struct xfs_buf *bp;
int i;
int error = 0;
+ unsigned int expected_level = 0;
uint16_t magic;
ASSERT(*pbp == NULL);
@@ -246,6 +247,18 @@ xfs_attr_node_list_lookup(
dp->d_ops->node_hdr_from_disk(&nodehdr, node);
+ /* Tree taller than we can handle; bail out! */
+ if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
+ goto out_corruptbuf;
+
+ /* Check the level from the root node. */
+ if (cursor->blkno == 0)
+ expected_level = nodehdr.level - 1;
+ else if (expected_level != nodehdr.level)
+ goto out_corruptbuf;
+ else
+ expected_level--;
+
btree = dp->d_ops->node_tree_p(node);
for (i = 0; i < nodehdr.count; btree++, i++) {
if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
@@ -259,8 +272,15 @@ xfs_attr_node_list_lookup(
if (i == nodehdr.count)
return 0;
+
+ /* We can't point back to the root. */
+ if (cursor->blkno == 0)
+ return -EFSCORRUPTED;
}
+ if (expected_level != 0)
+ goto out_corruptbuf;
+
*pbp = bp;
return 0;