mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-13 03:37:15 +00:00
python3-tornado: Fix CVE-2026-103261
This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/tornadoweb/tornado/commit/03945136ea9746eccf61caf88edae39642e59c93 [2] https://nvd.nist.gov/vuln/detail/CVE-2026-103261 Signed-off-by: Yogita Urade <yurade@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
1 parent
131bcf4881
commit
30603fc2bc
2 files changed
+99
No files matched your search
@@ -0,0 +1,98 @@
|
||||
From 03945136ea9746eccf61caf88edae39642e59c93 Mon Sep 17 00:00:00 2001
|
||||
From: Claude <noreply@anthropic.com>
|
||||
Date: Sun, 13 Sep 2026 03:32:19 +0000
|
||||
Subject: [PATCH] httputil: Apply the argument count limit to query strings
|
||||
|
||||
parse_body_arguments limits the number of fields in a urlencoded body
|
||||
(added in 6.5.8), but HTTPServerRequest.__init__ parsed the query string
|
||||
with no such limit, so the same superlinear parsing cost was reachable
|
||||
through the request line instead of the body.
|
||||
|
||||
Measured on the unpatched code, a query string with 400k fields took
|
||||
3.2s of CPU to parse. In the default configuration the request line is
|
||||
bounded by max_header_size (64KB), which caps this at roughly 12,700
|
||||
arguments and ~47ms per request, but that is still an order of magnitude
|
||||
past the limit the body path enforces, and applications are free to
|
||||
raise max_header_size.
|
||||
|
||||
Pass the same max_arguments limit here. Over-limit query strings now
|
||||
raise HTTPInputError, which the server already turns into a 400.
|
||||
|
||||
The limit is read from the global _DEFAULT_PARSE_BODY_CONFIG because
|
||||
HTTPServerRequest has no access to any per-connection configuration.
|
||||
This is the same limitation the body path already has in practice:
|
||||
_parse_body calls parse_body_arguments without a config, so the body
|
||||
limit is likewise only adjustable through set_parse_body_config.
|
||||
|
||||
CVE: CVE-2026-103261
|
||||
Upstream-Status: Backport [https://github.com/tornadoweb/tornado/commit/03945136ea9746eccf61caf88edae39642e59c93]
|
||||
|
||||
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||||
Claude-Session: https://claude.ai/code/session_01JD7LUuFMdyPJB1Dwdq6fPg
|
||||
Signed-off-by: Yogita Urade <yurade@cisco.com>
|
||||
---
|
||||
tornado/httputil.py | 14 +++++++++++++-
|
||||
tornado/test/httputil_test.py | 15 +++++++++++++++
|
||||
2 files changed, 28 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tornado/httputil.py b/tornado/httputil.py
|
||||
index b80c796c..6a5db233 100644
|
||||
--- a/tornado/httputil.py
|
||||
+++ b/tornado/httputil.py
|
||||
@@ -550,7 +550,19 @@ class HTTPServerRequest:
|
||||
|
||||
if uri is not None:
|
||||
self.path, sep, self.query = uri.partition("?")
|
||||
- self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
|
||||
+ try:
|
||||
+ self.arguments = parse_qs_bytes(
|
||||
+ self.query,
|
||||
+ keep_blank_values=True,
|
||||
+ # The query string is bounded by max_header_size, but parsing
|
||||
+ # is expensive enough per field to be worth limiting. Use the
|
||||
+ # same limit as a urlencoded body. This reads the global
|
||||
+ # config because HTTPServerRequest has no access to the
|
||||
+ # per-connection configuration; see set_parse_body_config.
|
||||
+ max_num_fields=_DEFAULT_PARSE_BODY_CONFIG.urlencoded.max_arguments,
|
||||
+ )
|
||||
+ except Exception as e:
|
||||
+ raise HTTPInputError("Invalid query string: %s" % e) from e
|
||||
self.query_arguments = copy.deepcopy(self.arguments)
|
||||
self.body_arguments = {} # type: Dict[str, List[bytes]]
|
||||
|
||||
diff --git a/tornado/test/httputil_test.py b/tornado/test/httputil_test.py
|
||||
index afb15879..0e9d5c41 100644
|
||||
--- a/tornado/test/httputil_test.py
|
||||
+++ b/tornado/test/httputil_test.py
|
||||
@@ -11,6 +11,7 @@ from tornado.httputil import (
|
||||
HTTPInputError,
|
||||
HTTPFile,
|
||||
ParseMultipartConfig,
|
||||
+ _DEFAULT_PARSE_BODY_CONFIG,
|
||||
)
|
||||
from tornado.escape import utf8, native_str
|
||||
from tornado.log import gen_log
|
||||
@@ -658,6 +659,20 @@ class HTTPServerRequestTest(unittest.TestCase):
|
||||
)
|
||||
self.assertNotIn("Canary", repr(request))
|
||||
|
||||
+ def test_query_arguments_within_limit(self):
|
||||
+ n = _DEFAULT_PARSE_BODY_CONFIG.urlencoded.max_arguments
|
||||
+ request = HTTPServerRequest(uri="/?" + "&".join("a=%d" % i for i in range(n)))
|
||||
+ self.assertEqual(len(request.arguments["a"]), n)
|
||||
+
|
||||
+ def test_max_query_arguments(self):
|
||||
+ # The query string is subject to the same limit on the number of
|
||||
+ # arguments as a urlencoded body: parsing is superlinear enough in
|
||||
+ # the number of fields to be worth bounding.
|
||||
+ n = _DEFAULT_PARSE_BODY_CONFIG.urlencoded.max_arguments + 1
|
||||
+ with self.assertRaises(HTTPInputError) as cm:
|
||||
+ HTTPServerRequest(uri="/?" + "&".join("a=%d" % i for i in range(n)))
|
||||
+ self.assertIn("Max number of fields exceeded", str(cm.exception))
|
||||
+
|
||||
|
||||
class ParseRequestStartLineTest(unittest.TestCase):
|
||||
METHOD = "GET"
|
||||
--
|
||||
2.35.6
|
||||
|
||||
@@ -11,6 +11,7 @@ SRC_URI[sha256sum] = "66c513a76cda70d53907bc27cf1447557699c2e95aa48ba27a442ff61c
|
||||
SRC_URI += "file://CVE-2026-91990.patch \
|
||||
file://CVE-2026-82397.patch \
|
||||
file://CVE-2026-91991.patch \
|
||||
file://CVE-2026-103261.patch \
|
||||
"
|
||||
|
||||
inherit pypi python_setuptools_build_meta
|
||||
|
||||
Reference in new issue
Block a user