diff mbox series

[meta-python,kirkstone,4/5] python3-tornado: patch CVE-2024-52804

Message ID 20260108074618.2782232-4-skandigraun@gmail.com
State New
Headers show
Series [meta-oe,kirkstone,1/5] php: ignore CVE-2024-3566 | expand

Commit Message

Gyorgy Sarvari Jan. 8, 2026, 7:46 a.m. UTC
Details: https://nvd.nist.gov/vuln/detail/CVE-2024-52804

Pick the patch mentioned by the NVD advisory.

Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
---
 .../python3-tornado/CVE-2024-52804.patch      | 142 ++++++++++++++++++
 .../python/python3-tornado_6.1.bb             |   4 +-
 2 files changed, 145 insertions(+), 1 deletion(-)
 create mode 100644 meta-python/recipes-devtools/python/python3-tornado/CVE-2024-52804.patch
diff mbox series

Patch

diff --git a/meta-python/recipes-devtools/python/python3-tornado/CVE-2024-52804.patch b/meta-python/recipes-devtools/python/python3-tornado/CVE-2024-52804.patch
new file mode 100644
index 0000000000..0279c6859c
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-tornado/CVE-2024-52804.patch
@@ -0,0 +1,142 @@ 
+From b4918d1e62a3f53cdba19d1b1af5938c7b6b1720 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.
+
+CVE: CVE-2024-52804
+Upstream-Status: Backport [https://github.com/tornadoweb/tornado/commit/d5ba4a1695fbf7c6a3e54313262639b198291533]
+Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
+---
+ 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 bd32cd0..bb50786 100644
+--- a/tornado/httputil.py
++++ b/tornado/httputil.py
+@@ -1052,15 +1052,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.
+     """
+@@ -1081,30 +1086,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 0fad403..25faf66 100644
+--- a/tornado/test/httputil_test.py
++++ b/tornado/test/httputil_test.py
+@@ -519,3 +519,49 @@ class ParseCookieTest(unittest.TestCase):
+         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")
diff --git a/meta-python/recipes-devtools/python/python3-tornado_6.1.bb b/meta-python/recipes-devtools/python/python3-tornado_6.1.bb
index d4cb58febc..0d96cbd10e 100644
--- a/meta-python/recipes-devtools/python/python3-tornado_6.1.bb
+++ b/meta-python/recipes-devtools/python/python3-tornado_6.1.bb
@@ -6,7 +6,9 @@  HOMEPAGE = "http://www.tornadoweb.org/en/stable/"
 LICENSE = "Apache-2.0"
 LIC_FILES_CHKSUM = "file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57"
 
-SRC_URI += "file://CVE-2023-28370.patch"
+SRC_URI += "file://CVE-2023-28370.patch \
+            file://CVE-2024-52804.patch \
+"
 SRC_URI[md5sum] = "f324f5e7607798552359d6ab054c4321"
 SRC_URI[sha256sum] = "33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"