[PATCH v2] btrfs: lzo: reject inline extents without compressed data

David Lee <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
inline Btrfs LZO payload shorter than two LZO headers.

Fix the validation or lifetime rule at the vulnerable boundary so malformed
or racing input cannot reach the faulting path.

A four-byte extent produced the following KASAN report on Linux 7.2-rc2:

  BUG: KASAN: slab-out-of-bounds in lzo_decompress+0x57d/0x700
  Read of size 4 at addr ffff888006f2e644 by task btrfs_lzo_inlin/77

  Call Trace:
   <TASK>
   dump_stack_lvl+0x5b/0x70
   print_report+0xd1/0x610
   ? _raw_spin_lock_irqsave+0x78/0xc0
   ? kasan_complete_mode_report_info+0x2a/0x200
   kasan_report+0xe0/0x110
   ? lzo_decompress+0x57d/0x700
   ? lzo_decompress+0x57d/0x700
   __asan_report_load_n_noabort+0x13/0x20
   lzo_decompress+0x57d/0x700
   ? lzo_decompress_bio+0x1e80/0x1e80
   btrfs_decompress+0x140/0x1c0
   uncompress_inline+0x147/0x1b0
   btrfs_get_extent+0xb23/0x10a0
   ? btrfs_rename2+0xb0/0xb0
   ? _raw_spin_lock+0x72/0xb0
   ? _raw_read_lock_irq+0x50/0x50
   ? __kasan_check_read+0x15/0x20
   ? btrfs_folio_test_uptodate+0xc8/0x140
   btrfs_do_readpage.constprop.0+0x538/0x1ac0
   ? btrfs_lookup_ordered_extent+0x2c0/0x2c0
   ? xa_load+0xb0/0x1e0
   btrfs_readahead+0x32f/0x5f0
   ? btrfs_writepages+0x180/0x180
   ? lruvec_stat_mod_folio+0x240/0x330
   ? write_one_eb+0xb30/0xb30
   read_pages+0x16f/0x850
   ? __kasan_check_read+0x15/0x20
   ? __folio_batch_add_and_move+0x134/0x1c0
   ? ractl_alloc_folio.constprop.0+0x90/0x90
   ? filemap_add_folio+0x1cd/0x4f0
   ? __folio_alloc_noprof+0x69/0xa0
   page_cache_ra_unbounded+0x296/0x490
   do_page_cache_ra+0xd9/0x130
   page_cache_sync_ra+0x3ee/0x6f0
   filemap_get_pages+0x306/0x15c0
   ? is_bpf_text_address+0x14/0x30
   ? kernel_text_address+0x89/0xf0
   ? filemap_add_folio+0x4f0/0x4f0
   ? putname+0x78/0xc0
   filemap_read+0x329/0xd00
   ? kasan_save_track+0x18/0x40
   ? __kasan_slab_free+0x44/0x60
   ? putname+0x78/0xc0
   ? entry_SYSCALL_64_after_hwframe+0x4b/0x53
   ? filemap_get_pages+0x15c0/0x15c0
   btrfs_file_read_iter+0x1f8/0x2b0
   vfs_read+0x4ef/0x720
   ? putname+0x78/0xc0
   ? __kasan_slab_free+0x56/0x60
   ? kernel_read+0x180/0x180
   ? putname+0x78/0xc0
   ? __kasan_check_read+0x15/0x20
   ksys_read+0xf8/0x1d0
   ? vfs_write+0xa30/0xa30
   ? __x64_sys_open+0x180/0x180
   __x64_sys_read+0x71/0xb0
   ? __kasan_check_read+0x15/0x20
   x64_sys_call+0x1ab0/0x1b70
   do_syscall_64+0x61/0x470
   entry_SYSCALL_64_after_hwframe+0x4b/0x53
   </TASK>

Link: https://lore.kernel.org/all/[email protected]/
Fixes: a6fa6fae40ec ("btrfs: Add lzo compression support")
Assisted-by: Codex:gpt-5.5
Signed-off-by: David Lee <[email protected]>
---
Changes in v2:
- Reject an eight-byte extent containing headers but no compressed data.
- Rebase onto btrfs for-next and update the invalid-header diagnostic.
- Include the complete KASAN call trace.

Trail of Bits has a reproducer for this bug demonstrating Kernel Panic which can be shared further if needed.

 fs/btrfs/lzo.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 1531adb117d1..2f0996692da0 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -552,9 +552,10 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
 	size_t max_segment_len = workspace_buf_length(fs_info);
 	int ret;
 
-	if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2)) {
+	if (unlikely(srclen <= LZO_LEN * 2 ||
+		     srclen > max_segment_len + LZO_LEN * 2)) {
 		btrfs_err(fs_info, "invalid lzo header length, has %zu expect (%u, %zu)",
-			  srclen, LZO_LEN, max_segment_len + LZO_LEN * 2);
+			  srclen, LZO_LEN * 2, max_segment_len + LZO_LEN * 2);
 		return -EUCLEAN;
 	}
 

-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.