Sync from SUSE:ALP:Source:Standard:1.0 python-tornado6 revision 69da5f547f4fbc6a8c26e0fe396f8a3d
This commit is contained in:
parent
ea5a0f3b2e
commit
120cae1d7a
138
CVE-2024-52804-avoid-quadratic-cookie-parsing.patch
Normal file
138
CVE-2024-52804-avoid-quadratic-cookie-parsing.patch
Normal file
@ -0,0 +1,138 @@
|
||||
From d5ba4a1695fbf7c6a3e54313262639b198291533 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Darnell <ben@bendarnell.com>
|
||||
Date: Thu, 21 Nov 2024 14:48:05 -0500
|
||||
Subject: [PATCH] httputil: Fix quadratic performance of cookie parsing
|
||||
|
||||
Maliciously-crafted cookies can cause Tornado to
|
||||
spend an unreasonable amount of CPU time and block
|
||||
the event loop.
|
||||
|
||||
This change replaces the quadratic algorithm with
|
||||
a more efficient one. The implementation is copied
|
||||
from the Python 3.13 standard library (the
|
||||
previous one was from Python 3.5).
|
||||
|
||||
Fixes CVE-2024-52804
|
||||
See CVE-2024-7592 for a similar vulnerability in cpython.
|
||||
|
||||
Thanks to github.com/kexinoh for the report.
|
||||
---
|
||||
tornado/httputil.py | 38 ++++++++---------------------
|
||||
tornado/test/httputil_test.py | 46 +++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 56 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/tornado/httputil.py b/tornado/httputil.py
|
||||
index 9ce992d82b..ebdc8059c1 100644
|
||||
--- a/tornado/httputil.py
|
||||
+++ b/tornado/httputil.py
|
||||
@@ -1057,15 +1057,20 @@ def qs_to_qsl(qs: Dict[str, List[AnyStr]]) -> Iterable[Tuple[str, AnyStr]]:
|
||||
yield (k, v)
|
||||
|
||||
|
||||
-_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
|
||||
-_QuotePatt = re.compile(r"[\\].")
|
||||
-_nulljoin = "".join
|
||||
+_unquote_sub = re.compile(r"\\(?:([0-3][0-7][0-7])|(.))").sub
|
||||
+
|
||||
+
|
||||
+def _unquote_replace(m: re.Match) -> str:
|
||||
+ if m[1]:
|
||||
+ return chr(int(m[1], 8))
|
||||
+ else:
|
||||
+ return m[2]
|
||||
|
||||
|
||||
def _unquote_cookie(s: str) -> str:
|
||||
"""Handle double quotes and escaping in cookie values.
|
||||
|
||||
- This method is copied verbatim from the Python 3.5 standard
|
||||
+ This method is copied verbatim from the Python 3.13 standard
|
||||
library (http.cookies._unquote) so we don't have to depend on
|
||||
non-public interfaces.
|
||||
"""
|
||||
@@ -1086,30 +1091,7 @@ def _unquote_cookie(s: str) -> str:
|
||||
# \012 --> \n
|
||||
# \" --> "
|
||||
#
|
||||
- i = 0
|
||||
- n = len(s)
|
||||
- res = []
|
||||
- while 0 <= i < n:
|
||||
- o_match = _OctalPatt.search(s, i)
|
||||
- q_match = _QuotePatt.search(s, i)
|
||||
- if not o_match and not q_match: # Neither matched
|
||||
- res.append(s[i:])
|
||||
- break
|
||||
- # else:
|
||||
- j = k = -1
|
||||
- if o_match:
|
||||
- j = o_match.start(0)
|
||||
- if q_match:
|
||||
- k = q_match.start(0)
|
||||
- if q_match and (not o_match or k < j): # QuotePatt matched
|
||||
- res.append(s[i:k])
|
||||
- res.append(s[k + 1])
|
||||
- i = k + 2
|
||||
- else: # OctalPatt matched
|
||||
- res.append(s[i:j])
|
||||
- res.append(chr(int(s[j + 1 : j + 4], 8)))
|
||||
- i = j + 4
|
||||
- return _nulljoin(res)
|
||||
+ return _unquote_sub(_unquote_replace, s)
|
||||
|
||||
|
||||
def parse_cookie(cookie: str) -> Dict[str, str]:
|
||||
diff --git a/tornado/test/httputil_test.py b/tornado/test/httputil_test.py
|
||||
index 6d618839e0..975900aa9c 100644
|
||||
--- a/tornado/test/httputil_test.py
|
||||
+++ b/tornado/test/httputil_test.py
|
||||
@@ -560,3 +560,49 @@ def test_invalid_cookies(self):
|
||||
self.assertEqual(
|
||||
parse_cookie(" = b ; ; = ; c = ; "), {"": "b", "c": ""}
|
||||
)
|
||||
+
|
||||
+ def test_unquote(self):
|
||||
+ # Copied from
|
||||
+ # https://github.com/python/cpython/blob/dc7a2b6522ec7af41282bc34f405bee9b306d611/Lib/test/test_http_cookies.py#L62
|
||||
+ cases = [
|
||||
+ (r'a="b=\""', 'b="'),
|
||||
+ (r'a="b=\\"', "b=\\"),
|
||||
+ (r'a="b=\="', "b=="),
|
||||
+ (r'a="b=\n"', "b=n"),
|
||||
+ (r'a="b=\042"', 'b="'),
|
||||
+ (r'a="b=\134"', "b=\\"),
|
||||
+ (r'a="b=\377"', "b=\xff"),
|
||||
+ (r'a="b=\400"', "b=400"),
|
||||
+ (r'a="b=\42"', "b=42"),
|
||||
+ (r'a="b=\\042"', "b=\\042"),
|
||||
+ (r'a="b=\\134"', "b=\\134"),
|
||||
+ (r'a="b=\\\""', 'b=\\"'),
|
||||
+ (r'a="b=\\\042"', 'b=\\"'),
|
||||
+ (r'a="b=\134\""', 'b=\\"'),
|
||||
+ (r'a="b=\134\042"', 'b=\\"'),
|
||||
+ ]
|
||||
+ for encoded, decoded in cases:
|
||||
+ with self.subTest(encoded):
|
||||
+ c = parse_cookie(encoded)
|
||||
+ self.assertEqual(c["a"], decoded)
|
||||
+
|
||||
+ def test_unquote_large(self):
|
||||
+ # Adapted from
|
||||
+ # https://github.com/python/cpython/blob/dc7a2b6522ec7af41282bc34f405bee9b306d611/Lib/test/test_http_cookies.py#L87
|
||||
+ # Modified from that test because we handle semicolons differently from the stdlib.
|
||||
+ #
|
||||
+ # This is a performance regression test: prior to improvements in Tornado 6.4.2, this test
|
||||
+ # would take over a minute with n= 100k. Now it runs in tens of milliseconds.
|
||||
+ n = 100000
|
||||
+ for encoded in r"\\", r"\134":
|
||||
+ with self.subTest(encoded):
|
||||
+ start = time.time()
|
||||
+ data = 'a="b=' + encoded * n + '"'
|
||||
+ value = parse_cookie(data)["a"]
|
||||
+ end = time.time()
|
||||
+ self.assertEqual(value[:3], "b=\\")
|
||||
+ self.assertEqual(value[-3:], "\\\\\\")
|
||||
+ self.assertEqual(len(value), n + 2)
|
||||
+
|
||||
+ # Very loose performance check to avoid false positives
|
||||
+ self.assertLess(end - start, 1, "Test took too long")
|
@ -1,3 +1,10 @@
|
||||
-------------------------------------------------------------------
|
||||
Wed Nov 27 04:23:13 UTC 2024 - Steve Kowalik <steven.kowalik@suse.com>
|
||||
|
||||
- Add patch CVE-2024-52804-avoid-quadratic-cookie-parsing.patch:
|
||||
* Avoid quadratic performance of cookie parsing.
|
||||
(CVE-2024-52804, bsc#1233668)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Jan 11 13:28:34 UTC 2024 - Daniel Garcia <daniel.garcia@suse.com>
|
||||
|
||||
|
@ -30,6 +30,9 @@ Source99: python-tornado6-rpmlintrc
|
||||
Patch0: ignore-resourcewarning-doctests.patch
|
||||
# PATCH-FIX-OPENSUSE openssl-3.2.patch gh#tornadoweb/tornado#3355
|
||||
Patch1: openssl-3.2.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2024-52804 bsc#1233668
|
||||
# gh#tornadoweb/tornado#d5ba4a1695fbf7c6a3e54313262639b198291533
|
||||
Patch2: CVE-2024-52804-avoid-quadratic-cookie-parsing.patch
|
||||
BuildRequires: %{python_module base >= 3.8}
|
||||
BuildRequires: %{python_module devel}
|
||||
BuildRequires: %{python_module pip}
|
||||
|
Loading…
Reference in New Issue
Block a user