diff options
-rw-r--r-- | disk-io.c | 2 | ||||
-rw-r--r-- | kerncompat.h | 8 | ||||
-rw-r--r-- | volumes.c | 29 |
3 files changed, 36 insertions, 3 deletions
@@ -40,8 +40,6 @@ #define BTRFS_BAD_LEVEL (-3) #define BTRFS_BAD_NRITEMS (-4) -#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) - /* Calculate max possible nritems for a leaf/node */ static u32 max_nritems(u8 level, u32 nodesize) { diff --git a/kerncompat.h b/kerncompat.h index 7c627ba..0f207b7 100644 --- a/kerncompat.h +++ b/kerncompat.h @@ -310,6 +310,14 @@ static inline long IS_ERR(const void *ptr) #define __bitwise #endif +/* Alignment check */ +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + +static inline int is_power_of_2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} + typedef u16 __bitwise __le16; typedef u16 __bitwise __be16; typedef u32 __bitwise __le32; @@ -1591,6 +1591,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, struct cache_extent *ce; u64 logical; u64 length; + u64 stripe_len; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; @@ -1599,6 +1600,33 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, logical = key->offset; length = btrfs_chunk_length(leaf, chunk); + stripe_len = btrfs_chunk_stripe_len(leaf, chunk); + num_stripes = btrfs_chunk_num_stripes(leaf, chunk); + /* Validation check */ + if (!num_stripes) { + error("invalid chunk num_stripes: %u", num_stripes); + return -EIO; + } + if (!IS_ALIGNED(logical, root->sectorsize)) { + error("invalid chunk logical %llu", logical); + return -EIO; + } + if (!length || !IS_ALIGNED(length, root->sectorsize)) { + error("invalid chunk length %llu", length); + return -EIO; + } + if (!is_power_of_2(stripe_len)) { + error("invalid chunk stripe length: %llu", stripe_len); + return -EIO; + } + if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & + btrfs_chunk_type(leaf, chunk)) { + error("unrecognized chunk type: %llu", + ~(BTRFS_BLOCK_GROUP_TYPE_MASK | + BTRFS_BLOCK_GROUP_PROFILE_MASK) & + btrfs_chunk_type(leaf, chunk)); + return -EIO; + } ce = search_cache_extent(&map_tree->cache_tree, logical); @@ -1607,7 +1635,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, return 0; } - num_stripes = btrfs_chunk_num_stripes(leaf, chunk); map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS); if (!map) return -ENOMEM; |