mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-07 13:44:50 +00:00
This patch applies the reviewed upstream fix shown in [1]. The advisory identifying the fix is referenced in [2]. The generated aiohttp/_http_parser.c changes are omitted. The recipe-time Cython regeneration introduced with CVE-2025-69224 regenerates that file from the patched _http_parser.pyx before the accelerated parser is compiled. [1] https://github.com/aio-libs/aiohttp/commit/5ab61bb4cd88f19b712f12c7c9295fe262bf804d [2] https://nvd.nist.gov/vuln/detail/CVE-2026-54277 Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
97 lines
4.4 KiB
Diff
97 lines
4.4 KiB
Diff
From 83788a36c646a1bdfba912267feab5db796a828e Mon Sep 17 00:00:00 2001
|
|
From: "J. Nick Koston" <nick@koston.org>
|
|
Date: Sun, 7 Jun 2026 00:33:03 -0500
|
|
Subject: [PATCH] [PR #12826/36df6c13 backport][3.14] Enforce max_line_size on
|
|
fragmented request target and reason in C parser (#12837)
|
|
|
|
CVE: CVE-2026-54277
|
|
Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/5ab61bb4cd88f19b712f12c7c9295fe262bf804d]
|
|
|
|
Backport Changes:
|
|
- Omitted generated `aiohttp/_http_parser.c` changes because the
|
|
Scarthgap recipe regenerates that file from `_http_parser.pyx`
|
|
during `do_configure`.
|
|
- This fix depends on the max_line_size buffer logic introduced by
|
|
CVE-2026-22815. Keep CVE-2026-22815.patch earlier in SRC_URI.
|
|
|
|
(cherry picked from commit 5ab61bb4cd88f19b712f12c7c9295fe262bf804d)
|
|
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
|
---
|
|
CHANGES/12826.bugfix.rst | 1 +
|
|
aiohttp/_http_parser.pyx | 4 ++--
|
|
tests/test_http_parser.py | 22 ++++++++++++++++++++++
|
|
3 files changed, 25 insertions(+), 2 deletions(-)
|
|
create mode 100644 CHANGES/12826.bugfix.rst
|
|
|
|
diff --git a/CHANGES/12826.bugfix.rst b/CHANGES/12826.bugfix.rst
|
|
new file mode 100644
|
|
index 000000000..7e095615d
|
|
--- /dev/null
|
|
+++ b/CHANGES/12826.bugfix.rst
|
|
@@ -0,0 +1 @@
|
|
+Fixed the C HTTP parser not enforcing ``max_line_size`` on a request target or response reason phrase that is split across multiple reads; each fragment was checked on its own, so an accumulated line could exceed the limit without raising ``LineTooLong``. The accumulated length is now checked, matching the pure-Python parser -- by :user:`bdraco`.
|
|
diff --git a/aiohttp/_http_parser.pyx b/aiohttp/_http_parser.pyx
|
|
index 8e9ecae69..01a0f859c 100644
|
|
--- a/aiohttp/_http_parser.pyx
|
|
+++ b/aiohttp/_http_parser.pyx
|
|
@@ -718,7 +718,7 @@ cdef int cb_on_url(cparser.llhttp_t* parser,
|
|
const char *at, size_t length) except -1:
|
|
cdef HttpParser pyparser = <HttpParser>parser.data
|
|
try:
|
|
- if length > pyparser._max_line_size:
|
|
+ if len(pyparser._buf) + length > pyparser._max_line_size:
|
|
status = pyparser._buf + at[:length]
|
|
raise LineTooLong(status[:100] + b"...", pyparser._max_line_size)
|
|
extend(pyparser._buf, at, length)
|
|
@@ -733,7 +733,7 @@ cdef int cb_on_status(cparser.llhttp_t* parser,
|
|
const char *at, size_t length) except -1:
|
|
cdef HttpParser pyparser = <HttpParser>parser.data
|
|
try:
|
|
- if length > pyparser._max_line_size:
|
|
+ if len(pyparser._buf) + length > pyparser._max_line_size:
|
|
reason = pyparser._buf + at[:length]
|
|
raise LineTooLong(reason[:100] + b"...", pyparser._max_line_size)
|
|
extend(pyparser._buf, at, length)
|
|
diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py
|
|
index 3e1f7dfaa..a724aae63 100644
|
|
--- a/tests/test_http_parser.py
|
|
+++ b/tests/test_http_parser.py
|
|
@@ -1161,6 +1161,17 @@ def test_http_request_max_status_line_under_limit(parser: HttpRequestParser) ->
|
|
assert msg.url == URL("/path" + path.decode())
|
|
|
|
|
|
+def test_http_request_max_status_line_fragmented(
|
|
+ parser: HttpRequestParser,
|
|
+) -> None:
|
|
+ # Split an overlong request target across reads so that each callback
|
|
+ # fragment is under the limit but the accumulated target is not.
|
|
+ match = "400, message:\n Got more than 8190 bytes when reading"
|
|
+ with pytest.raises(http_exceptions.LineTooLong, match=match):
|
|
+ parser.feed_data(b"GET /" + b"a" * 8000)
|
|
+ parser.feed_data(b"a" * 8000 + b" HTTP/1.1\r\nHost: a\r\n\r\n")
|
|
+
|
|
+
|
|
def test_http_response_parser_utf8(response) -> None:
|
|
text = "HTTP/1.1 200 Ok\r\nx-test:тест\r\n\r\n".encode()
|
|
|
|
@@ -1238,6 +1249,17 @@ def test_http_response_parser_status_line_under_limit(
|
|
assert msg.reason == reason.decode()
|
|
|
|
|
|
+def test_http_response_parser_status_line_too_long_fragmented(
|
|
+ response: HttpResponseParser,
|
|
+) -> None:
|
|
+ # Split an overlong reason phrase across reads so that each callback
|
|
+ # fragment is under the limit but the accumulated reason is not.
|
|
+ match = "400, message:\n Got more than 8190 bytes when reading"
|
|
+ with pytest.raises(http_exceptions.LineTooLong, match=match):
|
|
+ response.feed_data(b"HTTP/1.1 200 " + b"a" * 8000)
|
|
+ response.feed_data(b"a" * 8000 + b"\r\n\r\n")
|
|
+
|
|
+
|
|
def test_http_response_parser_bad_version(response) -> None:
|
|
with pytest.raises(http_exceptions.BadHttpMessage):
|
|
response.feed_data(b"HT/11 200 Ok\r\n\r\n")
|
|
--
|
|
2.35.6
|