]> git.hungrycats.org Git - linux/commitdiff
btrfs: add more checks to btrfs_read_sys_array
authorDavid Sterba <dsterba@suse.cz>
Wed, 5 Nov 2014 14:24:51 +0000 (15:24 +0100)
committerZygo Blaxell <zblaxell@waya.furryterror.org>
Sun, 22 Mar 2015 18:43:58 +0000 (14:43 -0400)
Verify that the sys_array has enough bytes to read the next item.

Signed-off-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Chris Mason <clm@fb.com>
(cherry picked from commit e3540eab29e1b2260bc4b9b3979a49a00e3e3af8)

fs/btrfs/volumes.c

index 5eb8c2a16500851744089afe0a2e8d7cb61dbdc1..3796c5d713af3d902d56e379710070560954f92a 100644 (file)
@@ -6291,20 +6291,34 @@ int btrfs_read_sys_array(struct btrfs_root *root)
 
        while (cur_offset < array_size) {
                disk_key = (struct btrfs_disk_key *)array_ptr;
+               len = sizeof(*disk_key);
+               if (cur_offset + len > array_size)
+                       goto out_short_read;
+
                btrfs_disk_key_to_cpu(&key, disk_key);
 
-               len = sizeof(*disk_key);
                array_ptr += len;
                sb_array_offset += len;
                cur_offset += len;
 
                if (key.type == BTRFS_CHUNK_ITEM_KEY) {
                        chunk = (struct btrfs_chunk *)sb_array_offset;
+                       /*
+                        * At least one btrfs_chunk with one stripe must be
+                        * present, exact stripe count check comes afterwards
+                        */
+                       len = btrfs_chunk_item_size(1);
+                       if (cur_offset + len > array_size)
+                               goto out_short_read;
+
+                       num_stripes = btrfs_chunk_num_stripes(sb, chunk);
+                       len = btrfs_chunk_item_size(num_stripes);
+                       if (cur_offset + len > array_size)
+                               goto out_short_read;
+
                        ret = read_one_chunk(root, &key, sb, chunk);
                        if (ret)
                                break;
-                       num_stripes = btrfs_chunk_num_stripes(sb, chunk);
-                       len = btrfs_chunk_item_size(num_stripes);
                } else {
                        ret = -EIO;
                        break;
@@ -6315,6 +6329,12 @@ int btrfs_read_sys_array(struct btrfs_root *root)
        }
        free_extent_buffer(sb);
        return ret;
+
+out_short_read:
+       printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n",
+                       len, cur_offset);
+       free_extent_buffer(sb);
+       return -EIO;
 }
 
 int btrfs_read_chunk_tree(struct btrfs_root *root)