Skip to content

Commit 1f55ee6

Browse files
fdmananakdave
authored andcommitted
btrfs: fix invalid leaf access due to inline extent during lseek
During lseek, for SEEK_DATA and SEEK_HOLE modes, we access the disk_bytenr of an extent without checking its type. However inline extents have their data starting the offset of the disk_bytenr field, so accessing that field when we have an inline extent can result in either of the following: 1) Interpret the inline extent's data as a disk_bytenr value; 2) In case the inline data is less than 8 bytes, we access part of some other item in the leaf, or unused space in the leaf; 3) In case the inline data is less than 8 bytes and the extent item is the first item in the leaf, we can access beyond the leaf's limit. So fix this by not accessing the disk_bytenr field if we have an inline extent. Fixes: b6e8335 ("btrfs: make hole and data seeking a lot more efficient") Reported-by: Matthias Schoepfer <[email protected]> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=216908 Link: https://lore.kernel.org/linux-btrfs/[email protected]/ CC: [email protected] # 6.1 Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 26ecf24 commit 1f55ee6

File tree

1 file changed

+10
-3
lines changed

1 file changed

+10
-3
lines changed

fs/btrfs/file.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,6 +3541,7 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
35413541
struct extent_buffer *leaf = path->nodes[0];
35423542
struct btrfs_file_extent_item *extent;
35433543
u64 extent_end;
3544+
u8 type;
35443545

35453546
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
35463547
ret = btrfs_next_leaf(root, path);
@@ -3596,10 +3597,16 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
35963597

35973598
extent = btrfs_item_ptr(leaf, path->slots[0],
35983599
struct btrfs_file_extent_item);
3600+
type = btrfs_file_extent_type(leaf, extent);
35993601

3600-
if (btrfs_file_extent_disk_bytenr(leaf, extent) == 0 ||
3601-
btrfs_file_extent_type(leaf, extent) ==
3602-
BTRFS_FILE_EXTENT_PREALLOC) {
3602+
/*
3603+
* Can't access the extent's disk_bytenr field if this is an
3604+
* inline extent, since at that offset, it's where the extent
3605+
* data starts.
3606+
*/
3607+
if (type == BTRFS_FILE_EXTENT_PREALLOC ||
3608+
(type == BTRFS_FILE_EXTENT_REG &&
3609+
btrfs_file_extent_disk_bytenr(leaf, extent) == 0)) {
36033610
/*
36043611
* Explicit hole or prealloc extent, search for delalloc.
36053612
* A prealloc extent is treated like a hole.

0 commit comments

Comments
 (0)