Current we only do chunk validation check at mount time.

It's good for most case, but for fuzzed or manually crafted images, we
can insert a CHUNK_ITEM key into root tree.

Since mount time check will only check chunk tree, it will not check
CHUNK_ITEM in root tree.

Even with previous key type check against leaf owner, it is still
possible to modify the leaf owner to by-pass it.

So we still need to check chunk validation before processing it.

Reported-by: Lukas Lueg <lukas.l...@gmail.com>
Signed-off-by: Qu Wenruo <quwen...@cn.fujitsu.com>
---
 cmds-check.c | 16 ++++++++++++++++
 volumes.c    |  8 ++++----
 volumes.h    |  4 ++++
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index 617b867..1e1f7c9 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -5220,8 +5220,24 @@ static int process_chunk_item(struct cache_tree 
*chunk_cache,
                              int slot)
 {
        struct chunk_record *rec;
+       struct btrfs_chunk *chunk;
        int ret = 0;
 
+       chunk = btrfs_item_ptr(eb, slot, struct btrfs_chunk);
+       /*
+        * Do extra check for this chunk item,
+        *
+        * It's still possible one can craft a leaf with CHUNK_ITEM, with
+        * wrong onwer(3) out of chunk tree, to pass both chunk tree check
+        * and owner<->key_type check.
+        */
+       ret = btrfs_check_chunk_valid(global_info->tree_root, eb, chunk, slot,
+                                     key->offset);
+       if (ret < 0) {
+               error("chunk(%llu, %llu) is not valid, ignore it",
+                     key->offset, btrfs_chunk_length(eb, chunk));
+               return 0;
+       }
        rec = btrfs_new_chunk_record(eb, key, slot);
        ret = insert_cache_extent(chunk_cache, &rec->cache);
        if (ret) {
diff --git a/volumes.c b/volumes.c
index 9a5580a..2d07e66 100644
--- a/volumes.c
+++ b/volumes.c
@@ -1614,10 +1614,10 @@ static struct btrfs_device *fill_missing_device(u64 
devid)
  * slot == -1: SYSTEM chunk
  * return -EIO on error, otherwise return 0
  */
-static int btrfs_check_chunk_valid(struct btrfs_root *root,
-                                  struct extent_buffer *leaf,
-                                  struct btrfs_chunk *chunk,
-                                  int slot, u64 logical)
+int btrfs_check_chunk_valid(struct btrfs_root *root,
+                           struct extent_buffer *leaf,
+                           struct btrfs_chunk *chunk,
+                           int slot, u64 logical)
 {
        u64 length;
        u64 stripe_len;
diff --git a/volumes.h b/volumes.h
index af7182b..d7b7d3c 100644
--- a/volumes.h
+++ b/volumes.h
@@ -226,4 +226,8 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
                             struct extent_buffer *eb,
                             struct btrfs_multi_bio *multi,
                             u64 stripe_len, u64 *raid_map);
+int btrfs_check_chunk_valid(struct btrfs_root *root,
+                           struct extent_buffer *leaf,
+                           struct btrfs_chunk *chunk,
+                           int slot, u64 logical);
 #endif
-- 
2.9.3



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to