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

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git


The following commit(s) were added to refs/heads/master by this push:
     new 3c50b8226 Reject short LZMA properties and oversized dictionary in 
LZMADecoder (#784)
3c50b8226 is described below

commit 3c50b8226b81ddca4d59d6af4fa8f1b7617b3a20
Author: KALI 834X <[email protected]>
AuthorDate: Mon Jul 13 22:36:14 2026 +0530

    Reject short LZMA properties and oversized dictionary in LZMADecoder (#784)
    
    * Reject short LZMA properties and oversized dictionary in LZMADecoder
    
    * Potential fix for pull request finding
    
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
    
    ---------
    
    Co-authored-by: Gary Gregory <[email protected]>
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
---
 .../compress/archivers/sevenz/LZMADecoder.java     | 14 ++++--
 .../archivers/sevenz/SevenZLZMADecoderTest.java    | 56 ++++++++++++++++++++++
 2 files changed, 65 insertions(+), 5 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java 
b/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java
index 893867d07..d56cc5176 100644
--- 
a/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java
+++ 
b/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java
@@ -47,9 +47,6 @@ InputStream decode(final String archiveName, final 
InputStream in, final long un
         }
         final byte propsByte = coder.properties[0];
         final int dictSize = getDictionarySize(coder);
-        if (dictSize > LZMAInputStream.DICT_SIZE_MAX) {
-            throw new ArchiveException("Dictionary larger than 4 GiB maximum 
size used in '%s'", archiveName);
-        }
         final int memoryUsageKiB = LZMAInputStream.getMemoryUsage(dictSize, 
propsByte);
         MemoryLimitException.checkKiB(memoryUsageKiB, maxMemoryLimitKiB);
         final LZMAInputStream lzmaIn = new LZMAInputStream(in, 
uncompressedLength, propsByte, dictSize);
@@ -63,8 +60,15 @@ OutputStream encode(final OutputStream out, final Object 
opts) throws IOExceptio
         return new FlushShieldFilterOutputStream(new LZMAOutputStream(out, 
getOptions(opts), false));
     }
 
-    private int getDictionarySize(final Coder coder) throws 
IllegalArgumentException {
-        return (int) ByteUtils.fromLittleEndian(coder.properties, 1, 4);
+    private int getDictionarySize(final Coder coder) throws ArchiveException {
+        if (coder.properties.length < 5) {
+            throw new ArchiveException("LZMA properties too short (expected 5 
bytes)");
+        }
+        final long dictionarySize = 
ByteUtils.fromLittleEndian(coder.properties, 1, 4);
+        if (dictionarySize > LZMAInputStream.DICT_SIZE_MAX) {
+            throw new ArchiveException("Dictionary larger than 4 GiB maximum 
size");
+        }
+        return (int) dictionarySize;
     }
 
     private LZMA2Options getOptions(final Object opts) throws IOException {
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZLZMADecoderTest.java
 
b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZLZMADecoderTest.java
new file mode 100644
index 000000000..ae6383317
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZLZMADecoderTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.compress.archivers.sevenz;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for class {@link LZMADecoder}.
+ *
+ * @see LZMADecoder
+ **/
+class SevenZLZMADecoderTest {
+
+    private static final byte VALID_PROPS_BYTE = 0x5d; // lc=3, lp=0, pb=2
+
+    @Test
+    void testDecodeRejectsOversizedDictionary() {
+        // 5 valid property bytes but a 4 GiB - 1 dictionary size; the value 
must not narrow to a negative int and slip past the cap
+        final byte[] properties = { VALID_PROPS_BYTE, (byte) 0xff, (byte) 
0xff, (byte) 0xff, (byte) 0xff };
+        final Coder coder = new Coder(null, 0, 0, properties);
+        assertThrows(ArchiveException.class,
+                () -> new LZMADecoder().decode("x", new 
ByteArrayInputStream(new byte[0]), 0, coder, null, Integer.MAX_VALUE));
+    }
+
+    @Test
+    void testDecodeRejectsShortProperties() throws IOException {
+        // LZMA properties are 5 bytes; a shorter field must not over-read the 
dictionary size bytes
+        final byte[] properties = { VALID_PROPS_BYTE };
+        final Coder coder = new Coder(null, 0, 0, properties);
+        assertThrows(ArchiveException.class,
+                () -> new LZMADecoder().decode("x", new 
ByteArrayInputStream(new byte[0]), 0, coder, null, Integer.MAX_VALUE));
+    }
+}

Reply via email to