Raise on overlapping file blocks

This commit is contained in:
Danny Lin 2025-05-25 17:28:40 +08:00
parent a788a001a4
commit ae01b8cd69
2 changed files with 40 additions and 10 deletions

View file

@ -2024,6 +2024,21 @@ def test_repack_data_descriptor_no_sig_and_zip64(self):
# check file size
self.assertEqual(os.path.getsize(TESTFN), expected_size)
def test_repack_overlapping_blocks(self):
for ii in ([0], [1], [2]):
with self.subTest(remove=ii):
self._prepare_zip_from_test_files(TESTFN, self.test_files)
with open(TESTFN, 'r+b') as fh:
with zipfile.ZipFile(fh, 'a') as zh:
zh.writestr('file.txt', b'dummy')
for i in ii:
zh.infolist()[i].file_size += 50
zh.infolist()[i].compress_size += 50
with zipfile.ZipFile(TESTFN, 'a') as zh:
with self.assertRaises(zipfile.BadZipFile):
zh.repack()
@mock.patch('zipfile._ZipRepacker')
def test_repack_closed(self, m_repack):
self._prepare_zip_from_test_files(TESTFN, self.test_files)

View file

@ -1452,25 +1452,40 @@ def _repack(self, zfile):
# doesn't match the actual entry order
filelist = sorted(zfile.filelist, key=lambda x: x.header_offset)
try:
data_offset = filelist[0].header_offset
except IndexError:
data_offset = zfile.start_dir
# calculate the starting entry offset (bytes to skip)
entry_offset = self._calc_initial_entry_offset(fp, data_offset)
# move file entries
# calculate each entry size and validate
entry_size_list = []
used_entry_size_list = []
for i, zinfo in enumerate(filelist):
# get the total size of the entry
try:
offset = filelist[i + 1].header_offset
except IndexError:
offset = zfile.start_dir
entry_size = offset - zinfo.header_offset
# may raise on an invalid local file header
used_entry_size = self._calc_local_file_entry_size(fp, zinfo)
self._debug(3, i, zinfo.orig_filename, entry_size, used_entry_size)
if used_entry_size > entry_size:
raise BadZipFile(
f"Overlapped entries: {zinfo.orig_filename!r} "
f"(possible zip bomb)")
entry_size_list.append(entry_size)
used_entry_size_list.append(used_entry_size)
# calculate the starting entry offset (bytes to skip)
try:
data_offset = filelist[0].header_offset
except IndexError:
data_offset = zfile.start_dir
entry_offset = self._calc_initial_entry_offset(fp, data_offset)
# move file entries
for i, zinfo in enumerate(filelist):
entry_size = entry_size_list[i]
used_entry_size = used_entry_size_list[i]
# update the header and move entry data to the new position
if entry_offset > 0:
old_header_offset = zinfo.header_offset