mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] btrfs: lzo: reject inline extents without compressed data
@ 2026-07-15  9:05 David Lee
  2026-07-15  9:31 ` Qu Wenruo
  0 siblings, 1 reply; 2+ messages in thread
From: David Lee @ 2026-07-15  9:05 UTC (permalink / raw)
  To: Chris Mason
  Cc: David Lee, Qu Wenruo, David Sterba,
	Dominik 'Disconnect3d' Czarnota, linux-btrfs,
	linux-kernel

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/20260714071054.1715464-1-david.lee@trailofbits.com/
Fixes: a6fa6fae40ec ("btrfs: Add lzo compression support")
Assisted-by: Codex:gpt-5.5
Signed-off-by: David Lee <david.lee@trailofbits.com>
---
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

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] btrfs: lzo: reject inline extents without compressed data
  2026-07-15  9:05 [PATCH v2] btrfs: lzo: reject inline extents without compressed data David Lee
@ 2026-07-15  9:31 ` Qu Wenruo
  0 siblings, 0 replies; 2+ messages in thread
From: Qu Wenruo @ 2026-07-15  9:31 UTC (permalink / raw)
  To: David Lee, Chris Mason
  Cc: David Sterba, Dominik 'Disconnect3d' Czarnota,
	linux-btrfs, linux-kernel

The new subject line is a little confusing.

The patch is not just rejecting empty payload, but also cases where 
there is not even enough space for needed headers.

Something like "reject invalid sized inline extents" would be better.

在 2026/7/15 18:35, David Lee 写道:
> inline Btrfs LZO payload shorter than two LZO headers.

This is not even a sentence, sorry I didn't point this out in the 
initial patch.

> Fix the validation or lifetime rule

So what the "lifetime rule" is?

> at the vulnerable boundary so malformed
> or racing input cannot reach the faulting path.

The same for "racing input". I see no racing behavior.

Malformed on-disk data is self-explaining, but "racing input" is not.

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

Please remove unrelated stacks which start with a question mark.

I have removed the remaining ones as an example.
>     kasan_report+0xe0/0x110
>     __asan_report_load_n_noabort+0x13/0x20
>     lzo_decompress+0x57d/0x700
>     btrfs_decompress+0x140/0x1c0
>     uncompress_inline+0x147/0x1b0
>     btrfs_get_extent+0xb23/0x10a0
>     btrfs_do_readpage.constprop.0+0x538/0x1ac0
>     btrfs_readahead+0x32f/0x5f0
>     read_pages+0x16f/0x850
>     page_cache_ra_unbounded+0x296/0x490
>     do_page_cache_ra+0xd9/0x130
>     page_cache_sync_ra+0x3ee/0x6f0
>     filemap_get_pages+0x306/0x15c0
>     filemap_read+0x329/0xd00
>     btrfs_file_read_iter+0x1f8/0x2b0
>     vfs_read+0x4ef/0x720
>     ksys_read+0xf8/0x1d0
>     __x64_sys_read+0x71/0xb0
>     x64_sys_call+0x1ab0/0x1b70
>     do_syscall_64+0x61/0x470
>     entry_SYSCALL_64_after_hwframe+0x4b/0x53
>     </TASK>
> 

A very short explanation would help, something like:

   An inlined lzo compressed extent should have one lzo header (4 bytes),
   followed by one segment header (4 bytes) then payload.
   For the 4 bytes sized inline extent, there is no space for the segment
   header.

   Without proper validation, reading the segment header will be out the
   inlined extent.

Feel free to use LLM to fix whatever grammar errors in the above example.

> Link: https://lore.kernel.org/all/20260714071054.1715464-1-david.lee@trailofbits.com/

We do not use Link: just to point back to an older version.

We use it for the original bug report (not the patch).

> Fixes: a6fa6fae40ec ("btrfs: Add lzo compression support")
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: David Lee <david.lee@trailofbits.com>
> ---
> 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;
>   	}
>   
> 


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-15  9:31 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-15  9:05 [PATCH v2] btrfs: lzo: reject inline extents without compressed data David Lee
2026-07-15  9:31 ` Qu Wenruo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome