aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2014-11-05 09:24:51 -0500
committerChris Mason <clm@fb.com>2015-02-02 22:24:39 -0500
commite3540eab29e1b2260bc4b9b3979a49a00e3e3af8 (patch)
treedb22ad2525c71e04922ca49b92416dd92687f7ea /fs/btrfs/volumes.c
parent1ffb22cf8c322bbfea6b35fe23d025841b49fede (diff)
btrfs: add more checks to btrfs_read_sys_array
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>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index b33c83be2a97..2c4cab2dbd1a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6296,20 +6296,34 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6296 6296
6297 while (cur_offset < array_size) { 6297 while (cur_offset < array_size) {
6298 disk_key = (struct btrfs_disk_key *)array_ptr; 6298 disk_key = (struct btrfs_disk_key *)array_ptr;
6299 len = sizeof(*disk_key);
6300 if (cur_offset + len > array_size)
6301 goto out_short_read;
6302
6299 btrfs_disk_key_to_cpu(&key, disk_key); 6303 btrfs_disk_key_to_cpu(&key, disk_key);
6300 6304
6301 len = sizeof(*disk_key);
6302 array_ptr += len; 6305 array_ptr += len;
6303 sb_array_offset += len; 6306 sb_array_offset += len;
6304 cur_offset += len; 6307 cur_offset += len;
6305 6308
6306 if (key.type == BTRFS_CHUNK_ITEM_KEY) { 6309 if (key.type == BTRFS_CHUNK_ITEM_KEY) {
6307 chunk = (struct btrfs_chunk *)sb_array_offset; 6310 chunk = (struct btrfs_chunk *)sb_array_offset;
6311 /*
6312 * At least one btrfs_chunk with one stripe must be
6313 * present, exact stripe count check comes afterwards
6314 */
6315 len = btrfs_chunk_item_size(1);
6316 if (cur_offset + len > array_size)
6317 goto out_short_read;
6318
6319 num_stripes = btrfs_chunk_num_stripes(sb, chunk);
6320 len = btrfs_chunk_item_size(num_stripes);
6321 if (cur_offset + len > array_size)
6322 goto out_short_read;
6323
6308 ret = read_one_chunk(root, &key, sb, chunk); 6324 ret = read_one_chunk(root, &key, sb, chunk);
6309 if (ret) 6325 if (ret)
6310 break; 6326 break;
6311 num_stripes = btrfs_chunk_num_stripes(sb, chunk);
6312 len = btrfs_chunk_item_size(num_stripes);
6313 } else { 6327 } else {
6314 ret = -EIO; 6328 ret = -EIO;
6315 break; 6329 break;
@@ -6320,6 +6334,12 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6320 } 6334 }
6321 free_extent_buffer(sb); 6335 free_extent_buffer(sb);
6322 return ret; 6336 return ret;
6337
6338out_short_read:
6339 printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n",
6340 len, cur_offset);
6341 free_extent_buffer(sb);
6342 return -EIO;
6323} 6343}
6324 6344
6325int btrfs_read_chunk_tree(struct btrfs_root *root) 6345int btrfs_read_chunk_tree(struct btrfs_root *root)