summaryrefslogtreecommitdiff
path: root/disk-io.c
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2016-08-30 11:29:32 +0800
committerDavid Sterba <dsterba@suse.com>2016-09-05 10:04:24 +0200
commit245cf06dfaec144fac3423e91d0bbb2b686b5ed1 (patch)
tree479723a45d39649cd06aaf7953f9ad44d2d7f220 /disk-io.c
parent767ae9e348a667fa4e05e3b1a01630ecaff1f27d (diff)
btrfs-progs: check: do early check for read_tree_block
Although we have enhanced read_tree_block() from a lot of different aspects, it lacks the early bytenr/blocksize alignment check. And the lack of such check can lead to strange use-after-free bugs, due to the fact that alloc_extent_buffer() will free overlapping extent buffers, and allocate new eb for the usage. So we should not allow invalid bytenr/blocksize even passed to btrfs_find_create_tree_block(). This patch will add such check so we won't trigger use-after-free bug then. Reported-by: Lukas Lueg <lukas.lueg@gmail.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'disk-io.c')
-rw-r--r--disk-io.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/disk-io.c b/disk-io.c
index ca4578f7..f5340c31 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -313,11 +313,29 @@ struct extent_buffer* read_tree_block_fs_info(
int ret;
struct extent_buffer *eb;
u64 best_transid = 0;
+ u32 sectorsize = btrfs_super_sectorsize(fs_info->super_copy);
+ u32 nodesize = btrfs_super_nodesize(fs_info->super_copy);
int mirror_num = 0;
int good_mirror = 0;
int num_copies;
int ignore = 0;
+ /*
+ * Don't even try to create tree block for unaligned tree block
+ * bytenr.
+ * Such unaligned tree block will free overlapping extent buffer,
+ * causing use-after-free bugs for fuzzed images.
+ */
+ if (!IS_ALIGNED(bytenr, sectorsize)) {
+ error("tree block bytenr %llu is not aligned to sectorsize %u",
+ bytenr, sectorsize);
+ return ERR_PTR(-EIO);
+ }
+ if (!IS_ALIGNED(blocksize, nodesize)) {
+ error("tree block size %u is not aligned to nodesize %u",
+ blocksize, nodesize);
+ return ERR_PTR(-EIO);
+ }
eb = btrfs_find_create_tree_block(fs_info, bytenr, blocksize);
if (!eb)
return ERR_PTR(-ENOMEM);