[oe][meta-python][wrynose][PATCH 10/10] python3-aiohttp: fix CVE-2026-54280
"Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" <[email protected]>
| Newsgroups | org.openembedded.lists.openembedded-devel |
|---|---|
| Message-ID | <[email protected]> |
From: Darsh Kelaiya <[email protected]> This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/aio-libs/aiohttp/commit/a762eda5242f6490d6ba667533193f8b473ad587 [2] https://github.com/advisories/GHSA-9x8q-7h8h-wcw9 Signed-off-by: Darsh Kelaiya <[email protected]> --- .../python3-aiohttp/CVE-2026-54280.patch | 138 ++++++++++++++++++ .../python/python3-aiohttp_3.13.5.bb | 1 + 2 files changed, 139 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-54280.patch diff --git a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-54280.patch b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-54280.patch new file mode 100644 index 0000000000..c598a5194c --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2026-54280.patch @@ -0,0 +1,138 @@ +From 724ae4d652417c4490a71ea0b16b8804dad3004f Mon Sep 17 00:00:00 2001 +From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> +Date: Sun, 7 Jun 2026 05:47:16 +0000 +Subject: [PATCH] [PR #12831/1ac92dae backport][3.14] Payload close on + disconnect (#12843) + +CVE: CVE-2026-54280 +Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/a762eda5242f6490d6ba667533193f8b473ad587] + +Co-authored-by: J. Nick Koston <[email protected]> +(cherry picked from commit a762eda5242f6490d6ba667533193f8b473ad587) +Signed-off-by: Darsh Kelaiya <[email protected]> +--- + CHANGES/12831.bugfix.rst | 1 + + aiohttp/web_response.py | 6 ++-- + tests/test_web_response.py | 73 +++++++++++++++++++++++++++++++++++++- + 3 files changed, 77 insertions(+), 3 deletions(-) + create mode 100644 CHANGES/12831.bugfix.rst + +diff --git a/CHANGES/12831.bugfix.rst b/CHANGES/12831.bugfix.rst +new file mode 100644 +index 000000000..bf460ffcc +--- /dev/null ++++ b/CHANGES/12831.bugfix.rst +@@ -0,0 +1 @@ ++Fixed :meth:`aiohttp.web.Response.write_eof` skipping ``Payload.close()`` when the body write was interrupted by an error or cancellation, for example when a client disconnects mid-response; the payload close hook now runs in a ``finally`` so a :class:`~aiohttp.payload.Payload` body always releases its resources -- by :user:`bdraco`. +diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py +index 364270e4d..cea5d4b45 100644 +--- a/aiohttp/web_response.py ++++ b/aiohttp/web_response.py +@@ -779,8 +779,10 @@ class Response(StreamResponse): + if body is None or self._must_be_empty_body: + await super().write_eof() + elif isinstance(self._body, Payload): +- await self._body.write(self._payload_writer) +- await self._body.close() ++ try: ++ await self._body.write(self._payload_writer) ++ finally: ++ await self._body.close() + await super().write_eof() + else: + await super().write_eof(cast(bytes, body)) +diff --git a/tests/test_web_response.py b/tests/test_web_response.py +index 5a4fb7e66..f094cd3d2 100644 +--- a/tests/test_web_response.py ++++ b/tests/test_web_response.py +@@ -1,3 +1,4 @@ ++import asyncio + import collections.abc + import datetime + import gzip +@@ -18,7 +19,7 @@ from aiohttp.abc import AbstractStreamWriter + from aiohttp.helpers import ETag + from aiohttp.http_writer import StreamWriter, _serialize_headers + from aiohttp.multipart import BodyPartReader, MultipartWriter +-from aiohttp.payload import BytesPayload, StringPayload ++from aiohttp.payload import BytesPayload, Payload, StringPayload + from aiohttp.test_utils import make_mocked_request + from aiohttp.web import ContentCoding, Response, StreamResponse, json_response + +@@ -1370,6 +1371,76 @@ async def test_consecutive_write_eof() -> None: + writer.write_eof.assert_called_once_with(data) + + ++class _ClosingPayload(Payload): ++ """Payload test double that records whether close() ran.""" ++ ++ def __init__(self) -> None: ++ super().__init__(None) ++ self.close_called = False ++ self.started = asyncio.Event() ++ self.release = asyncio.Event() ++ self.fail = False ++ ++ async def write(self, writer: AbstractStreamWriter) -> None: ++ self.started.set() ++ if self.fail: ++ raise ConnectionResetError("client gone") ++ await self.release.wait() ++ ++ async def close(self) -> None: ++ self.close_called = True ++ await super().close() ++ ++ def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: ++ assert False ++ ++ ++async def test_write_eof_closes_payload_on_success() -> None: ++ writer = mock.create_autospec(AbstractStreamWriter, spec_set=True, instance=True) ++ req = make_request("GET", "/", writer=writer) ++ payload = _ClosingPayload() ++ payload.release.set() ++ resp = web.Response(body=payload) ++ ++ await resp.prepare(req) ++ await resp.write_eof() ++ ++ assert payload.close_called ++ assert writer.write_eof.called ++ ++ ++async def test_write_eof_closes_payload_on_write_error() -> None: ++ writer = mock.create_autospec(AbstractStreamWriter, spec_set=True, instance=True) ++ req = make_request("GET", "/", writer=writer) ++ payload = _ClosingPayload() ++ payload.fail = True ++ resp = web.Response(body=payload) ++ ++ await resp.prepare(req) ++ with pytest.raises(ConnectionResetError): ++ await resp.write_eof() ++ ++ assert payload.close_called ++ assert not writer.write_eof.called ++ ++ ++async def test_write_eof_closes_payload_on_cancel() -> None: ++ writer = mock.create_autospec(AbstractStreamWriter, spec_set=True, instance=True) ++ req = make_request("GET", "/", writer=writer) ++ payload = _ClosingPayload() ++ resp = web.Response(body=payload) ++ ++ await resp.prepare(req) ++ task = asyncio.ensure_future(resp.write_eof()) ++ await payload.started.wait() ++ task.cancel() ++ with pytest.raises(asyncio.CancelledError): ++ await task ++ ++ assert payload.close_called ++ assert not writer.write_eof.called ++ ++ + def test_set_text_with_content_type() -> None: + resp = Response() + resp.content_type = "text/html" diff --git a/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb b/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb index 9102175f24..b9d08ac97b 100644 --- a/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb +++ b/meta-python/recipes-devtools/python/python3-aiohttp_3.13.5.bb @@ -16,6 +16,7 @@ SRC_URI += " \ file://CVE-2026-54277.patch \ file://CVE-2026-54278.patch \ file://CVE-2026-54279.patch \ + file://CVE-2026-54280.patch \ " CVE_PRODUCT = "aiohttp" -- 2.35.6