You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@orc.apache.org by do...@apache.org on 2026/05/14 18:24:56 UTC

(orc) branch main updated: ORC-2165: [C++] Fix bounds check for LZO stop command trailer

This is an automated email from the ASF dual-hosted git repository.

dongjoon-hyun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/orc.git


The following commit(s) were added to refs/heads/main by this push:
     new 473ac95ed ORC-2165: [C++] Fix bounds check for LZO stop command trailer
473ac95ed is described below

commit 473ac95ed62cf254e3fff25af835c42f9059fad1
Author: ffacs <ff...@gmail.com>
AuthorDate: Thu May 14 11:24:48 2026 -0700

    ORC-2165: [C++] Fix bounds check for LZO stop command trailer
    
    ### What changes were proposed in this pull request?
    
      This PR fixes the C++ LZO decompressor stop command trailer validation. It now checks that two trailer bytes are available before reading them, and validates the trailer bytes
      explicitly.
    
      A regression test was added for truncated LZO stop command trailers.
    
    ### Why are the changes needed?
    
      Malformed LZO-compressed ORC input can end immediately after the LZO stop command, or with only one trailer byte remaining. The previous validation could read two bytes before safely
      confirming that two bytes were available, causing an out-of-bounds read on truncated input.
    
      The new check makes truncated LZO input fail cleanly with `ParseError`.
    
    ### How was this patch tested?
    
      Ran:
    
    ```bash
      cmake --build build --target orc-test -j 8
      build/c++/test/orc-test '--gtest_filter=TestDecompression.testLzo*'
    ```
      The LZO decompression tests passed.
    
      Also ran a minimal AddressSanitizer harness against truncated LZO stop command inputs and confirmed there was no ASan report.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
      Yes. Generated with OpenAI Codex.
    
    Closes #2621 from ffacs/ORC-2165-lzo-stop-trailer.
    
    Authored-by: ffacs <ff...@gmail.com>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 c++/src/LzoDecompressor.cc    |  5 ++++-
 c++/test/TestDecompression.cc | 30 ++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/c++/src/LzoDecompressor.cc b/c++/src/LzoDecompressor.cc
index 68e25425c..cc03adb3d 100644
--- a/c++/src/LzoDecompressor.cc
+++ b/c++/src/LzoDecompressor.cc
@@ -365,7 +365,10 @@ namespace orc {
         lastLiteralLength = literalLength;
       }
 
-      if (input + SIZE_OF_SHORT > inputLimit && *reinterpret_cast<const int16_t*>(input) != 0) {
+      if (input + SIZE_OF_SHORT > inputLimit) {
+        throw MalformedInputException(input - inputAddress);
+      }
+      if (input[0] != 0 || input[1] != 0) {
         throw MalformedInputException(input - inputAddress);
       }
       input += SIZE_OF_SHORT;
diff --git a/c++/test/TestDecompression.cc b/c++/test/TestDecompression.cc
index ecf0d3d5b..08ef50ab3 100644
--- a/c++/test/TestDecompression.cc
+++ b/c++/test/TestDecompression.cc
@@ -357,6 +357,36 @@ namespace orc {
     ASSERT_TRUE(!result->Next(&ptr, &length));
   }
 
+  TEST_F(TestDecompression, testLzoTruncatedStopCommand) {
+    const unsigned char missingTrailer[] = {0x02, 0x00, 0x00, 0x11};
+    std::unique_ptr<SeekableInputStream> missingTrailerResult = createDecompressor(
+        CompressionKind_LZO,
+        std::make_unique<SeekableArrayInputStream>(missingTrailer, ARRAY_SIZE(missingTrailer)),
+        128 * 1024, *getDefaultPool(), getDefaultReaderMetrics());
+
+    const void* ptr;
+    int length;
+    EXPECT_THROW(
+        {
+          bool next = missingTrailerResult->Next(&ptr, &length);
+          static_cast<void>(next);
+        },
+        ParseError);
+
+    const unsigned char shortTrailer[] = {0x04, 0x00, 0x00, 0x11, 0x00};
+    std::unique_ptr<SeekableInputStream> shortTrailerResult = createDecompressor(
+        CompressionKind_LZO,
+        std::make_unique<SeekableArrayInputStream>(shortTrailer, ARRAY_SIZE(shortTrailer)),
+        128 * 1024, *getDefaultPool(), getDefaultReaderMetrics());
+
+    EXPECT_THROW(
+        {
+          bool next = shortTrailerResult->Next(&ptr, &length);
+          static_cast<void>(next);
+        },
+        ParseError);
+  }
+
   TEST_F(TestDecompression, testLzoLong) {
     // set up a framed lzo buffer with 100,000 'a'
     unsigned char buffer[482];