diff --git a/src/main/java/org/xerial/snappy/SnappyFramedInputStream.java b/src/main/java/org/xerial/snappy/SnappyFramedInputStream.java index 8e975735..04a8a311 100644 --- a/src/main/java/org/xerial/snappy/SnappyFramedInputStream.java +++ b/src/main/java/org/xerial/snappy/SnappyFramedInputStream.java @@ -551,6 +551,11 @@ private boolean ensureBuffer() input.position(frameData.offset); final int uncompressedLength = Snappy.uncompressedLength(input); + if (uncompressedLength > SnappyInputStream.MAX_CHUNK_SIZE) { + throw new SnappyIOException(SnappyErrorCode.INVALID_CHUNK_SIZE, String.format( + "declared uncompressed length %,d exceeds the maximum chunk size of %,d bytes", + uncompressedLength, SnappyInputStream.MAX_CHUNK_SIZE)); + } if (uncompressedLength > uncompressedDirect.capacity()) { bufferPool.releaseDirect(uncompressedDirect); diff --git a/src/test/java/org/xerial/snappy/SnappyFramedStreamTest.java b/src/test/java/org/xerial/snappy/SnappyFramedStreamTest.java index e428bf98..292baf0e 100644 --- a/src/test/java/org/xerial/snappy/SnappyFramedStreamTest.java +++ b/src/test/java/org/xerial/snappy/SnappyFramedStreamTest.java @@ -126,6 +126,32 @@ public void testShortBlockHeader() uncompressBlock(new byte[] {0}); } + @Test + public void testDeclaredUncompressedLengthExceedsMaxBlockSize() + throws Exception + { + // Snappy block declaring 1 GiB uncompressed (varint 0x80 0x80 0x80 0x80 0x04), + // above SnappyInputStream.MAX_CHUNK_SIZE, followed by a single literal byte. + byte[] snappyBlock = {(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, 0x04, 0x00, 0x61}; + int chunkLength = 4 + snappyBlock.length; + byte[] chunk = new byte[4 + 4 + snappyBlock.length]; + chunk[0] = COMPRESSED_DATA_FLAG; + chunk[1] = (byte) (chunkLength & 0xFF); + chunk[2] = (byte) ((chunkLength >>> 8) & 0xFF); + chunk[3] = (byte) ((chunkLength >>> 16) & 0xFF); + // masked crc32c (bytes 4..7) left as zero: the declared length must be + // rejected before the checksum is ever reached + System.arraycopy(snappyBlock, 0, chunk, 8, snappyBlock.length); + + try { + uncompressBlock(chunk); + fail("expected SnappyIOException"); + } + catch (SnappyIOException e) { + assertEquals(SnappyErrorCode.INVALID_CHUNK_SIZE, e.getErrorCode()); + } + } + @Test(expected = EOFException.class) public void testShortBlockData() throws Exception