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 commits shown in [1] and [2]. The advisory identifying the fix is referenced in [3]. [1] https://github.com/aio-libs/aiohttp/commit/e00ca3cca92c465c7913c4beb763a72da9ed8349 [2] https://github.com/aio-libs/aiohttp/commit/53e2e6fc58b89c6185be7820bd2c9f40216b3000 [3] https://nvd.nist.gov/vuln/detail/CVE-2026-34525 Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
129 lines
4.3 KiB
Diff
129 lines
4.3 KiB
Diff
From 4032dcab4b75e875cb81e9a8726214c38b66747a Mon Sep 17 00:00:00 2001
|
|
From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com>
|
|
Date: Sun, 15 Mar 2026 13:58:08 +0000
|
|
Subject: [PATCH] [PR #12240/345d2537 backport][3.13] Reject duplicate
|
|
singleton headers in C extension parser (#12241)
|
|
|
|
**This is a backport of PR #12240 as merged into master
|
|
(345d25371562dd56de099f1fcd5720e96c6e7702).**
|
|
|
|
CVE: CVE-2026-34525
|
|
Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/e00ca3cca92c465c7913c4beb763a72da9ed8349]
|
|
|
|
Co-authored-by: Rodrigo Nogueira <rodrigo.b.nogueira@gmail.com>
|
|
(cherry picked from commit e00ca3cca92c465c7913c4beb763a72da9ed8349)
|
|
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
|
---
|
|
CHANGES/12240.bugfix.rst | 5 +++++
|
|
aiohttp/_http_parser.pyx | 22 +++++++++++++++++++++
|
|
tests/test_http_parser.py | 41 +++++++++++++++++++++++++++++++++++++++
|
|
3 files changed, 68 insertions(+)
|
|
create mode 100644 CHANGES/12240.bugfix.rst
|
|
|
|
diff --git a/CHANGES/12240.bugfix.rst b/CHANGES/12240.bugfix.rst
|
|
new file mode 100644
|
|
index 000000000..49508b3f5
|
|
--- /dev/null
|
|
+++ b/CHANGES/12240.bugfix.rst
|
|
@@ -0,0 +1,5 @@
|
|
+Rejected duplicate singleton headers (``Host``, ``Content-Type``,
|
|
+``Content-Length``, etc.) in the C extension HTTP parser to match
|
|
+the pure Python parser behavior, preventing potential host-based
|
|
+access control bypasses via parser differentials
|
|
+-- by :user:`rodrigobnogueira`.
|
|
diff --git a/aiohttp/_http_parser.pyx b/aiohttp/_http_parser.pyx
|
|
index 213ce2f0c..bb7bf673d 100644
|
|
--- a/aiohttp/_http_parser.pyx
|
|
+++ b/aiohttp/_http_parser.pyx
|
|
@@ -72,6 +72,20 @@ cdef object StreamReader = _StreamReader
|
|
cdef object DeflateBuffer = _DeflateBuffer
|
|
|
|
|
|
+# https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-6
|
|
+cdef tuple SINGLETON_HEADERS = (
|
|
+ hdrs.CONTENT_LENGTH,
|
|
+ hdrs.CONTENT_LOCATION,
|
|
+ hdrs.CONTENT_RANGE,
|
|
+ hdrs.CONTENT_TYPE,
|
|
+ hdrs.ETAG,
|
|
+ hdrs.HOST,
|
|
+ hdrs.MAX_FORWARDS,
|
|
+ hdrs.SERVER,
|
|
+ hdrs.TRANSFER_ENCODING,
|
|
+ hdrs.USER_AGENT,
|
|
+)
|
|
+
|
|
cdef inline object extend(object buf, const char* at, size_t length):
|
|
cdef Py_ssize_t s
|
|
cdef char* ptr
|
|
@@ -438,6 +452,14 @@ cdef class HttpParser:
|
|
raw_headers = tuple(self._raw_headers)
|
|
headers = CIMultiDictProxy(self._headers)
|
|
|
|
+ # https://www.rfc-editor.org/rfc/rfc9110.html#name-collected-abnf
|
|
+ bad_hdr = next(
|
|
+ (h for h in SINGLETON_HEADERS if len(headers.getall(h, ())) > 1),
|
|
+ None,
|
|
+ )
|
|
+ if bad_hdr is not None:
|
|
+ raise BadHttpMessage(f"Duplicate '{bad_hdr}' header found.")
|
|
+
|
|
if self._cparser.type == cparser.HTTP_REQUEST:
|
|
h_upg = headers.get("upgrade", "")
|
|
allowed = upgrade and h_upg.isascii() and h_upg.lower() in ALLOWED_UPGRADES
|
|
diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py
|
|
index be7446e0a..b0a282f3e 100644
|
|
--- a/tests/test_http_parser.py
|
|
+++ b/tests/test_http_parser.py
|
|
@@ -263,6 +263,47 @@ def test_content_length_transfer_encoding(parser: Any) -> None:
|
|
parser.feed_data(text)
|
|
|
|
|
|
+@pytest.mark.parametrize(
|
|
+ "hdr",
|
|
+ (
|
|
+ "Content-Length",
|
|
+ "Content-Location",
|
|
+ "Content-Range",
|
|
+ "Content-Type",
|
|
+ "ETag",
|
|
+ "Host",
|
|
+ "Max-Forwards",
|
|
+ "Server",
|
|
+ "Transfer-Encoding",
|
|
+ "User-Agent",
|
|
+ ),
|
|
+)
|
|
+def test_duplicate_singleton_header_rejected(
|
|
+ parser: HttpRequestParser, hdr: str
|
|
+) -> None:
|
|
+ val1, val2 = ("1", "2") if hdr == "Content-Length" else ("value1", "value2")
|
|
+ text = (
|
|
+ f"GET /test HTTP/1.1\r\n"
|
|
+ f"Host: example.com\r\n"
|
|
+ f"{hdr}: {val1}\r\n"
|
|
+ f"{hdr}: {val2}\r\n"
|
|
+ f"\r\n"
|
|
+ ).encode()
|
|
+ with pytest.raises(http_exceptions.BadHttpMessage, match="Duplicate"):
|
|
+ parser.feed_data(text)
|
|
+
|
|
+
|
|
+def test_duplicate_host_header_rejected(parser: HttpRequestParser) -> None:
|
|
+ text = (
|
|
+ b"GET /admin HTTP/1.1\r\n"
|
|
+ b"Host: admin.example\r\n"
|
|
+ b"Host: public.example\r\n"
|
|
+ b"\r\n"
|
|
+ )
|
|
+ with pytest.raises(http_exceptions.BadHttpMessage, match="Duplicate.*Host"):
|
|
+ parser.feed_data(text)
|
|
+
|
|
+
|
|
def test_bad_chunked_py(loop: Any, protocol: Any) -> None:
|
|
"""Test that invalid chunked encoding doesn't allow content-length to be used."""
|
|
parser = HttpRequestParserPy(
|
|
|
|
--
|
|
2.35.6
|