Skip to content

Commit 7db72c3

Browse files
adam900710gregkh
authored andcommitted
btrfs: tree-checker: add inode extref checks
[ Upstream commit aab9458 ] Like inode refs, inode extrefs have a variable length name, which means we have to do a proper check to make sure no header nor name can exceed the item limits. The check itself is very similar to check_inode_ref(), just a different structure (btrfs_inode_extref vs btrfs_inode_ref). Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 32054a9 commit 7db72c3

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

fs/btrfs/tree-checker.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ static bool check_prev_ino(struct extent_buffer *leaf,
183183
/* Only these key->types needs to be checked */
184184
ASSERT(key->type == BTRFS_XATTR_ITEM_KEY ||
185185
key->type == BTRFS_INODE_REF_KEY ||
186+
key->type == BTRFS_INODE_EXTREF_KEY ||
186187
key->type == BTRFS_DIR_INDEX_KEY ||
187188
key->type == BTRFS_DIR_ITEM_KEY ||
188189
key->type == BTRFS_EXTENT_DATA_KEY);
@@ -1770,6 +1771,39 @@ static int check_inode_ref(struct extent_buffer *leaf,
17701771
return 0;
17711772
}
17721773

1774+
static int check_inode_extref(struct extent_buffer *leaf,
1775+
struct btrfs_key *key, struct btrfs_key *prev_key,
1776+
int slot)
1777+
{
1778+
unsigned long ptr = btrfs_item_ptr_offset(leaf, slot);
1779+
unsigned long end = ptr + btrfs_item_size(leaf, slot);
1780+
1781+
if (unlikely(!check_prev_ino(leaf, key, slot, prev_key)))
1782+
return -EUCLEAN;
1783+
1784+
while (ptr < end) {
1785+
struct btrfs_inode_extref *extref = (struct btrfs_inode_extref *)ptr;
1786+
u16 namelen;
1787+
1788+
if (unlikely(ptr + sizeof(*extref)) > end) {
1789+
inode_ref_err(leaf, slot,
1790+
"inode extref overflow, ptr %lu end %lu inode_extref size %zu",
1791+
ptr, end, sizeof(*extref));
1792+
return -EUCLEAN;
1793+
}
1794+
1795+
namelen = btrfs_inode_extref_name_len(leaf, extref);
1796+
if (unlikely(ptr + sizeof(*extref) + namelen > end)) {
1797+
inode_ref_err(leaf, slot,
1798+
"inode extref overflow, ptr %lu end %lu namelen %u",
1799+
ptr, end, namelen);
1800+
return -EUCLEAN;
1801+
}
1802+
ptr += sizeof(*extref) + namelen;
1803+
}
1804+
return 0;
1805+
}
1806+
17731807
static int check_raid_stripe_extent(const struct extent_buffer *leaf,
17741808
const struct btrfs_key *key, int slot)
17751809
{
@@ -1881,6 +1915,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
18811915
case BTRFS_INODE_REF_KEY:
18821916
ret = check_inode_ref(leaf, key, prev_key, slot);
18831917
break;
1918+
case BTRFS_INODE_EXTREF_KEY:
1919+
ret = check_inode_extref(leaf, key, prev_key, slot);
1920+
break;
18841921
case BTRFS_BLOCK_GROUP_ITEM_KEY:
18851922
ret = check_block_group_item(leaf, key, slot);
18861923
break;

0 commit comments

Comments
 (0)