diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 4f20209927e7b3..c4e0ddba525acd 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -4114,6 +4114,16 @@ def test_read_zipfile_error(self): with self.assertRaises(zipfile.BadZipfile): zipfile.ZipFile(TESTFN, "r").close() + def test_read_zipfile_with_corrupted_extra_field(self): + with zipfile.ZipFile(TESTFN, mode='w') as zf: + zinfo = zipfile.ZipInfo("file.txt") + zinfo.extra = struct.pack(' data_len: + raise BadZipFile( + "Corrupt extra field %04x (size=%d)" % (xid, xlen)) + yield data[pos:pos + 4 + xlen], xid + pos += 4 + xlen @classmethod def strip(cls, data, xids): """Remove Extra fields with specified IDs.""" return b''.join( ex - for ex in cls.split(data) - if ex.id not in xids + for ex, xid in cls.iter(data) + if xid not in xids ) + @classmethod + def update(cls, data, extra): + """Insert fields from extra and strip duplicates.""" + # early return for empty data + if not data: + return extra + + extras = { + xid: ex + for ex, xid in cls.iter(extra) + if xid is not None + } + # New fields first since data may have a corrupted tail that renders + # following fields inaccessible. (The caller is responsible for making + # sure that extra is valid.) + return b''.join(extras.values()) + cls.strip(data, extras) + def _check_zipfile(fp): try: @@ -585,14 +599,10 @@ def _encodeFilenameFlags(self): def _decodeExtra(self, filename_crc): # Try to decode the extra field. - extra = self.extra unpack = struct.unpack - while len(extra) >= 4: - tp, ln = unpack(' len(extra): - raise BadZipFile("Corrupt extra field %04x (size=%d)" % (tp, ln)) + for extra, tp in _Extra.iter(self.extra, True): if tp == 0x0001: - data = extra[4:ln+4] + data = extra[4:] # ZIP64 extension (large files and/or large archives) try: if self.file_size in (0xFFFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF): @@ -610,7 +620,7 @@ def _decodeExtra(self, filename_crc): raise BadZipFile(f"Corrupt zip64 extra field. " f"{field} not found.") from None elif tp == 0x7075: - data = extra[4:ln+4] + data = extra[4:] # Unicode Path Extra Field try: up_version, up_name_crc = unpack('