summaryrefslogtreecommitdiff
path: root/django/utils/archive.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/utils/archive.py')
-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 5b9998f89c..f2f153a1fc 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 and not os.path.exists(filename):
os.makedirs(filename)
@@ -198,11 +207,13 @@ 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 not name:
+ continue
+ filename = self.target_filename(to_path, name)
dirname = os.path.dirname(filename)
if dirname and not os.path.exists(dirname):
os.makedirs(dirname)
- if filename.endswith(('/', '\\')):
+ if name.endswith(('/', '\\')):
# A directory
if not os.path.exists(filename):
os.makedirs(filename)