Files
python-PyPDF2/CVE-2025-55197.patch
Simon Lees dc93183e5e I did not manage to run the testsuite (many tests needing internet), but the tests added by the patches were fine
- Add security patches:
  * CVE-2025-55197.patch (bsc#1248089)
  * CVE-2026-27024.patch (bsc#1258691)
  * CVE-2026-27025.patch (bsc#1258692)
  * CVE-2026-27026.patch (bsc#1258693)

OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-PyPDF2?expand=0&rev=26
2026-02-23 11:32:38 +00:00

119 lines
4.4 KiB
Diff

From bb3a69030fde7da545229438ff327b8c971cef49 Mon Sep 17 00:00:00 2001
From: Stefan <96178532+stefan6419846@users.noreply.github.com>
Date: Mon, 11 Aug 2025 16:10:25 +0200
Subject: [PATCH] SEC: Limit decompressed size for FlateDecode filter (#3430)
Closes #3429.
---
PyPDF2/_reader.py | 10 ++++-
PyPDF2/errors.py | 4 ++
PyPDF2/filters.py | 89 +++++++++++++++++++++++++---------------
tests/example_files.yaml | 2 +
tests/test_filters.py | 41 ++++++++++++++----
tests/test_reader.py | 15 +++++++
6 files changed, 119 insertions(+), 42 deletions(-)
Index: PyPDF2-2.11.1/PyPDF2/_reader.py
===================================================================
--- PyPDF2-2.11.1.orig/PyPDF2/_reader.py
+++ PyPDF2-2.11.1/PyPDF2/_reader.py
@@ -1681,15 +1681,20 @@ class PdfReader:
xrefstream = cast(ContentStream, read_object(stream, self))
assert cast(str, xrefstream["/Type"]) == "/XRef"
self.cache_indirect_object(generation, idnum, xrefstream)
- stream_data = BytesIO(b_(xrefstream.get_data()))
+
# Index pairs specify the subsections in the dictionary. If
# none create one subsection that spans everything.
- idx_pairs = xrefstream.get("/Index", [0, xrefstream.get("/Size")])
+ if "/Size" not in xrefstream:
+ # According to table 17 of the PDF 2.0 specification, this key is required.
+ raise PdfReadError(f"Size missing from XRef stream {xrefstream!r}!")
+ idx_pairs = xrefstream.get("/Index", [0, xrefstream["/Size"]])
entry_sizes = cast(Dict[Any, Any], xrefstream.get("/W"))
assert len(entry_sizes) >= 3
if self.strict and len(entry_sizes) > 3:
raise PdfReadError(f"Too many entry sizes: {entry_sizes}")
+ stream_data = BytesIO(xrefstream.get_data())
+
def get_entry(i: int) -> Union[int, Tuple[int, ...]]:
# Reads the correct number of bytes for each entry. See the
# discussion of the W parameter in PDF spec table 17.
Index: PyPDF2-2.11.1/PyPDF2/errors.py
===================================================================
--- PyPDF2-2.11.1.orig/PyPDF2/errors.py
+++ PyPDF2-2.11.1/PyPDF2/errors.py
@@ -46,3 +46,7 @@ class EmptyFileError(PdfReadError):
STREAM_TRUNCATED_PREMATURELY = "Stream has ended unexpectedly"
+
+
+class LimitReachedError(PyPdfError):
+ """Raised when a limit is reached."""
Index: PyPDF2-2.11.1/PyPDF2/filters.py
===================================================================
--- PyPDF2-2.11.1.orig/PyPDF2/filters.py
+++ PyPDF2-2.11.1/PyPDF2/filters.py
@@ -58,12 +58,12 @@ from .constants import GraphicsStatePara
from .constants import ImageAttributes as IA
from .constants import LzwFilterParameters as LZW
from .constants import StreamAttributes as SA
-from .errors import PdfReadError, PdfStreamError
+from .errors import LimitReachedError, PdfReadError, PdfStreamError
def decompress(data: bytes) -> bytes:
try:
- return zlib.decompress(data)
+ return _decompress_with_limit(data)
except zlib.error:
d = zlib.decompressobj(zlib.MAX_WBITS | 32)
result_str = b""
@@ -74,6 +74,18 @@ def decompress(data: bytes) -> bytes:
pass
return result_str
+ZLIB_MAX_OUTPUT_LENGTH = 75_000_000
+
+
+def _decompress_with_limit(data: bytes) -> bytes:
+ decompressor = zlib.decompressobj()
+ result = decompressor.decompress(data, max_length=ZLIB_MAX_OUTPUT_LENGTH)
+ if decompressor.unconsumed_tail:
+ raise LimitReachedError(
+ f"Limit reached while decompressing. {len(decompressor.unconsumed_tail)} bytes remaining."
+ )
+ return result
+
class FlateDecode:
@staticmethod
Index: PyPDF2-2.11.1/tests/test_filters.py
===================================================================
--- PyPDF2-2.11.1.orig/tests/test_filters.py
+++ PyPDF2-2.11.1/tests/test_filters.py
@@ -1,4 +1,5 @@
import string
+import zlib
from io import BytesIO
from itertools import product as cartesian_product
from unittest.mock import patch
@@ -6,13 +7,14 @@ from unittest.mock import patch
import pytest
from PyPDF2 import PdfReader
-from PyPDF2.errors import PdfReadError, PdfStreamError
+from PyPDF2.errors import LimitReachedError, PdfReadError, PdfStreamError
from PyPDF2.filters import (
ASCII85Decode,
ASCIIHexDecode,
CCITParameters,
CCITTFaxDecode,
FlateDecode,
+ decompress,
)
from PyPDF2.generic import ArrayObject, DictionaryObject, NumberObject