]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #4844: ZipFile now raises BadZipFile when opens a ZIP file with an
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 31 Jan 2013 13:27:07 +0000 (15:27 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 31 Jan 2013 13:27:07 +0000 (15:27 +0200)
incomplete "End of Central Directory" record.  Original patch by Guilherme
Polo and Alan McIntyre.

Lib/test/test_zipfile.py
Lib/zipfile.py
Misc/NEWS

index 367f37ee04d12a227e25cd680cda7d48ea0e7775..741cee96678f21482ef4bb61b73920e563582ec3 100644 (file)
@@ -844,6 +844,20 @@ class OtherTests(unittest.TestCase):
         chk = zipfile.is_zipfile(fp)
         self.assertTrue(not chk)
 
+    def test_damaged_zipfile(self):
+        """Check that zipfiles with missing bytes at the end raise BadZipFile."""
+        # - Create a valid zip file
+        fp = io.BytesIO()
+        with zipfile.ZipFile(fp, mode="w") as zipf:
+            zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
+        zipfiledata = fp.getvalue()
+
+        # - Now create copies of it missing the last N bytes and make sure
+        #   a BadZipFile exception is raised when we try to open it
+        for N in range(len(zipfiledata)):
+            fp = io.BytesIO(zipfiledata[:N])
+            self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, fp)
+
     def test_is_zip_valid_file(self):
         """Check that is_zipfile() correctly identifies zip files."""
         # - passing a filename
index a7cee72ae67aa45d1296e4c22b41b178cb5b3e10..f900abd80135349055212051a34377b2f5ccf498 100644 (file)
@@ -176,6 +176,8 @@ def _EndRecData64(fpin, offset, endrec):
         return endrec
 
     data = fpin.read(sizeEndCentDir64Locator)
+    if len(data) != sizeEndCentDir64Locator:
+        return endrec
     sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
     if sig != stringEndArchive64Locator:
         return endrec
@@ -186,6 +188,8 @@ def _EndRecData64(fpin, offset, endrec):
     # Assume no 'zip64 extensible data'
     fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
     data = fpin.read(sizeEndCentDir64)
+    if len(data) != sizeEndCentDir64:
+        return endrec
     sig, sz, create_version, read_version, disk_num, disk_dir, \
             dircount, dircount2, dirsize, diroffset = \
             struct.unpack(structEndArchive64, data)
@@ -221,7 +225,9 @@ def _EndRecData(fpin):
     except IOError:
         return None
     data = fpin.read()
-    if data[0:4] == stringEndArchive and data[-2:] == b"\000\000":
+    if (len(data) == sizeEndCentDir and
+        data[0:4] == stringEndArchive and
+        data[-2:] == b"\000\000"):
         # the signature is correct and there's no comment, unpack structure
         endrec = struct.unpack(structEndArchive, data)
         endrec=list(endrec)
@@ -245,6 +251,9 @@ def _EndRecData(fpin):
     if start >= 0:
         # found the magic number; attempt to unpack and interpret
         recData = data[start:start+sizeEndCentDir]
+        if len(recData) != sizeEndCentDir:
+            # Zip file is corrupted.
+            return None
         endrec = list(struct.unpack(structEndArchive, recData))
         commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file
         comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize]
@@ -256,7 +265,7 @@ def _EndRecData(fpin):
                              endrec)
 
     # Unable to find a valid end of central directory structure
-    return
+    return None
 
 
 class ZipInfo (object):
@@ -819,9 +828,11 @@ class ZipFile:
         total = 0
         while total < size_cd:
             centdir = fp.read(sizeCentralDir)
-            if centdir[0:4] != stringCentralDir:
-                raise BadZipFile("Bad magic number for central directory")
+            if len(centdir) != sizeCentralDir:
+                raise BadZipFile("Truncated central directory")
             centdir = struct.unpack(structCentralDir, centdir)
+            if centdir[_CD_SIGNATURE] != stringCentralDir:
+                raise BadZipFile("Bad magic number for central directory")
             if self.debug > 2:
                 print(centdir)
             filename = fp.read(centdir[_CD_FILENAME_LENGTH])
@@ -964,10 +975,12 @@ class ZipFile:
 
             # Skip the file header:
             fheader = zef_file.read(sizeFileHeader)
-            if fheader[0:4] != stringFileHeader:
+            if len(fheader) != sizeFileHeader:
+                raise BadZipFile("Truncated file header")
+            fheader = struct.unpack(structFileHeader, fheader)
+            if fheader[_FH_SIGNATURE] != stringFileHeader:
                 raise BadZipFile("Bad magic number for file header")
 
-            fheader = struct.unpack(structFileHeader, fheader)
             fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
             if fheader[_FH_EXTRA_FIELD_LENGTH]:
                 zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
index 7400f5e483ce7862f3bc82fcd37a4ac72ffeb6fc..34f4a6bdfe2fc2903e643b4f91af9d34b002fc6e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -216,6 +216,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #4844: ZipFile now raises BadZipFile when opens a ZIP file with an
+  incomplete "End of Central Directory" record.  Original patch by Guilherme
+  Polo and Alan McIntyre.
+
 - Issue #15505: `unittest.installHandler` no longer assumes SIGINT handler is
   set to a callable object.