mirror of
git://git.openembedded.org/meta-openembedded
synced 2026-05-17 15:16:42 +00:00
python3-aiohttp: patch CVE-2025-69227
Details: https://nvd.nist.gov/vuln/detail/CVE-2025-69227 Backport the patch that is referenced by teh NVD advisory. Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
parent
4ac10b5dbb
commit
0ea6c04dde
@ -0,0 +1,148 @@
|
||||
From 635c8c03b609b1099d93fb8ea8c8691624237b0f Mon Sep 17 00:00:00 2001
|
||||
From: Gyorgy Sarvari <skandigraun@gmail.com>
|
||||
Date: Sat, 3 Jan 2026 04:53:29 +0000
|
||||
Subject: [PATCH] Replace asserts with exceptions (#11897) (#11914)
|
||||
|
||||
From: Sam Bull <git@sambull.org>
|
||||
|
||||
(cherry picked from commit d5bf65f15c0c718b6b95e9bc9d0914a92c51e60f)
|
||||
|
||||
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
|
||||
|
||||
CVE: CVE-2025-69227
|
||||
Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/bc1319ec3cbff9438a758951a30907b072561259]
|
||||
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
|
||||
---
|
||||
aiohttp/multipart.py | 10 ++++------
|
||||
aiohttp/web_request.py | 8 +++-----
|
||||
tests/test_multipart.py | 12 +++++++++++-
|
||||
tests/test_web_request.py | 24 +++++++++++++++++++++++-
|
||||
4 files changed, 41 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py
|
||||
index 54dfd48..7783ac5 100644
|
||||
--- a/aiohttp/multipart.py
|
||||
+++ b/aiohttp/multipart.py
|
||||
@@ -357,11 +357,8 @@ class BodyPartReader:
|
||||
self._read_bytes += len(chunk)
|
||||
if self._read_bytes == self._length:
|
||||
self._at_eof = True
|
||||
- if self._at_eof:
|
||||
- clrf = await self._content.readline()
|
||||
- assert (
|
||||
- b"\r\n" == clrf
|
||||
- ), "reader did not read all the data or it is malformed"
|
||||
+ if self._at_eof and await self._content.readline() != b"\r\n":
|
||||
+ raise ValueError("Reader did not read all the data or it is malformed")
|
||||
return chunk
|
||||
|
||||
async def _read_chunk_from_length(self, size: int) -> bytes:
|
||||
@@ -390,7 +387,8 @@ class BodyPartReader:
|
||||
while len(chunk) < self._boundary_len:
|
||||
chunk += await self._content.read(size)
|
||||
self._content_eof += int(self._content.at_eof())
|
||||
- assert self._content_eof < 3, "Reading after EOF"
|
||||
+ if self._content_eof > 2:
|
||||
+ raise ValueError("Reading after EOF")
|
||||
if self._content_eof:
|
||||
break
|
||||
if len(chunk) > size:
|
||||
diff --git a/aiohttp/web_request.py b/aiohttp/web_request.py
|
||||
index 6e09027..96222b0 100644
|
||||
--- a/aiohttp/web_request.py
|
||||
+++ b/aiohttp/web_request.py
|
||||
@@ -721,13 +721,13 @@ class BaseRequest(MutableMapping[str, Any], HeadersMixin):
|
||||
multipart = await self.multipart()
|
||||
max_size = self._client_max_size
|
||||
|
||||
- field = await multipart.next()
|
||||
- while field is not None:
|
||||
+ while (field := await multipart.next()) is not None:
|
||||
size = 0
|
||||
field_ct = field.headers.get(hdrs.CONTENT_TYPE)
|
||||
|
||||
if isinstance(field, BodyPartReader):
|
||||
- assert field.name is not None
|
||||
+ if field.name is None:
|
||||
+ raise ValueError("Multipart field missing name.")
|
||||
|
||||
# Note that according to RFC 7578, the Content-Type header
|
||||
# is optional, even for files, so we can't assume it's
|
||||
@@ -779,8 +779,6 @@ class BaseRequest(MutableMapping[str, Any], HeadersMixin):
|
||||
raise ValueError(
|
||||
"To decode nested multipart you need to use custom reader",
|
||||
)
|
||||
-
|
||||
- field = await multipart.next()
|
||||
else:
|
||||
data = await self.read()
|
||||
if data:
|
||||
diff --git a/tests/test_multipart.py b/tests/test_multipart.py
|
||||
index 75b73a7..5351945 100644
|
||||
--- a/tests/test_multipart.py
|
||||
+++ b/tests/test_multipart.py
|
||||
@@ -221,11 +221,21 @@ class TestPartReader:
|
||||
with Stream(data) as stream:
|
||||
obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)
|
||||
result = b""
|
||||
- with pytest.raises(AssertionError):
|
||||
+ with pytest.raises(ValueError):
|
||||
for _ in range(4):
|
||||
result += await obj.read_chunk(7)
|
||||
assert data == result
|
||||
|
||||
+ async def test_read_with_content_length_malformed_crlf(self) -> None:
|
||||
+ # Content-Length is correct but data after content is not \r\n
|
||||
+ content = b"Hello"
|
||||
+ h = CIMultiDictProxy(CIMultiDict({"CONTENT-LENGTH": str(len(content))}))
|
||||
+ # Malformed: "XX" instead of "\r\n" after content
|
||||
+ with Stream(content + b"XX--:--") as stream:
|
||||
+ obj = aiohttp.BodyPartReader(BOUNDARY, h, stream)
|
||||
+ with pytest.raises(ValueError, match="malformed"):
|
||||
+ await obj.read()
|
||||
+
|
||||
async def test_read_boundary_with_incomplete_chunk(self) -> None:
|
||||
with Stream(b"") as stream:
|
||||
|
||||
diff --git a/tests/test_web_request.py b/tests/test_web_request.py
|
||||
index da80ca9..125b95e 100644
|
||||
--- a/tests/test_web_request.py
|
||||
+++ b/tests/test_web_request.py
|
||||
@@ -10,6 +10,7 @@ from multidict import CIMultiDict, CIMultiDictProxy, MultiDict
|
||||
from yarl import URL
|
||||
|
||||
from aiohttp import HttpVersion
|
||||
+from aiohttp.base_protocol import BaseProtocol
|
||||
from aiohttp.http_parser import RawRequestMessage
|
||||
from aiohttp.streams import StreamReader
|
||||
from aiohttp.test_utils import make_mocked_request
|
||||
@@ -815,7 +816,28 @@ async def test_multipart_formdata(protocol) -> None:
|
||||
assert dict(result) == {"a": "b", "c": "d"}
|
||||
|
||||
|
||||
-async def test_multipart_formdata_file(protocol) -> None:
|
||||
+async def test_multipart_formdata_field_missing_name(protocol: BaseProtocol) -> None:
|
||||
+ # Ensure ValueError is raised when Content-Disposition has no name
|
||||
+ payload = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())
|
||||
+ payload.feed_data(
|
||||
+ b"-----------------------------326931944431359\r\n"
|
||||
+ b"Content-Disposition: form-data\r\n" # Missing name!
|
||||
+ b"\r\n"
|
||||
+ b"value\r\n"
|
||||
+ b"-----------------------------326931944431359--\r\n"
|
||||
+ )
|
||||
+ content_type = (
|
||||
+ "multipart/form-data; boundary=---------------------------326931944431359"
|
||||
+ )
|
||||
+ payload.feed_eof()
|
||||
+ req = make_mocked_request(
|
||||
+ "POST", "/", headers={"CONTENT-TYPE": content_type}, payload=payload
|
||||
+ )
|
||||
+ with pytest.raises(ValueError, match="Multipart field missing name"):
|
||||
+ await req.post()
|
||||
+
|
||||
+
|
||||
+async def test_multipart_formdata_file(protocol: BaseProtocol) -> None:
|
||||
# Make sure file uploads work, even without a content type
|
||||
payload = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())
|
||||
payload.feed_data(
|
||||
@ -7,6 +7,7 @@ LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=748073912af33aa59430d3702aa32d41"
|
||||
SRC_URI += "file://CVE-2025-69224.patch \
|
||||
file://CVE-2025-69225.patch \
|
||||
file://CVE-2025-69226.patch \
|
||||
file://CVE-2025-69227.patch \
|
||||
"
|
||||
SRC_URI[sha256sum] = "4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user