Skip to content

Commit ae01b8c

Browse files
committed
Raise on overlapping file blocks
1 parent a788a00 commit ae01b8c

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

Lib/test/test_zipfile/test_core.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,6 +2024,21 @@ def test_repack_data_descriptor_no_sig_and_zip64(self):
20242024
# check file size
20252025
self.assertEqual(os.path.getsize(TESTFN), expected_size)
20262026

2027+
def test_repack_overlapping_blocks(self):
2028+
for ii in ([0], [1], [2]):
2029+
with self.subTest(remove=ii):
2030+
self._prepare_zip_from_test_files(TESTFN, self.test_files)
2031+
with open(TESTFN, 'r+b') as fh:
2032+
with zipfile.ZipFile(fh, 'a') as zh:
2033+
zh.writestr('file.txt', b'dummy')
2034+
for i in ii:
2035+
zh.infolist()[i].file_size += 50
2036+
zh.infolist()[i].compress_size += 50
2037+
2038+
with zipfile.ZipFile(TESTFN, 'a') as zh:
2039+
with self.assertRaises(zipfile.BadZipFile):
2040+
zh.repack()
2041+
20272042
@mock.patch('zipfile._ZipRepacker')
20282043
def test_repack_closed(self, m_repack):
20292044
self._prepare_zip_from_test_files(TESTFN, self.test_files)

Lib/zipfile/__init__.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,25 +1452,40 @@ def _repack(self, zfile):
14521452
# doesn't match the actual entry order
14531453
filelist = sorted(zfile.filelist, key=lambda x: x.header_offset)
14541454

1455-
try:
1456-
data_offset = filelist[0].header_offset
1457-
except IndexError:
1458-
data_offset = zfile.start_dir
1459-
1460-
# calculate the starting entry offset (bytes to skip)
1461-
entry_offset = self._calc_initial_entry_offset(fp, data_offset)
1462-
1463-
# move file entries
1455+
# calculate each entry size and validate
1456+
entry_size_list = []
1457+
used_entry_size_list = []
14641458
for i, zinfo in enumerate(filelist):
1465-
# get the total size of the entry
14661459
try:
14671460
offset = filelist[i + 1].header_offset
14681461
except IndexError:
14691462
offset = zfile.start_dir
14701463
entry_size = offset - zinfo.header_offset
14711464

1465+
# may raise on an invalid local file header
14721466
used_entry_size = self._calc_local_file_entry_size(fp, zinfo)
14731467

1468+
self._debug(3, i, zinfo.orig_filename, entry_size, used_entry_size)
1469+
if used_entry_size > entry_size:
1470+
raise BadZipFile(
1471+
f"Overlapped entries: {zinfo.orig_filename!r} "
1472+
f"(possible zip bomb)")
1473+
1474+
entry_size_list.append(entry_size)
1475+
used_entry_size_list.append(used_entry_size)
1476+
1477+
# calculate the starting entry offset (bytes to skip)
1478+
try:
1479+
data_offset = filelist[0].header_offset
1480+
except IndexError:
1481+
data_offset = zfile.start_dir
1482+
entry_offset = self._calc_initial_entry_offset(fp, data_offset)
1483+
1484+
# move file entries
1485+
for i, zinfo in enumerate(filelist):
1486+
entry_size = entry_size_list[i]
1487+
used_entry_size = used_entry_size_list[i]
1488+
14741489
# update the header and move entry data to the new position
14751490
if entry_offset > 0:
14761491
old_header_offset = zinfo.header_offset

0 commit comments

Comments
 (0)