tree-checker.c (7d7ae873b5e0f46d19e5dc818d1a7809e4b7cc81) | tree-checker.c (c1bf973f57b7ca62e868c5bc7f3cbdf8ea8d5dc5) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) Qu Wenruo 2017. All rights reserved. 4 */ 5 6/* 7 * The module is used to catch unexpected/corrupted tree block data. 8 * Such behavior can be caused either by a fuzzed image or bugs. --- 15 unchanged lines hidden (view full) --- 24#include "disk-io.h" 25#include "compression.h" 26#include "volumes.h" 27#include "misc.h" 28#include "fs.h" 29#include "accessors.h" 30#include "file-item.h" 31#include "inode-item.h" | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) Qu Wenruo 2017. All rights reserved. 4 */ 5 6/* 7 * The module is used to catch unexpected/corrupted tree block data. 8 * Such behavior can be caused either by a fuzzed image or bugs. --- 15 unchanged lines hidden (view full) --- 24#include "disk-io.h" 25#include "compression.h" 26#include "volumes.h" 27#include "misc.h" 28#include "fs.h" 29#include "accessors.h" 30#include "file-item.h" 31#include "inode-item.h" |
32#include "extent-tree.h" |
|
32 33/* 34 * Error message should follow the following format: 35 * corrupt <type>: <identifier>, <reason>[, <bad_value>] 36 * 37 * @type: leaf or node 38 * @identifier: the necessary info to locate the leaf/node. 39 * It's recommended to decode key.objecitd/offset if it's --- 1229 unchanged lines hidden (view full) --- 1269 struct btrfs_key *prev_key) 1270{ 1271 struct btrfs_fs_info *fs_info = leaf->fs_info; 1272 struct btrfs_extent_item *ei; 1273 bool is_tree_block = false; 1274 unsigned long ptr; /* Current pointer inside inline refs */ 1275 unsigned long end; /* Extent item end */ 1276 const u32 item_size = btrfs_item_size(leaf, slot); | 33 34/* 35 * Error message should follow the following format: 36 * corrupt <type>: <identifier>, <reason>[, <bad_value>] 37 * 38 * @type: leaf or node 39 * @identifier: the necessary info to locate the leaf/node. 40 * It's recommended to decode key.objecitd/offset if it's --- 1229 unchanged lines hidden (view full) --- 1270 struct btrfs_key *prev_key) 1271{ 1272 struct btrfs_fs_info *fs_info = leaf->fs_info; 1273 struct btrfs_extent_item *ei; 1274 bool is_tree_block = false; 1275 unsigned long ptr; /* Current pointer inside inline refs */ 1276 unsigned long end; /* Extent item end */ 1277 const u32 item_size = btrfs_item_size(leaf, slot); |
1278 u8 last_type = 0; 1279 u64 last_seq = U64_MAX; |
|
1277 u64 flags; 1278 u64 generation; 1279 u64 total_refs; /* Total refs in btrfs_extent_item */ 1280 u64 inline_refs = 0; /* found total inline refs */ 1281 1282 if (unlikely(key->type == BTRFS_METADATA_ITEM_KEY && 1283 !btrfs_fs_incompat(fs_info, SKINNY_METADATA))) { 1284 generic_err(leaf, slot, --- 30 unchanged lines hidden (view full) --- 1315 * 2.1) The ref type, one of the 4 1316 * TREE_BLOCK_REF Tree block only 1317 * SHARED_BLOCK_REF Tree block only 1318 * EXTENT_DATA_REF Data only 1319 * SHARED_DATA_REF Data only 1320 * 2.2) Ref type specific data 1321 * Either using btrfs_extent_inline_ref::offset, or specific 1322 * data structure. | 1280 u64 flags; 1281 u64 generation; 1282 u64 total_refs; /* Total refs in btrfs_extent_item */ 1283 u64 inline_refs = 0; /* found total inline refs */ 1284 1285 if (unlikely(key->type == BTRFS_METADATA_ITEM_KEY && 1286 !btrfs_fs_incompat(fs_info, SKINNY_METADATA))) { 1287 generic_err(leaf, slot, --- 30 unchanged lines hidden (view full) --- 1318 * 2.1) The ref type, one of the 4 1319 * TREE_BLOCK_REF Tree block only 1320 * SHARED_BLOCK_REF Tree block only 1321 * EXTENT_DATA_REF Data only 1322 * SHARED_DATA_REF Data only 1323 * 2.2) Ref type specific data 1324 * Either using btrfs_extent_inline_ref::offset, or specific 1325 * data structure. |
1326 * 1327 * All above inline items should follow the order: 1328 * 1329 * - All btrfs_extent_inline_ref::type should be in an ascending 1330 * order 1331 * 1332 * - Within the same type, the items should follow a descending 1333 * order by their sequence number. The sequence number is 1334 * determined by: 1335 * * btrfs_extent_inline_ref::offset for all types other than 1336 * EXTENT_DATA_REF 1337 * * hash_extent_data_ref() for EXTENT_DATA_REF |
|
1323 */ 1324 if (unlikely(item_size < sizeof(*ei))) { 1325 extent_err(leaf, slot, 1326 "invalid item size, have %u expect [%zu, %u)", 1327 item_size, sizeof(*ei), 1328 BTRFS_LEAF_DATA_SIZE(fs_info)); 1329 return -EUCLEAN; 1330 } --- 65 unchanged lines hidden (view full) --- 1396 ptr = (unsigned long)(struct btrfs_tree_block_info *)(info + 1); 1397 } 1398 1399 /* Check inline refs */ 1400 while (ptr < end) { 1401 struct btrfs_extent_inline_ref *iref; 1402 struct btrfs_extent_data_ref *dref; 1403 struct btrfs_shared_data_ref *sref; | 1338 */ 1339 if (unlikely(item_size < sizeof(*ei))) { 1340 extent_err(leaf, slot, 1341 "invalid item size, have %u expect [%zu, %u)", 1342 item_size, sizeof(*ei), 1343 BTRFS_LEAF_DATA_SIZE(fs_info)); 1344 return -EUCLEAN; 1345 } --- 65 unchanged lines hidden (view full) --- 1411 ptr = (unsigned long)(struct btrfs_tree_block_info *)(info + 1); 1412 } 1413 1414 /* Check inline refs */ 1415 while (ptr < end) { 1416 struct btrfs_extent_inline_ref *iref; 1417 struct btrfs_extent_data_ref *dref; 1418 struct btrfs_shared_data_ref *sref; |
1419 u64 seq; |
|
1404 u64 dref_offset; 1405 u64 inline_offset; 1406 u8 inline_type; 1407 1408 if (unlikely(ptr + sizeof(*iref) > end)) { 1409 extent_err(leaf, slot, 1410"inline ref item overflows extent item, ptr %lu iref size %zu end %lu", 1411 ptr, sizeof(*iref), end); 1412 return -EUCLEAN; 1413 } 1414 iref = (struct btrfs_extent_inline_ref *)ptr; 1415 inline_type = btrfs_extent_inline_ref_type(leaf, iref); 1416 inline_offset = btrfs_extent_inline_ref_offset(leaf, iref); | 1420 u64 dref_offset; 1421 u64 inline_offset; 1422 u8 inline_type; 1423 1424 if (unlikely(ptr + sizeof(*iref) > end)) { 1425 extent_err(leaf, slot, 1426"inline ref item overflows extent item, ptr %lu iref size %zu end %lu", 1427 ptr, sizeof(*iref), end); 1428 return -EUCLEAN; 1429 } 1430 iref = (struct btrfs_extent_inline_ref *)ptr; 1431 inline_type = btrfs_extent_inline_ref_type(leaf, iref); 1432 inline_offset = btrfs_extent_inline_ref_offset(leaf, iref); |
1433 seq = inline_offset; |
|
1417 if (unlikely(ptr + btrfs_extent_inline_ref_size(inline_type) > end)) { 1418 extent_err(leaf, slot, 1419"inline ref item overflows extent item, ptr %lu iref size %u end %lu", 1420 ptr, btrfs_extent_inline_ref_size(inline_type), end); 1421 return -EUCLEAN; 1422 } 1423 1424 switch (inline_type) { --- 14 unchanged lines hidden (view full) --- 1439 break; 1440 /* 1441 * Contains owner subvolid, owner key objectid, adjusted offset. 1442 * The only obvious corruption can happen in that offset. 1443 */ 1444 case BTRFS_EXTENT_DATA_REF_KEY: 1445 dref = (struct btrfs_extent_data_ref *)(&iref->offset); 1446 dref_offset = btrfs_extent_data_ref_offset(leaf, dref); | 1434 if (unlikely(ptr + btrfs_extent_inline_ref_size(inline_type) > end)) { 1435 extent_err(leaf, slot, 1436"inline ref item overflows extent item, ptr %lu iref size %u end %lu", 1437 ptr, btrfs_extent_inline_ref_size(inline_type), end); 1438 return -EUCLEAN; 1439 } 1440 1441 switch (inline_type) { --- 14 unchanged lines hidden (view full) --- 1456 break; 1457 /* 1458 * Contains owner subvolid, owner key objectid, adjusted offset. 1459 * The only obvious corruption can happen in that offset. 1460 */ 1461 case BTRFS_EXTENT_DATA_REF_KEY: 1462 dref = (struct btrfs_extent_data_ref *)(&iref->offset); 1463 dref_offset = btrfs_extent_data_ref_offset(leaf, dref); |
1464 seq = hash_extent_data_ref( 1465 btrfs_extent_data_ref_root(leaf, dref), 1466 btrfs_extent_data_ref_objectid(leaf, dref), 1467 btrfs_extent_data_ref_offset(leaf, dref)); |
|
1447 if (unlikely(!IS_ALIGNED(dref_offset, 1448 fs_info->sectorsize))) { 1449 extent_err(leaf, slot, 1450 "invalid data ref offset, have %llu expect aligned to %u", 1451 dref_offset, fs_info->sectorsize); 1452 return -EUCLEAN; 1453 } 1454 inline_refs += btrfs_extent_data_ref_count(leaf, dref); --- 10 unchanged lines hidden (view full) --- 1465 } 1466 inline_refs += btrfs_shared_data_ref_count(leaf, sref); 1467 break; 1468 default: 1469 extent_err(leaf, slot, "unknown inline ref type: %u", 1470 inline_type); 1471 return -EUCLEAN; 1472 } | 1468 if (unlikely(!IS_ALIGNED(dref_offset, 1469 fs_info->sectorsize))) { 1470 extent_err(leaf, slot, 1471 "invalid data ref offset, have %llu expect aligned to %u", 1472 dref_offset, fs_info->sectorsize); 1473 return -EUCLEAN; 1474 } 1475 inline_refs += btrfs_extent_data_ref_count(leaf, dref); --- 10 unchanged lines hidden (view full) --- 1486 } 1487 inline_refs += btrfs_shared_data_ref_count(leaf, sref); 1488 break; 1489 default: 1490 extent_err(leaf, slot, "unknown inline ref type: %u", 1491 inline_type); 1492 return -EUCLEAN; 1493 } |
1494 if (inline_type < last_type) { 1495 extent_err(leaf, slot, 1496 "inline ref out-of-order: has type %u, prev type %u", 1497 inline_type, last_type); 1498 return -EUCLEAN; 1499 } 1500 /* Type changed, allow the sequence starts from U64_MAX again. */ 1501 if (inline_type > last_type) 1502 last_seq = U64_MAX; 1503 if (seq > last_seq) { 1504 extent_err(leaf, slot, 1505"inline ref out-of-order: has type %u offset %llu seq 0x%llx, prev type %u seq 0x%llx", 1506 inline_type, inline_offset, seq, 1507 last_type, last_seq); 1508 return -EUCLEAN; 1509 } 1510 last_type = inline_type; 1511 last_seq = seq; |
|
1473 ptr += btrfs_extent_inline_ref_size(inline_type); 1474 } 1475 /* No padding is allowed */ 1476 if (unlikely(ptr != end)) { 1477 extent_err(leaf, slot, 1478 "invalid extent item size, padding bytes found"); 1479 return -EUCLEAN; 1480 } --- 557 unchanged lines hidden --- | 1512 ptr += btrfs_extent_inline_ref_size(inline_type); 1513 } 1514 /* No padding is allowed */ 1515 if (unlikely(ptr != end)) { 1516 extent_err(leaf, slot, 1517 "invalid extent item size, padding bytes found"); 1518 return -EUCLEAN; 1519 } --- 557 unchanged lines hidden --- |