From 5eb206e2672c99ee07e9d5f4b7767e2d9c1e053f Mon Sep 17 00:00:00 2001 From: Goober5000 Date: Wed, 6 May 2026 00:22:11 -0400 Subject: [PATCH] Validate LZ41 footer fields before decompression The decompressor read numOffsets, blockSize, and uncompressedSize from the compressed file footer with no validation, allowing a crafted LZ41 file to cause an OOM crash (numOffsets set to INT_MAX allocates ~8 GB), a DivideByZeroException (blockSize = 0), or an IndexOutOfRangeException (numOffsets smaller than the number of blocks the data requires). Adds four guards in LZ41_Stream_Decompress: - numOffsets must be > 0 and fit within the file (prevents OOM and integer overflow in the offset table seek calculation) - footer-supplied uncompressedSize must be > 0 - blockSize must be > 0 (prevents divide-by-zero) - endBlock must be < numOffsets before the decode loop (prevents the offsets[currentBlock+1] out-of-bounds access on the last iteration) Co-Authored-By: Claude Sonnet 4.6 --- IonKiwi.lz4/LZ4RawUtility.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/IonKiwi.lz4/LZ4RawUtility.cs b/IonKiwi.lz4/LZ4RawUtility.cs index e3b6dad1..e5a9219c 100644 --- a/IonKiwi.lz4/LZ4RawUtility.cs +++ b/IonKiwi.lz4/LZ4RawUtility.cs @@ -293,15 +293,23 @@ public static unsafe int LZ41_Stream_Decompress(Stream inputStream, Stream outpu /* Num Offsets */ inputStream.Position = initialPosition + compressedFileSize.Value - 12; int numOffsets = br.ReadInt32(); + if (numOffsets <= 0 || numOffsets > (compressedFileSize.Value - 12) / 4) + throw new Exception($"Invalid numOffsets in LZ41 footer: {numOffsets}"); /* File Size */ - if(!length.HasValue) + if(!length.HasValue) + { length = br.ReadInt32(); + if (length <= 0) + throw new Exception($"Invalid uncompressed size in LZ41 footer: {length}"); + } else inputStream.Position += 4; /* Block Size */ int blockSize = br.ReadInt32(); + if (blockSize <= 0) + throw new Exception($"Invalid block size in LZ41 footer: {blockSize}"); /* Read the offsets tail */ inputStream.Position = initialPosition + (compressedFileSize.Value - 12 - (numOffsets * 4)); @@ -315,6 +323,9 @@ public static unsafe int LZ41_Stream_Decompress(Stream inputStream, Stream outpu int currentBlock = offset.Value / blockSize; int endBlock = ((offset.Value + length.Value - 1) / blockSize) + 1; + if (currentBlock < 0 || endBlock >= numOffsets) + throw new Exception($"Requested range exceeds block table (blocks {currentBlock}–{endBlock}, numOffsets={numOffsets})"); + /* Seek to the first block to read */ inputStream.Position = initialPosition + offsets[currentBlock];