/[packages]/updates/8/python-django/current/SOURCES/8d2f7cff76200cbd2337b2cf1707e383eb1fb54b.patch
ViewVC logotype

Contents of /updates/8/python-django/current/SOURCES/8d2f7cff76200cbd2337b2cf1707e383eb1fb54b.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1766876 - (show annotations) (download)
Tue Jan 4 20:20:05 2022 UTC (16 months, 3 weeks ago) by neoclust
File size: 4838 byte(s)
Add P100->102: Fixes CVE-2021-4511[56] and CVE-2021-45452 (mga#29843)
1 From 8d2f7cff76200cbd2337b2cf1707e383eb1fb54b Mon Sep 17 00:00:00 2001
2 From: Florian Apolloner <florian@apolloner.eu>
3 Date: Fri, 17 Dec 2021 21:07:50 +0100
4 Subject: [PATCH] [3.2.x] Fixed CVE-2021-45452 -- Fixed potential path
5 traversal in storage subsystem.
6
7 Thanks to Dennis Brinkrolf for the report.
8 ---
9 django/core/files/storage.py | 9 ++++++++-
10 docs/releases/2.2.26.txt | 9 +++++++++
11 docs/releases/3.2.11.txt | 9 +++++++++
12 tests/file_storage/test_generate_filename.py | 19 +++++++++++++------
13 tests/file_storage/tests.py | 6 ++++++
14 5 files changed, 45 insertions(+), 7 deletions(-)
15
16 diff --git a/django/core/files/storage.py b/django/core/files/storage.py
17 index 3e68853b59f8..22984f9498d9 100644
18 --- a/django/core/files/storage.py
19 +++ b/django/core/files/storage.py
20 @@ -51,7 +51,10 @@ def save(self, name, content, max_length=None):
21 content = File(content, name)
22
23 name = self.get_available_name(name, max_length=max_length)
24 - return self._save(name, content)
25 + name = self._save(name, content)
26 + # Ensure that the name returned from the storage system is still valid.
27 + validate_file_name(name, allow_relative_path=True)
28 + return name
29
30 # These methods are part of the public API, with default implementations.
31
32 @@ -75,6 +78,7 @@ def get_available_name(self, name, max_length=None):
33 Return a filename that's free on the target storage system and
34 available for new content to be written to.
35 """
36 + name = str(name).replace('\\', '/')
37 dir_name, file_name = os.path.split(name)
38 if '..' in pathlib.PurePath(dir_name).parts:
39 raise SuspiciousFileOperation("Detected path traversal attempt in '%s'" % dir_name)
40 @@ -108,6 +112,7 @@ def generate_filename(self, filename):
41 Validate the filename by calling get_valid_name() and return a filename
42 to be passed to the save() method.
43 """
44 + filename = str(filename).replace('\\', '/')
45 # `filename` may include a path as returned by FileField.upload_to.
46 dirname, filename = os.path.split(filename)
47 if '..' in pathlib.PurePath(dirname).parts:
48 @@ -297,6 +302,8 @@ def _save(self, name, content):
49 if self.file_permissions_mode is not None:
50 os.chmod(full_path, self.file_permissions_mode)
51
52 + # Ensure the saved path is always relative to the storage root.
53 + name = os.path.relpath(full_path, self.location)
54 # Store filenames with forward slashes, even on Windows.
55 return str(name).replace('\\', '/')
56
57 diff --git a/tests/file_storage/test_generate_filename.py b/tests/file_storage/test_generate_filename.py
58 index 66551c495b21..78fd0647321a 100644
59 --- a/tests/file_storage/test_generate_filename.py
60 +++ b/tests/file_storage/test_generate_filename.py
61 @@ -53,13 +53,20 @@ def test_storage_dangerous_paths(self):
62 s.generate_filename(file_name)
63
64 def test_storage_dangerous_paths_dir_name(self):
65 - file_name = '/tmp/../path'
66 + candidates = [
67 + ('tmp/../path', 'tmp/..'),
68 + ('tmp\\..\\path', 'tmp/..'),
69 + ('/tmp/../path', '/tmp/..'),
70 + ('\\tmp\\..\\path', '/tmp/..'),
71 + ]
72 s = FileSystemStorage()
73 - msg = "Detected path traversal attempt in '/tmp/..'"
74 - with self.assertRaisesMessage(SuspiciousFileOperation, msg):
75 - s.get_available_name(file_name)
76 - with self.assertRaisesMessage(SuspiciousFileOperation, msg):
77 - s.generate_filename(file_name)
78 + for file_name, path in candidates:
79 + msg = "Detected path traversal attempt in '%s'" % path
80 + with self.subTest(file_name=file_name):
81 + with self.assertRaisesMessage(SuspiciousFileOperation, msg):
82 + s.get_available_name(file_name)
83 + with self.assertRaisesMessage(SuspiciousFileOperation, msg):
84 + s.generate_filename(file_name)
85
86 def test_filefield_dangerous_filename(self):
87 candidates = [
88 diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py
89 index 6d17a7118b4e..72380932447f 100644
90 --- a/tests/file_storage/tests.py
91 +++ b/tests/file_storage/tests.py
92 @@ -297,6 +297,12 @@ def test_file_save_with_path(self):
93
94 self.storage.delete('path/to/test.file')
95
96 + def test_file_save_abs_path(self):
97 + test_name = 'path/to/test.file'
98 + f = ContentFile('file saved with path')
99 + f_name = self.storage.save(os.path.join(self.temp_dir, test_name), f)
100 + self.assertEqual(f_name, test_name)
101 +
102 def test_save_doesnt_close(self):
103 with TemporaryUploadedFile('test', 'text/plain', 1, 'utf8') as file:
104 file.write(b'1')

  ViewVC Help
Powered by ViewVC 1.1.28