Skip to content

Commit

Permalink
Fix out of bounds read due to negative length
Browse files Browse the repository at this point in the history
If the computed literal or match length was greater than
Integer.MAX_VALUE, the value would overflow to a negative
and cause a read before the beginning of the buffer.
  • Loading branch information
martint committed Feb 9, 2024
1 parent 99de82a commit 7cef2d0
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/main/java/io/airlift/compress/lz4/Lz4RawDecompressor.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public static int decompress(
}
while (value == 255 && input < inputLimit - 15);
}
if (literalLength < 0) {
throw new MalformedInputException(input - inputAddress);
}

// copy literal
long literalEnd = input + literalLength;
Expand Down Expand Up @@ -127,6 +130,9 @@ public static int decompress(
while (value == 255);
}
matchLength += MIN_MATCH; // implicit length from initial 4-byte match in encoder
if (matchLength < 0) {
throw new MalformedInputException(input - inputAddress);
}

long matchOutputLimit = output + matchLength;

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/io/airlift/compress/lzo/LzoRawDecompressor.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ else if ((command & 0b1100_0000) != 0) {
}
firstCommand = false;

if (matchLength < 0) {
throw new MalformedInputException(input - inputAddress);
}

// copy match
if (matchLength != 0) {
// lzo encodes match offset minus one
Expand Down Expand Up @@ -316,6 +320,9 @@ else if ((command & 0b1100_0000) != 0) {
}

// copy literal
if (literalLength < 0) {
throw new MalformedInputException(input - inputAddress);
}
long literalOutputLimit = output + literalLength;
if (literalOutputLimit > fastOutputLimit || input + literalLength > inputLimit - SIZE_OF_LONG) {
if (literalOutputLimit > outputLimit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ private static int uncompressAll(

if ((opCode & 0x3) == LITERAL) {
int literalLength = length + trailer;
if (literalLength < 0) {
throw new MalformedInputException(input - inputAddress);
}

// copy literal
long literalOutputLimit = output + literalLength;
Expand Down
22 changes: 22 additions & 0 deletions src/test/java/io/airlift/compress/snappy/TestSnappy.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
import io.airlift.compress.AbstractTestCompression;
import io.airlift.compress.Compressor;
import io.airlift.compress.Decompressor;
import io.airlift.compress.MalformedInputException;
import io.airlift.compress.thirdparty.XerialSnappyCompressor;
import io.airlift.compress.thirdparty.XerialSnappyDecompressor;
import org.testng.annotations.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class TestSnappy
extends AbstractTestCompression
Expand Down Expand Up @@ -45,4 +49,22 @@ protected Decompressor getVerifyDecompressor()
{
return new XerialSnappyDecompressor();
}

@Test
public void testInvalidLiteralLength()
{
byte[] data = {
// Encoded uncompressed length 1024
-128, 8,
// op-code
(byte) 252,
// Trailer value Integer.MAX_VALUE
(byte) 0b1111_1111, (byte) 0b1111_1111, (byte) 0b1111_1111, (byte) 0b0111_1111,
// Some arbitrary data
0, 0, 0, 0, 0, 0, 0, 0
};

assertThatThrownBy(() -> new SnappyDecompressor().decompress(data, 0, data.length, new byte[1024], 0, 1024))
.isInstanceOf(MalformedInputException.class);
}
}

0 comments on commit 7cef2d0

Please sign in to comment.