[PATCH v1 1/3] lib/842: reject output overflows from index and short data

From: Karl Mehltretter

Date: Sat Aug 29 2026 - 05:21:03 EST


The output length passed to sw842_decompress() is the caller's buffer
capacity. Indexed copies write 2, 4 or 8 bytes and short-data templates
write up to 7, but neither checks that capacity before writing and
decrementing p->olen.

Overwriting an undersized destination then underflows p->olen, which is
unsigned, so every later bounds check in the stream passes. Subsequent
operations keep writing past the destination, and a matching CRC lets
sw842_decompress() return success with an output length larger than the
capacity the caller supplied.

This is reachable through zram's compressed writeback path. With 842
selected, targeted corruption of the compressed data on its backing device
made a KASAN kernel report vmalloc-out-of-bounds writes in __do_index() and
sw842_decompress() when zram read the page back.

Check the remaining output before both operations and return -ENOSPC,
matching the other output-producing templates.

Fixes: 2da572c959dd ("lib: add software 842 compression/decompression")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
---
Review notes:

- Baseline i386 and x86_64 return success and change post-capacity
canaries for both vectors; fixed kernels return -ENOSPC without
changing them.
- QEMU 11.0.2 TCG with x86_64 KASAN reproduced both operations through
zram. A 568-byte compressed page was written to a virtio backing disk
with compressed_writeback enabled, then its backing block was replaced
before readback. Since zram supplies a PAGE_SIZE destination, these
were PAGE_SIZE-scaled versions of the KUnit streams: the baseline
reported an eight-byte vmalloc-out-of-bounds write in __do_index() for
the indexed copy and a one-byte write in sw842_decompress() for short
data. Fixed readback returned -EIO without a KASAN report.

lib/842/842_decompress.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/lib/842/842_decompress.c b/lib/842/842_decompress.c
index 582085ef8b49c..87d1e0f8a4926 100644
--- a/lib/842/842_decompress.c
+++ b/lib/842/842_decompress.c
@@ -165,6 +165,9 @@ static int __do_index(struct sw842_param *p, u8 size, u8 bits, u64 fsize)
u64 index, offset, total = round_down(p->out - p->ostart, 8);
int ret;

+ if (size > p->olen)
+ return -ENOSPC;
+
ret = next_bits(p, &index, bits);
if (ret)
return ret;
@@ -344,6 +347,8 @@ int sw842_decompress(const u8 *in, unsigned int ilen,

if (!bytes || bytes > SHORT_DATA_BITS_MAX)
return -EINVAL;
+ if (bytes > p.olen)
+ return -ENOSPC;

while (bytes-- > 0) {
ret = next_bits(&p, &tmp, 8);
--
2.53.0