Skip to content

Commit

Permalink
ARROW-15502: [Java] Detect exceptional footer size in Arrow file reader
Browse files Browse the repository at this point in the history
When a malformed Arrow file containing an extremely large footer size (much larger than the file size) is fed to the ArrowFileReader, our implementation fails detect the problem, due to integer arithmetic overflow.

This will lead to extremely large memory allocation and eventually causing an OutOfMemoryError.

Closes apache#12296 from liyafan82/fly_0130_rd

Authored-by: liyafan82 <[email protected]>
Signed-off-by: liyafan82 <[email protected]>
  • Loading branch information
liyafan82 committed Feb 18, 2022
1 parent c54d7b9 commit f49547b
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ protected Schema readSchema() throws IOException {
throw new InvalidArrowFileException("missing Magic number " + Arrays.toString(buffer.array()));
}
int footerLength = MessageSerializer.bytesToInt(array);
if (footerLength <= 0 || footerLength + ArrowMagic.MAGIC_LENGTH * 2 + 4 > in.size()) {
if (footerLength <= 0 || footerLength + ArrowMagic.MAGIC_LENGTH * 2 + 4 > in.size() ||
footerLength > footerLengthOffset) {
throw new InvalidArrowFileException("invalid footer length: " + footerLength);
}
long footerOffset = footerLengthOffset - footerLength;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;

public class TestArrowReaderWriter {

Expand Down Expand Up @@ -879,4 +880,36 @@ public void testCustomMetaData() throws IOException {
}
}
}

/**
* This test case covers the case for which the footer size is extremely large
* (much larger than the file size).
* Due to integer overflow, our implementation fails detect the problem, which
* leads to extremely large memory allocation and eventually causing an OutOfMemoryError.
*/
@Test
public void testFileFooterSizeOverflow() {
// copy of org.apache.arrow.vector.ipc.ArrowMagic#MAGIC
final byte[] magicBytes = "ARROW1".getBytes(StandardCharsets.UTF_8);

// prepare input data
byte[] data = new byte[30];
System.arraycopy(magicBytes, 0, data, 0, ArrowMagic.MAGIC_LENGTH);
int footerLength = Integer.MAX_VALUE;
byte[] footerLengthBytes =
ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()).putInt(footerLength).array();
int footerOffset = data.length - ArrowMagic.MAGIC_LENGTH - 4;
System.arraycopy(footerLengthBytes, 0, data, footerOffset, 4);
System.arraycopy(magicBytes, 0, data, footerOffset + 4, ArrowMagic.MAGIC_LENGTH);

// test file reader
InvalidArrowFileException e = Assertions.assertThrows(InvalidArrowFileException.class, () -> {
try (SeekableReadChannel channel = new SeekableReadChannel(new ByteArrayReadableSeekableByteChannel(data));
ArrowFileReader reader = new ArrowFileReader(channel, allocator)) {
reader.getVectorSchemaRoot().getSchema();
}
});

assertEquals("invalid footer length: " + footerLength, e.getMessage());
}
}

0 comments on commit f49547b

Please sign in to comment.