summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2021-01-22 12:23:18 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-02-01 09:13:58 +0100
commit02e6592835b4559909aa3aaaf67988fef435f624 (patch)
treeb90a7513252dec0aebc82eeccbc86257e6418a5a /django
parent03a86784d0dbfc5890f5aaba2d2f29c1deb0009d (diff)
[3.1.x] Fixed CVE-2021-3281 -- Fixed potential directory-traversal via archive.extract().
Thanks Florian Apolloner, Shai Berger, and Simon Charette for reviews. Thanks Wang Baohua for the report. Backport of 05413afa8c18cdb978fcdf470e09f7a12b234a23 from master.
Diffstat (limited to 'django')
-rw-r--r--django/utils/archive.py17
1 files changed, 14 insertions, 3 deletions
diff --git a/django/utils/archive.py b/django/utils/archive.py
index 235809f2ad..d5a0cf0446 100644
--- a/django/utils/archive.py
+++ b/django/utils/archive.py
@@ -27,6 +27,8 @@ import stat
import tarfile
import zipfile
+from django.core.exceptions import SuspiciousOperation
+
class ArchiveException(Exception):
"""
@@ -133,6 +135,13 @@ class BaseArchive:
return False
return True
+ def target_filename(self, to_path, name):
+ target_path = os.path.abspath(to_path)
+ filename = os.path.abspath(os.path.join(target_path, name))
+ if not filename.startswith(target_path):
+ raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
+ return filename
+
def extract(self):
raise NotImplementedError('subclasses of BaseArchive must provide an extract() method')
@@ -155,7 +164,7 @@ class TarArchive(BaseArchive):
name = member.name
if leading:
name = self.split_leading_dir(name)[1]
- filename = os.path.join(to_path, name)
+ filename = self.target_filename(to_path, name)
if member.isdir():
if filename:
os.makedirs(filename, exist_ok=True)
@@ -198,8 +207,10 @@ class ZipArchive(BaseArchive):
info = self._archive.getinfo(name)
if leading:
name = self.split_leading_dir(name)[1]
- filename = os.path.join(to_path, name)
- if filename.endswith(('/', '\\')):
+ if not name:
+ continue
+ filename = self.target_filename(to_path, name)
+ if name.endswith(('/', '\\')):
# A directory
os.makedirs(filename, exist_ok=True)
else: