Skip to content

Commit 71bf92a

Browse files
adam900710kdave
authored andcommitted
btrfs: tree-checker: Add check for INODE_REF
For INODE_REF we will check: - Objectid (ino) against previous key To detect missing INODE_ITEM. - No overflow/padding in the data payload Much like DIR_ITEM, but with less members to check. Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent c18679e commit 71bf92a

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

fs/btrfs/tree-checker.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,56 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
12471247
return 0;
12481248
}
12491249

1250+
#define inode_ref_err(fs_info, eb, slot, fmt, args...) \
1251+
inode_item_err(fs_info, eb, slot, fmt, ##args)
1252+
static int check_inode_ref(struct extent_buffer *leaf,
1253+
struct btrfs_key *key, struct btrfs_key *prev_key,
1254+
int slot)
1255+
{
1256+
struct btrfs_inode_ref *iref;
1257+
unsigned long ptr;
1258+
unsigned long end;
1259+
1260+
/* namelen can't be 0, so item_size == sizeof() is also invalid */
1261+
if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) {
1262+
inode_ref_err(fs_info, leaf, slot,
1263+
"invalid item size, have %u expect (%zu, %u)",
1264+
btrfs_item_size_nr(leaf, slot),
1265+
sizeof(*iref), BTRFS_LEAF_DATA_SIZE(leaf->fs_info));
1266+
return -EUCLEAN;
1267+
}
1268+
1269+
ptr = btrfs_item_ptr_offset(leaf, slot);
1270+
end = ptr + btrfs_item_size_nr(leaf, slot);
1271+
while (ptr < end) {
1272+
u16 namelen;
1273+
1274+
if (ptr + sizeof(iref) > end) {
1275+
inode_ref_err(fs_info, leaf, slot,
1276+
"inode ref overflow, ptr %lu end %lu inode_ref_size %zu",
1277+
ptr, end, sizeof(iref));
1278+
return -EUCLEAN;
1279+
}
1280+
1281+
iref = (struct btrfs_inode_ref *)ptr;
1282+
namelen = btrfs_inode_ref_name_len(leaf, iref);
1283+
if (ptr + sizeof(*iref) + namelen > end) {
1284+
inode_ref_err(fs_info, leaf, slot,
1285+
"inode ref overflow, ptr %lu end %lu namelen %u",
1286+
ptr, end, namelen);
1287+
return -EUCLEAN;
1288+
}
1289+
1290+
/*
1291+
* NOTE: In theory we should record all found index numbers
1292+
* to find any duplicated indexes, but that will be too time
1293+
* consuming for inodes with too many hard links.
1294+
*/
1295+
ptr += sizeof(*iref) + namelen;
1296+
}
1297+
return 0;
1298+
}
1299+
12501300
/*
12511301
* Common point to switch the item-specific validation.
12521302
*/
@@ -1269,6 +1319,9 @@ static int check_leaf_item(struct extent_buffer *leaf,
12691319
case BTRFS_XATTR_ITEM_KEY:
12701320
ret = check_dir_item(leaf, key, prev_key, slot);
12711321
break;
1322+
case BTRFS_INODE_REF_KEY:
1323+
ret = check_inode_ref(leaf, key, prev_key, slot);
1324+
break;
12721325
case BTRFS_BLOCK_GROUP_ITEM_KEY:
12731326
ret = check_block_group_item(leaf, key, slot);
12741327
break;

0 commit comments

Comments
 (0)