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

From: Qu Wenruo

Date: Wed Jul 15 2026 - 05:36:53 EST


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@xxxxxxxxxxxxxxx/

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@xxxxxxxxxxxxxxx>
---
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;
}