diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2024-01-10 13:55:36 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-10 13:55:36 (GMT) |
commit | 66363b9a7b9fe7c99eba3a185b74c5fdbf842eba (patch) | |
tree | 9ec743e764771d1adca1142c7165eb2090217a3a /Lib/zipfile | |
parent | 183b97bb9db075197153ad82b8ffdfce8e913250 (diff) | |
download | cpython-66363b9a7b9fe7c99eba3a185b74c5fdbf842eba.zip cpython-66363b9a7b9fe7c99eba3a185b74c5fdbf842eba.tar.gz cpython-66363b9a7b9fe7c99eba3a185b74c5fdbf842eba.tar.bz2 |
gh-109858: Protect zipfile from "quoted-overlap" zipbomb (GH-110016)
Raise BadZipFile when try to read an entry that overlaps with other entry or
central directory.
Diffstat (limited to 'Lib/zipfile')
-rw-r--r-- | Lib/zipfile/__init__.py | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 1c415a2..1d8a607 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -395,6 +395,7 @@ class ZipInfo (object): 'compress_size', 'file_size', '_raw_time', + '_end_offset', ) def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)): @@ -429,6 +430,7 @@ class ZipInfo (object): self.external_attr = 0 # External file attributes self.compress_size = 0 # Size of the compressed file self.file_size = 0 # Size of the uncompressed file + self._end_offset = None # Start of the next local header or central directory # Other attributes are set by class ZipFile: # header_offset Byte offset to the file header # CRC CRC-32 of the uncompressed file @@ -1488,6 +1490,12 @@ class ZipFile: if self.debug > 2: print("total", total) + end_offset = self.start_dir + for zinfo in sorted(self.filelist, + key=lambda zinfo: zinfo.header_offset, + reverse=True): + zinfo._end_offset = end_offset + end_offset = zinfo.header_offset def namelist(self): """Return a list of file names in the archive.""" @@ -1644,6 +1652,10 @@ class ZipFile: 'File name in directory %r and header %r differ.' % (zinfo.orig_filename, fname)) + if (zinfo._end_offset is not None and + zef_file.tell() + zinfo.compress_size > zinfo._end_offset): + raise BadZipFile(f"Overlapped entries: {zinfo.orig_filename!r} (possible zip bomb)") + # check for encrypted flag & handle password is_encrypted = zinfo.flag_bits & _MASK_ENCRYPTED if is_encrypted: |