Skip to content

Commit adf3c6a

Browse files
committed
ORC-2190: [C++] Reject compressed chunk length exceeding block size in C++ reader
### What changes were proposed in this pull request? This PR makes the ORC C++ reader reject a compressed chunk whose length exceeds the configured compression block size, matching the Java reader. https://github.com/apache/orc/blob/5d3cf1318b58416719e89169ae9d56f758311f7e/java/core/src/java/org/apache/orc/impl/InStream.java#L504-L507 ### Why are the changes needed? The Java reader already performs this check in `InStream.CompressedStream.readHeader`, but the C++ reader was missing it. This is a defense-in-depth hardening (not a CVE): the chunk length is already bounded to ~8MB by the 3-byte header, but the spec-mandated first check was absent on the C++ side. Well-formed files are unaffected. ### How was this patch tested? Pass the CIs with the newly added test case. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Claude Fable 5 Closes #2671 from dongjoon-hyun/ORC-2190. Authored-by: Dongjoon Hyun <dongjoon@apache.org> Signed-off-by: Dongjoon Hyun <dongjoon@apache.org> (cherry picked from commit 6015de5) Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
1 parent 8e3297a commit adf3c6a

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

c++/src/Compression.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ namespace orc {
419419
MemoryPool& pool;
420420
std::unique_ptr<SeekableInputStream> input;
421421

422+
// the configured compression block size, used to validate chunk lengths
423+
size_t blockSize;
424+
422425
// uncompressed output
423426
DataBuffer<char> outputDataBuffer;
424427

@@ -460,6 +463,7 @@ namespace orc {
460463
ReaderMetrics* metrics)
461464
: pool(pool),
462465
input(std::move(inStream)),
466+
blockSize(bufferSize),
463467
outputDataBuffer(pool, bufferSize),
464468
state(DECOMPRESS_HEADER),
465469
outputBufferStart(nullptr),
@@ -518,6 +522,12 @@ namespace orc {
518522
state = DECOMPRESS_START;
519523
}
520524
remainingLength = header >> 1;
525+
if (state == DECOMPRESS_START && remainingLength > blockSize) {
526+
std::ostringstream ss;
527+
ss << "Buffer size too small. size = " << blockSize << " needed = " << remainingLength
528+
<< " in " << getName();
529+
throw ParseError(ss.str());
530+
}
521531
} else {
522532
remainingLength = 0;
523533
}

c++/test/TestDecompression.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,19 @@ namespace orc {
569569
EXPECT_EQ(16, static_cast<const char*>(ptr)[2]);
570570
}
571571

572+
TEST(Zlib, testChunkLengthExceedsBlockSize) {
573+
// Craft a compressed chunk header whose chunkLength (100) exceeds the
574+
// configured block size (5). header = chunkLength << 1 = 200 = 0xC8.
575+
const unsigned char buffer[] = {0xc8, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5};
576+
std::unique_ptr<SeekableInputStream> result = createDecompressor(
577+
CompressionKind_ZLIB,
578+
std::make_unique<SeekableArrayInputStream>(buffer, ARRAY_SIZE(buffer), 5), 5,
579+
*getDefaultPool(), getDefaultReaderMetrics());
580+
const void* ptr;
581+
int length;
582+
EXPECT_THROW(result->Next(&ptr, &length), ParseError);
583+
}
584+
572585
TEST(Zlib, testInflate) {
573586
const unsigned char buffer[] = {0xe, 0x0, 0x0, 0x63, 0x60, 0x64, 0x62, 0xc0, 0x8d, 0x0};
574587
std::unique_ptr<SeekableInputStream> result =

0 commit comments

Comments
 (0)