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 ---