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