From 237f286c5347458a7a7fd5c17df2ee35136967b012bf10e62b7351d210b966fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Schr=C3=B6ter?= Date: Wed, 4 Sep 2024 09:08:57 +0200 Subject: [PATCH] Sync from SUSE:SLFO:Main python-Django revision 2bd7ba1c498ee607b8fe04ff26398472 --- CVE-2024-27351.patch | 121 ----------------- CVE-2024-38875.patch | 164 +++++++++++++++++++++++ CVE-2024-39329.patch | 87 ++++++++++++ CVE-2024-39330.patch | 180 +++++++++++++++++++++++++ CVE-2024-39614.patch | 135 +++++++++++++++++++ CVE-2024-41989.patch | 79 +++++++++++ CVE-2024-41990.patch | 64 +++++++++ CVE-2024-41991.patch | 117 ++++++++++++++++ CVE-2024-42005.patch | 78 +++++++++++ CVE-2024-45230.patch | 133 +++++++++++++++++++ CVE-2024-45231.patch | 159 ++++++++++++++++++++++ Django-4.2.11.checksum.txt | 67 ++++++++++ Django-4.2.11.tar.gz | 3 + Django-4.2.6.checksum.txt | 67 ---------- Django-4.2.6.tar.gz | 3 - dirty-hack-remove-assert.patch | 25 ++++ fix-safemimetext-set_payload.patch | 14 ++ python-Django.changes | 182 +++++++++++++++++++------ python-Django.keyring | 205 +++++++++++++++++------------ python-Django.spec | 35 ++++- 20 files changed, 1596 insertions(+), 322 deletions(-) delete mode 100644 CVE-2024-27351.patch create mode 100644 CVE-2024-38875.patch create mode 100644 CVE-2024-39329.patch create mode 100644 CVE-2024-39330.patch create mode 100644 CVE-2024-39614.patch create mode 100644 CVE-2024-41989.patch create mode 100644 CVE-2024-41990.patch create mode 100644 CVE-2024-41991.patch create mode 100644 CVE-2024-42005.patch create mode 100644 CVE-2024-45230.patch create mode 100644 CVE-2024-45231.patch create mode 100644 Django-4.2.11.checksum.txt create mode 100644 Django-4.2.11.tar.gz delete mode 100644 Django-4.2.6.checksum.txt delete mode 100644 Django-4.2.6.tar.gz create mode 100644 dirty-hack-remove-assert.patch create mode 100644 fix-safemimetext-set_payload.patch diff --git a/CVE-2024-27351.patch b/CVE-2024-27351.patch deleted file mode 100644 index ffa4ab9..0000000 --- a/CVE-2024-27351.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 2d173757922183f7e9b79d31fd4ccd9086cc6ce2 Mon Sep 17 00:00:00 2001 -From: Shai Berger -Date: Mon, 19 Feb 2024 13:56:37 +0100 -Subject: [PATCH] [4.2.x] Fixed CVE-2024-27351 -- Prevented potential ReDoS in - Truncator.words(). - -Thanks Seokchan Yoon for the report. - -Co-Authored-By: Mariusz Felisiak ---- - django/utils/text.py | 57 ++++++++++++++++++++++++++++++++-- - docs/releases/3.2.25.txt | 8 +++++ - docs/releases/4.2.11.txt | 8 +++++ - tests/utils_tests/test_text.py | 26 ++++++++++++++++ - 4 files changed, 97 insertions(+), 2 deletions(-) - -Index: Django-4.2.6/django/utils/text.py -=================================================================== ---- Django-4.2.6.orig/django/utils/text.py -+++ Django-4.2.6/django/utils/text.py -@@ -23,8 +23,61 @@ def capfirst(x): - return x[0].upper() + x[1:] - - --# Set up regular expressions --re_words = _lazy_re_compile(r"<[^>]+?>|([^<>\s]+)", re.S) -+# ----- Begin security-related performance workaround ----- -+ -+# We used to have, below -+# -+# re_words = _lazy_re_compile(r"<[^>]+?>|([^<>\s]+)", re.S) -+# -+# But it was shown that this regex, in the way we use it here, has some -+# catastrophic edge-case performance features. Namely, when it is applied to -+# text with only open brackets "<<<...". The class below provides the services -+# and correct answers for the use cases, but in these edge cases does it much -+# faster. -+re_notag = _lazy_re_compile(r"([^<>\s]+)", re.S) -+re_prt = _lazy_re_compile(r"<|([^<>\s]+)", re.S) -+ -+ -+class WordsRegex: -+ @staticmethod -+ def search(text, pos): -+ # Look for "<" or a non-tag word. -+ partial = re_prt.search(text, pos) -+ if partial is None or partial[1] is not None: -+ return partial -+ -+ # "<" was found, look for a closing ">". -+ end = text.find(">", partial.end(0)) -+ if end < 0: -+ # ">" cannot be found, look for a word. -+ return re_notag.search(text, pos + 1) -+ else: -+ # "<" followed by a ">" was found -- fake a match. -+ end += 1 -+ return FakeMatch(text[partial.start(0) : end], end) -+ -+ -+class FakeMatch: -+ __slots__ = ["_text", "_end"] -+ -+ def end(self, group=0): -+ assert group == 0, "This specific object takes only group=0" -+ return self._end -+ -+ def __getitem__(self, group): -+ if group == 1: -+ return None -+ assert group == 0, "This specific object takes only group in {0,1}" -+ return self._text -+ -+ def __init__(self, text, end): -+ self._text, self._end = text, end -+ -+ -+# ----- End security-related performance workaround ----- -+ -+# Set up regular expressions. -+re_words = WordsRegex - re_chars = _lazy_re_compile(r"<[^>]+?>|(.)", re.S) - re_tag = _lazy_re_compile(r"<(/)?(\S+?)(?:(\s*/)|\s.*?)?>", re.S) - re_newlines = _lazy_re_compile(r"\r\n|\r") # Used in normalize_newlines -Index: Django-4.2.6/tests/utils_tests/test_text.py -=================================================================== ---- Django-4.2.6.orig/tests/utils_tests/test_text.py -+++ Django-4.2.6/tests/utils_tests/test_text.py -@@ -183,6 +183,32 @@ class TestUtilsText(SimpleTestCase): - truncator = text.Truncator("

I <3 python, what about you?

") - self.assertEqual("

I <3 python,…

", truncator.words(3, html=True)) - -+ # Only open brackets. -+ test = "<" * 60_000 -+ truncator = text.Truncator(test) -+ self.assertEqual(truncator.words(1, html=True), test) -+ -+ # Tags with special chars in attrs. -+ truncator = text.Truncator( -+ """Hello, my dear lady!""" -+ ) -+ self.assertEqual( -+ """Hello, my dear…""", -+ truncator.words(3, html=True), -+ ) -+ -+ # Tags with special non-latin chars in attrs. -+ truncator = text.Truncator("""

Hello, my dear lady!

""") -+ self.assertEqual( -+ """

Hello, my dear…

