Skip to content

Commit

Permalink
xfs: validity check the directory block leaf entry count
Browse files Browse the repository at this point in the history
The directory block format verifier fails to check that the leaf
entry count is in a valid range, and so if it is corrupted then it
can lead to derefencing a pointer outside the block buffer. While we
can't exactly validate the count without first walking the directory
block, we can ensure the count lands in the valid area within the
directory block and hence avoid out-of-block references.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Oct 30, 2013
1 parent b01ef65 commit a629362
Showing 1 changed file with 15 additions and 4 deletions.
19 changes: 15 additions & 4 deletions fs/xfs/xfs_dir2_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,32 @@ __xfs_dir3_data_check(
const struct xfs_dir_ops *ops;

mp = bp->b_target->bt_mount;
hdr = bp->b_addr;

/*
* We can be passed a null dp here from a verifier, so we need to go the
* hard way to get them.
*/
ops = xfs_dir_get_ops(mp, dp);

hdr = bp->b_addr;
p = (char *)ops->data_entry_p(hdr);

switch (hdr->magic) {
case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
btp = xfs_dir2_block_tail_p(mp, hdr);
lep = xfs_dir2_block_leaf_p(btp);
endp = (char *)lep;

/*
* The number of leaf entries is limited by the size of the
* block and the amount of space used by the data entries.
* We don't know how much space is used by the data entries yet,
* so just ensure that the count falls somewhere inside the
* block right now.
*/
XFS_WANT_CORRUPTED_RETURN(be32_to_cpu(btp->count) <
((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry));
break;
case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
Expand All @@ -88,13 +100,12 @@ __xfs_dir3_data_check(
XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp);
return EFSCORRUPTED;
}
bf = ops->data_bestfree_p(hdr);
p = (char *)ops->data_entry_p(hdr);

count = lastfree = freeseen = 0;
/*
* Account for zero bestfree entries.
*/
bf = ops->data_bestfree_p(hdr);
count = lastfree = freeseen = 0;
if (!bf[0].length) {
XFS_WANT_CORRUPTED_RETURN(!bf[0].offset);
freeseen |= 1 << 0;
Expand Down

0 comments on commit a629362

Please sign in to comment.