From a01ba546c448ad44f133ed4870b8418d18d1e33b Mon Sep 17 00:00:00 2001 From: CoraleSoft <82213665+Coralesoft@users.noreply.github.com> Date: Tue, 4 Aug 2026 21:02:27 +1200 Subject: [PATCH] Reject invalid DEFLATE HLIT values (GH #1368) Inflator::DecodeHeader() accepted HLIT values 30 and 31, although RFC 1951 limits the field to 0 through 29. With HLIT and HDIST both set to 31, the declared code-length total reaches 320 entries against a 318-entry table. The repeat-run guard checked only against that declared total, allowing an out-of-bounds write. HDIST values 30 and 31 remain valid. RFC 1951 permits all 32 distance code lengths, and CreateFixedDistanceDecoder() initialises all 32 entries. Reject invalid HLIT values before filling the table and bound repeat runs against both the declared total and the table capacity. --- zinflate.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/zinflate.cpp b/zinflate.cpp index d9b36c0e1..86a09c45a 100644 --- a/zinflate.cpp +++ b/zinflate.cpp @@ -403,7 +403,17 @@ void Inflator::DecodeHeader() unsigned int hclen = m_reader.GetBits(4); unsigned int i = 0; + // RFC 1951 allows HLIT values 0 to 29, encoding 257 to 286 literal/length + // codes. Values 30 and 31 are invalid and can overrun codeLengths below. + if (hlit > 29) + throw BadBlockErr(); + + const unsigned int literalCount = hlit + 257; + const unsigned int distanceCount = hdist + 1; + const unsigned int codeLengthCount = literalCount + distanceCount; + FixedSizeSecBlock codeLengths; + CRYPTOPP_ASSERT(codeLengthCount <= codeLengths.size()); static const unsigned int border[] = { // Order of the bit length code lengths 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; std::fill(codeLengths.begin(), codeLengths+19, 0); @@ -418,7 +428,7 @@ void Inflator::DecodeHeader() bool result = false; unsigned int k=0, count=0, repeater=0; HuffmanDecoder codeLengthDecoder(codeLengths, 19); - for (i=0; i < hlit+257+hdist+1; ) + for (i=0; i < codeLengthCount; ) { k = 0, count = 0, repeater = 0; result = codeLengthDecoder.Decode(m_reader, k); @@ -452,19 +462,21 @@ void Inflator::DecodeHeader() repeater = 0; break; } - if (i + count > hlit+257+hdist+1) + if (count > codeLengthCount - i || + i > codeLengths.size() || + count > codeLengths.size() - i) throw BadBlockErr(); std::fill(codeLengths + i, codeLengths + i + count, repeater); i += count; } - m_dynamicLiteralDecoder.Initialize(codeLengths, hlit+257); - if (hdist == 0 && codeLengths[hlit+257] == 0) + m_dynamicLiteralDecoder.Initialize(codeLengths, literalCount); + if (hdist == 0 && codeLengths[literalCount] == 0) { if (hlit != 0) // a single zero distance code length means all literals throw BadBlockErr(); } else - m_dynamicDistanceDecoder.Initialize(codeLengths+hlit+257, hdist+1); + m_dynamicDistanceDecoder.Initialize(codeLengths+literalCount, distanceCount); m_nextDecode = LITERAL; } catch (HuffmanDecoder::Err &)