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

tballison pushed a commit to branch branch_3x
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/branch_3x by this push:
     new fa1f055a88 TIKA-4761 - improve sevenz memory limits
fa1f055a88 is described below

commit fa1f055a88b147e1cd29e01618796a30814367d0
Author: tallison <[email protected]>
AuthorDate: Thu Jun 25 11:50:40 2026 -0400

    TIKA-4761 - improve sevenz memory limits
---
 .../org/apache/tika/parser/pkg/PackageParser.java  | 27 +++++++++++++++++++++-
 .../apache/tika/parser/pkg/Seven7ParserTest.java   | 18 +++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java
index f596828fa8..8db2714264 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java
@@ -38,6 +38,7 @@ import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.zip.ZipEntry;
 
+import org.apache.commons.compress.MemoryLimitException;
 import org.apache.commons.compress.PasswordRequiredException;
 import org.apache.commons.compress.archivers.ArchiveEntry;
 import org.apache.commons.compress.archivers.ArchiveException;
@@ -65,6 +66,7 @@ import org.apache.tika.config.Field;
 import org.apache.tika.detect.EncodingDetector;
 import org.apache.tika.exception.EncryptedDocumentException;
 import org.apache.tika.exception.TikaException;
+import org.apache.tika.exception.TikaMemoryLimitException;
 import org.apache.tika.extractor.EmbeddedDocumentExtractor;
 import org.apache.tika.extractor.EmbeddedDocumentUtil;
 import org.apache.tika.io.TemporaryResources;
@@ -235,6 +237,7 @@ public class PackageParser extends 
AbstractEncodingDetectorParser {
     }
 
     private boolean detectCharsetsInEntryNames = true;
+    private int memoryLimitInKb = 100000;
 
     public PackageParser() {
         super();
@@ -312,7 +315,9 @@ public class PackageParser extends 
AbstractEncodingDetectorParser {
 
                 SevenZFile sevenz;
                 try {
-                    SevenZFile.Builder builder = new 
SevenZFile.Builder().setFile(tstream.getFile());
+                    // Use setMaxMemoryLimitKiB (direct KiB); 
setMaxMemoryLimitKb divides by 1024.
+                    SevenZFile.Builder builder = new 
SevenZFile.Builder().setFile(tstream.getFile())
+                            .setMaxMemoryLimitKiB(memoryLimitInKb);
                     if (password == null) {
                         sevenz = builder.get();
                     } else {
@@ -320,6 +325,8 @@ public class PackageParser extends 
AbstractEncodingDetectorParser {
                     }
                 } catch (PasswordRequiredException e) {
                     throw new EncryptedDocumentException(e);
+                } catch (MemoryLimitException e) {
+                    throw new TikaMemoryLimitException(e.getMessage());
                 }
 
                 // Pending a fix for COMPRESS-269 / TIKA-1525, this bit is a 
little nasty
@@ -359,6 +366,8 @@ public class PackageParser extends 
AbstractEncodingDetectorParser {
                         true);
                 parseEntries(ais, metadata, extractor, xhtml, true, entryCnt);
             }
+        } catch (MemoryLimitException e) {
+            throw new TikaMemoryLimitException(e.getMessage());
         } finally {
             ais.close();
             tmp.close();
@@ -662,4 +671,20 @@ public class PackageParser extends 
AbstractEncodingDetectorParser {
     public boolean isDetectCharsetsInEntryNames() {
         return detectCharsetsInEntryNames;
     }
+
+    /**
+     * Maximum memory in kibibytes to allow for LZMA/LZMA2 dictionary 
allocation when parsing
+     * 7z archives. A tiny crafted 7z can declare a multi-GiB dictionary in a 
single header byte;
+     * this caps it so commons-compress throws a MemoryLimitException instead 
of OOMing the parser.
+     *
+     * @param memoryLimitInKb
+     */
+    @Field
+    public void setMemoryLimitInKb(int memoryLimitInKb) {
+        this.memoryLimitInKb = memoryLimitInKb;
+    }
+
+    public int getMemoryLimitInKb() {
+        return memoryLimitInKb;
+    }
 }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/Seven7ParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/Seven7ParserTest.java
index 1afce70fbd..d53a93e966 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/Seven7ParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/Seven7ParserTest.java
@@ -19,6 +19,7 @@ package org.apache.tika.parser.pkg;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.InputStream;
@@ -26,7 +27,9 @@ import java.io.InputStream;
 import org.junit.jupiter.api.Test;
 import org.xml.sax.ContentHandler;
 
+import org.apache.tika.exception.TikaMemoryLimitException;
 import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.ParseContext;
 import org.apache.tika.sax.BodyContentHandler;
 
 /**
@@ -72,4 +75,19 @@ public class Seven7ParserTest extends AbstractPkgTest {
             assertTrue(mod.startsWith("20"), "Modified at " + mod);
         }
     }
+
+    /**
+     * A 7z whose declared LZMA2 dictionary exceeds the configured limit must 
fail with a
+     * {@link TikaMemoryLimitException} rather than eagerly allocating the 
dictionary (which a
+     * tiny crafted 7z can drive to multiple GiB, OOMing the parser).
+     */
+    @Test
+    public void testMemoryLimit() throws Exception {
+        PackageParser parser = new PackageParser();
+        parser.setMemoryLimitInKb(1); // 1 KiB, smaller than any real LZMA2 
dictionary
+        try (InputStream stream = 
getResourceAsStream("/test-documents/test-documents.7z")) {
+            assertThrows(TikaMemoryLimitException.class, () -> 
parser.parse(stream,
+                    new BodyContentHandler(), new Metadata(), new 
ParseContext()));
+        }
+    }
 }

Reply via email to