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.
This commit is contained in:
parent
18fae3f954
commit
0be506a5ba
|
@ -760,6 +760,20 @@ class OtherTests(unittest.TestCase):
|
||||||
chk = zipfile.is_zipfile(fp)
|
chk = zipfile.is_zipfile(fp)
|
||||||
self.assertTrue(not chk)
|
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):
|
def test_is_zip_valid_file(self):
|
||||||
"""Check that is_zipfile() correctly identifies zip files."""
|
"""Check that is_zipfile() correctly identifies zip files."""
|
||||||
# - passing a filename
|
# - passing a filename
|
||||||
|
|
|
@ -166,6 +166,8 @@ def _EndRecData64(fpin, offset, endrec):
|
||||||
return endrec
|
return endrec
|
||||||
|
|
||||||
data = fpin.read(sizeEndCentDir64Locator)
|
data = fpin.read(sizeEndCentDir64Locator)
|
||||||
|
if len(data) != sizeEndCentDir64Locator:
|
||||||
|
return endrec
|
||||||
sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
|
sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
|
||||||
if sig != stringEndArchive64Locator:
|
if sig != stringEndArchive64Locator:
|
||||||
return endrec
|
return endrec
|
||||||
|
@ -176,6 +178,8 @@ def _EndRecData64(fpin, offset, endrec):
|
||||||
# Assume no 'zip64 extensible data'
|
# Assume no 'zip64 extensible data'
|
||||||
fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
|
fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
|
||||||
data = fpin.read(sizeEndCentDir64)
|
data = fpin.read(sizeEndCentDir64)
|
||||||
|
if len(data) != sizeEndCentDir64:
|
||||||
|
return endrec
|
||||||
sig, sz, create_version, read_version, disk_num, disk_dir, \
|
sig, sz, create_version, read_version, disk_num, disk_dir, \
|
||||||
dircount, dircount2, dirsize, diroffset = \
|
dircount, dircount2, dirsize, diroffset = \
|
||||||
struct.unpack(structEndArchive64, data)
|
struct.unpack(structEndArchive64, data)
|
||||||
|
@ -211,7 +215,9 @@ def _EndRecData(fpin):
|
||||||
except IOError:
|
except IOError:
|
||||||
return None
|
return None
|
||||||
data = fpin.read()
|
data = fpin.read()
|
||||||
if data[0:4] == stringEndArchive and data[-2:] == "\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
|
# the signature is correct and there's no comment, unpack structure
|
||||||
endrec = struct.unpack(structEndArchive, data)
|
endrec = struct.unpack(structEndArchive, data)
|
||||||
endrec=list(endrec)
|
endrec=list(endrec)
|
||||||
|
@ -235,6 +241,9 @@ def _EndRecData(fpin):
|
||||||
if start >= 0:
|
if start >= 0:
|
||||||
# found the magic number; attempt to unpack and interpret
|
# found the magic number; attempt to unpack and interpret
|
||||||
recData = data[start:start+sizeEndCentDir]
|
recData = data[start:start+sizeEndCentDir]
|
||||||
|
if len(recData) != sizeEndCentDir:
|
||||||
|
# Zip file is corrupted.
|
||||||
|
return None
|
||||||
endrec = list(struct.unpack(structEndArchive, recData))
|
endrec = list(struct.unpack(structEndArchive, recData))
|
||||||
commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file
|
commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file
|
||||||
comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize]
|
comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize]
|
||||||
|
@ -246,7 +255,7 @@ def _EndRecData(fpin):
|
||||||
endrec)
|
endrec)
|
||||||
|
|
||||||
# Unable to find a valid end of central directory structure
|
# Unable to find a valid end of central directory structure
|
||||||
return
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ZipInfo (object):
|
class ZipInfo (object):
|
||||||
|
@ -818,9 +827,11 @@ class ZipFile(object):
|
||||||
total = 0
|
total = 0
|
||||||
while total < size_cd:
|
while total < size_cd:
|
||||||
centdir = fp.read(sizeCentralDir)
|
centdir = fp.read(sizeCentralDir)
|
||||||
if centdir[0:4] != stringCentralDir:
|
if len(centdir) != sizeCentralDir:
|
||||||
raise BadZipfile, "Bad magic number for central directory"
|
raise BadZipfile("Truncated central directory")
|
||||||
centdir = struct.unpack(structCentralDir, centdir)
|
centdir = struct.unpack(structCentralDir, centdir)
|
||||||
|
if centdir[_CD_SIGNATURE] != stringCentralDir:
|
||||||
|
raise BadZipfile("Bad magic number for central directory")
|
||||||
if self.debug > 2:
|
if self.debug > 2:
|
||||||
print centdir
|
print centdir
|
||||||
filename = fp.read(centdir[_CD_FILENAME_LENGTH])
|
filename = fp.read(centdir[_CD_FILENAME_LENGTH])
|
||||||
|
@ -948,10 +959,12 @@ class ZipFile(object):
|
||||||
|
|
||||||
# Skip the file header:
|
# Skip the file header:
|
||||||
fheader = zef_file.read(sizeFileHeader)
|
fheader = zef_file.read(sizeFileHeader)
|
||||||
if fheader[0:4] != stringFileHeader:
|
if len(fheader) != sizeFileHeader:
|
||||||
raise BadZipfile, "Bad magic number for file header"
|
raise BadZipfile("Truncated file header")
|
||||||
|
|
||||||
fheader = struct.unpack(structFileHeader, fheader)
|
fheader = struct.unpack(structFileHeader, fheader)
|
||||||
|
if fheader[_FH_SIGNATURE] != stringFileHeader:
|
||||||
|
raise BadZipfile("Bad magic number for file header")
|
||||||
|
|
||||||
fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
|
fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
|
||||||
if fheader[_FH_EXTRA_FIELD_LENGTH]:
|
if fheader[_FH_EXTRA_FIELD_LENGTH]:
|
||||||
zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
|
zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
|
||||||
|
|
|
@ -202,6 +202,10 @@ Core and Builtins
|
||||||
Library
|
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
|
- Issue #15505: `unittest.installHandler` no longer assumes SIGINT handler is
|
||||||
set to a callable object.
|
set to a callable object.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue