pkgsrc-Changes archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
CVS commit: pkgsrc/lang/python314
Module Name:    pkgsrc
Committed By:   wiz
Date:           Sat Oct 11 10:14:06 UTC 2025
Modified Files:
        pkgsrc/lang/python314: Makefile distinfo options.mk
Added Files:
        pkgsrc/lang/python314/patches:
            patch-Lib_test_test__zipfile_test__core.py
            patch-Lib_zipfile_____init____.py
Log Message:
python314: fix zip vulnerability using upstream patch
Bump PKGREVISION.
While here, fix option name and some pkglint.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 pkgsrc/lang/python314/Makefile
cvs rdiff -u -r1.1 -r1.2 pkgsrc/lang/python314/distinfo \
    pkgsrc/lang/python314/options.mk
cvs rdiff -u -r0 -r1.1 \
    pkgsrc/lang/python314/patches/patch-Lib_test_test__zipfile_test__core.py \
    pkgsrc/lang/python314/patches/patch-Lib_zipfile_____init____.py
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: pkgsrc/lang/python314/Makefile
diff -u pkgsrc/lang/python314/Makefile:1.3 pkgsrc/lang/python314/Makefile:1.4
--- pkgsrc/lang/python314/Makefile:1.3  Fri Oct 10 13:57:52 2025
+++ pkgsrc/lang/python314/Makefile      Sat Oct 11 10:14:06 2025
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.3 2025/10/10 13:57:52 wiz Exp $
+# $NetBSD: Makefile,v 1.4 2025/10/11 10:14:06 wiz Exp $
 
 .include "dist.mk"
 
@@ -42,10 +42,10 @@ PTHREAD_OPTS+=      require
 .include "../../mk/bsd.prefs.mk"
 
 # NetBSD-8 curses has enough support for py-curses
-USE_CURSES=    getsyx update_panels wide
+USE_CURSES=            getsyx update_panels wide
 # But we build as ncurses still to get the full feature set easily
 .if ${OPSYS} == "NetBSD"
-FAKE_NCURSES=  yes
+FAKE_NCURSES=          yes
 ## Force use of libuuid
 CONFIGURE_ARGS+=       ac_cv_header_uuid_h=false
 .endif
@@ -197,6 +197,8 @@ setuptools-preinstall:
 
 # for testing
 ALLOW_NETWORK_ACCESS=  yes
+# test status as of 3.14.0
+# Total test files: run=499/491 failed=10 skipped=31 resource_denied=2 rerun=10
 
 .if ${OPSYS} == "Linux"
 .include "../../databases/gdbm_compat/buildlink3.mk"
Index: pkgsrc/lang/python314/distinfo
diff -u pkgsrc/lang/python314/distinfo:1.1 pkgsrc/lang/python314/distinfo:1.2
--- pkgsrc/lang/python314/distinfo:1.1  Wed Oct  8 07:13:08 2025
+++ pkgsrc/lang/python314/distinfo      Sat Oct 11 10:14:06 2025
@@ -1,4 +1,4 @@
-$NetBSD: distinfo,v 1.1 2025/10/08 07:13:08 adam Exp $
+$NetBSD: distinfo,v 1.2 2025/10/11 10:14:06 wiz Exp $
 
 BLAKE2s (Python-3.14.0.tar.xz) = 8b0bc589285d6bb131423b9cc89e5c322eaa4aaa77c3ae12216a16d9b5235064
 SHA512 (Python-3.14.0.tar.xz) = 46e9e205c3a084cba68bf7f267ab2fd0862a05430165e0eb713f2d6b3a1a4452f72f563de5de55caea824be9df56f66dd568f4814941667a9bb0954229772c53
@@ -6,6 +6,8 @@ Size (Python-3.14.0.tar.xz) = 23595844 b
 SHA1 (patch-Include_pymacro.h) = 7611315fefc305a48b4965f2f2b9bee53ae3d987
 SHA1 (patch-Lib_ctypes_util.py) = 3dec1b6b7a36e46cbfa0dfcd71c5e7fac9f60764
 SHA1 (patch-Lib_sysconfig_____init____.py) = 76a35b78b098978209f9bcc0e5357d439f281c6b
+SHA1 (patch-Lib_test_test__zipfile_test__core.py) = 6d487c732bf055ce83d61c2f994f1cc90d2b70b3
+SHA1 (patch-Lib_zipfile_____init____.py) = a2c5ec38abc88318938e0496fd49c2aab5dc782c
 SHA1 (patch-Makefile.pre.in) = 620fa538eaebdf4e374eff0ed475a87775fb0a29
 SHA1 (patch-Modules_faulthandler.c) = ca59c378d25bfc0769a7f5da887369d8c913e70c
 SHA1 (patch-Modules_readline.c) = 232f6ac43b5a0e87c915f13117bae91ef069a6c1
