Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c871b0f2 authored by Liu Bo's avatar Liu Bo Committed by David Sterba
Browse files

Btrfs: check if extent buffer is aligned to sectorsize



Thanks to fuzz testing, we can pass an invalid bytenr to extent buffer
via alloc_extent_buffer().  An unaligned eb can have more pages than it
should have, which ends up extent buffer's leak or some corrupted content
in extent buffer.

This adds a warning to let us quickly know what was happening.

Now that alloc_extent_buffer() no more returns NULL, this changes its
caller and callers of its caller to match with the new error
handling.

Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 16ff4b45
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2512,6 +2512,8 @@ read_block_for_search(struct btrfs_trans_handle *trans,
		if (!btrfs_buffer_uptodate(tmp, 0, 0))
			ret = -EIO;
		free_extent_buffer(tmp);
	} else {
		ret = PTR_ERR(tmp);
	}
	return ret;
}
+4 −4
Original line number Diff line number Diff line
@@ -1098,7 +1098,7 @@ void readahead_tree_block(struct btrfs_root *root, u64 bytenr)
	struct inode *btree_inode = root->fs_info->btree_inode;

	buf = btrfs_find_create_tree_block(root, bytenr);
	if (!buf)
	if (IS_ERR(buf))
		return;
	read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
				 buf, 0, WAIT_NONE, btree_get_extent, 0);
@@ -1114,7 +1114,7 @@ int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr,
	int ret;

	buf = btrfs_find_create_tree_block(root, bytenr);
	if (!buf)
	if (IS_ERR(buf))
		return 0;

	set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags);
@@ -1172,8 +1172,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
	int ret;

	buf = btrfs_find_create_tree_block(root, bytenr);
	if (!buf)
		return ERR_PTR(-ENOMEM);
	if (IS_ERR(buf))
		return buf;

	ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
	if (ret) {
+6 −4
Original line number Diff line number Diff line
@@ -8016,8 +8016,9 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
	struct extent_buffer *buf;

	buf = btrfs_find_create_tree_block(root, bytenr);
	if (!buf)
		return ERR_PTR(-ENOMEM);
	if (IS_ERR(buf))
		return buf;

	btrfs_set_header_generation(buf, trans->transid);
	btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
	btrfs_tree_lock(buf);
@@ -8659,8 +8660,9 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
	next = btrfs_find_tree_block(root->fs_info, bytenr);
	if (!next) {
		next = btrfs_find_create_tree_block(root, bytenr);
		if (!next)
			return -ENOMEM;
		if (IS_ERR(next))
			return PTR_ERR(next);

		btrfs_set_buffer_lockdep_class(root->root_key.objectid, next,
					       level - 1);
		reada = 1;
+12 −3
Original line number Diff line number Diff line
@@ -4892,18 +4892,25 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
	int uptodate = 1;
	int ret;

	if (!IS_ALIGNED(start, fs_info->tree_root->sectorsize)) {
		btrfs_err(fs_info, "bad tree block start %llu", start);
		return ERR_PTR(-EINVAL);
	}

	eb = find_extent_buffer(fs_info, start);
	if (eb)
		return eb;

	eb = __alloc_extent_buffer(fs_info, start, len);
	if (!eb)
		return NULL;
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < num_pages; i++, index++) {
		p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL);
		if (!p)
		if (!p) {
			exists = ERR_PTR(-ENOMEM);
			goto free_eb;
		}

		spin_lock(&mapping->private_lock);
		if (PagePrivate(p)) {
@@ -4948,8 +4955,10 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
		set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
again:
	ret = radix_tree_preload(GFP_NOFS);
	if (ret)
	if (ret) {
		exists = ERR_PTR(ret);
		goto free_eb;
	}

	spin_lock(&fs_info->buffer_lock);
	ret = radix_tree_insert(&fs_info->buffer_radix,
+2 −2
Original line number Diff line number Diff line
@@ -2422,8 +2422,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
		root_owner = btrfs_header_owner(parent);

		next = btrfs_find_create_tree_block(root, bytenr);
		if (!next)
			return -ENOMEM;
		if (IS_ERR(next))
			return PTR_ERR(next);

		if (*level == 1) {
			ret = wc->process_func(root, next, wc, ptr_gen);
Loading