From c8a6b2465c5f5c772b777252174a3338324539e6 Mon Sep 17 00:00:00 2001 From: Sebastian Gassner Date: Tue, 7 Nov 2023 16:54:43 +0100 Subject: [PATCH 1/3] fixing #111791: delegating extraction in shutil.unpack_archive to zipfile shutil.unpack_archive fails, if file name contains '..'; zipfile handles everything correctly, i.e. in the same way than 'unzip'; let zipfile unpack archives, instead of reinventing the wheel here --- Lib/shutil.py | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py index 0fed0117a63234..b929ff21d7d358 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1252,27 +1252,10 @@ def _unpack_zipfile(filename, extract_dir): if not zipfile.is_zipfile(filename): raise ReadError("%s is not a zip file" % filename) - zip = zipfile.ZipFile(filename) - try: - for info in zip.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name: - continue - - targetpath = os.path.join(extract_dir, *name.split('/')) - if not targetpath: - continue - - _ensure_directory(targetpath) - if not name.endswith('/'): - # file - with zip.open(name, 'r') as source, \ - open(targetpath, 'wb') as target: - copyfileobj(source, target) - finally: - zip.close() + with zipfile.ZipFile(filename) as zf: + # delegate extracting the archive to zipfile + _ensure_directory(extract_dir) + zf.extractall(extract_dir) def _unpack_tarfile(filename, extract_dir, *, filter=None): """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` From d50ea17ab1b6f61484ca9869d61d98198568628b Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 17:08:10 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2023-11-07-17-08-09.gh-issue-111791.oJbxOQ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-11-07-17-08-09.gh-issue-111791.oJbxOQ.rst diff --git a/Misc/NEWS.d/next/Library/2023-11-07-17-08-09.gh-issue-111791.oJbxOQ.rst b/Misc/NEWS.d/next/Library/2023-11-07-17-08-09.gh-issue-111791.oJbxOQ.rst new file mode 100644 index 00000000000000..eb0b18cfa77a4e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-07-17-08-09.gh-issue-111791.oJbxOQ.rst @@ -0,0 +1 @@ +ZIP archive entries containing two dots ".." in their name caused shutil's unpack_archive method to silently skip these files during extraction. This has been fixed, shutil's unpack_archive method now generates the same results as Python's own extractall method in the zipfile module, or the Linux unzip tool. From 9de81b161e2f2e62070b736f29dc5a00c612077b Mon Sep 17 00:00:00 2001 From: Sebastian Gassner Date: Tue, 7 Nov 2023 18:41:34 +0100 Subject: [PATCH 3/3] Update shutil.rst Filenames containing two dots ".." do not necessarily indicate relative path components. Only "../" identify a relative path component. --- Doc/library/shutil.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index d1949d698f5614..0ca42e466c16ed 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -703,7 +703,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Never extract archives from untrusted sources without prior inspection. It is possible that files are created outside of the path specified in the *extract_dir* argument, e.g. members that have absolute filenames - starting with "/" or filenames with two dots "..". + starting with "/" or filenames with relative path components "../". .. versionchanged:: 3.7 Accepts a :term:`path-like object` for *filename* and *extract_dir*.