summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python
diff options
context:
space:
mode:
authorJiaying Song <jiaying.song.cn@windriver.com>2025-07-16 15:37:58 +0800
committerGyorgy Sarvari <skandigraun@gmail.com>2025-09-06 16:27:05 +0200
commit78afe9d40cb41f9b7691b4ec4183ca442e70fb63 (patch)
tree6618e6bd598b9ac16572b890908801e6e64a1fa1 /meta-python/recipes-devtools/python
parent89b98ccbfb7c52577ebab7c4306c9fdb8aee81a6 (diff)
downloadmeta-openembedded-78afe9d40cb41f9b7691b4ec4183ca442e70fb63.tar.gz
python3-aiohttp: fix CVE-2025-53643 and drop CVE-2024-42367 patch
- Fix CVE-2025-53643: AIOHTTP is an asynchronous HTTP client/server framework for asyncio and Python. Prior to version 3.12.14, the Python parser is vulnerable to a request smuggling vulnerability due to not parsing trailer sections of an HTTP request. If a pure Python version of aiohttp is installed (i.e. without the usual C extensions) or AIOHTTP_NO_EXTENSIONS is enabled, then an attacker may be able to execute a request smuggling attack to bypass certain firewalls or proxy protections. Version 3.12.14 contains a patch for this issue. References: https://nvd.nist.gov/vuln/detail/CVE-2025-53643 - Drop CVE-2024-42367.patch: According to upstream discussion and advisory [1][2], aiohttp 3.8.6 is not affected by CVE-2024-42367, and the patch is therefore no longer needed. [1] https://github.com/advisories/GHSA-jwhx-xcg6-8xhj [2] https://github.com/aio-libs/aiohttp/issues/11149 Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
Diffstat (limited to 'meta-python/recipes-devtools/python')
-rw-r--r--meta-python/recipes-devtools/python/python3-aiohttp/CVE-2024-42367.patch65
-rw-r--r--meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch197
-rw-r--r--meta-python/recipes-devtools/python/python3-aiohttp_3.8.6.bb2
3 files changed, 198 insertions, 66 deletions
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2024-42367.patch b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2024-42367.patch
deleted file mode 100644
index dadec31f3a..0000000000
--- a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2024-42367.patch
+++ /dev/null
@@ -1,65 +0,0 @@
1From e19cb50fb529bbe75cc4f1b68eeb0a3f631ad0d0 Mon Sep 17 00:00:00 2001
2From: "J. Nick Koston" <nick@koston.org>
3Date: Thu, 8 Aug 2024 11:19:28 -0500
4Subject: [PATCH] Do not follow symlinks for compressed file variants (#8652)
5
6CVE: CVE-2024-42367
7
8Upstream-Status: Backport
9[https://github.com/aio-libs/aiohttp/commit/ce2e9758814527589b10759a20783fb03b98339f]
10
11Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
12Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
13---
14 CHANGES/8652.bugfix.rst | 1 +
15 aiohttp/web_fileresponse.py | 26 ++++++++++++++++++++++++++
16 2 files changed, 27 insertions(+)
17 create mode 100644 CHANGES/8652.bugfix.rst
18
19diff --git a/CHANGES/8652.bugfix.rst b/CHANGES/8652.bugfix.rst
20new file mode 100644
21index 000000000..3a1003e50
22--- /dev/null
23+++ b/CHANGES/8652.bugfix.rst
24@@ -0,0 +1 @@
25+Fixed incorrectly following symlinks for compressed file variants -- by :user:`steverep`.
26diff --git a/aiohttp/web_fileresponse.py b/aiohttp/web_fileresponse.py
27index f41ed3fd0..35dbd41e1 100644
28--- a/aiohttp/web_fileresponse.py
29+++ b/aiohttp/web_fileresponse.py
30@@ -127,6 +127,32 @@ class FileResponse(StreamResponse):
31 self.content_length = 0
32 return await super().prepare(request)
33
34+ def _get_file_path_stat_encoding(
35+ self, accept_encoding: str
36+ ) -> Tuple[pathlib.Path, os.stat_result, Optional[str]]:
37+ """Return the file path, stat result, and encoding.
38+
39+ If an uncompressed file is returned, the encoding is set to
40+ :py:data:`None`.
41+
42+ This method should be called from a thread executor
43+ since it calls os.stat which may block.
44+ """
45+ file_path = self._path
46+ for file_extension, file_encoding in ENCODING_EXTENSIONS.items():
47+ if file_encoding not in accept_encoding:
48+ continue
49+
50+ compressed_path = file_path.with_suffix(file_path.suffix + file_extension)
51+ with suppress(OSError):
52+ # Do not follow symlinks and ignore any non-regular files.
53+ st = compressed_path.lstat()
54+ if S_ISREG(st.st_mode):
55+ return compressed_path, st, file_encoding
56+
57+ # Fallback to the uncompressed file
58+ return file_path, file_path.stat(), None
59+
60 async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]:
61 filepath = self._path
62
63--
642.34.1
65
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch
new file mode 100644
index 0000000000..19eef35bb2
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch
@@ -0,0 +1,197 @@
1From 4c4dec318f21e2eae9c69cd5b83cb54b4f9bb746 Mon Sep 17 00:00:00 2001
2From: Sam Bull <git@sambull.org>
3Date: Wed, 9 Jul 2025 19:55:22 +0100
4Subject: [PATCH] Add trailer parsing logic (#11269) (#11287)
5
6(cherry picked from commit 7dd4b5535e6bf9c2d2f05fde638517bff065ba74)
7
8CVE: CVE-2025-53643
9
10Upstream-Status: Backport
11[https://github.com/aio-libs/aiohttp/commit/e8d774f635dc6d1cd3174d0e38891da5de0e2b6a]
12
13Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
14---
15 aiohttp/http_parser.py | 70 ++++++++++++++++++++++--------------------
16 aiohttp/multipart.py | 2 +-
17 2 files changed, 38 insertions(+), 34 deletions(-)
18
19diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py
20index 1ee126940..175eb7f68 100644
21--- a/aiohttp/http_parser.py
22+++ b/aiohttp/http_parser.py
23@@ -147,8 +147,8 @@ class HeadersParser:
24 headers: CIMultiDict[str] = CIMultiDict()
25 raw_headers = []
26
27- lines_idx = 1
28- line = lines[1]
29+ lines_idx = 0
30+ line = lines[lines_idx]
31 line_count = len(lines)
32
33 while line:
34@@ -386,6 +386,7 @@ class HttpParser(abc.ABC, Generic[_MsgT]):
35 response_with_body=self.response_with_body,
36 auto_decompress=self._auto_decompress,
37 lax=self.lax,
38+ headers_parser=self._headers_parser,
39 )
40 if not payload_parser.done:
41 self._payload_parser = payload_parser
42@@ -405,6 +406,7 @@ class HttpParser(abc.ABC, Generic[_MsgT]):
43 readall=True,
44 auto_decompress=self._auto_decompress,
45 lax=self.lax,
46+ headers_parser=self._headers_parser,
47 )
48 else:
49 if (
50@@ -429,6 +431,7 @@ class HttpParser(abc.ABC, Generic[_MsgT]):
51 response_with_body=self.response_with_body,
52 auto_decompress=self._auto_decompress,
53 lax=self.lax,
54+ headers_parser=self._headers_parser,
55 )
56 if not payload_parser.done:
57 self._payload_parser = payload_parser
58@@ -462,6 +465,10 @@ class HttpParser(abc.ABC, Generic[_MsgT]):
59
60 eof = True
61 data = b""
62+ if isinstance(
63+ underlying_exc, (InvalidHeader, TransferEncodingError)
64+ ):
65+ raise
66
67 if eof:
68 start_pos = 0
69@@ -617,7 +624,7 @@ class HttpRequestParser(HttpParser[RawRequestMessage]):
70 compression,
71 upgrade,
72 chunked,
73- ) = self.parse_headers(lines)
74+ ) = self.parse_headers(lines[1:])
75
76 if close is None: # then the headers weren't set in the request
77 if version_o <= HttpVersion10: # HTTP 1.0 must asks to not close
78@@ -696,7 +703,7 @@ class HttpResponseParser(HttpParser[RawResponseMessage]):
79 compression,
80 upgrade,
81 chunked,
82- ) = self.parse_headers(lines)
83+ ) = self.parse_headers(lines[1:])
84
85 if close is None:
86 close = version_o <= HttpVersion10
87@@ -727,6 +734,8 @@ class HttpPayloadParser:
88 response_with_body: bool = True,
89 auto_decompress: bool = True,
90 lax: bool = False,
91+ *,
92+ headers_parser: HeadersParser,
93 ) -> None:
94 self._length = 0
95 self._type = ParseState.PARSE_NONE
96@@ -735,6 +744,8 @@ class HttpPayloadParser:
97 self._chunk_tail = b""
98 self._auto_decompress = auto_decompress
99 self._lax = lax
100+ self._headers_parser = headers_parser
101+ self._trailer_lines: list[bytes] = []
102 self.done = False
103
104 # payload decompression wrapper
105@@ -822,7 +833,7 @@ class HttpPayloadParser:
106 size_b = chunk[:i] # strip chunk-extensions
107 # Verify no LF in the chunk-extension
108 if b"\n" in (ext := chunk[i:pos]):
109- exc = BadHttpMessage(
110+ exc = TransferEncodingError(
111 f"Unexpected LF in chunk-extension: {ext!r}"
112 )
113 set_exception(self.payload, exc)
114@@ -843,7 +854,7 @@ class HttpPayloadParser:
115
116 chunk = chunk[pos + len(SEP) :]
117 if size == 0: # eof marker
118- self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
119+ self._chunk = ChunkState.PARSE_TRAILERS
120 if self._lax and chunk.startswith(b"\r"):
121 chunk = chunk[1:]
122 else:
123@@ -881,38 +892,31 @@ class HttpPayloadParser:
124 self._chunk_tail = chunk
125 return False, b""
126
127- # if stream does not contain trailer, after 0\r\n
128- # we should get another \r\n otherwise
129- # trailers needs to be skiped until \r\n\r\n
130- if self._chunk == ChunkState.PARSE_MAYBE_TRAILERS:
131- head = chunk[: len(SEP)]
132- if head == SEP:
133- # end of stream
134- self.payload.feed_eof()
135- return True, chunk[len(SEP) :]
136- # Both CR and LF, or only LF may not be received yet. It is
137- # expected that CRLF or LF will be shown at the very first
138- # byte next time, otherwise trailers should come. The last
139- # CRLF which marks the end of response might not be
140- # contained in the same TCP segment which delivered the
141- # size indicator.
142- if not head:
143- return False, b""
144- if head == SEP[:1]:
145- self._chunk_tail = head
146- return False, b""
147- self._chunk = ChunkState.PARSE_TRAILERS
148-
149- # read and discard trailer up to the CRLF terminator
150 if self._chunk == ChunkState.PARSE_TRAILERS:
151 pos = chunk.find(SEP)
152- if pos >= 0:
153- chunk = chunk[pos + len(SEP) :]
154- self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
155- else:
156+ if pos < 0: # No line found
157 self._chunk_tail = chunk
158 return False, b""
159
160+ line = chunk[:pos]
161+ chunk = chunk[pos + len(SEP) :]
162+ if SEP == b"\n": # For lax response parsing
163+ line = line.rstrip(b"\r")
164+ self._trailer_lines.append(line)
165+
166+ # \r\n\r\n found, end of stream
167+ if self._trailer_lines[-1] == b"":
168+ # Headers and trailers are defined the same way,
169+ # so we reuse the HeadersParser here.
170+ try:
171+ trailers, raw_trailers = self._headers_parser.parse_headers(
172+ self._trailer_lines
173+ )
174+ finally:
175+ self._trailer_lines.clear()
176+ self.payload.feed_eof()
177+ return True, chunk
178+
179 # Read all bytes until eof
180 elif self._type == ParseState.PARSE_UNTIL_EOF:
181 self.payload.feed_data(chunk, len(chunk))
182diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py
183index 9cd49bb5d..2457f80ec 100644
184--- a/aiohttp/multipart.py
185+++ b/aiohttp/multipart.py
186@@ -718,7 +718,7 @@ class MultipartReader:
187 raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}")
188
189 async def _read_headers(self) -> "CIMultiDictProxy[str]":
190- lines = [b""]
191+ lines = []
192 while True:
193 chunk = await self._content.readline()
194 chunk = chunk.strip()
195--
1962.34.1
197
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp_3.8.6.bb b/meta-python/recipes-devtools/python/python3-aiohttp_3.8.6.bb
index fdecf9ef4c..50103da47d 100644
--- a/meta-python/recipes-devtools/python/python3-aiohttp_3.8.6.bb
+++ b/meta-python/recipes-devtools/python/python3-aiohttp_3.8.6.bb
@@ -10,7 +10,7 @@ SRC_URI += "file://CVE-2024-23334.patch \
10 file://CVE-2024-52304.patch \ 10 file://CVE-2024-52304.patch \
11 file://CVE-2023-49082.patch \ 11 file://CVE-2023-49082.patch \
12 file://CVE-2024-27306.patch \ 12 file://CVE-2024-27306.patch \
13 file://CVE-2024-42367.patch \ 13 file://CVE-2025-53643.patch \
14 " 14 "
15 15
16SRC_URI[sha256sum] = "b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c" 16SRC_URI[sha256sum] = "b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"