From e66014eb082d50d0b1442ce35f9a992216102a34 Mon Sep 17 00:00:00 2001 From: wk333 <13474090681@163.com> Date: Mon, 9 Dec 2024 10:24:52 +0800 Subject: [PATCH] Fix CVE-2024-53907 CVE-2024-53908 (cherry picked from commit 66ebce54912f2aee338790ac1090d3fb018a8902) --- CVE-2024-53907.patch | 88 ++++++++++++++++++++++++++ CVE-2024-53908.patch | 145 +++++++++++++++++++++++++++++++++++++++++++ python-django.spec | 7 ++- 3 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 CVE-2024-53907.patch create mode 100644 CVE-2024-53908.patch diff --git a/CVE-2024-53907.patch b/CVE-2024-53907.patch new file mode 100644 index 0000000..0f4d966 --- /dev/null +++ b/CVE-2024-53907.patch @@ -0,0 +1,88 @@ +From 790eb058b0716c536a2f2e8d1c6d5079d776c22b Mon Sep 17 00:00:00 2001 +From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +Date: Wed, 13 Nov 2024 15:06:23 +0100 +Subject: [PATCH] [4.2.x] Fixed CVE-2024-53907 -- Mitigated potential DoS in + strip_tags(). + +Origin: https://github.com/django/django/commit/790eb058b0716c536a2f2e8d1c6d5079d776c22b + +Thanks to jiangniao for the report, and Shai Berger and Natalia Bidart +for the reviews. +--- + django/utils/html.py | 10 ++++++++-- + tests/utils_tests/test_html.py | 7 +++++++ + 3 files changed, 31 insertions(+), 2 deletions(-) + +diff --git a/django/utils/html.py b/django/utils/html.py +index df38c2051994..a3a7238cba44 100644 +--- a/django/utils/html.py ++++ b/django/utils/html.py +@@ -6,6 +6,7 @@ + from html.parser import HTMLParser + from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit + ++from django.core.exceptions import SuspiciousOperation + from django.utils.encoding import punycode + from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text + from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS +@@ -14,6 +15,7 @@ + from django.utils.text import normalize_newlines + + MAX_URL_LENGTH = 2048 ++MAX_STRIP_TAGS_DEPTH = 50 + + + @keep_lazy(SafeString) +@@ -172,15 +174,19 @@ def _strip_once(value): + @keep_lazy_text + def strip_tags(value): + """Return the given HTML with all tags stripped.""" +- # Note: in typical case this loop executes _strip_once once. Loop condition +- # is redundant, but helps to reduce number of executions of _strip_once. + value = str(value) ++ # Note: in typical case this loop executes _strip_once twice (the second ++ # execution does not remove any more tags). ++ strip_tags_depth = 0 + while "<" in value and ">" in value: ++ if strip_tags_depth >= MAX_STRIP_TAGS_DEPTH: ++ raise SuspiciousOperation + new_value = _strip_once(value) + if value.count("<") == new_value.count("<"): + # _strip_once wasn't able to detect more tags. + break + value = new_value ++ strip_tags_depth += 1 + return value + + +diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py +index 7ff5020fb6d3..579bb2a1e359 100644 +--- a/tests/utils_tests/test_html.py ++++ b/tests/utils_tests/test_html.py +@@ -1,6 +1,7 @@ + import os + from datetime import datetime + ++from django.core.exceptions import SuspiciousOperation + from django.core.serializers.json import DjangoJSONEncoder + from django.test import SimpleTestCase + from django.utils.functional import lazystr +@@ -113,12 +114,18 @@ def test_strip_tags(self): + ("&h", "alert()h"), + (">br>br>br>X", "XX"), ++ ("<" * 50 + "a>" * 50, ""), + ) + for value, output in items: + with self.subTest(value=value, output=output): + self.check_output(strip_tags, value, output) + self.check_output(strip_tags, lazystr(value), output) + ++ def test_strip_tags_suspicious_operation(self): ++ value = "<" * 51 + "a>" * 51, "" ++ with self.assertRaises(SuspiciousOperation): ++ strip_tags(value) ++ + def test_strip_tags_files(self): + # Test with more lengthy content (also catching performance regressions) + for filename in ("strip_tags1.html", "strip_tags2.txt"): diff --git a/CVE-2024-53908.patch b/CVE-2024-53908.patch new file mode 100644 index 0000000..cd0b0a6 --- /dev/null +++ b/CVE-2024-53908.patch @@ -0,0 +1,145 @@ +From 7376bcbf508883282ffcc0f0fac5cf0ed2d6cbc5 Mon Sep 17 00:00:00 2001 +From: Simon Charette +Date: Fri, 8 Nov 2024 21:27:31 -0500 +Subject: [PATCH] [4.2.x] Fixed CVE-2024-53908 -- Prevented SQL injections in + direct HasKeyLookup usage on Oracle. + +Origin: https://github.com/django/django/commit/7376bcbf508883282ffcc0f0fac5cf0ed2d6cbc5 + +Thanks Seokchan Yoon for the report, and Mariusz Felisiak and Sarah +Boyce for the reviews. +--- + django/db/models/fields/json.py | 53 ++++++++++++++++++---------- + tests/model_fields/test_jsonfield.py | 9 +++++ + 3 files changed, 53 insertions(+), 18 deletions(-) + +diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py +index b7cde157c4fa..b9c6ff1752b9 100644 +--- a/django/db/models/fields/json.py ++++ b/django/db/models/fields/json.py +@@ -216,20 +216,18 @@ def compile_json_path_final_key(self, key_transform): + # Compile the final key without interpreting ints as array elements. + return ".%s" % json.dumps(key_transform) + +- def as_sql(self, compiler, connection, template=None): ++ def _as_sql_parts(self, compiler, connection): + # Process JSON path from the left-hand side. + if isinstance(self.lhs, KeyTransform): +- lhs, lhs_params, lhs_key_transforms = self.lhs.preprocess_lhs( ++ lhs_sql, lhs_params, lhs_key_transforms = self.lhs.preprocess_lhs( + compiler, connection + ) + lhs_json_path = compile_json_path(lhs_key_transforms) + else: +- lhs, lhs_params = self.process_lhs(compiler, connection) ++ lhs_sql, lhs_params = self.process_lhs(compiler, connection) + lhs_json_path = "$" +- sql = template % lhs + # Process JSON path from the right-hand side. + rhs = self.rhs +- rhs_params = [] + if not isinstance(rhs, (list, tuple)): + rhs = [rhs] + for key in rhs: +@@ -240,24 +238,43 @@ def as_sql(self, compiler, connection, template=None): + *rhs_key_transforms, final_key = rhs_key_transforms + rhs_json_path = compile_json_path(rhs_key_transforms, include_root=False) + rhs_json_path += self.compile_json_path_final_key(final_key) +- rhs_params.append(lhs_json_path + rhs_json_path) ++ yield lhs_sql, lhs_params, lhs_json_path + rhs_json_path ++ ++ def _combine_sql_parts(self, parts): + # Add condition for each key. + if self.logical_operator: +- sql = "(%s)" % self.logical_operator.join([sql] * len(rhs_params)) +- return sql, tuple(lhs_params) + tuple(rhs_params) ++ return "(%s)" % self.logical_operator.join(parts) ++ return "".join(parts) ++ ++ def as_sql(self, compiler, connection, template=None): ++ sql_parts = [] ++ params = [] ++ for lhs_sql, lhs_params, rhs_json_path in self._as_sql_parts( ++ compiler, connection ++ ): ++ sql_parts.append(template % (lhs_sql, "%s")) ++ params.extend(lhs_params + [rhs_json_path]) ++ return self._combine_sql_parts(sql_parts), tuple(params) + + def as_mysql(self, compiler, connection): + return self.as_sql( +- compiler, connection, template="JSON_CONTAINS_PATH(%s, 'one', %%s)" ++ compiler, connection, template="JSON_CONTAINS_PATH(%s, 'one', %s)" + ) + + def as_oracle(self, compiler, connection): +- sql, params = self.as_sql( +- compiler, connection, template="JSON_EXISTS(%s, '%%s')" +- ) +- # Add paths directly into SQL because path expressions cannot be passed +- # as bind variables on Oracle. +- return sql % tuple(params), [] ++ template = "JSON_EXISTS(%s, '%s')" ++ sql_parts = [] ++ params = [] ++ for lhs_sql, lhs_params, rhs_json_path in self._as_sql_parts( ++ compiler, connection ++ ): ++ # Add right-hand-side directly into SQL because it cannot be passed ++ # as bind variables to JSON_EXISTS. It might result in invalid ++ # queries but it is assumed that it cannot be evaded because the ++ # path is JSON serialized. ++ sql_parts.append(template % (lhs_sql, rhs_json_path)) ++ params.extend(lhs_params) ++ return self._combine_sql_parts(sql_parts), tuple(params) + + def as_postgresql(self, compiler, connection): + if isinstance(self.rhs, KeyTransform): +@@ -269,7 +286,7 @@ def as_postgresql(self, compiler, connection): + + def as_sqlite(self, compiler, connection): + return self.as_sql( +- compiler, connection, template="JSON_TYPE(%s, %%s) IS NOT NULL" ++ compiler, connection, template="JSON_TYPE(%s, %s) IS NOT NULL" + ) + + +@@ -467,9 +484,9 @@ def as_oracle(self, compiler, connection): + return "(NOT %s OR %s IS NULL)" % (sql, lhs), tuple(params) + tuple(lhs_params) + + def as_sqlite(self, compiler, connection): +- template = "JSON_TYPE(%s, %%s) IS NULL" ++ template = "JSON_TYPE(%s, %s) IS NULL" + if not self.rhs: +- template = "JSON_TYPE(%s, %%s) IS NOT NULL" ++ template = "JSON_TYPE(%s, %s) IS NOT NULL" + return HasKeyOrArrayIndex(self.lhs.lhs, self.lhs.key_name).as_sql( + compiler, + connection, +diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py +index 4a1cc075b4c4..4c8d14bf9a17 100644 +--- a/tests/model_fields/test_jsonfield.py ++++ b/tests/model_fields/test_jsonfield.py +@@ -29,6 +29,7 @@ + from django.db.models.expressions import RawSQL + from django.db.models.fields.json import ( + KT, ++ HasKey, + KeyTextTransform, + KeyTransform, + KeyTransformFactory, +@@ -607,6 +608,14 @@ def test_has_key_deep(self): + [expected], + ) + ++ def test_has_key_literal_lookup(self): ++ self.assertSequenceEqual( ++ NullableJSONModel.objects.filter( ++ HasKey(Value({"foo": "bar"}, JSONField()), "foo") ++ ).order_by("id"), ++ self.objs, ++ ) ++ + def test_has_key_list(self): + obj = NullableJSONModel.objects.create(value=[{"a": 1}, {"b": "x"}]) + tests = [ diff --git a/python-django.spec b/python-django.spec index a27240a..49a89fb 100644 --- a/python-django.spec +++ b/python-django.spec @@ -1,13 +1,15 @@ %global _empty_manifest_terminate_build 0 Name: python-django Version: 4.2.15 -Release: 2 +Release: 3 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design. License: Apache-2.0 and Python-2.0 and BSD-3-Clause URL: https://www.djangoproject.com/ Source0: https://files.pythonhosted.org/packages/source/d/Django/Django-%{version}.tar.gz Patch0: CVE-2024-45230.patch Patch1: CVE-2024-45231.patch +Patch2: CVE-2024-53907.patch +Patch3: CVE-2024-53908.patch BuildArch: noarch %description @@ -74,6 +76,9 @@ mv %{buildroot}/doclist.lst . %{_docdir}/* %changelog +* Mon Dec 09 2024 wangkai <13474090681@163.com> - 4.2.15-3 +- Fix CVE-2024-53907 CVE-2024-53908 + * Thu Oct 10 2024 zhangxianting - 4.2.15-2 - Fix CVE-2024-45230 CVE-2024-45231 -- Gitee