Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: python-z...@packages.debian.org
Control: affects -1 + src:python-zipp
User: release.debian....@packages.debian.org
Usertags: pu

Fixes one minor security issue, includes a backport of
the test case. Debdiff below.

Cheers,
        Moritz

diff -Nru python-zipp-1.0.0/debian/changelog python-zipp-1.0.0/debian/changelog
--- python-zipp-1.0.0/debian/changelog  2022-12-21 23:06:15.000000000 +0100
+++ python-zipp-1.0.0/debian/changelog  2025-05-18 00:34:40.000000000 +0200
@@ -1,3 +1,9 @@
+python-zipp (1.0.0-6+deb12u1) bookworm; urgency=medium
+
+  * CVE-2024-5569
+
+ -- Moritz Mühlenhoff <j...@debian.org>  Sun, 18 May 2025 00:34:40 +0200
+
 python-zipp (1.0.0-6) unstable; urgency=medium
 
   * Team upload.
diff -Nru python-zipp-1.0.0/debian/patches/CVE-2024-5569.patch 
python-zipp-1.0.0/debian/patches/CVE-2024-5569.patch
--- python-zipp-1.0.0/debian/patches/CVE-2024-5569.patch        1970-01-01 
01:00:00.000000000 +0100
+++ python-zipp-1.0.0/debian/patches/CVE-2024-5569.patch        2025-05-18 
00:34:25.000000000 +0200
@@ -0,0 +1,109 @@
+
+
+--- python-zipp-1.0.0.orig/test_zipp.py
++++ python-zipp-1.0.0/test_zipp.py
+@@ -196,3 +196,20 @@ class TestPath(unittest.TestCase):
+         for alpharep in self.zipfile_alpharep():
+             root = zipp.Path(alpharep)
+             assert (root / 'missing dir/').parent.at == ''
++
++    def test_malformed_paths(self):
++        """
++        Path should handle malformed paths.
++        """
++        data = io.BytesIO()
++        zf = zipfile.ZipFile(data, "w")
++        zf.writestr("/one-slash.txt", b"content")
++        zf.writestr("//two-slash.txt", b"content")
++        zf.writestr("../parent.txt", b"content")
++        zf.filename = ''
++        root = zipp.Path(zf)
++        assert list(map(str, root.iterdir())) == [
++            'one-slash.txt',
++            'two-slash.txt',
++            'parent.txt',
++        ]
+\ No newline at end of file
+--- python-zipp-1.0.0.orig/zipp.py
++++ python-zipp-1.0.0/zipp.py
+@@ -8,6 +8,7 @@ import posixpath
+ import zipfile
+ import functools
+ import itertools
++import re
+ 
+ import more_itertools
+ 
+@@ -54,7 +55,63 @@ def _ancestry(path):
+         yield path
+         path, tail = posixpath.split(path)
+ 
++class SanitizedNames:
++    """
++    ZipFile mix-in to ensure names are sanitized.
++    """
++
++    def namelist(self):
++        return list(map(self._sanitize, super().namelist()))
++
++    @staticmethod
++    def _sanitize(name):
++        r"""
++        Ensure a relative path with posix separators and no dot names.
++        Modeled after
++        
https://github.com/python/cpython/blob/bcc1be39cb1d04ad9fc0bd1b9193d3972835a57c/Lib/zipfile/__init__.py#L1799-L1813
++        but provides consistent cross-platform behavior.
++        >>> san = SanitizedNames._sanitize
++        >>> san('/foo/bar')
++        'foo/bar'
++        >>> san('//foo.txt')
++        'foo.txt'
++        >>> san('foo/.././bar.txt')
++        'foo/bar.txt'
++        >>> san('foo../.bar.txt')
++        'foo../.bar.txt'
++        >>> san('\\foo\\bar.txt')
++        'foo/bar.txt'
++        >>> san('D:\\foo.txt')
++        'D/foo.txt'
++        >>> san('\\\\server\\share\\file.txt')
++        'server/share/file.txt'
++        >>> san('\\\\?\\GLOBALROOT\\Volume3')
++        '?/GLOBALROOT/Volume3'
++        >>> san('\\\\.\\PhysicalDrive1\\root')
++        'PhysicalDrive1/root'
++        Retain any trailing slash.
++        >>> san('abc/')
++        'abc/'
++        Raises a ValueError if the result is empty.
++        >>> san('../..')
++        Traceback (most recent call last):
++        ...
++        ValueError: Empty filename
++        """
++
++        def allowed(part):
++            return part and part not in {'..', '.'}
+ 
++        # Remove the drive letter.
++        # Don't use ntpath.splitdrive, because that also strips UNC paths
++        bare = re.sub('^([A-Z]):', r'\1', name, flags=re.IGNORECASE)
++        clean = bare.replace('\\', '/')
++        parts = clean.split('/')
++        joined = '/'.join(filter(allowed, parts))
++        if not joined:
++            raise ValueError("Empty filename")
++        return joined + '/' * name.endswith('/')
++    
+ class Path:
+     """
+     A pathlib-compatible interface for zip files.
+@@ -214,7 +271,7 @@ class Path:
+         return self._next(parent_at)
+ 
+     def _names(self):
+-        return self._add_implied_dirs(self.root.namelist())
++        return self._add_implied_dirs(list(map(SanitizedNames._sanitize, 
self.root.namelist())))
+ 
+     if sys.version_info < (3,):
+         __div__ = __truediv__
diff -Nru python-zipp-1.0.0/debian/patches/series 
python-zipp-1.0.0/debian/patches/series
--- python-zipp-1.0.0/debian/patches/series     1970-01-01 01:00:00.000000000 
+0100
+++ python-zipp-1.0.0/debian/patches/series     2025-05-18 00:34:20.000000000 
+0200
@@ -0,0 +1 @@
+CVE-2024-5569.patch

Reply via email to