diff options
author | Soumya Sambu <soumya.sambu@windriver.com> | 2025-01-10 13:17:56 +0000 |
---|---|---|
committer | Armin Kuster <akuster808@gmail.com> | 2025-01-22 19:20:12 -0500 |
commit | 91d60c9b0aafc368acdc034cc5f86fdf7d0a3343 (patch) | |
tree | 47b2fe23038a8e8afe84b6fb42599a64aabd418d /meta-python/recipes-devtools/python/python3-django | |
parent | e13c721bed30ec9ab67a6c802314b3fb2cd97831 (diff) | |
download | meta-openembedded-91d60c9b0aafc368acdc034cc5f86fdf7d0a3343.tar.gz |
python3-django: Fix CVE-2024-39614
An issue was discovered in Django 5.0 before 5.0.7 and 4.2 before 4.2.14.
get_supported_language_variant() was subject to a potential denial-of-service
attack when used with very long strings containing specific characters.
Reference:
https://nvd.nist.gov/vuln/detail/CVE-2024-39614
Upstream-patch:
https://github.com/django/django/commit/17358fb35fb7217423d4c4877ccb6d1a3a40b1c3
Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Diffstat (limited to 'meta-python/recipes-devtools/python/python3-django')
-rw-r--r-- | meta-python/recipes-devtools/python/python3-django/CVE-2024-39614.patch | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-django/CVE-2024-39614.patch b/meta-python/recipes-devtools/python/python3-django/CVE-2024-39614.patch new file mode 100644 index 0000000000..340cfceac8 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-django/CVE-2024-39614.patch | |||
@@ -0,0 +1,138 @@ | |||
1 | From 17358fb35fb7217423d4c4877ccb6d1a3a40b1c3 Mon Sep 17 00:00:00 2001 | ||
2 | From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | ||
3 | Date: Wed, 26 Jun 2024 12:11:54 +0200 | ||
4 | Subject: [PATCH] [4.2.x] Fixed CVE-2024-39614 -- Mitigated potential DoS in | ||
5 | get_supported_language_variant(). | ||
6 | |||
7 | Language codes are now parsed with a maximum length limit of 500 chars. | ||
8 | |||
9 | Thanks to MProgrammer for the report. | ||
10 | |||
11 | CVE: CVE-2024-39614 | ||
12 | |||
13 | Upstream-Status: Backport [https://github.com/django/django/commit/17358fb35fb7217423d4c4877ccb6d1a3a40b1c3] | ||
14 | |||
15 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
16 | --- | ||
17 | django/utils/translation/trans_real.py | 24 ++++++++++++++++++++---- | ||
18 | docs/ref/utils.txt | 10 ++++++++++ | ||
19 | tests/i18n/tests.py | 11 +++++++++++ | ||
20 | 3 files changed, 41 insertions(+), 4 deletions(-) | ||
21 | |||
22 | diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py | ||
23 | index 7f658cf..56b4ef1 100644 | ||
24 | --- a/django/utils/translation/trans_real.py | ||
25 | +++ b/django/utils/translation/trans_real.py | ||
26 | @@ -30,8 +30,10 @@ _default = None | ||
27 | CONTEXT_SEPARATOR = "\x04" | ||
28 | |||
29 | # Maximum number of characters that will be parsed from the Accept-Language | ||
30 | -# header to prevent possible denial of service or memory exhaustion attacks. | ||
31 | -ACCEPT_LANGUAGE_HEADER_MAX_LENGTH = 500 | ||
32 | +# header or cookie to prevent possible denial of service or memory exhaustion | ||
33 | +# attacks. About 10x longer than the longest value shown on MDN’s | ||
34 | +# Accept-Language page. | ||
35 | +LANGUAGE_CODE_MAX_LENGTH = 500 | ||
36 | |||
37 | # Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9 | ||
38 | # and RFC 3066, section 2.1 | ||
39 | @@ -472,11 +474,25 @@ def get_supported_language_variant(lang_code, strict=False): | ||
40 | If `strict` is False (the default), look for a country-specific variant | ||
41 | when neither the language code nor its generic variant is found. | ||
42 | |||
43 | + The language code is truncated to a maximum length to avoid potential | ||
44 | + denial of service attacks. | ||
45 | + | ||
46 | lru_cache should have a maxsize to prevent from memory exhaustion attacks, | ||
47 | as the provided language codes are taken from the HTTP request. See also | ||
48 | <https://www.djangoproject.com/weblog/2007/oct/26/security-fix/>. | ||
49 | """ | ||
50 | if lang_code: | ||
51 | + # Truncate the language code to a maximum length to avoid potential | ||
52 | + # denial of service attacks. | ||
53 | + if len(lang_code) > LANGUAGE_CODE_MAX_LENGTH: | ||
54 | + if ( | ||
55 | + not strict | ||
56 | + and (index := lang_code.rfind("-", 0, LANGUAGE_CODE_MAX_LENGTH)) > 0 | ||
57 | + ): | ||
58 | + # There is a generic variant under the maximum length accepted length. | ||
59 | + lang_code = lang_code[:index] | ||
60 | + else: | ||
61 | + raise ValueError("'lang_code' exceeds the maximum accepted length") | ||
62 | # If 'fr-ca' is not supported, try special fallback or language-only 'fr'. | ||
63 | possible_lang_codes = [lang_code] | ||
64 | try: | ||
65 | @@ -598,12 +614,12 @@ def parse_accept_lang_header(lang_string): | ||
66 | `functools.lru_cache()` to avoid repetitive parsing of common header values. | ||
67 | """ | ||
68 | # If the header value doesn't exceed the maximum allowed length, parse it. | ||
69 | - if len(lang_string) <= ACCEPT_LANGUAGE_HEADER_MAX_LENGTH: | ||
70 | + if len(lang_string) <= LANGUAGE_CODE_MAX_LENGTH: | ||
71 | return _parse_accept_lang_header(lang_string) | ||
72 | |||
73 | # If there is at least one comma in the value, parse up to the last comma, | ||
74 | # skipping any truncated parts at the end of the header value. | ||
75 | - index = lang_string.rfind(",", 0, ACCEPT_LANGUAGE_HEADER_MAX_LENGTH) | ||
76 | + index = lang_string.rfind(",", 0, LANGUAGE_CODE_MAX_LENGTH) | ||
77 | if index > 0: | ||
78 | return _parse_accept_lang_header(lang_string[:index]) | ||
79 | |||
80 | diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt | ||
81 | index 390f167..63a56e5 100644 | ||
82 | --- a/docs/ref/utils.txt | ||
83 | +++ b/docs/ref/utils.txt | ||
84 | @@ -1142,6 +1142,11 @@ functions without the ``u``. | ||
85 | ``lang_code`` is ``'es-ar'`` and ``'es'`` is in :setting:`LANGUAGES` but | ||
86 | ``'es-ar'`` isn't. | ||
87 | |||
88 | + ``lang_code`` has a maximum accepted length of 500 characters. A | ||
89 | + :exc:`ValueError` is raised if ``lang_code`` exceeds this limit and | ||
90 | + ``strict`` is ``True``, or if there is no generic variant and ``strict`` | ||
91 | + is ``False``. | ||
92 | + | ||
93 | If ``strict`` is ``False`` (the default), a country-specific variant may | ||
94 | be returned when neither the language code nor its generic variant is found. | ||
95 | For example, if only ``'es-co'`` is in :setting:`LANGUAGES`, that's | ||
96 | @@ -1150,6 +1155,11 @@ functions without the ``u``. | ||
97 | |||
98 | Raises :exc:`LookupError` if nothing is found. | ||
99 | |||
100 | + .. versionchanged:: 4.2.14 | ||
101 | + | ||
102 | + In older versions, ``lang_code`` values over 500 characters were | ||
103 | + processed without raising a :exc:`ValueError`. | ||
104 | + | ||
105 | .. function:: to_locale(language) | ||
106 | |||
107 | Turns a language name (en-us) into a locale name (en_US). | ||
108 | diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py | ||
109 | index 6efc3a5..0e93395 100644 | ||
110 | --- a/tests/i18n/tests.py | ||
111 | +++ b/tests/i18n/tests.py | ||
112 | @@ -39,6 +39,7 @@ from django.utils.translation import ( | ||
113 | from django.utils.translation.reloader import ( | ||
114 | translation_file_changed, watch_for_translation_changes, | ||
115 | ) | ||
116 | +from django.utils.translation.trans_real import LANGUAGE_CODE_MAX_LENGTH | ||
117 | |||
118 | from .forms import CompanyForm, I18nForm, SelectDateForm | ||
119 | from .models import Company, TestModel | ||
120 | @@ -1462,6 +1463,16 @@ class MiscTests(SimpleTestCase): | ||
121 | g('xyz') | ||
122 | with self.assertRaises(LookupError): | ||
123 | g('xy-zz') | ||
124 | + msg = "'lang_code' exceeds the maximum accepted length" | ||
125 | + with self.assertRaises(LookupError): | ||
126 | + g("x" * LANGUAGE_CODE_MAX_LENGTH) | ||
127 | + with self.assertRaisesMessage(ValueError, msg): | ||
128 | + g("x" * (LANGUAGE_CODE_MAX_LENGTH + 1)) | ||
129 | + # 167 * 3 = 501 which is LANGUAGE_CODE_MAX_LENGTH + 1. | ||
130 | + self.assertEqual(g("en-" * 167), "en") | ||
131 | + with self.assertRaisesMessage(ValueError, msg): | ||
132 | + g("en-" * 167, strict=True) | ||
133 | + self.assertEqual(g("en-" * 30000), "en") # catastrophic test | ||
134 | |||
135 | def test_get_supported_language_variant_null(self): | ||
136 | g = trans_null.get_supported_language_variant | ||
137 | -- | ||
138 | 2.40.0 | ||