Index: pkgsrc/lang/python314/options.mk
diff -u pkgsrc/lang/python314/options.mk:1.1 pkgsrc/lang/python314/options.mk:1.2
--- pkgsrc/lang/python314/options.mk:1.1        Wed Oct  8 07:13:08 2025
+++ pkgsrc/lang/python314/options.mk    Sat Oct 11 10:14:06 2025
@@ -1,6 +1,6 @@
-# $NetBSD: options.mk,v 1.1 2025/10/08 07:13:08 adam Exp $
+# $NetBSD: options.mk,v 1.2 2025/10/11 10:14:06 wiz Exp $
 
-PKG_OPTIONS_VAR=       PKG_OPTIONS.python313
+PKG_OPTIONS_VAR=       PKG_OPTIONS.python314
 PKG_SUPPORTED_OPTIONS= dtrace pymalloc tkinter x11 readline
 PKG_SUGGESTED_OPTIONS= x11 readline
 
Added files:
Index: pkgsrc/lang/python314/patches/patch-Lib_test_test__zipfile_test__core.py
diff -u /dev/null pkgsrc/lang/python314/patches/patch-Lib_test_test__zipfile_test__core.py:1.1
--- /dev/null   Sat Oct 11 10:14:06 2025
+++ pkgsrc/lang/python314/patches/patch-Lib_test_test__zipfile_test__core.py    Sat Oct 11 10:14:06 2025
@@ -0,0 +1,162 @@
+$NetBSD: patch-Lib_test_test__zipfile_test__core.py,v 1.1 2025/10/11 10:14:06 wiz Exp $
+
+https://github.com/python/cpython/commit/d11e69d6203080e3ec450446bfed0516727b85c3
+
+--- Lib/test/test_zipfile/test_core.py.orig    2025-10-07 09:34:52.000000000 +0000
++++ Lib/test/test_zipfile/test_core.py
+@@ -898,6 +898,8 @@ class StoredTestZip64InSmallFiles(Abstra
+         self, file_size_64_set=False, file_size_extra=False,
+         compress_size_64_set=False, compress_size_extra=False,
+         header_offset_64_set=False, header_offset_extra=False,
++        extensible_data=b'',
++        end_of_central_dir_size=None, offset_to_end_of_central_dir=None,
+     ):
+         """Generate bytes sequence for a zip with (incomplete) zip64 data.
+ 
+@@ -951,6 +953,12 @@ class StoredTestZip64InSmallFiles(Abstra
+ 
+         central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
+         offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
++        if end_of_central_dir_size is None:
++            end_of_central_dir_size = 44 + len(extensible_data)
++        if offset_to_end_of_central_dir is None:
++            offset_to_end_of_central_dir = (108
++                                            + 8 * len(local_zip64_fields)
++                                            + 8 * len(central_zip64_fields))
+ 
+         local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
+         central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
+@@ -979,14 +987,17 @@ class StoredTestZip64InSmallFiles(Abstra
+             + filename
+             + central_extra
+             # Zip64 end of central directory
+-            + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
+-            + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
++            + b"PK\x06\x06"
++            + struct.pack('<Q', end_of_central_dir_size)
++            + b"-\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
+             + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
+             + central_dir_size
+             + offset_to_central_dir
++            + extensible_data
+             # Zip64 end of central directory locator
+-            + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
+-            + b"\x00\x00\x00"
++            + b"PK\x06\x07\x00\x00\x00\x00"
++            + struct.pack('<Q', offset_to_end_of_central_dir)
++            + b"\x01\x00\x00\x00"
+             # end of central directory
+             + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
+             + b"\x00\x00\x00\x00"
+@@ -1017,6 +1028,7 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
+         self.assertIn('file size', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_file_size_extra)))
+ 
+         # zip64 file size present, zip64 compress size present, one field in
+         # extra, expecting two, equals missing compress size.
+@@ -1028,6 +1040,7 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
+         self.assertIn('compress size', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra)))
+ 
+         # zip64 compress size present, no fields in extra, expecting one,
+         # equals missing compress size.
+@@ -1037,6 +1050,7 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
+         self.assertIn('compress size', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra)))
+ 
+         # zip64 file size present, zip64 compress size present, zip64 header
+         # offset present, two fields in extra, expecting three, equals missing
+@@ -1051,6 +1065,7 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
+         self.assertIn('header offset', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
+ 
+         # zip64 compress size present, zip64 header offset present, one field
+         # in extra, expecting two, equals missing header offset
+@@ -1063,6 +1078,7 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
+         self.assertIn('header offset', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
+ 
+         # zip64 file size present, zip64 header offset present, one field in
+         # extra, expecting two, equals missing header offset
+@@ -1075,6 +1091,7 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
+         self.assertIn('header offset', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
+ 
+         # zip64 header offset present, no fields in extra, expecting one,
+         # equals missing header offset
+@@ -1086,6 +1103,63 @@ class StoredTestZip64InSmallFiles(Abstra
+         with self.assertRaises(zipfile.BadZipFile) as e:
+             zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
+         self.assertIn('header offset', str(e.exception).lower())
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
++
++    def test_bad_zip64_end_of_central_dir(self):
++        zipdata = self.make_zip64_file(end_of_central_dir_size=0)
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
++            zipfile.ZipFile(io.BytesIO(zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++        zipdata = self.make_zip64_file(end_of_central_dir_size=100)
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
++            zipfile.ZipFile(io.BytesIO(zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++        zipdata = self.make_zip64_file(offset_to_end_of_central_dir=0)
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
++            zipfile.ZipFile(io.BytesIO(zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++        zipdata = self.make_zip64_file(offset_to_end_of_central_dir=1000)
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*locator'):
++            zipfile.ZipFile(io.BytesIO(zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++    def test_zip64_end_of_central_dir_record_not_found(self):
++        zipdata = self.make_zip64_file()
++        zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4)
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
++            zipfile.ZipFile(io.BytesIO(zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++        zipdata = self.make_zip64_file(
++            extensible_data=b'\xca\xfe\x04\x00\x00\x00data')
++        zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4)
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
++            zipfile.ZipFile(io.BytesIO(zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++    def test_zip64_extensible_data(self):
++        # These values are what is set in the make_zip64_file method.
++        expected_file_size = 8
++        expected_compress_size = 8
++        expected_header_offset = 0
++        expected_content = b"test1234"
++
++        zipdata = self.make_zip64_file(
++            extensible_data=b'\xca\xfe\x04\x00\x00\x00data')
++        with zipfile.ZipFile(io.BytesIO(zipdata)) as zf:
++            zinfo = zf.infolist()[0]
++            self.assertEqual(zinfo.file_size, expected_file_size)
++            self.assertEqual(zinfo.compress_size, expected_compress_size)
++            self.assertEqual(zinfo.header_offset, expected_header_offset)
++            self.assertEqual(zf.read(zinfo), expected_content)
++        self.assertTrue(zipfile.is_zipfile(io.BytesIO(zipdata)))
++
++        with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
++            zipfile.ZipFile(io.BytesIO(b'prepended' + zipdata))
++        self.assertFalse(zipfile.is_zipfile(io.BytesIO(b'prepended' + zipdata)))
+ 
+     def test_generated_valid_zip64_extra(self):
+         # These values are what is set in the make_zip64_file method.
Index: pkgsrc/lang/python314/patches/patch-Lib_zipfile_____init____.py
diff -u /dev/null pkgsrc/lang/python314/patches/patch-Lib_zipfile_____init____.py:1.1
--- /dev/null   Sat Oct 11 10:14:06 2025
+++ pkgsrc/lang/python314/patches/patch-Lib_zipfile_____init____.py     Sat Oct 11 10:14:06 2025
@@ -0,0 +1,122 @@
+$NetBSD: patch-Lib_zipfile_____init____.py,v 1.1 2025/10/11 10:14:06 wiz Exp $
+
+https://github.com/python/cpython/commit/d11e69d6203080e3ec450446bfed0516727b85c3
+
+--- Lib/zipfile/__init__.py.orig       2025-10-07 09:34:52.000000000 +0000
++++ Lib/zipfile/__init__.py
+@@ -265,7 +265,7 @@ def is_zipfile(filename):
+         else:
+             with open(filename, "rb") as fp:
+                 result = _check_zipfile(fp)
+-    except OSError:
++    except (OSError, BadZipFile):
+         pass
+     return result
+ 
+@@ -275,9 +275,6 @@ def _handle_prepended_data(endrec, debug
+ 
+     # "concat" is zero, unless zip was concatenated to another file
+     concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
+-    if endrec[_ECD_SIGNATURE] == stringEndArchive64:
+-        # If Zip64 extension structures are present, account for them
+-        concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator)
+ 
+     if debug > 2:
+         inferred = concat + offset_cd
+@@ -289,16 +286,15 @@ def _EndRecData64(fpin, offset, endrec):
+     """
+     Read the ZIP64 end-of-archive records and use that to update endrec
+     """
+-    try:
+-        fpin.seek(offset - sizeEndCentDir64Locator, 2)
+-    except OSError:
+-        # If the seek fails, the file is not large enough to contain a ZIP64
++    offset -= sizeEndCentDir64Locator
++    if offset < 0:
++        # The file is not large enough to contain a ZIP64
+         # end-of-archive record, so just return the end record we were given.
+         return endrec
+-
++    fpin.seek(offset)
+     data = fpin.read(sizeEndCentDir64Locator)
+     if len(data) != sizeEndCentDir64Locator:
+-        return endrec
++        raise OSError("Unknown I/O error")
+     sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
+     if sig != stringEndArchive64Locator:
+         return endrec
+@@ -306,16 +302,33 @@ def _EndRecData64(fpin, offset, endrec):
+     if diskno != 0 or disks > 1:
+         raise BadZipFile("zipfiles that span multiple disks are not supported")
+ 
+-    # Assume no 'zip64 extensible data'
+-    fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
++    offset -= sizeEndCentDir64
++    if reloff > offset:
++        raise BadZipFile("Corrupt zip64 end of central directory locator")
++    # First, check the assumption that there is no prepended data.
++    fpin.seek(reloff)
++    extrasz = offset - reloff
+     data = fpin.read(sizeEndCentDir64)
+     if len(data) != sizeEndCentDir64:
+-        return endrec
++        raise OSError("Unknown I/O error")
++    if not data.startswith(stringEndArchive64) and reloff != offset:
++        # Since we already have seen the Zip64 EOCD Locator, it's
++        # possible we got here because there is prepended data.
++        # Assume no 'zip64 extensible data'
++        fpin.seek(offset)
++        extrasz = 0
++        data = fpin.read(sizeEndCentDir64)
++        if len(data) != sizeEndCentDir64:
++            raise OSError("Unknown I/O error")
++    if not data.startswith(stringEndArchive64):
++        raise BadZipFile("Zip64 end of central directory record not found")
++
+     sig, sz, create_version, read_version, disk_num, disk_dir, \
+         dircount, dircount2, dirsize, diroffset = \
+         struct.unpack(structEndArchive64, data)
+-    if sig != stringEndArchive64:
+-        return endrec
++    if (diroffset + dirsize != reloff or
++        sz + 12 != sizeEndCentDir64 + extrasz):
++        raise BadZipFile("Corrupt zip64 end of central directory record")
+ 
+     # Update the original endrec using data from the ZIP64 record
+     endrec[_ECD_SIGNATURE] = sig
+@@ -325,6 +338,7 @@ def _EndRecData64(fpin, offset, endrec):
+     endrec[_ECD_ENTRIES_TOTAL] = dircount2
+     endrec[_ECD_SIZE] = dirsize
+     endrec[_ECD_OFFSET] = diroffset
++    endrec[_ECD_LOCATION] = offset - extrasz
+     return endrec
+ 
+ 
+@@ -358,7 +372,7 @@ def _EndRecData(fpin):
+         endrec.append(filesize - sizeEndCentDir)
+ 
+         # Try to read the "Zip64 end of central directory" structure
+-        return _EndRecData64(fpin, -sizeEndCentDir, endrec)
++        return _EndRecData64(fpin, filesize - sizeEndCentDir, endrec)
+ 
+     # Either this is not a ZIP file, or it is a ZIP file with an archive
+     # comment.  Search the end of the file for the "end of central directory"
+@@ -382,8 +396,7 @@ def _EndRecData(fpin):
+         endrec.append(maxCommentStart + start)
+ 
+         # Try to read the "Zip64 end of central directory" structure
+-        return _EndRecData64(fpin, maxCommentStart + start - filesize,
+-                             endrec)
++        return _EndRecData64(fpin, maxCommentStart + start, endrec)
+ 
+     # Unable to find a valid end of central directory structure
+     return None
+@@ -2142,7 +2155,7 @@ class ZipFile:
+                                    " would require ZIP64 extensions")
+             zip64endrec = struct.pack(
+                 structEndArchive64, stringEndArchive64,
+-                44, 45, 45, 0, 0, centDirCount, centDirCount,
++                sizeEndCentDir64 - 12, 45, 45, 0, 0, centDirCount, centDirCount,
+                 centDirSize, centDirOffset)
+             self.fp.write(zip64endrec)
+ 
Home |
Main Index |
Thread Index |
Old Index