From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org
Subject: [PATCH v2 1/2] btrfs: Check each block group has corresponding chunk at mount time
Date: Tue, 3 Jul 2018 16:08:29 +0800 [thread overview]
Message-ID: <20180703080830.8300-1-wqu@suse.com> (raw)
Reported in https://bugzilla.kernel.org/show_bug.cgi?id=199837, if a
crafted btrfs with incorrect chunk<->block group mapping, it could leads
to a lot of unexpected behavior.
Although the crafted image can be catched by block group item checker
added in "[PATCH] btrfs: tree-checker: Verify block_group_item", if one
crafted a valid enough block group item which can pass above check but
still mismatch with existing chunk, it could cause a lot of undefined
behavior.
This patch will add extra block group -> chunk mapping check, to ensure
we have a completely matching (start, len, flags) chunk for each block
group at mount time.
Reported-by: Xu Wen <wen.xu@gatech.edu>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
changelog:
v2:
Add better error message for each mismatch case.
Rename function name, to co-operate with later patch.
Add flags mismatch check.
---
fs/btrfs/extent-tree.c | 55 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 53 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3d9fe58c0080..82b446f014b9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -10003,6 +10003,41 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,
return cache;
}
+static int check_exist_chunk(struct btrfs_fs_info *fs_info, u64 start, u64 len,
+ u64 flags)
+{
+ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+ struct extent_map *em;
+ int ret;
+
+ read_lock(&map_tree->map_tree.lock);
+ em = lookup_extent_mapping(&map_tree->map_tree, start, len);
+ read_unlock(&map_tree->map_tree.lock);
+
+ if (!em) {
+ btrfs_err_rl(fs_info,
+ "block group start=%llu len=%llu doesn't have corresponding chunk",
+ start, len);
+ ret = -ENOENT;
+ goto out;
+ }
+ if (em->start != start || em->len != len ||
+ (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK) !=
+ (flags & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
+ btrfs_err_rl(fs_info,
+"block group start=%llu len=%llu flags=0x%llx doesn't match with chunk start=%llu len=%llu flags=0x%llx",
+ start, len , flags & BTRFS_BLOCK_GROUP_TYPE_MASK,
+ em->start, em->len, em->map_lookup->type &
+ BTRFS_BLOCK_GROUP_TYPE_MASK);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ ret = 0;
+out:
+ free_extent_map(em);
+ return ret;
+}
+
int btrfs_read_block_groups(struct btrfs_fs_info *info)
{
struct btrfs_path *path;
@@ -10036,6 +10071,9 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
need_clear = 1;
while (1) {
+ struct btrfs_block_group_item bg;
+ int slot;
+
ret = find_first_block_group(info, path, &key);
if (ret > 0)
break;
@@ -10043,7 +10081,20 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
goto error;
leaf = path->nodes[0];
- btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+ slot = path->slots[0];
+ btrfs_item_key_to_cpu(leaf, &found_key, slot);
+
+ read_extent_buffer(leaf, &bg, btrfs_item_ptr_offset(leaf, slot),
+ sizeof(bg));
+ /*
+ * Chunk and block group must have 1:1 mapping.
+ * So there must be a chunk for this block group.
+ */
+ ret = check_exist_chunk(info, found_key.objectid,
+ found_key.offset,
+ btrfs_block_group_flags(&bg));
+ if (ret < 0)
+ goto error;
cache = btrfs_create_block_group_cache(info, found_key.objectid,
found_key.offset);
@@ -10068,7 +10119,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
}
read_extent_buffer(leaf, &cache->item,
- btrfs_item_ptr_offset(leaf, path->slots[0]),
+ btrfs_item_ptr_offset(leaf, slot),
sizeof(cache->item));
cache->flags = btrfs_block_group_flags(&cache->item);
if (!mixed &&
--
2.18.0
next reply other threads:[~2018-07-03 8:08 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-03 8:08 Qu Wenruo [this message]
2018-07-03 8:08 ` [PATCH v2 2/2] btrfs: Verify every chunk has corresponding block group at mount time Qu Wenruo
2018-07-03 8:33 ` [PATCH v2 1/2] btrfs: Check each block group has corresponding chunk " Nikolay Borisov
2018-07-03 8:40 ` Nikolay Borisov
2018-07-03 8:47 ` Qu Wenruo
2018-07-03 9:08 ` Nikolay Borisov
2018-07-03 18:58 ` Martin Steigerwald
2018-07-04 15:37 ` David Sterba
2018-07-04 15:45 ` David Sterba
-- strict thread matches above, loose matches on Subject: below --
2018-07-06 5:35 Qu Wenruo
2018-07-06 8:06 ` Gu, Jinxiang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180703080830.8300-1-wqu@suse.com \
--to=wqu@suse.com \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).