From 14f0e395f90946b2ae54205c42b892d52b6c940d Mon Sep 17 00:00:00 2001 From: Daniel Hillier Date: Tue, 9 Jul 2019 14:17:10 +1000 Subject: [PATCH 1/3] bpo-36993: Improve error reporting for zipfiles with bad zip64 extra data. --- Lib/test/test_zipfile.py | 183 +++++++++++++++++++++++++++++++++++++++ Lib/zipfile.py | 12 +++ 2 files changed, 195 insertions(+) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 0c8ffcdbf14afe..d6a160ea7a2cd2 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -773,6 +773,189 @@ def test_too_many_files_append(self): self.assertEqual(content, "%d" % (i**3 % 57)) zipf2.close() + def make_zip64_file( + 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, + ): + """Generate bytes sequence for a zip with (incomplete) zip64 data.""" + actual_size = 8 + actual_header_offset = 0 + local_zip64_fields = [] + central_zip64_fields = [] + + file_size = actual_size + if file_size_64_set: + file_size = 0xffffffff + if file_size_extra: + local_zip64_fields.append(actual_size) + central_zip64_fields.append(actual_size) + file_size = struct.pack(" Date: Tue, 9 Jul 2019 05:44:41 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2019-07-09-05-44-39.bpo-36993.4javqu.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2019-07-09-05-44-39.bpo-36993.4javqu.rst diff --git a/Misc/NEWS.d/next/Library/2019-07-09-05-44-39.bpo-36993.4javqu.rst b/Misc/NEWS.d/next/Library/2019-07-09-05-44-39.bpo-36993.4javqu.rst new file mode 100644 index 00000000000000..f21f0c52eaa53b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-07-09-05-44-39.bpo-36993.4javqu.rst @@ -0,0 +1 @@ +Improve error reporting for corrupt zip files with bad zip64 extra data. \ No newline at end of file From 4b4cd5727ea7532aabfbc086b130486866f2bcb8 Mon Sep 17 00:00:00 2001 From: Daniel Hillier Date: Tue, 29 Oct 2019 10:52:45 +1100 Subject: [PATCH 3/3] bpo-36993: add zip64 error reporting review suggestions --- Lib/test/test_zipfile.py | 143 +++++++++++------- Lib/zipfile.py | 6 +- .../2019-07-09-05-44-39.bpo-36993.4javqu.rst | 3 +- 3 files changed, 96 insertions(+), 56 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index d6a160ea7a2cd2..b59719ed27426b 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -1,6 +1,7 @@ import contextlib import importlib.util import io +import itertools import os import pathlib import posixpath @@ -773,12 +774,67 @@ def test_too_many_files_append(self): self.assertEqual(content, "%d" % (i**3 % 57)) zipf2.close() + def tearDown(self): + zipfile.ZIP64_LIMIT = self._limit + zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit + unlink(TESTFN) + unlink(TESTFN2) + + +class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, + unittest.TestCase): + compression = zipfile.ZIP_STORED + + def large_file_exception_test(self, f, compression): + with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.write, TESTFN, "another.name") + + def large_file_exception_test2(self, f, compression): + with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp: + self.assertRaises(zipfile.LargeZipFile, + zipfp.writestr, "another.name", self.data) + + def test_large_file_exception(self): + for f in get_files(self): + self.large_file_exception_test(f, zipfile.ZIP_STORED) + self.large_file_exception_test2(f, zipfile.ZIP_STORED) + + def test_absolute_arcnames(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED, + allowZip64=True) as zipfp: + zipfp.write(TESTFN, "/absolute") + + with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp: + self.assertEqual(zipfp.namelist(), ["absolute"]) + + def test_append(self): + # Test that appending to the Zip64 archive doesn't change + # extra fields of existing entries. + with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp: + zipfp.writestr("strfile", self.data) + with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp: + zinfo = zipfp.getinfo("strfile") + extra = zinfo.extra + with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp: + zipfp.writestr("strfile2", self.data) + with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp: + zinfo = zipfp.getinfo("strfile") + self.assertEqual(zinfo.extra, extra) + def make_zip64_file( 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, ): - """Generate bytes sequence for a zip with (incomplete) zip64 data.""" + """Generate bytes sequence for a zip with (incomplete) zip64 data. + + The actual values (not the zip 64 0xffffffff values) stored in the file + are: + file_size: 8 + compress_size: 8 + header_offset: 0 + """ actual_size = 8 actual_header_offset = 0 local_zip64_fields = [] @@ -822,30 +878,33 @@ def make_zip64_file( ) central_dir_size = struct.pack('