[PATCH v1 2/3] lib/842: require a complete history block for repeat templates
From: Karl Mehltretter
Date: Sat Aug 29 2026 - 05:21:26 EST
An 842 repeat template copies the preceding eight-byte output block. The
decoder rejects a repeat only when no output has been produced. A
short-data operation can produce between one and seven bytes before a
repeat.
Such a stream makes the repeat copy read before the start of the output
buffer. Depending on the surrounding mapping, this can fault or bring
preceding memory into the decompressed data.
This is also reachable through zram's compressed writeback path. With 842
selected, targeted corruption of the compressed data on its backing device
to a short-data-then-repeat stream made a KASAN kernel report a
vmalloc-out-of-bounds read when zram read the page back.
Require at least one complete output block before accepting a repeat.
Fixes: 2da572c959dd ("lib: add software 842 compression/decompression")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
---
Review notes:
- add_short_data_template() has one caller, immediately before
add_end_template(), so valid compressor output cannot place a repeat
after short data.
- QEMU 11.0.2 TCG with x86_64 KASAN reproduced this through zram. A page
was written to a virtio backing disk with compressed_writeback enabled,
then the backing block was replaced with SHORT_DATA(seven bytes),
REPEAT(one block), END and CRC. Baseline readback reported an eight-byte
vmalloc-out-of-bounds read starting one byte before zram's output page.
Fixed readback returned -EIO without a KASAN report.
lib/842/842_decompress.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/842/842_decompress.c b/lib/842/842_decompress.c
index 87d1e0f8a4926..45a9815abd637 100644
--- a/lib/842/842_decompress.c
+++ b/lib/842/842_decompress.c
@@ -309,7 +309,7 @@ int sw842_decompress(const u8 *in, unsigned int ilen,
if (ret)
return ret;
- if (p.out == out) /* no previous bytes */
+ if (p.out - p.ostart < 8) /* no complete previous block */
return -EINVAL;
/* copy rep + 1 */
--
2.53.0