""", -+ truncator.words(3, html=True), -+ ) -+ -+ # Misplaced brackets. -+ truncator = text.Truncator("hello >< world") -+ self.assertEqual(truncator.words(1, html=True), "hello…") -+ self.assertEqual(truncator.words(2, html=True), "hello >< world") -+ - @patch("django.utils.text.Truncator.MAX_LENGTH_HTML", 10_000) - def test_truncate_words_html_size_limit(self): - max_len = text.Truncator.MAX_LENGTH_HTML diff --git a/CVE-2024-38875.patch b/CVE-2024-38875.patch new file mode 100644 index 0000000..adaa487 --- /dev/null +++ b/CVE-2024-38875.patch @@ -0,0 +1,164 @@ +From 79f368764295df109a37192f6182fb6f361d85b5 Mon Sep 17 00:00:00 2001 +From: Adam Johnson +Date: Mon, 24 Jun 2024 15:30:59 +0200 +Subject: [PATCH] [4.2.x] Fixed CVE-2024-38875 -- Mitigated potential DoS in + urlize and urlizetrunc template filters. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Thank you to Elias Myllymäki for the report. + +Co-authored-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +--- + django/utils/html.py | 90 +++++++++++++++++++++++++--------- + tests/utils_tests/test_html.py | 7 +++ + 2 files changed, 73 insertions(+), 24 deletions(-) + +diff --git a/django/utils/html.py b/django/utils/html.py +index fdb88d6709..fd313ff9ca 100644 +--- a/django/utils/html.py ++++ b/django/utils/html.py +@@ -7,7 +7,7 @@ from html.parser import HTMLParser + from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit + + from django.utils.encoding import punycode +-from django.utils.functional import Promise, keep_lazy, keep_lazy_text ++from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text + from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS + from django.utils.regex_helper import _lazy_re_compile + from django.utils.safestring import SafeData, SafeString, mark_safe +@@ -225,6 +225,16 @@ def smart_urlquote(url): + return urlunsplit((scheme, netloc, path, query, fragment)) + + ++class CountsDict(dict): ++ def __init__(self, *args, word, **kwargs): ++ super().__init__(*args, *kwargs) ++ self.word = word ++ ++ def __missing__(self, key): ++ self[key] = self.word.count(key) ++ return self[key] ++ ++ + class Urlizer: + """ + Convert any URLs in text into clickable links. +@@ -330,40 +340,72 @@ class Urlizer: + return x + return "%s…" % x[: max(0, limit - 1)] + ++ @cached_property ++ def wrapping_punctuation_openings(self): ++ return "".join(dict(self.wrapping_punctuation).keys()) ++ ++ @cached_property ++ def trailing_punctuation_chars_no_semicolon(self): ++ return self.trailing_punctuation_chars.replace(";", "") ++ ++ @cached_property ++ def trailing_punctuation_chars_has_semicolon(self): ++ return ";" in self.trailing_punctuation_chars ++ + def trim_punctuation(self, word): + """ + Trim trailing and wrapping punctuation from `word`. Return the items of + the new state. + """ +- lead, middle, trail = "", word, "" ++ # Strip all opening wrapping punctuation. ++ middle = word.lstrip(self.wrapping_punctuation_openings) ++ lead = word[: len(word) - len(middle)] ++ trail = "" ++ + # Continue trimming until middle remains unchanged. + trimmed_something = True +- while trimmed_something: ++ counts = CountsDict(word=middle) ++ while trimmed_something and middle: + trimmed_something = False + # Trim wrapping punctuation. + for opening, closing in self.wrapping_punctuation: +- if middle.startswith(opening): +- middle = middle[len(opening) :] +- lead += opening +- trimmed_something = True +- # Keep parentheses at the end only if they're balanced. +- if ( +- middle.endswith(closing) +- and middle.count(closing) == middle.count(opening) + 1 +- ): +- middle = middle[: -len(closing)] +- trail = closing + trail +- trimmed_something = True +- # Trim trailing punctuation (after trimming wrapping punctuation, +- # as encoded entities contain ';'). Unescape entities to avoid +- # breaking them by removing ';'. +- middle_unescaped = html.unescape(middle) +- stripped = middle_unescaped.rstrip(self.trailing_punctuation_chars) +- if middle_unescaped != stripped: +- punctuation_count = len(middle_unescaped) - len(stripped) +- trail = middle[-punctuation_count:] + trail +- middle = middle[:-punctuation_count] ++ if counts[opening] < counts[closing]: ++ rstripped = middle.rstrip(closing) ++ if rstripped != middle: ++ strip = counts[closing] - counts[opening] ++ trail = middle[-strip:] ++ middle = middle[:-strip] ++ trimmed_something = True ++ counts[closing] -= strip ++ ++ rstripped = middle.rstrip(self.trailing_punctuation_chars_no_semicolon) ++ if rstripped != middle: ++ trail = middle[len(rstripped) :] + trail ++ middle = rstripped + trimmed_something = True ++ ++ if self.trailing_punctuation_chars_has_semicolon and middle.endswith(";"): ++ # Only strip if not part of an HTML entity. ++ amp = middle.rfind("&") ++ if amp == -1: ++ can_strip = True ++ else: ++ potential_entity = middle[amp:] ++ escaped = html.unescape(potential_entity) ++ can_strip = (escaped == potential_entity) or escaped.endswith(";") ++ ++ if can_strip: ++ rstripped = middle.rstrip(";") ++ amount_stripped = len(middle) - len(rstripped) ++ if amp > -1 and amount_stripped > 1: ++ # Leave a trailing semicolon as might be an entity. ++ trail = middle[len(rstripped) + 1 :] + trail ++ middle = rstripped + ";" ++ else: ++ trail = middle[len(rstripped) :] + trail ++ middle = rstripped ++ trimmed_something = True ++ + return lead, middle, trail + + @staticmethod +diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py +index b7a7396075..6dab41634a 100644 +--- a/tests/utils_tests/test_html.py ++++ b/tests/utils_tests/test_html.py +@@ -342,6 +342,13 @@ class TestUtilsHtml(SimpleTestCase): + "foo@.example.com", + "foo@localhost", + "foo@localhost.", ++ # trim_punctuation catastrophic tests ++ "(" * 100_000 + ":" + ")" * 100_000, ++ "(" * 100_000 + "&:" + ")" * 100_000, ++ "([" * 100_000 + ":" + "])" * 100_000, ++ "[(" * 100_000 + ":" + ")]" * 100_000, ++ "([[" * 100_000 + ":" + "]])" * 100_000, ++ "&:" + ";" * 100_000, + ) + for value in tests: + with self.subTest(value=value): +-- +2.45.2 + diff --git a/CVE-2024-39329.patch b/CVE-2024-39329.patch new file mode 100644 index 0000000..9a18615 --- /dev/null +++ b/CVE-2024-39329.patch @@ -0,0 +1,87 @@ +From 156d3186c96e3ec2ca73b8b25dc2ef366e38df14 Mon Sep 17 00:00:00 2001 +From: Michael Manfre +Date: Fri, 14 Jun 2024 22:12:58 -0400 +Subject: [PATCH] [4.2.x] Fixed CVE-2024-39329 -- Standarized timing of + verify_password() when checking unusuable passwords. + +Refs #20760. + +Thanks Michael Manfre for the fix and to Adam Johnson for the review. +--- + django/contrib/auth/hashers.py | 10 ++++++++-- + tests/auth_tests/test_hashers.py | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 40 insertions(+), 2 deletions(-) + +diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py +index 9db5a12e13..f11bc8a0f3 100644 +--- a/django/contrib/auth/hashers.py ++++ b/django/contrib/auth/hashers.py +@@ -43,14 +43,20 @@ def check_password(password, encoded, setter=None, preferred="default"): + If setter is specified, it'll be called when you need to + regenerate the password. + """ +- if password is None or not is_password_usable(encoded): +- return False ++ fake_runtime = password is None or not is_password_usable(encoded) + + preferred = get_hasher(preferred) + try: + hasher = identify_hasher(encoded) + except ValueError: + # encoded is gibberish or uses a hasher that's no longer installed. ++ fake_runtime = True ++ ++ if fake_runtime: ++ # Run the default password hasher once to reduce the timing difference ++ # between an existing user with an unusable password and a nonexistent ++ # user or missing hasher (similar to #20760). ++ make_password(get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH)) + return False + + hasher_changed = hasher.algorithm != preferred.algorithm +diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py +index 36f22d5f09..3da495f2be 100644 +--- a/tests/auth_tests/test_hashers.py ++++ b/tests/auth_tests/test_hashers.py +@@ -613,6 +613,38 @@ class TestUtilsHashPass(SimpleTestCase): + check_password("wrong_password", encoded) + self.assertEqual(hasher.harden_runtime.call_count, 1) + ++ def test_check_password_calls_make_password_to_fake_runtime(self): ++ hasher = get_hasher("default") ++ cases = [ ++ (None, None, None), # no plain text password provided ++ ("foo", make_password(password=None), None), # unusable encoded ++ ("letmein", make_password(password="letmein"), ValueError), # valid encoded ++ ] ++ for password, encoded, hasher_side_effect in cases: ++ with ( ++ self.subTest(encoded=encoded), ++ mock.patch( ++ "django.contrib.auth.hashers.identify_hasher", ++ side_effect=hasher_side_effect, ++ ) as mock_identify_hasher, ++ mock.patch( ++ "django.contrib.auth.hashers.make_password" ++ ) as mock_make_password, ++ mock.patch( ++ "django.contrib.auth.hashers.get_random_string", ++ side_effect=lambda size: "x" * size, ++ ), ++ mock.patch.object(hasher, "verify"), ++ ): ++ # Ensure make_password is called to standardize timing. ++ check_password(password, encoded) ++ self.assertEqual(hasher.verify.call_count, 0) ++ self.assertEqual(mock_identify_hasher.mock_calls, [mock.call(encoded)]) ++ self.assertEqual( ++ mock_make_password.mock_calls, ++ [mock.call("x" * UNUSABLE_PASSWORD_SUFFIX_LENGTH)], ++ ) ++ + def test_encode_invalid_salt(self): + hasher_classes = [ + MD5PasswordHasher, +-- +2.45.2 + diff --git a/CVE-2024-39330.patch b/CVE-2024-39330.patch new file mode 100644 index 0000000..c91443b --- /dev/null +++ b/CVE-2024-39330.patch @@ -0,0 +1,180 @@ +From 2b00edc0151a660d1eb86da4059904a0fc4e095e Mon Sep 17 00:00:00 2001 +From: Natalia <124304+nessita@users.noreply.github.com> +Date: Wed, 20 Mar 2024 13:55:21 -0300 +Subject: [PATCH] [4.2.x] Fixed CVE-2024-39330 -- Added extra file name + validation in Storage's save method. + +Thanks to Josh Schneier for the report, and to Carlton Gibson and Sarah +Boyce for the reviews. +--- + django/core/files/storage/base.py | 11 +++++ + django/core/files/utils.py | 7 ++-- + tests/file_storage/test_base.py | 70 +++++++++++++++++++++++++++++++ + tests/file_storage/tests.py | 11 ++--- + tests/file_uploads/tests.py | 2 +- + 5 files changed, 88 insertions(+), 13 deletions(-) + create mode 100644 tests/file_storage/test_base.py + +diff --git a/django/core/files/storage/base.py b/django/core/files/storage/base.py +index 16ac22f70a..03a1b44edb 100644 +--- a/django/core/files/storage/base.py ++++ b/django/core/files/storage/base.py +@@ -34,7 +34,18 @@ class Storage: + if not hasattr(content, "chunks"): + content = File(content, name) + ++ # Ensure that the name is valid, before and after having the storage ++ # system potentially modifying the name. This duplicates the check made ++ # inside `get_available_name` but it's necessary for those cases where ++ # `get_available_name` is overriden and validation is lost. ++ validate_file_name(name, allow_relative_path=True) ++ ++ # Potentially find a different name depending on storage constraints. + name = self.get_available_name(name, max_length=max_length) ++ # Validate the (potentially) new name. ++ validate_file_name(name, allow_relative_path=True) ++ ++ # The save operation should return the actual name of the file saved. + name = self._save(name, content) + # Ensure that the name returned from the storage system is still valid. + validate_file_name(name, allow_relative_path=True) +diff --git a/django/core/files/utils.py b/django/core/files/utils.py +index 85342b2f3f..11e4f07724 100644 +--- a/django/core/files/utils.py ++++ b/django/core/files/utils.py +@@ -10,10 +10,9 @@ def validate_file_name(name, allow_relative_path=False): + raise SuspiciousFileOperation("Could not derive file name from '%s'" % name) + + if allow_relative_path: +- # Use PurePosixPath() because this branch is checked only in +- # FileField.generate_filename() where all file paths are expected to be +- # Unix style (with forward slashes). +- path = pathlib.PurePosixPath(name) ++ # Ensure that name can be treated as a pure posix path, i.e. Unix ++ # style (with forward slashes). ++ path = pathlib.PurePosixPath(str(name).replace("\\", "/")) + if path.is_absolute() or ".." in path.parts: + raise SuspiciousFileOperation( + "Detected path traversal attempt in '%s'" % name +diff --git a/tests/file_storage/test_base.py b/tests/file_storage/test_base.py +new file mode 100644 +index 0000000000..c5338b8e66 +--- /dev/null ++++ b/tests/file_storage/test_base.py +@@ -0,0 +1,70 @@ ++import os ++from unittest import mock ++ ++from django.core.exceptions import SuspiciousFileOperation ++from django.core.files.storage import Storage ++from django.test import SimpleTestCase ++ ++ ++class CustomStorage(Storage): ++ """Simple Storage subclass implementing the bare minimum for testing.""" ++ ++ def exists(self, name): ++ return False ++ ++ def _save(self, name): ++ return name ++ ++ ++class StorageValidateFileNameTests(SimpleTestCase): ++ invalid_file_names = [ ++ os.path.join("path", "to", os.pardir, "test.file"), ++ os.path.join(os.path.sep, "path", "to", "test.file"), ++ ] ++ error_msg = "Detected path traversal attempt in '%s'" ++ ++ def test_validate_before_get_available_name(self): ++ s = CustomStorage() ++ # The initial name passed to `save` is not valid nor safe, fail early. ++ for name in self.invalid_file_names: ++ with ( ++ self.subTest(name=name), ++ mock.patch.object(s, "get_available_name") as mock_get_available_name, ++ mock.patch.object(s, "_save") as mock_internal_save, ++ ): ++ with self.assertRaisesMessage( ++ SuspiciousFileOperation, self.error_msg % name ++ ): ++ s.save(name, content="irrelevant") ++ self.assertEqual(mock_get_available_name.mock_calls, []) ++ self.assertEqual(mock_internal_save.mock_calls, []) ++ ++ def test_validate_after_get_available_name(self): ++ s = CustomStorage() ++ # The initial name passed to `save` is valid and safe, but the returned ++ # name from `get_available_name` is not. ++ for name in self.invalid_file_names: ++ with ( ++ self.subTest(name=name), ++ mock.patch.object(s, "get_available_name", return_value=name), ++ mock.patch.object(s, "_save") as mock_internal_save, ++ ): ++ with self.assertRaisesMessage( ++ SuspiciousFileOperation, self.error_msg % name ++ ): ++ s.save("valid-file-name.txt", content="irrelevant") ++ self.assertEqual(mock_internal_save.mock_calls, []) ++ ++ def test_validate_after_internal_save(self): ++ s = CustomStorage() ++ # The initial name passed to `save` is valid and safe, but the result ++ # from `_save` is not (this is achieved by monkeypatching _save). ++ for name in self.invalid_file_names: ++ with ( ++ self.subTest(name=name), ++ mock.patch.object(s, "_save", return_value=name), ++ ): ++ with self.assertRaisesMessage( ++ SuspiciousFileOperation, self.error_msg % name ++ ): ++ s.save("valid-file-name.txt", content="irrelevant") +diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py +index 7fb57fbce4..44bea8c180 100644 +--- a/tests/file_storage/tests.py ++++ b/tests/file_storage/tests.py +@@ -342,22 +342,17 @@ class FileStorageTests(SimpleTestCase): + + self.storage.delete("path/to/test.file") + +- def test_file_save_abs_path(self): +- test_name = "path/to/test.file" +- f = ContentFile("file saved with path") +- f_name = self.storage.save(os.path.join(self.temp_dir, test_name), f) +- self.assertEqual(f_name, test_name) +- + @unittest.skipUnless( + symlinks_supported(), "Must be able to symlink to run this test." + ) + def test_file_save_broken_symlink(self): + """A new path is created on save when a broken symlink is supplied.""" + nonexistent_file_path = os.path.join(self.temp_dir, "nonexistent.txt") +- broken_symlink_path = os.path.join(self.temp_dir, "symlink.txt") ++ broken_symlink_file_name = "symlink.txt" ++ broken_symlink_path = os.path.join(self.temp_dir, broken_symlink_file_name) + os.symlink(nonexistent_file_path, broken_symlink_path) + f = ContentFile("some content") +- f_name = self.storage.save(broken_symlink_path, f) ++ f_name = self.storage.save(broken_symlink_file_name, f) + self.assertIs(os.path.exists(os.path.join(self.temp_dir, f_name)), True) + + def test_save_doesnt_close(self): +diff --git a/tests/file_uploads/tests.py b/tests/file_uploads/tests.py +index 693efc4c62..24c703a309 100644 +--- a/tests/file_uploads/tests.py ++++ b/tests/file_uploads/tests.py +@@ -826,7 +826,7 @@ class DirectoryCreationTests(SimpleTestCase): + default_storage.delete(UPLOAD_TO) + # Create a file with the upload directory name + with SimpleUploadedFile(UPLOAD_TO, b"x") as file: +- default_storage.save(UPLOAD_TO, file) ++ default_storage.save(UPLOAD_FOLDER, file) + self.addCleanup(default_storage.delete, UPLOAD_TO) + msg = "%s exists and is not a directory." % UPLOAD_TO + with self.assertRaisesMessage(FileExistsError, msg): +-- +2.45.2 + diff --git a/CVE-2024-39614.patch b/CVE-2024-39614.patch new file mode 100644 index 0000000..56c2a93 --- /dev/null +++ b/CVE-2024-39614.patch @@ -0,0 +1,135 @@ +From 17358fb35fb7217423d4c4877ccb6d1a3a40b1c3 Mon Sep 17 00:00:00 2001 +From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +Date: Wed, 26 Jun 2024 12:11:54 +0200 +Subject: [PATCH] [4.2.x] Fixed CVE-2024-39614 -- Mitigated potential DoS in + get_supported_language_variant(). + +Language codes are now parsed with a maximum length limit of 500 chars. + +Thanks to MProgrammer for the report. +--- + django/utils/translation/trans_real.py | 25 ++++++++++++++++++++----- + docs/ref/utils.txt | 10 ++++++++++ + tests/i18n/tests.py | 11 +++++++++++ + 3 files changed, 41 insertions(+), 5 deletions(-) + +diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py +index 872c80b00f..ce13d1e69c 100644 +--- a/django/utils/translation/trans_real.py ++++ b/django/utils/translation/trans_real.py +@@ -31,9 +31,10 @@ _default = None + CONTEXT_SEPARATOR = "\x04" + + # Maximum number of characters that will be parsed from the Accept-Language +-# header to prevent possible denial of service or memory exhaustion attacks. +-# About 10x longer than the longest value shown on MDN’s Accept-Language page. +-ACCEPT_LANGUAGE_HEADER_MAX_LENGTH = 500 ++# header or cookie to prevent possible denial of service or memory exhaustion ++# attacks. About 10x longer than the longest value shown on MDN’s ++# Accept-Language page. ++LANGUAGE_CODE_MAX_LENGTH = 500 + + # Format of Accept-Language header values. From RFC 9110 Sections 12.4.2 and + # 12.5.4, and RFC 5646 Section 2.1. +@@ -497,11 +498,25 @@ def get_supported_language_variant(lang_code, strict=False): + If `strict` is False (the default), look for a country-specific variant + when neither the language code nor its generic variant is found. + ++ The language code is truncated to a maximum length to avoid potential ++ denial of service attacks. ++ + lru_cache should have a maxsize to prevent from memory exhaustion attacks, + as the provided language codes are taken from the HTTP request. See also + . + """ + if lang_code: ++ # Truncate the language code to a maximum length to avoid potential ++ # denial of service attacks. ++ if len(lang_code) > LANGUAGE_CODE_MAX_LENGTH: ++ if ( ++ not strict ++ and (index := lang_code.rfind("-", 0, LANGUAGE_CODE_MAX_LENGTH)) > 0 ++ ): ++ # There is a generic variant under the maximum length accepted length. ++ lang_code = lang_code[:index] ++ else: ++ raise ValueError("'lang_code' exceeds the maximum accepted length") + # If 'zh-hant-tw' is not supported, try special fallback or subsequent + # language codes i.e. 'zh-hant' and 'zh'. + possible_lang_codes = [lang_code] +@@ -625,13 +640,13 @@ def parse_accept_lang_header(lang_string): + functools.lru_cache() to avoid repetitive parsing of common header values. + """ + # If the header value doesn't exceed the maximum allowed length, parse it. +- if len(lang_string) <= ACCEPT_LANGUAGE_HEADER_MAX_LENGTH: ++ if len(lang_string) <= LANGUAGE_CODE_MAX_LENGTH: + return _parse_accept_lang_header(lang_string) + + # If there is at least one comma in the value, parse up to the last comma + # before the max length, skipping any truncated parts at the end of the + # header value. +- if (index := lang_string.rfind(",", 0, ACCEPT_LANGUAGE_HEADER_MAX_LENGTH)) > 0: ++ if (index := lang_string.rfind(",", 0, LANGUAGE_CODE_MAX_LENGTH)) > 0: + return _parse_accept_lang_header(lang_string[:index]) + + # Don't attempt to parse if there is only one language-range value which is +diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt +index b2b826684d..471a4b31eb 100644 +--- a/docs/ref/utils.txt ++++ b/docs/ref/utils.txt +@@ -1155,6 +1155,11 @@ For a complete discussion on the usage of the following see the + ``lang_code`` is ``'es-ar'`` and ``'es'`` is in :setting:`LANGUAGES` but + ``'es-ar'`` isn't. + ++ ``lang_code`` has a maximum accepted length of 500 characters. A ++ :exc:`ValueError` is raised if ``lang_code`` exceeds this limit and ++ ``strict`` is ``True``, or if there is no generic variant and ``strict`` ++ is ``False``. ++ + If ``strict`` is ``False`` (the default), a country-specific variant may + be returned when neither the language code nor its generic variant is found. + For example, if only ``'es-co'`` is in :setting:`LANGUAGES`, that's +@@ -1163,6 +1168,11 @@ For a complete discussion on the usage of the following see the + + Raises :exc:`LookupError` if nothing is found. + ++ .. versionchanged:: 4.2.14 ++ ++ In older versions, ``lang_code`` values over 500 characters were ++ processed without raising a :exc:`ValueError`. ++ + .. function:: to_locale(language) + + Turns a language name (en-us) into a locale name (en_US). +diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py +index f517c5eac7..9b029d5992 100644 +--- a/tests/i18n/tests.py ++++ b/tests/i18n/tests.py +@@ -65,6 +65,7 @@ from django.utils.translation.reloader import ( + translation_file_changed, + watch_for_translation_changes, + ) ++from django.utils.translation.trans_real import LANGUAGE_CODE_MAX_LENGTH + + from .forms import CompanyForm, I18nForm, SelectDateForm + from .models import Company, TestModel +@@ -1888,6 +1889,16 @@ class MiscTests(SimpleTestCase): + g("xyz") + with self.assertRaises(LookupError): + g("xy-zz") ++ msg = "'lang_code' exceeds the maximum accepted length" ++ with self.assertRaises(LookupError): ++ g("x" * LANGUAGE_CODE_MAX_LENGTH) ++ with self.assertRaisesMessage(ValueError, msg): ++ g("x" * (LANGUAGE_CODE_MAX_LENGTH + 1)) ++ # 167 * 3 = 501 which is LANGUAGE_CODE_MAX_LENGTH + 1. ++ self.assertEqual(g("en-" * 167), "en") ++ with self.assertRaisesMessage(ValueError, msg): ++ g("en-" * 167, strict=True) ++ self.assertEqual(g("en-" * 30000), "en") # catastrophic test + + def test_get_supported_language_variant_null(self): + g = trans_null.get_supported_language_variant +-- +2.45.2 + diff --git a/CVE-2024-41989.patch b/CVE-2024-41989.patch new file mode 100644 index 0000000..c797c65 --- /dev/null +++ b/CVE-2024-41989.patch @@ -0,0 +1,79 @@ +From 0521744d21a7854e849336af1e3a3aad44cee017 Mon Sep 17 00:00:00 2001 +From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +Date: Fri, 12 Jul 2024 11:38:34 +0200 +Subject: [PATCH 1/4] [4.2.x] Fixed CVE-2024-41989 -- Prevented excessive + memory consumption in floatformat. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Thanks Elias Myllymäki for the report. + +Co-authored-by: Shai Berger +--- + django/template/defaultfilters.py | 13 +++++++++++++ + .../filter_tests/test_floatformat.py | 17 +++++++++++++++++ + 3 files changed, 39 insertions(+) + +diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py +index d446b54ade..3f89eba6bb 100644 +--- a/django/template/defaultfilters.py ++++ b/django/template/defaultfilters.py +@@ -163,6 +163,19 @@ def floatformat(text, arg=-1): + except ValueError: + return input_val + ++ _, digits, exponent = d.as_tuple() ++ try: ++ number_of_digits_and_exponent_sum = len(digits) + abs(exponent) ++ except TypeError: ++ # Exponent values can be "F", "n", "N". ++ number_of_digits_and_exponent_sum = 0 ++ ++ # Values with more than 200 digits, or with a large exponent, are returned "as is" ++ # to avoid high memory consumption and potential denial-of-service attacks. ++ # The cut-off of 200 is consistent with django.utils.numberformat.floatformat(). ++ if number_of_digits_and_exponent_sum > 200: ++ return input_val ++ + try: + m = int(d) - d + except (ValueError, OverflowError, InvalidOperation): +diff --git a/tests/template_tests/filter_tests/test_floatformat.py b/tests/template_tests/filter_tests/test_floatformat.py +index db17622309..c22b5dca6b 100644 +--- a/tests/template_tests/filter_tests/test_floatformat.py ++++ b/tests/template_tests/filter_tests/test_floatformat.py +@@ -77,6 +77,7 @@ class FunctionTests(SimpleTestCase): + self.assertEqual(floatformat(1.5e-15, 20), "0.00000000000000150000") + self.assertEqual(floatformat(1.5e-15, -20), "0.00000000000000150000") + self.assertEqual(floatformat(1.00000000000000015, 16), "1.0000000000000002") ++ self.assertEqual(floatformat("1e199"), "1" + "0" * 199) + + def test_force_grouping(self): + with translation.override("en"): +@@ -134,6 +135,22 @@ class FunctionTests(SimpleTestCase): + self.assertEqual(floatformat(pos_inf), "inf") + self.assertEqual(floatformat(neg_inf), "-inf") + self.assertEqual(floatformat(pos_inf / pos_inf), "nan") ++ self.assertEqual(floatformat("inf"), "inf") ++ self.assertEqual(floatformat("NaN"), "NaN") ++ ++ def test_too_many_digits_to_render(self): ++ cases = [ ++ "1e200", ++ "1E200", ++ "1E10000000000000000", ++ "-1E10000000000000000", ++ "1e10000000000000000", ++ "-1e10000000000000000", ++ "1" + "0" * 1_000_000, ++ ] ++ for value in cases: ++ with self.subTest(value=value): ++ self.assertEqual(floatformat(value), value) + + def test_float_dunder_method(self): + class FloatWrapper: +-- +2.34.1 + diff --git a/CVE-2024-41990.patch b/CVE-2024-41990.patch new file mode 100644 index 0000000..6d7e462 --- /dev/null +++ b/CVE-2024-41990.patch @@ -0,0 +1,64 @@ +From 729d7934e34ff91f262f3e7089e32cab701b09ca Mon Sep 17 00:00:00 2001 +From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +Date: Thu, 18 Jul 2024 13:19:34 +0200 +Subject: [PATCH 2/4] [4.2.x] Fixed CVE-2024-41990 -- Mitigated potential DoS + in urlize and urlizetrunc template filters. + +Thanks to MProgrammer for the report. +--- + django/utils/html.py | 18 ++++++++---------- + tests/utils_tests/test_html.py | 2 ++ + 3 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/django/utils/html.py b/django/utils/html.py +index fd313ff9ca..dd52f1f7fe 100644 +--- a/django/utils/html.py ++++ b/django/utils/html.py +@@ -378,7 +378,11 @@ class Urlizer: + trimmed_something = True + counts[closing] -= strip + +- rstripped = middle.rstrip(self.trailing_punctuation_chars_no_semicolon) ++ amp = middle.rfind("&") ++ if amp == -1: ++ rstripped = middle.rstrip(self.trailing_punctuation_chars) ++ else: ++ rstripped = middle.rstrip(self.trailing_punctuation_chars_no_semicolon) + if rstripped != middle: + trail = middle[len(rstripped) :] + trail + middle = rstripped +@@ -386,15 +390,9 @@ class Urlizer: + + if self.trailing_punctuation_chars_has_semicolon and middle.endswith(";"): + # Only strip if not part of an HTML entity. +- amp = middle.rfind("&") +- if amp == -1: +- can_strip = True +- else: +- potential_entity = middle[amp:] +- escaped = html.unescape(potential_entity) +- can_strip = (escaped == potential_entity) or escaped.endswith(";") +- +- if can_strip: ++ potential_entity = middle[amp:] ++ escaped = html.unescape(potential_entity) ++ if escaped == potential_entity or escaped.endswith(";"): + rstripped = middle.rstrip(";") + amount_stripped = len(middle) - len(rstripped) + if amp > -1 and amount_stripped > 1: +diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py +index 6dab41634a..c45e0dfac1 100644 +--- a/tests/utils_tests/test_html.py ++++ b/tests/utils_tests/test_html.py +@@ -349,6 +349,8 @@ class TestUtilsHtml(SimpleTestCase): + "[(" * 100_000 + ":" + ")]" * 100_000, + "([[" * 100_000 + ":" + "]])" * 100_000, + "&:" + ";" * 100_000, ++ "&.;" * 100_000, ++ ".;" * 100_000, + ) + for value in tests: + with self.subTest(value=value): +-- +2.34.1 + diff --git a/CVE-2024-41991.patch b/CVE-2024-41991.patch new file mode 100644 index 0000000..7945131 --- /dev/null +++ b/CVE-2024-41991.patch @@ -0,0 +1,117 @@ +From 772a73f70c3d249c99c23012849e66276b7b0715 Mon Sep 17 00:00:00 2001 +From: Mariusz Felisiak +Date: Wed, 10 Jul 2024 20:30:12 +0200 +Subject: [PATCH 3/4] [4.2.x] Fixed CVE-2024-41991 -- Prevented potential ReDoS + in django.utils.html.urlize() and AdminURLFieldWidget. + +Thanks Seokchan Yoon for the report. + +Co-authored-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +--- + django/contrib/admin/widgets.py | 2 +- + django/utils/html.py | 10 ++++++++-- + tests/admin_widgets/tests.py | 7 ++++++- + tests/utils_tests/test_html.py | 13 +++++++++++++ + 5 files changed, 35 insertions(+), 4 deletions(-) + +diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py +index 5e3416bc28..3d11a40efe 100644 +--- a/django/contrib/admin/widgets.py ++++ b/django/contrib/admin/widgets.py +@@ -383,7 +383,7 @@ class AdminURLFieldWidget(forms.URLInput): + context["current_label"] = _("Currently:") + context["change_label"] = _("Change:") + context["widget"]["href"] = ( +- smart_urlquote(context["widget"]["value"]) if value else "" ++ smart_urlquote(context["widget"]["value"]) if url_valid else "" + ) + context["url_valid"] = url_valid + return context +diff --git a/django/utils/html.py b/django/utils/html.py +index dd52f1f7fe..23575d3c11 100644 +--- a/django/utils/html.py ++++ b/django/utils/html.py +@@ -13,6 +13,8 @@ from django.utils.regex_helper import _lazy_re_compile + from django.utils.safestring import SafeData, SafeString, mark_safe + from django.utils.text import normalize_newlines + ++MAX_URL_LENGTH = 2048 ++ + + @keep_lazy(SafeString) + def escape(text): +@@ -300,9 +302,9 @@ class Urlizer: + # Make URL we want to point to. + url = None + nofollow_attr = ' rel="nofollow"' if nofollow else "" +- if self.simple_url_re.match(middle): ++ if len(middle) <= MAX_URL_LENGTH and self.simple_url_re.match(middle): + url = smart_urlquote(html.unescape(middle)) +- elif self.simple_url_2_re.match(middle): ++ elif len(middle) <= MAX_URL_LENGTH and self.simple_url_2_re.match(middle): + url = smart_urlquote("http://%s" % html.unescape(middle)) + elif ":" not in middle and self.is_email_simple(middle): + local, domain = middle.rsplit("@", 1) +@@ -417,6 +419,10 @@ class Urlizer: + except ValueError: + # value contains more than one @. + return False ++ # Max length for domain name labels is 63 characters per RFC 1034. ++ # Helps to avoid ReDoS vectors in the domain part. ++ if len(p2) > 63: ++ return False + # Dot must be in p2 (e.g. example.com) + if "." not in p2 or p2.startswith("."): + return False +diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py +index 0e20206048..4281ed07c6 100644 +--- a/tests/admin_widgets/tests.py ++++ b/tests/admin_widgets/tests.py +@@ -461,7 +461,12 @@ class AdminSplitDateTimeWidgetTest(SimpleTestCase): + class AdminURLWidgetTest(SimpleTestCase): + def test_get_context_validates_url(self): + w = widgets.AdminURLFieldWidget() +- for invalid in ["", "/not/a/full/url/", 'javascript:alert("Danger XSS!")']: ++ for invalid in [ ++ "", ++ "/not/a/full/url/", ++ 'javascript:alert("Danger XSS!")', ++ "http://" + "한.글." * 1_000_000 + "com", ++ ]: + with self.subTest(url=invalid): + self.assertFalse(w.get_context("name", invalid, {})["url_valid"]) + self.assertTrue(w.get_context("name", "http://example.com", {})["url_valid"]) +diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py +index c45e0dfac1..83ebe4334b 100644 +--- a/tests/utils_tests/test_html.py ++++ b/tests/utils_tests/test_html.py +@@ -328,6 +328,15 @@ class TestUtilsHtml(SimpleTestCase): + 'Search for google.com/?q=!', + ), + ("foo@example.com", 'foo@example.com'), ++ ( ++ "test@" + "한.글." * 15 + "aaa", ++ '' ++ + "test@" ++ + "한.글." * 15 ++ + "aaa", ++ ), + ) + for value, output in tests: + with self.subTest(value=value): +@@ -336,6 +345,10 @@ class TestUtilsHtml(SimpleTestCase): + def test_urlize_unchanged_inputs(self): + tests = ( + ("a" + "@a" * 50000) + "a", # simple_email_re catastrophic test ++ # Unicode domain catastrophic tests. ++ "a@" + "한.글." * 1_000_000 + "a", ++ "http://" + "한.글." * 1_000_000 + "com", ++ "www." + "한.글." * 1_000_000 + "com", + ("a" + "." * 1000000) + "a", # trailing_punctuation catastrophic test + "foo@", + "@foo.com", +-- +2.34.1 + diff --git a/CVE-2024-42005.patch b/CVE-2024-42005.patch new file mode 100644 index 0000000..f973d9b --- /dev/null +++ b/CVE-2024-42005.patch @@ -0,0 +1,78 @@ +From b6de28f897709ee5d94ca2da21bcc98f9dade01c Mon Sep 17 00:00:00 2001 +From: Simon Charette +Date: Thu, 25 Jul 2024 18:19:13 +0200 +Subject: [PATCH 4/4] [4.2.x] Fixed CVE-2024-42005 -- Mitigated + QuerySet.values() SQL injection attacks against JSON fields. + +Thanks Eyal (eyalgabay) for the report. +--- + django/db/models/sql/query.py | 2 ++ + tests/expressions/models.py | 7 +++++++ + tests/expressions/test_queryset_values.py | 17 +++++++++++++++-- + 4 files changed, 31 insertions(+), 2 deletions(-) + +diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py +index f98c6c668b..e68fd9efb7 100644 +--- a/django/db/models/sql/query.py ++++ b/django/db/models/sql/query.py +@@ -2415,6 +2415,8 @@ class Query(BaseExpression): + self.has_select_fields = True + + if fields: ++ for field in fields: ++ self.check_alias(field) + field_names = [] + extra_names = [] + annotation_names = [] +diff --git a/tests/expressions/models.py b/tests/expressions/models.py +index 0a8a0a6584..6b21e9ccf3 100644 +--- a/tests/expressions/models.py ++++ b/tests/expressions/models.py +@@ -106,3 +106,10 @@ class UUIDPK(models.Model): + class UUID(models.Model): + uuid = models.UUIDField(null=True) + uuid_fk = models.ForeignKey(UUIDPK, models.CASCADE, null=True) ++ ++ ++class JSONFieldModel(models.Model): ++ data = models.JSONField(null=True) ++ ++ class Meta: ++ required_db_features = {"supports_json_field"} +diff --git a/tests/expressions/test_queryset_values.py b/tests/expressions/test_queryset_values.py +index 80addef37b..47bd1358de 100644 +--- a/tests/expressions/test_queryset_values.py ++++ b/tests/expressions/test_queryset_values.py +@@ -1,7 +1,7 @@ + from django.db.models import F, Sum +-from django.test import TestCase ++from django.test import TestCase, skipUnlessDBFeature + +-from .models import Company, Employee ++from .models import Company, Employee, JSONFieldModel + + + class ValuesExpressionsTests(TestCase): +@@ -43,6 +43,19 @@ class ValuesExpressionsTests(TestCase): + with self.assertRaisesMessage(ValueError, msg): + Company.objects.values(**{crafted_alias: F("ceo__salary")}) + ++ @skipUnlessDBFeature("supports_json_field") ++ def test_values_expression_alias_sql_injection_json_field(self): ++ crafted_alias = """injected_name" from "expressions_company"; --""" ++ msg = ( ++ "Column aliases cannot contain whitespace characters, quotation marks, " ++ "semicolons, or SQL comments." ++ ) ++ with self.assertRaisesMessage(ValueError, msg): ++ JSONFieldModel.objects.values(f"data__{crafted_alias}") ++ ++ with self.assertRaisesMessage(ValueError, msg): ++ JSONFieldModel.objects.values_list(f"data__{crafted_alias}") ++ + def test_values_expression_group_by(self): + # values() applies annotate() first, so values selected are grouped by + # id, not firstname. +-- +2.34.1 + diff --git a/CVE-2024-45230.patch b/CVE-2024-45230.patch new file mode 100644 index 0000000..4e30948 --- /dev/null +++ b/CVE-2024-45230.patch @@ -0,0 +1,133 @@ +From 65a776dd25b657cc32edafaad98d91aa0b51e641 Mon Sep 17 00:00:00 2001 +From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +Date: Mon, 12 Aug 2024 15:17:57 +0200 +Subject: [PATCH 1/2] [4.2.x] Fixed CVE-2024-45230 -- Mitigated potential DoS + in urlize and urlizetrunc template filters. + +Thanks MProgrammer (https://hackerone.com/mprogrammer) for the report. +--- + django/utils/html.py | 17 ++++++++------ + docs/ref/templates/builtins.txt | 11 ++++++++++ + docs/releases/4.2.16.txt | 15 +++++++++++++ + docs/releases/index.txt | 1 + + .../filter_tests/test_urlize.py | 22 +++++++++++++++++++ + tests/utils_tests/test_html.py | 1 + + 6 files changed, 60 insertions(+), 7 deletions(-) + create mode 100644 docs/releases/4.2.16.txt + +Index: Django-4.2.11/django/utils/html.py +=================================================================== +--- Django-4.2.11.orig/django/utils/html.py ++++ Django-4.2.11/django/utils/html.py +@@ -395,14 +395,17 @@ class Urlizer: + potential_entity = middle[amp:] + escaped = html.unescape(potential_entity) + if escaped == potential_entity or escaped.endswith(";"): +- rstripped = middle.rstrip(";") +- amount_stripped = len(middle) - len(rstripped) +- if amp > -1 and amount_stripped > 1: +- # Leave a trailing semicolon as might be an entity. +- trail = middle[len(rstripped) + 1 :] + trail +- middle = rstripped + ";" ++ rstripped = middle.rstrip(self.trailing_punctuation_chars) ++ trail_start = len(rstripped) ++ amount_trailing_semicolons = len(middle) - len(middle.rstrip(";")) ++ if amp > -1 and amount_trailing_semicolons > 1: ++ # Leave up to most recent semicolon as might be an entity. ++ recent_semicolon = middle[trail_start:].index(";") ++ middle_semicolon_index = recent_semicolon + trail_start + 1 ++ trail = middle[middle_semicolon_index:] + trail ++ middle = rstripped + middle[trail_start:middle_semicolon_index] + else: +- trail = middle[len(rstripped) :] + trail ++ trail = middle[trail_start:] + trail + middle = rstripped + trimmed_something = True + +Index: Django-4.2.11/docs/ref/templates/builtins.txt +=================================================================== +--- Django-4.2.11.orig/docs/ref/templates/builtins.txt ++++ Django-4.2.11/docs/ref/templates/builtins.txt +@@ -2831,6 +2831,17 @@ Django's built-in :tfilter:`escape` filt + email addresses that contain single quotes (``'``), things won't work as + expected. Apply this filter only to plain text. + ++.. warning:: ++ ++ Using ``urlize`` or ``urlizetrunc`` can incur a performance penalty, which ++ can become severe when applied to user controlled values such as content ++ stored in a :class:`~django.db.models.TextField`. You can use ++ :tfilter:`truncatechars` to add a limit to such inputs: ++ ++ .. code-block:: html+django ++ ++ {{ value|truncatechars:500|urlize }} ++ + .. templatefilter:: urlizetrunc + + ``urlizetrunc`` +Index: Django-4.2.11/docs/releases/4.2.16.txt +=================================================================== +--- /dev/null ++++ Django-4.2.11/docs/releases/4.2.16.txt +@@ -0,0 +1,15 @@ ++=========================== ++Django 4.2.16 release notes ++=========================== ++ ++*September 3, 2024* ++ ++Django 4.2.16 fixes one security issue with severity "moderate" and one ++security issues with severity "low" in 4.2.15. ++ ++CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html.urlize()`` ++=========================================================================================== ++ ++:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential ++denial-of-service attack via very large inputs with a specific sequence of ++characters. +Index: Django-4.2.11/tests/template_tests/filter_tests/test_urlize.py +=================================================================== +--- Django-4.2.11.orig/tests/template_tests/filter_tests/test_urlize.py ++++ Django-4.2.11/tests/template_tests/filter_tests/test_urlize.py +@@ -305,6 +305,28 @@ class FunctionTests(SimpleTestCase): + "http://testing.com/example.,:;)"!", + ) + ++ def test_trailing_semicolon(self): ++ self.assertEqual( ++ urlize("http://example.com?x=&", autoescape=False), ++ '' ++ "http://example.com?x=&", ++ ) ++ self.assertEqual( ++ urlize("http://example.com?x=&;", autoescape=False), ++ '' ++ "http://example.com?x=&;", ++ ) ++ self.assertEqual( ++ urlize("http://example.com?x=&;;", autoescape=False), ++ '' ++ "http://example.com?x=&;;", ++ ) ++ self.assertEqual( ++ urlize("http://example.com?x=&.;...;", autoescape=False), ++ '' ++ "http://example.com?x=&.;...;", ++ ) ++ + def test_brackets(self): + """ + #19070 - Check urlize handles brackets properly +Index: Django-4.2.11/tests/utils_tests/test_html.py +=================================================================== +--- Django-4.2.11.orig/tests/utils_tests/test_html.py ++++ Django-4.2.11/tests/utils_tests/test_html.py +@@ -364,6 +364,7 @@ class TestUtilsHtml(SimpleTestCase): + "&:" + ";" * 100_000, + "&.;" * 100_000, + ".;" * 100_000, ++ "&" + ";:" * 100_000, + ) + for value in tests: + with self.subTest(value=value): diff --git a/CVE-2024-45231.patch b/CVE-2024-45231.patch new file mode 100644 index 0000000..d9842ae --- /dev/null +++ b/CVE-2024-45231.patch @@ -0,0 +1,159 @@ +From fe42da9cdacd9f43fb0d499244314c36f9a11a19 Mon Sep 17 00:00:00 2001 +From: Natalia <124304+nessita@users.noreply.github.com> +Date: Mon, 19 Aug 2024 14:47:38 -0300 +Subject: [PATCH 2/2] [4.2.x] Fixed CVE-2024-45231 -- Avoided server error on + password reset when email sending fails. + +On successful submission of a password reset request, an email is sent +to the accounts known to the system. If sending this email fails (due to +email backend misconfiguration, service provider outage, network issues, +etc.), an attacker might exploit this by detecting which password reset +requests succeed and which ones generate a 500 error response. + +Thanks to Thibaut Spriet for the report, and to Mariusz Felisiak and +Sarah Boyce for the reviews. +--- + django/contrib/auth/forms.py | 9 ++++++++- + docs/ref/logging.txt | 12 ++++++++++++ + docs/releases/4.2.16.txt | 11 +++++++++++ + docs/topics/auth/default.txt | 4 +++- + tests/auth_tests/test_forms.py | 21 +++++++++++++++++++++ + tests/mail/custombackend.py | 5 +++++ + 6 files changed, 60 insertions(+), 2 deletions(-) + +diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py +index 061dc81b42..20ce1ba39c 100644 +--- a/django/contrib/auth/forms.py ++++ b/django/contrib/auth/forms.py +@@ -1,3 +1,4 @@ ++import logging + import unicodedata + + from django import forms +@@ -16,6 +17,7 @@ from django.utils.translation import gettext + from django.utils.translation import gettext_lazy as _ + + UserModel = get_user_model() ++logger = logging.getLogger("django.contrib.auth") + + + def _unicode_ci_compare(s1, s2): +@@ -314,7 +316,12 @@ class PasswordResetForm(forms.Form): + html_email = loader.render_to_string(html_email_template_name, context) + email_message.attach_alternative(html_email, "text/html") + +- email_message.send() ++ try: ++ email_message.send() ++ except Exception: ++ logger.exception( ++ "Failed to send password reset email to %s:", context["user"].pk ++ ) + + def get_users(self, email): + """Given an email, return matching user(s) who should receive a reset. +diff --git a/docs/ref/logging.txt b/docs/ref/logging.txt +index b11fb752f7..3d33e0af63 100644 +--- a/docs/ref/logging.txt ++++ b/docs/ref/logging.txt +@@ -204,6 +204,18 @@ all database queries. + Support for logging transaction management queries (``BEGIN``, ``COMMIT``, + and ``ROLLBACK``) was added. + ++.. _django-contrib-auth-logger: ++ ++``django.contrib.auth`` ++~~~~~~~~~~~~~~~~~~~~~~~ ++ ++.. versionadded:: 4.2.16 ++ ++Log messages related to :doc:`contrib/auth`, particularly ``ERROR`` messages ++are generated when a :class:`~django.contrib.auth.forms.PasswordResetForm` is ++successfully submitted but the password reset email cannot be delivered due to ++a mail sending exception. ++ + .. _django-security-logger: + + ``django.security.*`` +diff --git a/docs/releases/4.2.16.txt b/docs/releases/4.2.16.txt +index 043041a97f..4e632d5d77 100644 +--- a/docs/releases/4.2.16.txt ++++ b/docs/releases/4.2.16.txt +@@ -13,3 +13,14 @@ CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html + :tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential + denial-of-service attack via very large inputs with a specific sequence of + characters. ++ ++CVE-2024-45231: Potential user email enumeration via response status on password reset ++====================================================================================== ++ ++Due to unhandled email sending failures, the ++:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote ++attackers to enumerate user emails by issuing password reset requests and ++observing the outcomes. ++ ++To mitigate this risk, exceptions occurring during password reset email sending ++are now handled and logged using the :ref:`django-contrib-auth-logger` logger. +diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt +index 528902416d..ad840c5e57 100644 +--- a/docs/topics/auth/default.txt ++++ b/docs/topics/auth/default.txt +@@ -1661,7 +1661,9 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`: + .. method:: send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None) + + Uses the arguments to send an ``EmailMultiAlternatives``. +- Can be overridden to customize how the email is sent to the user. ++ Can be overridden to customize how the email is sent to the user. If ++ you choose to override this method, be mindful of handling potential ++ exceptions raised due to email sending failures. + + :param subject_template_name: the template for the subject. + :param email_template_name: the template for the email body. +diff --git a/tests/auth_tests/test_forms.py b/tests/auth_tests/test_forms.py +index 81c56a428e..ccb1a26a2b 100644 +--- a/tests/auth_tests/test_forms.py ++++ b/tests/auth_tests/test_forms.py +@@ -1245,6 +1245,27 @@ class PasswordResetFormTest(TestDataMixin, TestCase): + ) + ) + ++ @override_settings(EMAIL_BACKEND="mail.custombackend.FailingEmailBackend") ++ def test_save_send_email_exceptions_are_catched_and_logged(self): ++ (user, username, email) = self.create_dummy_user() ++ form = PasswordResetForm({"email": email}) ++ self.assertTrue(form.is_valid()) ++ ++ with self.assertLogs("django.contrib.auth", level=0) as cm: ++ form.save() ++ ++ self.assertEqual(len(mail.outbox), 0) ++ self.assertEqual(len(cm.output), 1) ++ errors = cm.output[0].split("\n") ++ pk = user.pk ++ self.assertEqual( ++ errors[0], ++ f"ERROR:django.contrib.auth:Failed to send password reset email to {pk}:", ++ ) ++ self.assertEqual( ++ errors[-1], "ValueError: FailingEmailBackend is doomed to fail." ++ ) ++ + @override_settings(AUTH_USER_MODEL="auth_tests.CustomEmailField") + def test_custom_email_field(self): + email = "test@mail.com" +diff --git a/tests/mail/custombackend.py b/tests/mail/custombackend.py +index 14e7f077ba..c6c567b642 100644 +--- a/tests/mail/custombackend.py ++++ b/tests/mail/custombackend.py +@@ -12,3 +12,8 @@ class EmailBackend(BaseEmailBackend): + # Messages are stored in an instance variable for testing. + self.test_outbox.extend(email_messages) + return len(email_messages) ++ ++ ++class FailingEmailBackend(BaseEmailBackend): ++ def send_messages(self, email_messages): ++ raise ValueError("FailingEmailBackend is doomed to fail.") +-- +2.46.0 + diff --git a/Django-4.2.11.checksum.txt b/Django-4.2.11.checksum.txt new file mode 100644 index 0000000..0f5be3b --- /dev/null +++ b/Django-4.2.11.checksum.txt @@ -0,0 +1,67 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +This file contains MD5, SHA1, and SHA256 checksums for the source-code +tarball and wheel files of Django 4.2.11, released March 4, 2024. + +To use this file, you will need a working install of PGP or other +compatible public-key encryption software. You will also need to have +the Django release manager's public key in your keyring. This key has +the ID ``2EF56372BA48CD1B`` and can be imported from the MIT +keyserver, for example, if using the open-source GNU Privacy Guard +implementation of PGP: + + gpg --keyserver pgp.mit.edu --recv-key 2EF56372BA48CD1B + +or via the GitHub API: + + curl https://github.com/felixxm.gpg | gpg --import - + +Once the key is imported, verify this file: + + gpg --verify Django-4.2.11.checksum.txt + +Once you have verified this file, you can use normal MD5, SHA1, or SHA256 +checksumming applications to generate the checksums of the Django +package and compare them to the checksums listed below. + +Release packages +================ + +https://www.djangoproject.com/m/releases/4.2/Django-4.2.11-py3-none-any.whl +https://www.djangoproject.com/m/releases/4.2/Django-4.2.11.tar.gz + +MD5 checksums +============= + +5ac62cf0d75216275a8d5f3b9a87b7a1 Django-4.2.11-py3-none-any.whl +33dc961e25b6ed54e22b62726b334d4d Django-4.2.11.tar.gz + +SHA1 checksums +============== + +69943b2e90d352cd8d536f34a0cd38dc3d3026be Django-4.2.11-py3-none-any.whl +fda76a55736054cb5aafb73d2caa3f2d47765f9f Django-4.2.11.tar.gz + +SHA256 checksums +================ + +ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3 Django-4.2.11-py3-none-any.whl +6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 Django-4.2.11.tar.gz +-----BEGIN PGP SIGNATURE----- + +iQJPBAEBCAA5FiEEq7LCqM0B8WE2GLcNLvVjcrpIzRsFAmXle9IbHGZlbGlzaWFr +Lm1hcml1c3pAZ21haWwuY29tAAoJEC71Y3K6SM0bYRAP/RaamVJZrHq8H1vXx0IF ++H99BDF282S6rEjajxe4vhEz8JnWFUkALlvh9MQQ2GOH7M66EfYP5K0BBWZHJTki +Sf8zFRSaOYkblFaKvKMKC8m4nQ4XI2S2y3Nvx7KaaJSBsanahgDFFFcEdx8LnZdY +2Vj9S2hnm9eT/0GSbTO2nn1lWcrShoYm2ZVHgmrH1qkX24uBO7VXD3x6j2pzdplg +mW7rW03seWUtf/FQCGVnbTblxX7N0E+5BeeqwJvom8ijFEpcoFHY6EDLooXoq0MQ +aDKOU5xns4k6YnPIDWSlZKa/RhxLUhkAyyiMrS1ADZF8Ee7Xk+M8cAt6okv6EBul +gEWVtVKGYV9DKlKBqTkWcgiFH4nKSl+ckVrTK8OTss3zIUxkXQr34Ee5rJ6ciC+8 +2FHq3S55ylBvXDW1U+tfknyi78GLywjySxhdSOnZIEAaWDnFpW3X+838FKRUXMlC +rMvQJswtpPPx76E1RyzwSuBdpVkzHoC49GGeZfyPynlupZJ9Vcue7w2q8WvQ0GrX +/qhPFU21AEvf2siOlFwSr9TopjIMFckHMuLrSrVyoYoDZq1DXyprEpkasPXOq9zM +FTqWPscC7M2BI0mAAMcJTWPBlqmfwF0W7Jiqo7cZutmdSVhOxDrySr3zWYXBzfht +ERfQPBvTEYmsXtBC+H3mk040 +=I96k +-----END PGP SIGNATURE----- diff --git a/Django-4.2.11.tar.gz b/Django-4.2.11.tar.gz new file mode 100644 index 0000000..d340324 --- /dev/null +++ b/Django-4.2.11.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 +size 10426858 diff --git a/Django-4.2.6.checksum.txt b/Django-4.2.6.checksum.txt deleted file mode 100644 index e62be33..0000000 --- a/Django-4.2.6.checksum.txt +++ /dev/null @@ -1,67 +0,0 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA256 - -This file contains MD5, SHA1, and SHA256 checksums for the source-code -tarball and wheel files of Django 4.2.6, released October 4, 2023. - -To use this file, you will need a working install of PGP or other -compatible public-key encryption software. You will also need to have -the Django release manager's public key in your keyring. This key has -the ID ``2EE82A8D9470983E`` and can be imported from the MIT -keyserver, for example, if using the open-source GNU Privacy Guard -implementation of PGP: - - gpg --keyserver pgp.mit.edu --recv-key 2EE82A8D9470983E - -or via the GitHub API: - - curl https://github.com/nessita.gpg | gpg --import - - -Once the key is imported, verify this file: - - gpg --verify Django-4.2.6.checksum.txt - -Once you have verified this file, you can use normal MD5, SHA1, or SHA256 -checksumming applications to generate the checksums of the Django -package and compare them to the checksums listed below. - -Release packages -================ - -https://www.djangoproject.com/m/releases/4.2/Django-4.2.6-py3-none-any.whl -https://www.djangoproject.com/m/releases/4.2/Django-4.2.6.tar.gz - -MD5 checksums -============= - -db83d48600d6afff838e53f42f9ebebb Django-4.2.6-py3-none-any.whl -ad84c2b9bbebaa26427a2a656fe5ceea Django-4.2.6.tar.gz - -SHA1 checksums -============== - -36650eb323bd34afbe47936bd3e7bf62ed4d929c Django-4.2.6-py3-none-any.whl -6e912eeabd1df0b652e0da44cd3a556a496a1811 Django-4.2.6.tar.gz - -SHA256 checksums -================ - -a64d2487cdb00ad7461434320ccc38e60af9c404773a2f95ab0093b4453a3215 Django-4.2.6-py3-none-any.whl -08f41f468b63335aea0d904c5729e0250300f6a1907bf293a65499496cdbc68f Django-4.2.6.tar.gz ------BEGIN PGP SIGNATURE----- - -iQJcBAEBCABGFiEEW1sboQ2FrHxcduOPLugqjZRwmD4FAmUdYL4oHDEyNDMwNCtu -ZXNzaXRhQHVzZXJzLm5vcmVwbHkuZ2l0aHViLmNvbQAKCRAu6CqNlHCYPsQzEACE -1e0nWDjh2RkV0nLraeEOd8DkyeCAMhFsiWGVkNY7chpeoXnF0YksHg9z2MiTDDJ9 -12EyYLFZPMCzqt3gO1/4iWYu/zx7Pb8gPTeg5NTLUnezZt4QT6FSv3fY7ByubqXQ -lUp0jJJd8B3uc5zdZNLyg9OGBOHG7lqv7Eg7H3YUwXFo7VOkerLLgASTScE22Guo -jyQYlnnLtse70l/MTTdmJYwJxbNM7LP4RXSovHV34nL2HCI5vDWyNlOgVeU+MT9F -AQCW8Lb0H+GvrhL6Hc1D8xQl7OOvpo/5/53J1i/M2Ml60qeYbjWkqEByPI5d/9oS -oHMzZcbnhlWcePy7zEYfyzQ0qFv3m/qIIf2rcd3mnrusMScWGsCFSSjqWLdoT2eO -Cvz5Q+FGH8g2ce+DyfEDjDTzceReNL81lArmSPqntByYfp8COUuqBwe5PZ7T0yx7 -w2LWWICVmCfjKgQ12Rk7ElxcliIILFgETJVuPtjx6SrkDEzNDpiTVQH2E9LXZYsV -5Qd7QEfTh0oEBBTPxHtSskTnfP/mJWAk62uLWYEcbmHTTcw4wQdnncwJS01tG+BD -sd4iY0UeL4cof3sxkwGkvC6Sr0H5fgYCJs4AgAmcWBCzwFvtUp/J3+/WEr9wExBH -/Fveza/vFJifyN1FwiemueuOqG/tvy1XJL6jCRH3gQ== -=cttz ------END PGP SIGNATURE----- diff --git a/Django-4.2.6.tar.gz b/Django-4.2.6.tar.gz deleted file mode 100644 index 6a7f2b8..0000000 --- a/Django-4.2.6.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08f41f468b63335aea0d904c5729e0250300f6a1907bf293a65499496cdbc68f -size 10407018 diff --git a/dirty-hack-remove-assert.patch b/dirty-hack-remove-assert.patch new file mode 100644 index 0000000..fadb3c1 --- /dev/null +++ b/dirty-hack-remove-assert.patch @@ -0,0 +1,25 @@ +From 36736edaf595d2bbf1fe881609b2a4c8e3bac68a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Thu, 29 Jun 2023 12:29:21 +0200 +Subject: [PATCH] Dirty hack: Remove a failing assert, failure does not seem + critical + +--- + tests/settings_tests/tests.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py +index 62cbffb..b7432d3 100644 +--- a/tests/settings_tests/tests.py ++++ b/tests/settings_tests/tests.py +@@ -397,7 +397,6 @@ class TestComplexSettingOverride(SimpleTestCase): + with self.assertWarnsMessage(UserWarning, msg) as cm: + with override_settings(TEST_WARN="override"): + self.assertEqual(settings.TEST_WARN, "override") +- self.assertEqual(cm.filename, __file__) + + + class SecureProxySslHeaderTest(SimpleTestCase): +-- +2.40.1 + diff --git a/fix-safemimetext-set_payload.patch b/fix-safemimetext-set_payload.patch new file mode 100644 index 0000000..516c526 --- /dev/null +++ b/fix-safemimetext-set_payload.patch @@ -0,0 +1,14 @@ +Index: Django-4.2.11/django/core/mail/message.py +=================================================================== +--- Django-4.2.11.orig/django/core/mail/message.py ++++ Django-4.2.11/django/core/mail/message.py +@@ -168,7 +168,8 @@ class SafeMIMEText(MIMEMixin, MIMEText): + def set_payload(self, payload, charset=None): + if charset == "utf-8" and not isinstance(charset, Charset.Charset): + has_long_lines = any( +- len(line.encode()) > RFC5322_EMAIL_LINE_LENGTH_LIMIT ++ len(line.encode(errors="surrogateescape")) ++ > RFC5322_EMAIL_LINE_LENGTH_LIMIT + for line in payload.splitlines() + ) + # Quoted-Printable encoding has the side effect of shortening long diff --git a/python-Django.changes b/python-Django.changes index e29a23f..ff21693 100644 --- a/python-Django.changes +++ b/python-Django.changes @@ -1,7 +1,112 @@ ------------------------------------------------------------------- -Thu Feb 29 13:19:00 UTC 2024 - Alberto Planas Dominguez +Mon Sep 2 12:48:52 UTC 2024 - Markéta Machová -- Add CVE-2024-27351.patch patch (CVE-2024-27351, bsc#1220358) +- Add more security patches: + * CVE-2024-45230.patch (bsc#1229823) + * CVE-2024-45231.patch (bsc#1229824) + +------------------------------------------------------------------- +Thu Aug 1 09:37:57 UTC 2024 - Markéta Machová + +- Add bunch of security patches: + * CVE-2024-42005.patch (bsc#1228629) + * CVE-2024-41989.patch (bsc#1228630) + * CVE-2024-41990.patch (bsc#1228631) + * CVE-2024-41991.patch (bsc#1228632) + +------------------------------------------------------------------- +Fri Jul 12 12:40:47 UTC 2024 - Nico Krapp + +- Add CVE-2024-38875.patch (bsc#1227590) + * CVE-2024-38875: Potential denial-of-service attack via + certain inputs with a very large number of brackets +- Add CVE-2024-39329.patch (bsc#1227593) + * CVE-2024-39329: Username enumeration through timing difference + for users with unusable passwords +- Add CVE-2024-39330.patch (bsc#1227594) + * CVE-2024-39330: Potential directory traversal in + django.core.files.storage.Storage.save() +- Add CVE-2024-39614.patch (bsc#1227595) + * CVE-2024-39614: Potential denial-of-service through + django.utils.translation.get_supported_language_variant() + +------------------------------------------------------------------- +Thu Apr 18 06:39:36 UTC 2024 - Daniel Garcia + +- Add fix-safemimetext-set_payload.patch, to support python 3.11.9+ + (gh#django/django@b231bcd19e57, bsc#1222880) + +------------------------------------------------------------------- +Mon Mar 4 14:05:28 UTC 2024 - Alberto Planas Dominguez + +- Update to 4.2.11 (CVE-2024-27351, bsc#1220358) + * CVE-2024-27351: Potential regular expression denial-of-service in + django.utils.text.Truncator.words() + * Fixed a regression in Django 4.2.10 where intcomma template filter + could return a leading comma for string representation of floats +- Remove python3122.patch, already upstream + +------------------------------------------------------------------- +Fri Feb 9 10:18:37 UTC 2024 - Daniel Garcia + +- Add python3122.patch to fix tests with python 3.12.2 + gh#django/django#17843 +- Update to 4.2.10 (bsc#1219683, CVE-2024-24680): + - Django 4.2.10 fixes a security issue with severity "moderate" in + 4.2.9. + CVE-2024-24680: Potential denial-of-service in intcomma template + filter The intcomma template filter was subject to a potential + denial-of-service attack when used with very long strings. + +------------------------------------------------------------------- +Thu Jan 4 09:27:51 UTC 2024 - Alberto Planas Dominguez + +- Update to 4.2.9: + * Fixed a regression in Django 4.2.8 where admin fields on the same + line could overflow the page and become non-interactive + +------------------------------------------------------------------- +Mon Dec 4 10:21:00 UTC 2023 - Alberto Planas Dominguez + +- Update to 4.2.8 + * Fixed a regression in Django 4.2 that caused makemigrations + --check to stop displaying pending migrations + * Fixed a regression in Django 4.2 that caused a crash of + QuerySet.aggregate() with aggregates referencing other aggregates + or window functions through conditional expressions + * Fixed a regression in Django 4.2 that caused a crash when + annotating a QuerySet with a Window expressions composed of a + partition_by clause mixing field types and aggregation expressions + * Fixed a regression in Django 4.2 where the admin’s change list + page had misaligned pagination links and inputs when using + list_editable + * Fixed a regression in Django 4.2 where checkboxes in the admin + would be centered on narrower screen widths + * Fixed a regression in Django 4.2 that caused a crash of querysets + with aggregations on MariaDB when the ONLY_FULL_GROUP_BY SQL mode + was enabled + * Fixed a regression in Django 4.2 where the admin’s read-only + password widget and some help texts were incorrectly aligned at + tablet widths + * Fixed a regression in Django 4.2 that caused a migration crash on + SQLite when altering unsupported Meta.db_table_comment + +------------------------------------------------------------------- +Mon Nov 27 12:20:48 UTC 2023 - Dirk Müller + +- add dirty-hack-remove-assert.patch from fedora to fix + minor test failure with python 3.12 + +------------------------------------------------------------------- +Wed Nov 1 08:12:59 UTC 2023 - Alberto Planas Dominguez + +- Update to 4.2.7 + * Fixed a regression in Django 4.2 that caused a crash of + QuerySet.aggregate() with aggregates referencing expressions + containing subqueries + * Restored, following a regression in Django 4.2, creating + varchar/text_pattern_ops indexes on CharField and TextField with + deterministic collations on PostgreSQL ------------------------------------------------------------------- Mon Oct 16 08:33:05 UTC 2023 - Daniel Garcia Moreno @@ -26,7 +131,7 @@ Mon Oct 16 08:33:05 UTC 2023 - Daniel Garcia Moreno ------------------------------------------------------------------- Mon Sep 4 12:10:50 UTC 2023 - Alberto Planas Dominguez -- Update to 4.2.5 (CVE-2023-41164) +- Update to 4.2.5 (CVE-2023-41164) + Bugfixes * Fixed a regression in Django 4.2 that caused an incorrect validation of CheckConstraints on __isnull lookups against @@ -117,7 +222,8 @@ Tue Jun 6 06:35:28 UTC 2023 - Alberto Planas Dominguez Thu May 4 07:02:58 UTC 2023 - Alberto Planas Dominguez - Update to 4.2.1 - + CVE-2023-31047: Potential bypass of validation when uploading multiple files using one form field + + CVE-2023-31047: Potential bypass of validation when uploading + multiple files using one form field (bsc#1210866) + Bugfixes * Fixed a regression in Django 4.2 that caused a crash of QuerySet.defer() when deferring fields by attribute names @@ -157,7 +263,7 @@ Thu May 4 07:02:58 UTC 2023 - Alberto Planas Dominguez ------------------------------------------------------------------- Thu Apr 6 06:38:13 UTC 2023 - David Anes -- Update minimal dependency versions. +- Update minimal dependency versions. ------------------------------------------------------------------- Tue Apr 4 07:19:56 UTC 2023 - David Anes @@ -197,7 +303,7 @@ Wed Feb 1 12:48:49 UTC 2023 - Alberto Planas Dominguez Mon Jan 2 19:07:30 UTC 2023 - David Anes - Update to 4.1.5: - + Fixed a long standing bug in the __len lookup for ArrayField + + Fixed a long standing bug in the __len lookup for ArrayField that caused a crash of model validation on Meta.constraints. - Update keyring file. @@ -460,14 +566,14 @@ Tue Dec 7 14:09:24 UTC 2021 - Alberto Planas Dominguez deprecated and will be removed in Django 5.0. - The new *expressions positional argument of UniqueConstraint() enables creating functional unique - constraints on expressions and database functions. + constraints on expressions and database functions. - The new scrypt password hasher is more secure and recommended over PBKDF2. However, it’s not the default as it requires OpenSSL 1.1+ and more memory. - Redis cache backend - Template based form rendering. Forms, Formsets, and ErrorList are now rendered using the template engine to enhance - customization. + customization. ------------------------------------------------------------------- Tue Nov 2 12:45:45 UTC 2021 - Alberto Planas Dominguez @@ -576,7 +682,7 @@ Thu May 6 08:54:41 UTC 2021 - Alberto Planas Dominguez Wed May 5 17:25:18 UTC 2021 - Ben Greiner - Keep rpm runtime requirements in sync. Downstream packages often - read the egg-info and fail if they are not fulfilled. + read the egg-info and fail if they are not fulfilled. ------------------------------------------------------------------- Wed May 5 08:44:30 UTC 2021 - Alberto Planas Dominguez @@ -634,7 +740,7 @@ Tue Apr 6 09:27:50 UTC 2021 - Alberto Planas Dominguez + Customizing type of auto-created primary keys + Functional indexes + pymemcache support - + New decorators for the admin site + + New decorators for the admin site + For a complete description of new features check: https://github.com/django/django/blob/main/docs/releases/3.2.txt - Update PYTHOPATH to include the local tests @@ -713,13 +819,13 @@ Wed Sep 9 14:14:08 UTC 2020 - Marketa Calabkova - Update to 3.1.1 * CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+ - * CVE-2020-24584: Permission escalation in intermediate-level directories of the file + * CVE-2020-24584: Permission escalation in intermediate-level directories of the file system cache on Python 3.7+ - * Fixed a data loss possibility in the select_for_update(). When using related fields + * Fixed a data loss possibility in the select_for_update(). When using related fields pointing to a proxy model in the of argument, the corresponding model was not locked * Fixed a regression in Django 3.1 that caused a crash when decoding an invalid session data * Fixed __in lookup on key transforms for JSONField with MariaDB, MySQL, Oracle, and SQLite - * Fixed a regression in Django 3.1 that caused permission errors in CommonPasswordValidator + * Fixed a regression in Django 3.1 that caused permission errors in CommonPasswordValidator and settings.py ------------------------------------------------------------------- @@ -758,7 +864,7 @@ Wed Jul 8 11:52:27 UTC 2020 - Ondřej Súkup a filterable attribute to be used as the right-hand side in queryset filters * Fixed a regression in Django 3.0.2 that caused a migration crash on PostgreSQL when adding a foreign key to a model with a namespaced db_table - * Added compatibility for cx_Oracle 8 + * Added compatibility for cx_Oracle 8 ------------------------------------------------------------------- Thu Jun 4 14:35:25 UTC 2020 - Ondřej Súkup @@ -769,7 +875,7 @@ Thu Jun 4 14:35:25 UTC 2020 - Ondřej Súkup memcached keys * boo#1172167 - CVE-2020-13596: Possible XSS via admin ForeignKeyRawIdWidget - * many other bugfixes + * many other bugfixes ------------------------------------------------------------------- Thu Apr 30 05:14:28 UTC 2020 - Tomáš Chvátal @@ -780,7 +886,7 @@ Thu Apr 30 05:14:28 UTC 2020 - Tomáš Chvátal ------------------------------------------------------------------- Thu Apr 23 16:58:12 UTC 2020 - Marcus Rueckert -- Update to 3.0.5 +- Update to 3.0.5 https://docs.djangoproject.com/en/3.0/releases/3.0.5/ https://docs.djangoproject.com/en/3.0/releases/3.0.4/ https://docs.djangoproject.com/en/3.0/releases/3.0.3/ @@ -1025,14 +1131,14 @@ Mon Dec 10 11:52:42 UTC 2018 - Ondřej Súkup * Fixed admin view-only change form crash when using ModelAdmin.prepopulated_fields * Fixed “Please correct the errors below” error message when editing an object in the admin if the user only has the “view” permission on inlines - * Fixed a regression in Django 2.0 where combining Q objects with __in lookups + * Fixed a regression in Django 2.0 where combining Q objects with __in lookups and lists crashed * Fixed a regression in Django 2.0 where test databases aren’t reused with manage.py test --keepdb on MySQL * Fixed a regression where cached foreign keys that use to_field were incorrectly cleared in Model.save() * Fixed a regression in Django 2.0 where FileSystemStorage crashes - with FileExistsError if concurrent saves try to create the same directory + with FileExistsError if concurrent saves try to create the same directory ------------------------------------------------------------------- Thu Oct 4 13:13:00 UTC 2018 - Alberto Planas Dominguez @@ -1308,7 +1414,7 @@ Tue Dec 12 21:12:18 UTC 2017 - mimi.vx@gmail.com * Removed support for bytestrings in some places * Dropped support for Oracle 11.2 - Please read Release Notes - https://docs.djangoproject.com/en/2.0/releases/2.0/ - + ------------------------------------------------------------------- Tue Dec 12 05:16:57 UTC 2017 - tbechtold@suse.com @@ -1682,8 +1788,8 @@ Tue Apr 4 14:38:13 UTC 2017 - appleonkel@opensuse.org - Update to 1.10.7 Bugfixes - * Made admin’s RelatedFieldWidgetWrapper use the wrapped widget’s - value_omitted_from_data() method (#27905) + * Made admin’s RelatedFieldWidgetWrapper use the wrapped widget’s + value_omitted_from_data() method (#27905) * Fixed model form default fallback for SelectMultiple (#27993) ------------------------------------------------------------------- @@ -1691,15 +1797,15 @@ Wed Mar 1 14:24:17 UTC 2017 - appleonkel@opensuse.org - Update to 1.10.6 Bugfixes - * Fixed ClearableFileInput’s “Clear” checkbox on model form fields where the - model field has a default - * Fixed RequestDataTooBig and TooManyFieldsSent exceptions crashing rather than + * Fixed ClearableFileInput’s “Clear” checkbox on model form fields where the + model field has a default + * Fixed RequestDataTooBig and TooManyFieldsSent exceptions crashing rather than generating a bad request response - * Fixed a crash on Oracle and PostgreSQL when subtracting DurationField or - IntegerField from DateField - * Fixed query expression date subtraction accuracy on PostgreSQL for differences + * Fixed a crash on Oracle and PostgreSQL when subtracting DurationField or + IntegerField from DateField + * Fixed query expression date subtraction accuracy on PostgreSQL for differences large an a month - * Fixed a GDALException raised by GDALClose on GDAL >= 2.0 + * Fixed a GDALException raised by GDALClose on GDAL >= 2.0 ------------------------------------------------------------------- Tue Jan 31 14:00:11 UTC 2017 - michal@cihar.com @@ -1715,8 +1821,8 @@ Fri Dec 2 10:17:25 UTC 2016 - appleonkel@opensuse.org - Update to 1.9.12 Bugfixes - * Quoted the Oracle test user’s password in queries to fix the “ORA-00922: missing - or invalid option” error when the password starts with a number or + * Quoted the Oracle test user’s password in queries to fix the “ORA-00922: missing + or invalid option” error when the password starts with a number or special character (#27420) * DNS rebinding vulnerability when DEBUG=True * CSRF protection bypass on a site with Google Analytics @@ -1725,7 +1831,7 @@ Fri Dec 2 10:17:25 UTC 2016 - appleonkel@opensuse.org Sat Sep 24 16:42:55 UTC 2016 - sbahling@suse.com - Change Requires: python-Pillow to python-imaging for compatibility - with SLE-12 which provides PIL instead of Pillow. + with SLE-12 which provides PIL instead of Pillow. ------------------------------------------------------------------- Tue Aug 9 09:11:24 UTC 2016 - aplanas@suse.com @@ -1775,7 +1881,7 @@ Tue May 3 08:23:48 UTC 2016 - aplanas@suse.com Bugfixes * Added support for relative path redirects to the test client and to SimpleTestCase.assertRedirects() because Django 1.9 no longer - converts redirects to absolute URIs (#26428). + converts redirects to absolute URIs (#26428). * Fixed TimeField microseconds round-tripping on MySQL and SQLite (#26498). * Prevented makemigrations from generating infinite migrations for a @@ -1788,7 +1894,7 @@ Tue May 3 08:23:48 UTC 2016 - aplanas@suse.com of GenericIPAddressField on SQLite and MySQL (#26557). * Fixed a makemessages regression where temporary .py extensions were leaked in source file paths (#26341). - + ------------------------------------------------------------------- Sun May 1 12:29:52 UTC 2016 - michael@stroeder.com @@ -1885,12 +1991,12 @@ Wed Jan 27 15:25:25 UTC 2016 - aplanas@suse.com (#25894). * ... * https://docs.djangoproject.com/en/1.9/releases/1.9.1/ - + ------------------------------------------------------------------- Wed Dec 2 15:14:05 UTC 2015 - aplanas@suse.com - update to 1.9 (CVE-2016-7401, CVE-2015-8213) - * https://docs.djangoproject.com/en/1.9/releases/1.9/ + * https://docs.djangoproject.com/en/1.9/releases/1.9/ * Performing actions after a transaction commit * Password validation * Permission mixins for class-based views @@ -2045,12 +2151,12 @@ Wed Jan 14 07:57:46 UTC 2015 - mcihar@suse.cz affect users who have subclassed django.contrib.auth.hashers.PBKDF2PasswordHasher to change the default value. - * Fixed a crash in the CSRF middleware when handling non-ASCII referer + * Fixed a crash in the CSRF middleware when handling non-ASCII referer header (#23815). - * Fixed a crash in the django.contrib.auth.redirect_to_login view when + * Fixed a crash in the django.contrib.auth.redirect_to_login view when passing a reverse_lazy() result on Python 3 (#24097). * Added correct formats for Greek (el) (#23967). - * Fixed a migration crash when unapplying a migration where multiple + * Fixed a migration crash when unapplying a migration where multiple operations interact with the same model (#24110). ------------------------------------------------------------------- diff --git a/python-Django.keyring b/python-Django.keyring index b363dca..8de348c 100644 --- a/python-Django.keyring +++ b/python-Django.keyring @@ -1,90 +1,121 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -mQGiBErcoVkRBACt1HBsLQQ9HeRHrqMbYfWEW3d0KoWzjKU9ZW59oq8ceVCYfhyT -ZKxyLobyed+NhL3SJCE5e4hs5UfyBdS4c8I97MFDKCA5TBu3pMnYGxWje3fSwP6o -RGcP8Ji4/tISclyGrkMruDNzpT93R8H/SixPGFcH7kCp4xQxPBc0esdU4wCg1azF -kUuFijNryusT+i58hVE3dMkD/iAfCh4bcLyZ8aygLZxg3bn3YauJASEjuqVXUgTB -diBdhXnldq0xs2IwQJY1paAajXf5FsjlTVQrQWMtTQ5qWKpQr0lAanufnEDNu6GW -orWBzLaSWQWEkcRALmZS6MBkmVCx/JiIvt0sUxrG4boQ6qYlQYZsaHaAMUZT997v -1ktqA/4kPUfV2gqJuVzWwbhrKhAyhSivmhhe+1lUFa7phRmoMNw7/jXi9OV1lmL2 -ty+0LkeCXUChrXarey4AnPI58aR0xshiAxGEI2jPi+vWkgGblOG3TBoZBH5jV+d2 -/5mmlCs/KkJkdsN+LXR3m5o/oFs7MgGD8pxa1jwK9xcu1xKIqrQyTmF0YWxpYSBC -aWRhcnQgKG5lc3NpdGEpIDxuYXRhbGlhYmlkYXJ0QGdtYWlsLmNvbT6IYgQTEQIA -IgUCTG1snwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQrlwdYDo57Zf7 -lQCeIHmWQQek0zboTqMuy60phrUIzowAn0ONlnzzL0oWiNUpbY8nDsernILWiGAE -ExECACAFAkrcoVkCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCuXB1gOjnt -l5FdAKCSLwUJNZXs3WXqKabi2adRcdqZ8gCeLgbbqJ2Dqqaeb3tXK6zWC7ZO9CK0 -NE5hdGFsaWEgQmlkYXJ0IChuZXNzaXRhKSA8bmF0YWxpYS5iaWRhcnRAdWJ1bnR1 -LmNvbT6IZQQTEQIAJQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAk8oONcC -GQEACgkQrlwdYDo57ZejrgCdFyBg4VipDYmoQ5eOpXe4Vegiwl4AoK00YytEeMvO -EFqZY+qVvqaV3It6iGIEExECACIFAkvrLFwCGwMGCwkIBwMCBhUIAgkKCwQWAgMB -Ah4BAheAAAoJEK5cHWA6Oe2XD+QAoK02osWaLzROXg54drLpJMNLs/DGAJ9XlSak -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 -eAgTzM5bOOqtGR7VR2hlCM4I4k2D0Y/snh2HzA== -=ul9f +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 +mSNZUt/duetfr8yS4yBrC5IMCo5nvfBpu8E= +=DZRV -----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/python-Django.spec b/python-Django.spec index 664e1d4..6673737 100644 --- a/python-Django.spec +++ b/python-Django.spec @@ -1,7 +1,7 @@ # # spec file for package python-Django # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,7 +24,7 @@ %{?sle15_python_module_pythons} Name: python-Django # We want support LTS versions of Django - numbered 2.2 -> 3.2 -> 4.2 etc -Version: 4.2.6 +Version: 4.2.11 Release: 0 Summary: A high-level Python Web framework License: BSD-3-Clause @@ -34,9 +34,32 @@ Source1: https://media.djangoproject.com/pgp/Django-%{version}.checksum.t Source2: %{name}.keyring Source99: python-Django-rpmlintrc # PATCH-FIX-UPSTREAM https://github.com/django/django/commit/da2f8e8257d1bea4215381684ca4abfcee333c43 Refs #34118 -- Improved sanitize_address() error message for tuple with empty strings. -Patch: sanitize_address.patch -# PATCH-FIX-UPSTREAM CVE-2024-27351.patch bsc#1220358 -Patch1: CVE-2024-27351.patch +Patch0: sanitize_address.patch +# PATCH-FIX-OPENSUSE: ignore minor failure on Python 3.12 +Patch1: dirty-hack-remove-assert.patch +# PATCH-FIX-UPSTREAM: fix-safemimetext-set_payload.patch, gh#django/django@b231bcd19e57 +# Add support for python 3.11.9+ +Patch2: fix-safemimetext-set_payload.patch +# PATCH-FIX-UPSTREAM CVE-2024-38875.patch bsc#1227590 +Patch3: CVE-2024-38875.patch +# PATCH-FIX-UPSTREAM CVE-2024-39329.patch bsc#1227593 +Patch4: CVE-2024-39329.patch +# PATCH-FIX-UPSTREAM CVE-2024-39330.patch bsc#1227594 +Patch5: CVE-2024-39330.patch +# PATCH-FIX-UPSTREAM CVE-2024-39614.patch bsc#1227595 +Patch6: CVE-2024-39614.patch +# PATCH-FIX-UPSTREAM CVE-2024-41989.patch bsc#1228629 +Patch7: CVE-2024-41989.patch +# PATCH-FIX-UPSTREAM CVE-2024-41990.patch bsc#1228630 +Patch8: CVE-2024-41990.patch +# PATCH-FIX-UPSTREAM CVE-2024-41991.patch bsc#1228631 +Patch9: CVE-2024-41991.patch +# PATCH-FIX-UPSTREAM CVE-2024-42005.patch bsc#1228632 +Patch10: CVE-2024-42005.patch +# PATCH-FIX-UPSTREAM CVE-2024-45230.patch bsc#1229823 +Patch11: CVE-2024-45230.patch +# PATCH-FIX-UPSTREAM CVE-2024-45231.patch bsc#1229824 +Patch12: CVE-2024-45231.patch BuildRequires: %{python_module Jinja2 >= 2.9.2} BuildRequires: %{python_module Pillow >= 6.2.0} BuildRequires: %{python_module PyYAML} @@ -68,7 +91,7 @@ Requires: python-pytz Requires: python-setuptools Requires: python-sqlparse >= 0.3.1 Requires(post): update-alternatives -Requires(postun):update-alternatives +Requires(postun): update-alternatives Recommends: python-Jinja2 >= 2.9.2 Recommends: python-PyYAML Recommends: python-geoip2