@@ -6251,27 +6251,23 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
6251
6251
return dev ;
6252
6252
}
6253
6253
6254
- static int read_one_chunk (struct btrfs_root * root , struct btrfs_key * key ,
6255
- struct extent_buffer * leaf ,
6256
- struct btrfs_chunk * chunk )
6254
+ /* Return -EIO if any error, otherwise return 0. */
6255
+ static int btrfs_check_chunk_valid (struct btrfs_root * root ,
6256
+ struct extent_buffer * leaf ,
6257
+ struct btrfs_chunk * chunk , u64 logical )
6257
6258
{
6258
- struct btrfs_mapping_tree * map_tree = & root -> fs_info -> mapping_tree ;
6259
- struct map_lookup * map ;
6260
- struct extent_map * em ;
6261
- u64 logical ;
6262
6259
u64 length ;
6263
6260
u64 stripe_len ;
6264
- u64 devid ;
6265
- u8 uuid [BTRFS_UUID_SIZE ];
6266
- int num_stripes ;
6267
- int ret ;
6268
- int i ;
6261
+ u16 num_stripes ;
6262
+ u16 sub_stripes ;
6263
+ u64 type ;
6269
6264
6270
- logical = key -> offset ;
6271
6265
length = btrfs_chunk_length (leaf , chunk );
6272
6266
stripe_len = btrfs_chunk_stripe_len (leaf , chunk );
6273
6267
num_stripes = btrfs_chunk_num_stripes (leaf , chunk );
6274
- /* Validation check */
6268
+ sub_stripes = btrfs_chunk_sub_stripes (leaf , chunk );
6269
+ type = btrfs_chunk_type (leaf , chunk );
6270
+
6275
6271
if (!num_stripes ) {
6276
6272
btrfs_err (root -> fs_info , "invalid chunk num_stripes: %u" ,
6277
6273
num_stripes );
@@ -6282,6 +6278,11 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6282
6278
"invalid chunk logical %llu" , logical );
6283
6279
return - EIO ;
6284
6280
}
6281
+ if (btrfs_chunk_sector_size (leaf , chunk ) != root -> sectorsize ) {
6282
+ btrfs_err (root -> fs_info , "invalid chunk sectorsize %u" ,
6283
+ btrfs_chunk_sector_size (leaf , chunk ));
6284
+ return - EIO ;
6285
+ }
6285
6286
if (!length || !IS_ALIGNED (length , root -> sectorsize )) {
6286
6287
btrfs_err (root -> fs_info ,
6287
6288
"invalid chunk length %llu" , length );
@@ -6293,13 +6294,54 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6293
6294
return - EIO ;
6294
6295
}
6295
6296
if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK ) &
6296
- btrfs_chunk_type ( leaf , chunk ) ) {
6297
+ type ) {
6297
6298
btrfs_err (root -> fs_info , "unrecognized chunk type: %llu" ,
6298
6299
~(BTRFS_BLOCK_GROUP_TYPE_MASK |
6299
6300
BTRFS_BLOCK_GROUP_PROFILE_MASK ) &
6300
6301
btrfs_chunk_type (leaf , chunk ));
6301
6302
return - EIO ;
6302
6303
}
6304
+ if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2 ) ||
6305
+ (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1 ) ||
6306
+ (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2 ) ||
6307
+ (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3 ) ||
6308
+ (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2 ) ||
6309
+ ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK ) == 0 &&
6310
+ num_stripes != 1 )) {
6311
+ btrfs_err (root -> fs_info ,
6312
+ "invalid num_stripes:sub_stripes %u:%u for profile %llu" ,
6313
+ num_stripes , sub_stripes ,
6314
+ type & BTRFS_BLOCK_GROUP_PROFILE_MASK );
6315
+ return - EIO ;
6316
+ }
6317
+
6318
+ return 0 ;
6319
+ }
6320
+
6321
+ static int read_one_chunk (struct btrfs_root * root , struct btrfs_key * key ,
6322
+ struct extent_buffer * leaf ,
6323
+ struct btrfs_chunk * chunk )
6324
+ {
6325
+ struct btrfs_mapping_tree * map_tree = & root -> fs_info -> mapping_tree ;
6326
+ struct map_lookup * map ;
6327
+ struct extent_map * em ;
6328
+ u64 logical ;
6329
+ u64 length ;
6330
+ u64 stripe_len ;
6331
+ u64 devid ;
6332
+ u8 uuid [BTRFS_UUID_SIZE ];
6333
+ int num_stripes ;
6334
+ int ret ;
6335
+ int i ;
6336
+
6337
+ logical = key -> offset ;
6338
+ length = btrfs_chunk_length (leaf , chunk );
6339
+ stripe_len = btrfs_chunk_stripe_len (leaf , chunk );
6340
+ num_stripes = btrfs_chunk_num_stripes (leaf , chunk );
6341
+
6342
+ ret = btrfs_check_chunk_valid (root , leaf , chunk , logical );
6343
+ if (ret )
6344
+ return ret ;
6303
6345
6304
6346
read_lock (& map_tree -> map_tree .lock );
6305
6347
em = lookup_extent_mapping (& map_tree -> map_tree , logical , 1 );
@@ -6547,6 +6589,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6547
6589
u32 array_size ;
6548
6590
u32 len = 0 ;
6549
6591
u32 cur_offset ;
6592
+ u64 type ;
6550
6593
struct btrfs_key key ;
6551
6594
6552
6595
ASSERT (BTRFS_SUPER_INFO_SIZE <= root -> nodesize );
@@ -6613,6 +6656,15 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6613
6656
break ;
6614
6657
}
6615
6658
6659
+ type = btrfs_chunk_type (sb , chunk );
6660
+ if ((type & BTRFS_BLOCK_GROUP_SYSTEM ) == 0 ) {
6661
+ btrfs_err (root -> fs_info ,
6662
+ "invalid chunk type %llu in sys_array at offset %u" ,
6663
+ type , cur_offset );
6664
+ ret = - EIO ;
6665
+ break ;
6666
+ }
6667
+
6616
6668
len = btrfs_chunk_item_size (num_stripes );
6617
6669
if (cur_offset + len > array_size )
6618
6670
goto out_short_read ;
0 commit comments