* [scarthgap][PATCH 00/12] Fix multiple CVEs
@ 2026-04-09 6:16 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 01/12] gi-docgen: fix CVE-2025-11687 jinfeng.wang.cn
` (11 more replies)
0 siblings, 12 replies; 23+ messages in thread
From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw)
To: openembedded-core
From: Jinfeng Wang <jinfeng.wang.cn@windriver.com>
test steps:
bitbake world
built without introducing new building errors.
Note:
This libpcap 1.10.4 -> 1.10.6 upgrade introduces a new enum PCAP_SOCKET definition that conflicts with nmap in meta-openembedded. A corresponding fix has been submitted to the openembedded-devel mailing list to rename the conflicting enum in nmap.
Related patch: "[meta-oe] nmap: rename enum PCAP_SOCKET" submitted to openembedded-devel@lists.openembedded.org
Changqing Li (2):
libsoup: fix CVE-2025-14523/CVE-2025-32049
libsoup-2.4: fix CVE-2025-14523/CVE-2025-32049
Chen Qi (1):
busybox: fix CVE-2026-26157 and CVE-2026-26158
Guocai He (2):
python3-wheel: fix CVE-2026-24049
gnupg: fix CVE-2026-24882
Jiaying Song (2):
python3-pyasn1: fix CVE-2026-23490
python3-pyasn1: fix CVE-2026-30922
Kai Kang (1):
libpcap: 1.10.4 -> 1.10.6
Libo Chen (1):
python3-ply: fix CVE-2025-56005
Liyin Zhang (1):
zlib: upgrade 1.3.1 -> 1.3.2
Mingli Yu (1):
libxml2: Fix CVE-2026-1757
Zhang Peng (1):
gi-docgen: fix CVE-2025-11687
.../libpcap/libpcap/CVE-2023-7256-pre1.patch | 37 -
.../libpcap/libpcap/CVE-2023-7256.patch | 365 ---------
.../libpcap/libpcap/CVE-2024-8006.patch | 42 -
.../libpcap/libpcap/CVE-2025-11961-01.patch | 38 -
.../libpcap/libpcap/CVE-2025-11961-02.patch | 433 -----------
.../libpcap/libpcap/CVE-2025-11964.patch | 33 -
.../{libpcap_1.10.4.bb => libpcap_1.10.6.bb} | 8 +-
...-hardlink-components-GNU-tar-does-th.patch | 201 +++++
...nsafe-components-from-hardlinks-not-.patch | 39 +
meta/recipes-core/busybox/busybox_1.36.1.bb | 2 +
.../libxml/libxml2/CVE-2026-1757.patch | 49 ++
meta/recipes-core/libxml/libxml2_2.12.10.bb | 1 +
...configure-Pass-LDFLAGS-to-link-tests.patch | 78 --
.../zlib/zlib/CVE-2026-27171.patch | 63 --
.../zlib/{zlib_1.3.1.bb => zlib_1.3.2.bb} | 4 +-
.../recipes-devtools/python/python-pyasn1.inc | 4 +-
.../python/python3-ply/CVE-2025-56005.patch | 125 +++
.../python/python3-ply_3.11.bb | 4 +
.../python3-pyasn1/CVE-2026-23490.patch | 136 ++++
.../python3-pyasn1/CVE-2026-30922.patch | 257 +++++++
.../python/python3-wheel/CVE-2026-24049.patch | 73 ++
.../python/python3-wheel_0.42.0.bb | 2 +
.../gi-docgen/files/CVE-2025-11687.patch | 90 +++
.../gi-docgen/gi-docgen_2023.3.bb | 5 +-
.../gnupg/gnupg/CVE-2026-24882-0001.patch | 70 ++
.../gnupg/gnupg/CVE-2026-24882-0002.patch | 47 ++
meta/recipes-support/gnupg/gnupg_2.4.8.bb | 2 +
.../libsoup/libsoup-2.4/CVE-2025-14523.patch | 52 ++
.../libsoup-2.4/CVE-2025-32049-1.patch | 229 ++++++
.../libsoup-2.4/CVE-2025-32049-2.patch | 131 ++++
.../libsoup/libsoup-2.4_2.74.3.bb | 3 +
.../libsoup-3.4.4/CVE-2025-14523.patch | 715 ++++++++++++++++++
.../libsoup-3.4.4/CVE-2025-32049-1.patch | 229 ++++++
.../libsoup-3.4.4/CVE-2025-32049-2.patch | 34 +
.../libsoup-3.4.4/CVE-2025-32049-3.patch | 134 ++++
.../libsoup-3.4.4/CVE-2025-32049-4.patch | 292 +++++++
meta/recipes-support/libsoup/libsoup_3.4.4.bb | 5 +
37 files changed, 2931 insertions(+), 1101 deletions(-)
delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch
delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch
delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch
delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch
delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch
delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch
rename meta/recipes-connectivity/libpcap/{libpcap_1.10.4.bb => libpcap_1.10.6.bb} (83%)
create mode 100644 meta/recipes-core/busybox/busybox/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch
create mode 100644 meta/recipes-core/busybox/busybox/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch
create mode 100644 meta/recipes-core/libxml/libxml2/CVE-2026-1757.patch
delete mode 100644 meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch
delete mode 100644 meta/recipes-core/zlib/zlib/CVE-2026-27171.patch
rename meta/recipes-core/zlib/{zlib_1.3.1.bb => zlib_1.3.2.bb} (87%)
create mode 100644 meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch
create mode 100644 meta/recipes-devtools/python/python3-pyasn1/CVE-2026-23490.patch
create mode 100644 meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch
create mode 100644 meta/recipes-devtools/python/python3-wheel/CVE-2026-24049.patch
create mode 100644 meta/recipes-gnome/gi-docgen/files/CVE-2025-11687.patch
create mode 100644 meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0001.patch
create mode 100644 meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0002.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch
create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch
--
2.34.1
^ permalink raw reply [flat|nested] 23+ messages in thread* [scarthgap][PATCH 01/12] gi-docgen: fix CVE-2025-11687 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 jinfeng.wang.cn ` (10 subsequent siblings) 11 siblings, 0 replies; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Zhang Peng <peng.zhang1.cn@windriver.com> CVE-2025-11687: A flaw was found in the gi-docgen. This vulnerability allows arbitrary JavaScript execution in the context of the page — enabling DOM access, session cookie theft and other client-side attacks — via a crafted URL that supplies a malicious value to the q GET parameter (reflected DOM XSS). Reference: [https://nvd.nist.gov/vuln/detail/CVE-2025-11687] Upstream patch: [https://gitlab.gnome.org/GNOME/gi-docgen/-/commit/c53d2640bfa5823bbdf33683d95c160267c0ec68] Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../gi-docgen/files/CVE-2025-11687.patch | 90 +++++++++++++++++++ .../gi-docgen/gi-docgen_2023.3.bb | 5 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 meta/recipes-gnome/gi-docgen/files/CVE-2025-11687.patch diff --git a/meta/recipes-gnome/gi-docgen/files/CVE-2025-11687.patch b/meta/recipes-gnome/gi-docgen/files/CVE-2025-11687.patch new file mode 100644 index 0000000000..8a0c15e4a8 --- /dev/null +++ b/meta/recipes-gnome/gi-docgen/files/CVE-2025-11687.patch @@ -0,0 +1,90 @@ +From 0e97b155ff1b15bc3173118561316d8ea28ec9b7 Mon Sep 17 00:00:00 2001 +From: Emmanuele Bassi <ebassi@gnome.org> +Date: Fri, 10 Oct 2025 17:06:22 +0100 +Subject: [PATCH] Make sure to escape query strings + +Unescaped query strings should not be passed to the HTML parser, to +avoid unwanted execution of JavaScript. + +The query is shown in the header of the search results, so we can easily +split the header from the results; then we use a plain text node to +represent the query, and let the browser escape it. + +See: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html + +Fixes: #228 + +CVE: CVE-2025-11687 +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/gi-docgen/-/commit/c53d2640bfa5823bbdf33683d95c160267c0ec68] + +Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com> +--- + gidocgen/templates/basic/search.js | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/gidocgen/templates/basic/search.js b/gidocgen/templates/basic/search.js +index 29c204f..628f0a6 100644 +--- a/gidocgen/templates/basic/search.js ++++ b/gidocgen/templates/basic/search.js +@@ -182,17 +182,24 @@ function hideSearchResults() { + } + } + +-function renderResults(query, results) { +- let html = ""; ++function createResultsTitle(query, n_results) { ++ // Ensure we're returning an escaped query string, to ensure we ++ // prevent XSS vulnerabilities ++ let h1 = document.createElement("h1"); ++ let text = document.createTextNode("Results for “" + query + "” (" + n_results + ")"); ++ h1.appendChild(text) ++ return h1; ++} + +- html += "<h1>Results for "" + query + "" (" + results.length + ")</h1>" + +- "<div id=\"search-results\">" ++function createResultsContent(results) { ++ let search_results = document.createElement("div"); ++ search_results.setAttribute("id", "search-results"); + + if (results.length === 0) { +- html += "No results found."; ++ search_results.textContent = "No results found."; + } + else { +- html += "<div class=\"results\"><dl>"; ++ let html = "<div class=\"results\"><dl>"; + results.forEach(function(item) { + html += "<dt class=\"result " + TYPE_CLASSES[item.type] + "\">" + + "<a href=\"" + item.href + "\">" + item.text + "</a>" + +@@ -204,11 +211,11 @@ function renderResults(query, results) { + "<dd>" + item.summary + "</dd>"; + }); + html += "</dl></div>"; +- } + +- html += "</div>"; ++ search_results.innerHTML = html; ++ } + +- return html; ++ return search_results; + } + + function showResults(query, results) { +@@ -218,9 +225,10 @@ function showResults(query, results) { + window.history.replaceState(refs.input.value, "", baseUrl + extra + window.location.hash); + } + +- window.title = "Results for: " + query; ++ window.title = "Results for “" + query + "” (" + results.length + ")"; + window.scroll({ top: 0 }) +- refs.search.innerHTML = renderResults(query, results); ++ refs.search.appendChild(createResultsTitle(query, results.length)); ++ refs.search.appendChild(createResultsContent(results)); + showSearchResults(search); + } + +-- +2.50.0 + diff --git a/meta/recipes-gnome/gi-docgen/gi-docgen_2023.3.bb b/meta/recipes-gnome/gi-docgen/gi-docgen_2023.3.bb index 54d7ef7513..53641bcbe3 100644 --- a/meta/recipes-gnome/gi-docgen/gi-docgen_2023.3.bb +++ b/meta/recipes-gnome/gi-docgen/gi-docgen_2023.3.bb @@ -8,7 +8,10 @@ HOMEPAGE = "https://gnome.pages.gitlab.gnome.org/gi-docgen/" LICENSE = "GPL-3.0-or-later & Apache-2.0" LIC_FILES_CHKSUM = "file://gi-docgen.py;beginline=1;endline=5;md5=2dc0f1f01202478cfe813c0e7f80b326" -SRC_URI = "git://gitlab.gnome.org/GNOME/gi-docgen.git;protocol=https;branch=main" +SRC_URI = "\ + git://gitlab.gnome.org/GNOME/gi-docgen.git;protocol=https;branch=main \ + file://CVE-2025-11687.patch \ + " SRCREV = "96f2e9b93e1d8a5338eb05b87fd879856ab7b3cc" -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 01/12] gi-docgen: fix CVE-2025-11687 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-23 17:09 ` [OE-core] " Yoann Congal 2026-04-09 6:16 ` [scarthgap][PATCH 03/12] libsoup-2.4: " jinfeng.wang.cn ` (9 subsequent siblings) 11 siblings, 1 reply; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Changqing Li <changqing.li@windriver.com> Refer: https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 https://gitlab.gnome.org/GNOME/libsoup/-/issues/390 Signed-off-by: Changqing Li <changqing.li@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../libsoup-3.4.4/CVE-2025-14523.patch | 715 ++++++++++++++++++ .../libsoup-3.4.4/CVE-2025-32049-1.patch | 229 ++++++ .../libsoup-3.4.4/CVE-2025-32049-2.patch | 34 + .../libsoup-3.4.4/CVE-2025-32049-3.patch | 134 ++++ .../libsoup-3.4.4/CVE-2025-32049-4.patch | 292 +++++++ meta/recipes-support/libsoup/libsoup_3.4.4.bb | 5 + 6 files changed, 1409 insertions(+) create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch new file mode 100644 index 0000000000..b90f8bd29d --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch @@ -0,0 +1,715 @@ +From 70123da95418f5d6e00e8ac2d586fb6c5d02cdc6 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro <mcatanzaro@redhat.com> +Date: Wed, 7 Jan 2026 14:50:33 -0600 +Subject: [PATCH] Reject duplicate Host headers + +RFC 9112 section 3.2 says: + +A server MUST respond with a 400 (Bad Request) status code to any +HTTP/1.1 request message that lacks a Host header field and to any +request message that contains more than one Host header field line or a +Host header field with an invalid field value. + +In addition to rejecting a duplicate header when parsing headers, also +reject attempts to add the duplicate header using the +soup_message_headers_append() API, and add tests for both cases. + +These checks will also apply to HTTP/2. I'm not sure whether this is +actually desired or not, but the header processing code is not aware of +which HTTP version is in use. + +(Note that while SoupMessageHeaders does not require the Host header to +be present in an HTTP/1.1 request, SoupServer itself does. So we can't +test the case of missing Host header via the header parsing test, but it +really is enforced.) + +Fixes #472 + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/d3db5a6f8f03e1f0133754872877c92c0284c472] +CVE: CVE-2025-14523 + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + libsoup/soup-headers.c | 3 +- + libsoup/soup-message-headers-private.h | 4 +- + libsoup/soup-message-headers.c | 80 +++++++------ + tests/header-parsing-test.c | 148 +++++++++++++++++-------- + 4 files changed, 153 insertions(+), 82 deletions(-) + +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c +index 155c11d..3fec9b3 100644 +--- a/libsoup/soup-headers.c ++++ b/libsoup/soup-headers.c +@@ -139,7 +139,8 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) + for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) + *p = ' '; + +- soup_message_headers_append_untrusted_data (dest, name, value); ++ if (!soup_message_headers_append_untrusted_data (dest, name, value)) ++ goto done; + } + success = TRUE; + +diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h +index 9815464..770f3ef 100644 +--- a/libsoup/soup-message-headers-private.h ++++ b/libsoup/soup-message-headers-private.h +@@ -10,10 +10,10 @@ + + G_BEGIN_DECLS + +-void soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, ++gboolean soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, + const char *name, + const char *value); +-void soup_message_headers_append_common (SoupMessageHeaders *hdrs, ++gboolean soup_message_headers_append_common (SoupMessageHeaders *hdrs, + SoupHeaderName name, + const char *value); + const char *soup_message_headers_get_one_common (SoupMessageHeaders *hdrs, +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c +index d69d6e8..ce4b3b3 100644 +--- a/libsoup/soup-message-headers.c ++++ b/libsoup/soup-message-headers.c +@@ -267,12 +267,16 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) + soup_header_free_list (tokens); + } + +-void ++gboolean + soup_message_headers_append_common (SoupMessageHeaders *hdrs, + SoupHeaderName name, + const char *value) + { + SoupCommonHeader header; ++ if (name == SOUP_HEADER_HOST && soup_message_headers_get_one (hdrs, "Host")) { ++ g_warning ("soup_message_headers_append_common: Rejecting duplicate Host header"); ++ return FALSE; ++ } + + if (!hdrs->common_headers) + hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6); +@@ -284,32 +288,18 @@ soup_message_headers_append_common (SoupMessageHeaders *hdrs, + g_hash_table_remove (hdrs->common_concat, GUINT_TO_POINTER (header.name)); + + soup_message_headers_set (hdrs, name, value); ++ return TRUE; + } + +-/** +- * soup_message_headers_append: +- * @hdrs: a #SoupMessageHeaders +- * @name: the header name to add +- * @value: the new value of @name +- * +- * Appends a new header with name @name and value @value to @hdrs. +- * +- * (If there is an existing header with name @name, then this creates a second +- * one, which is only allowed for list-valued headers; see also +- * [method@MessageHeaders.replace].) +- * +- * The caller is expected to make sure that @name and @value are +- * syntactically correct. +- **/ +-void +-soup_message_headers_append (SoupMessageHeaders *hdrs, +- const char *name, const char *value) ++static gboolean ++soup_message_headers_append_internal (SoupMessageHeaders *hdrs, ++ const char *name, const char *value) + { + SoupUncommonHeader header; + SoupHeaderName header_name; + +- g_return_if_fail (name != NULL); +- g_return_if_fail (value != NULL); ++ g_return_val_if_fail (name != NULL, FALSE); ++ g_return_val_if_fail (value != NULL, FALSE); + + /* Setting a syntactically invalid header name or value is + * considered to be a programming error. However, it can also +@@ -317,23 +307,22 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, + * compiled with G_DISABLE_CHECKS. + */ + #ifndef G_DISABLE_CHECKS +- g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL); +- g_return_if_fail (strpbrk (value, "\r\n") == NULL); ++ g_return_val_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL, FALSE); ++ g_return_val_if_fail (strpbrk (value, "\r\n") == NULL, FALSE); + #else + if (*name && strpbrk (name, " \t\r\n:")) { +- g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name); +- return; ++ g_warning ("soup_message_headers_append: Rejecting bad name '%s'", name); ++ return FALSE; + } + if (strpbrk (value, "\r\n")) { +- g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value); +- return; ++ g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value); ++ return FALSE; + } + #endif + + header_name = soup_header_name_from_string (name); + if (header_name != SOUP_HEADER_UNKNOWN) { +- soup_message_headers_append_common (hdrs, header_name, value); +- return; ++ return soup_message_headers_append_common (hdrs, header_name, value); + } + + if (!hdrs->uncommon_headers) +@@ -344,21 +333,48 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, + g_array_append_val (hdrs->uncommon_headers, header); + if (hdrs->uncommon_concat) + g_hash_table_remove (hdrs->uncommon_concat, header.name); ++ return TRUE; ++} ++ ++/** ++ * soup_message_headers_append: ++ * @hdrs: a #SoupMessageHeaders ++ * @name: the header name to add ++ * @value: the new value of @name ++ * ++ * Appends a new header with name @name and value @value to @hdrs. ++ * ++ * (If there is an existing header with name @name, then this creates a second ++ * one, which is only allowed for list-valued headers; see also ++ * [method@MessageHeaders.replace].) ++ * ++ * The caller is expected to make sure that @name and @value are ++ * syntactically correct. ++ **/ ++void ++soup_message_headers_append (SoupMessageHeaders *hdrs, ++ const char *name, const char *value) ++{ ++ soup_message_headers_append_internal (hdrs, name, value); + } + + /* +- * Appends a header value ensuring that it is valid UTF8. ++ * Appends a header value ensuring that it is valid UTF-8, and also checking the ++ * return value of soup_message_headers_append_internal() to report whether the ++ * headers are invalid for various other reasons. + */ +-void ++gboolean + soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, + const char *name, + const char *value) + { + char *safe_value = g_utf8_make_valid (value, -1); + char *safe_name = g_utf8_make_valid (name, -1); +- soup_message_headers_append (hdrs, safe_name, safe_value); ++ gboolean result = soup_message_headers_append_internal (hdrs, safe_name, safe_value); ++ + g_free (safe_value); + g_free (safe_name); ++ return result; + } + + void +diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c +index 9490559..98a22a4 100644 +--- a/tests/header-parsing-test.c ++++ b/tests/header-parsing-test.c +@@ -24,6 +24,7 @@ static struct RequestTest { + const char *method, *path; + SoupHTTPVersion version; + Header headers[10]; ++ GLogLevelFlags log_flags; + } reqtests[] = { + /**********************/ + /*** VALID REQUESTS ***/ +@@ -33,7 +34,7 @@ static struct RequestTest { + "GET / HTTP/1.0\r\n", -1, + SOUP_STATUS_OK, + "GET", "/", SOUP_HTTP_1_0, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "Req w/ 1 header", NULL, +@@ -42,7 +43,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header, no leading whitespace", NULL, +@@ -51,7 +52,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header including trailing whitespace", NULL, +@@ -60,7 +61,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header, wrapped", NULL, +@@ -69,7 +70,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Foo", "bar baz" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header, wrapped with additional whitespace", NULL, +@@ -78,7 +79,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Foo", "bar baz" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header, wrapped with tab", NULL, +@@ -87,7 +88,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Foo", "bar baz" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header, wrapped before value", NULL, +@@ -96,7 +97,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Foo", "bar baz" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 1 header with empty value", NULL, +@@ -105,7 +106,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 2 headers", NULL, +@@ -115,7 +116,7 @@ static struct RequestTest { + { { "Host", "example.com" }, + { "Connection", "close" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 3 headers", NULL, +@@ -126,7 +127,7 @@ static struct RequestTest { + { "Connection", "close" }, + { "Blah", "blah" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 3 headers, 1st wrapped", NULL, +@@ -137,7 +138,7 @@ static struct RequestTest { + { "Foo", "bar baz" }, + { "Blah", "blah" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 3 headers, 2nd wrapped", NULL, +@@ -148,7 +149,7 @@ static struct RequestTest { + { "Blah", "blah" }, + { "Foo", "bar baz" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ 3 headers, 3rd wrapped", NULL, +@@ -159,7 +160,7 @@ static struct RequestTest { + { "Blah", "blah" }, + { "Foo", "bar baz" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ same header multiple times", NULL, +@@ -168,7 +169,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Foo", "bar, baz, quux" }, + { NULL } +- } ++ }, 0 + }, + + { "Connection header on HTTP/1.0 message", NULL, +@@ -178,21 +179,21 @@ static struct RequestTest { + { { "Connection", "Bar, Quux" }, + { "Foo", "bar" }, + { NULL } +- } ++ }, 0 + }, + + { "GET with full URI", "667637", + "GET http://example.com HTTP/1.1\r\n", -1, + SOUP_STATUS_OK, + "GET", "http://example.com", SOUP_HTTP_1_1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "GET with full URI in upper-case", "667637", + "GET HTTP://example.com HTTP/1.1\r\n", -1, + SOUP_STATUS_OK, + "GET", "HTTP://example.com", SOUP_HTTP_1_1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + /* It's better for this to be passed through: this means a SoupServer +@@ -202,7 +203,7 @@ static struct RequestTest { + "GET AbOuT: HTTP/1.1\r\n", -1, + SOUP_STATUS_OK, + "GET", "AbOuT:", SOUP_HTTP_1_1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + /****************************/ +@@ -217,7 +218,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + /* RFC 2616 section 3.1 says we MUST accept this */ +@@ -228,7 +229,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + /* RFC 2616 section 19.3 says we SHOULD accept these */ +@@ -240,7 +241,7 @@ static struct RequestTest { + { { "Host", "example.com" }, + { "Connection", "close" }, + { NULL } +- } ++ }, 0 + }, + + { "LF instead of CRLF after Request-Line", NULL, +@@ -249,7 +250,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + { "Mixed CRLF/LF", "666316", +@@ -261,7 +262,7 @@ static struct RequestTest { + { "e", "f" }, + { "g", "h" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ incorrect whitespace in Request-Line", NULL, +@@ -270,7 +271,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + { "Req w/ incorrect whitespace after Request-Line", "475169", +@@ -279,7 +280,7 @@ static struct RequestTest { + "GET", "/", SOUP_HTTP_1_1, + { { "Host", "example.com" }, + { NULL } +- } ++ }, 0 + }, + + /* If the request/status line is parseable, then we +@@ -293,7 +294,7 @@ static struct RequestTest { + { { "Host", "example.com" }, + { "Bar", "two" }, + { NULL } +- } ++ }, 0 + }, + + { "First header line is continuation", "666316", +@@ -303,7 +304,7 @@ static struct RequestTest { + { { "Host", "example.com" }, + { "c", "d" }, + { NULL } +- } ++ }, 0 + }, + + { "Zero-length header name", "666316", +@@ -313,7 +314,7 @@ static struct RequestTest { + { { "a", "b" }, + { "c", "d" }, + { NULL } +- } ++ }, 0 + }, + + { "CR in header name", "666316", +@@ -323,7 +324,7 @@ static struct RequestTest { + { { "a", "b" }, + { "c", "d" }, + { NULL } +- } ++ }, 0 + }, + + { "CR in header value", "666316", +@@ -336,7 +337,7 @@ static struct RequestTest { + { "s", "t" }, /* CR at end is ignored */ + { "c", "d" }, + { NULL } +- } ++ }, 0 + }, + + { "Tab in header name", "666316", +@@ -351,7 +352,7 @@ static struct RequestTest { + { "p", "q z: w" }, + { "c", "d" }, + { NULL } +- } ++ }, 0 + }, + + { "Tab in header value", "666316", +@@ -364,7 +365,7 @@ static struct RequestTest { + { "z", "w" }, /* trailing tab ignored */ + { "c", "d" }, + { NULL } +- } ++ }, 0 + }, + + /************************/ +@@ -375,77 +376,77 @@ static struct RequestTest { + "GET /\r\n", -1, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "HTTP 1.2 request (no such thing)", NULL, + "GET / HTTP/1.2\r\n", -1, + SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "HTTP 2000 request (no such thing)", NULL, + "GET / HTTP/2000.0\r\n", -1, + SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "Long HTTP version terminating at missing minor version", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/404", + unterminated_http_version, sizeof (unterminated_http_version), + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "Non-HTTP request", NULL, + "GET / SOUP/1.1\r\nHost: example.com\r\n", -1, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "Junk after Request-Line", NULL, + "GET / HTTP/1.1 blah\r\nHost: example.com\r\n", -1, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "NUL in Method", NULL, + "G\x00T / HTTP/1.1\r\nHost: example.com\r\n", 37, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "NUL at beginning of Method", "666316", + "\x00 / HTTP/1.1\r\nHost: example.com\r\n", 35, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "NUL in Path", NULL, + "GET /\x00 HTTP/1.1\r\nHost: example.com\r\n", 38, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "No terminating CRLF", NULL, + "GET / HTTP/1.1\r\nHost: example.com", -1, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "Unrecognized expectation", NULL, + "GET / HTTP/1.1\r\nHost: example.com\r\nExpect: the-impossible\r\n", -1, + SOUP_STATUS_EXPECTATION_FAILED, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + // https://gitlab.gnome.org/GNOME/libsoup/-/issues/377 +@@ -453,21 +454,40 @@ static struct RequestTest { + "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "NUL in header value", NULL, + "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28, + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 + }, + + { "Only newlines", NULL, + only_newlines, sizeof (only_newlines), + SOUP_STATUS_BAD_REQUEST, + NULL, NULL, -1, +- { { NULL } } ++ { { NULL } }, 0 ++ }, ++ { "Duplicate Host headers", ++ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", ++ "GET / HTTP/1.1\r\nHost: example.com\r\nHost: example.org\r\n", ++ -1, ++ SOUP_STATUS_BAD_REQUEST, ++ NULL, NULL, -1, ++ { { NULL } }, ++ G_LOG_LEVEL_WARNING ++ }, ++ ++ { "Duplicate Host headers, case insensitive", ++ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", ++ "GET / HTTP/1.1\r\nHost: example.com\r\nhost: example.org\r\n", ++ -1, ++ SOUP_STATUS_BAD_REQUEST, ++ NULL, NULL, -1, ++ { { NULL } }, ++ G_LOG_LEVEL_WARNING + } + }; + static const int num_reqtests = G_N_ELEMENTS (reqtests); +@@ -915,10 +935,17 @@ do_request_tests (void) + len = strlen (reqtests[i].request); + else + len = reqtests[i].length; ++ ++ if (reqtests[i].log_flags) ++ g_test_expect_message ("libsoup", reqtests[i].log_flags, "*"); ++ + status = soup_headers_parse_request (reqtests[i].request, len, + headers, &method, &path, + &version); + g_assert_cmpint (status, ==, reqtests[i].status); ++ if (reqtests[i].log_flags) ++ g_test_assert_expected_messages (); ++ + if (SOUP_STATUS_IS_SUCCESSFUL (status)) { + g_assert_cmpstr (method, ==, reqtests[i].method); + g_assert_cmpstr (path, ==, reqtests[i].path); +@@ -1312,6 +1339,32 @@ do_bad_header_tests (void) + soup_message_headers_unref (hdrs); + } + ++static void ++do_append_duplicate_host_test (void) ++{ ++ SoupMessageHeaders *hdrs; ++ const char *list_value; ++ ++ hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); ++ soup_message_headers_append (hdrs, "Host", "a"); ++ ++ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, ++ "soup_message_headers_append_common: Rejecting duplicate Host header"); ++ soup_message_headers_append (hdrs, "Host", "b"); ++ g_test_assert_expected_messages (); ++ ++ /* Case insensitive */ ++ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, ++ "soup_message_headers_append_common: Rejecting duplicate Host header"); ++ soup_message_headers_append (hdrs, "host", "b"); ++ g_test_assert_expected_messages (); ++ ++ list_value = soup_message_headers_get_list (hdrs, "Host"); ++ g_assert_cmpstr (list_value, ==, "a"); ++ ++ soup_message_headers_unref (hdrs); ++} ++ + int + main (int argc, char **argv) + { +@@ -1327,6 +1380,7 @@ main (int argc, char **argv) + g_test_add_func ("/header-parsing/content-type", do_content_type_tests); + g_test_add_func ("/header-parsing/append-param", do_append_param_tests); + g_test_add_func ("/header-parsing/bad", do_bad_header_tests); ++ g_test_add_func ("/header-parsing/append-duplicate-host", do_append_duplicate_host_test); + + ret = g_test_run (); + +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch new file mode 100644 index 0000000000..0772c759dc --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch @@ -0,0 +1,229 @@ +From 176cb31003252a69d3fc7908e8f505c0ee006b7a Mon Sep 17 00:00:00 2001 +From: Ignacio Casal Quinteiro <qignacio@amazon.com> +Date: Wed, 24 Jul 2024 15:20:35 +0200 +Subject: [PATCH 1/4] websocket: add a way to restrict the total message size + +Otherwise a client could send small packages smaller than +total-incoming-payload-size but still to break the server +with a big allocation + +Fixes: #390 + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/db87805ab565d67533dfed2cb409dbfd63c7fdce] +CVE: CVE-2025-32049 + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + libsoup/websocket/soup-websocket-connection.c | 107 +++++++++++++++++- + libsoup/websocket/soup-websocket-connection.h | 7 ++ + 2 files changed, 110 insertions(+), 4 deletions(-) + +diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c +index 5eb8150..19bdd39 100644 +--- a/libsoup/websocket/soup-websocket-connection.c ++++ b/libsoup/websocket/soup-websocket-connection.c +@@ -84,7 +84,7 @@ enum { + PROP_MAX_INCOMING_PAYLOAD_SIZE, + PROP_KEEPALIVE_INTERVAL, + PROP_EXTENSIONS, +- ++ PROP_MAX_TOTAL_MESSAGE_SIZE, + LAST_PROPERTY + }; + +@@ -126,6 +126,7 @@ typedef struct { + char *origin; + char *protocol; + guint64 max_incoming_payload_size; ++ guint64 max_total_message_size; + guint keepalive_interval; + + gushort peer_close_code; +@@ -156,6 +157,7 @@ typedef struct { + } SoupWebsocketConnectionPrivate; + + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 + #define READ_BUFFER_SIZE 1024 + #define MASK_LENGTH 4 + +@@ -670,8 +672,8 @@ bad_data_error_and_close (SoupWebsocketConnection *self) + } + + static void +-too_big_error_and_close (SoupWebsocketConnection *self, +- guint64 payload_len) ++too_big_incoming_payload_error_and_close (SoupWebsocketConnection *self, ++ guint64 payload_len) + { + SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); + GError *error; +@@ -687,6 +689,24 @@ too_big_error_and_close (SoupWebsocketConnection *self, + emit_error_and_close (self, error, TRUE); + } + ++static void ++too_big_message_error_and_close (SoupWebsocketConnection *self, ++ guint64 len) ++{ ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); ++ GError *error; ++ ++ error = g_error_new_literal (SOUP_WEBSOCKET_ERROR, ++ SOUP_WEBSOCKET_CLOSE_TOO_BIG, ++ priv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? ++ "Received WebSocket payload from the client larger than configured max-total-message-size" : ++ "Received WebSocket payload from the server larger than configured max-total-message-size"); ++ g_debug ("%s received message of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT, ++ priv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client", ++ len, priv->max_total_message_size); ++ emit_error_and_close (self, error, TRUE); ++} ++ + static void + close_connection (SoupWebsocketConnection *self, + gushort code, +@@ -918,6 +938,12 @@ process_contents (SoupWebsocketConnection *self, + switch (priv->message_opcode) { + case 0x01: + case 0x02: ++ /* Safety valve */ ++ if (priv->max_total_message_size > 0 && ++ (priv->message_data->len + payload_len) > priv->max_total_message_size) { ++ too_big_message_error_and_close (self, (priv->message_data->len + payload_len)); ++ return; ++ } + g_byte_array_append (priv->message_data, payload, payload_len); + break; + default: +@@ -1056,7 +1082,7 @@ process_frame (SoupWebsocketConnection *self) + /* Safety valve */ + if (priv->max_incoming_payload_size > 0 && + payload_len > priv->max_incoming_payload_size) { +- too_big_error_and_close (self, payload_len); ++ too_big_incoming_payload_error_and_close (self, payload_len); + return FALSE; + } + +@@ -1363,6 +1389,10 @@ soup_websocket_connection_get_property (GObject *object, + g_value_set_pointer (value, priv->extensions); + break; + ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: ++ g_value_set_uint64 (value, priv->max_total_message_size); ++ break; ++ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -1416,6 +1446,10 @@ soup_websocket_connection_set_property (GObject *object, + priv->extensions = g_value_get_pointer (value); + break; + ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: ++ priv->max_total_message_size = g_value_get_uint64 (value); ++ break; ++ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -1628,6 +1662,26 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + ++ /** ++ * SoupWebsocketConnection:max-total-message-size: ++ * ++ * The total message size for incoming packets. ++ * ++ * The protocol expects or 0 to not limit it. ++ * ++ * Since: 3.8 ++ */ ++ properties[PROP_MAX_TOTAL_MESSAGE_SIZE] = ++ g_param_spec_uint64 ("max-total-message-size", ++ "Max total message size", ++ "Max total message size ", ++ 0, ++ G_MAXUINT64, ++ MAX_TOTAL_MESSAGE_SIZE_DEFAULT, ++ G_PARAM_READWRITE | ++ G_PARAM_CONSTRUCT | ++ G_PARAM_STATIC_STRINGS); ++ + g_object_class_install_properties (gobject_class, LAST_PROPERTY, properties); + + /** +@@ -2111,6 +2165,51 @@ soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection + } + } + ++/** ++ * soup_websocket_connection_get_max_total_message_size: ++ * @self: the WebSocket ++ * ++ * Gets the maximum total message size allowed for packets. ++ * ++ * Returns: the maximum total message size. ++ * ++ * Since: 3.8 ++ */ ++guint64 ++soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self) ++{ ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); ++ ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); ++ ++ return priv->max_total_message_size; ++} ++ ++/** ++ * soup_websocket_connection_set_max_total_message_size: ++ * @self: the WebSocket ++ * @max_total_message_size: the maximum total message size ++ * ++ * Sets the maximum total message size allowed for packets. ++ * ++ * It does not limit the outgoing packet size. ++ * ++ * Since: 3.8 ++ */ ++void ++soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, ++ guint64 max_total_message_size) ++{ ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); ++ ++ g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self)); ++ ++ if (priv->max_total_message_size != max_total_message_size) { ++ priv->max_total_message_size = max_total_message_size; ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_TOTAL_MESSAGE_SIZE]); ++ } ++} ++ + /** + * soup_websocket_connection_get_keepalive_interval: + * @self: the WebSocket +diff --git a/libsoup/websocket/soup-websocket-connection.h b/libsoup/websocket/soup-websocket-connection.h +index eeb093d..922de56 100644 +--- a/libsoup/websocket/soup-websocket-connection.h ++++ b/libsoup/websocket/soup-websocket-connection.h +@@ -88,6 +88,13 @@ SOUP_AVAILABLE_IN_ALL + void soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection *self, + guint64 max_incoming_payload_size); + ++SOUP_AVAILABLE_IN_3_0 ++guint64 soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self); ++ ++SOUP_AVAILABLE_IN_3_0 ++void soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, ++ guint64 max_total_message_size); ++ + SOUP_AVAILABLE_IN_ALL + guint soup_websocket_connection_get_keepalive_interval (SoupWebsocketConnection *self); + +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch new file mode 100644 index 0000000000..6f00fabfdb --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch @@ -0,0 +1,34 @@ +From 81eb7cf7422878f0b78b833a3b741f734502921f Mon Sep 17 00:00:00 2001 +From: Ignacio Casal Quinteiro <qignacio@amazon.com> +Date: Fri, 20 Sep 2024 12:12:38 +0200 +Subject: [PATCH 2/4] websocket-test: set the total message size + +This is required when sending a big amount of data + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/4904a46a2d9a014efa6be01a186ac353dbf5047b] +CVE: CVE-2025-32049 + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + tests/websocket-test.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/websocket-test.c b/tests/websocket-test.c +index a0b8334..827b041 100644 +--- a/tests/websocket-test.c ++++ b/tests/websocket-test.c +@@ -567,6 +567,11 @@ test_send_big_packets (Test *test, + soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1); + g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1)); + ++ soup_websocket_connection_set_max_total_message_size (test->client, 1000 * 1000 + 1); ++ g_assert (soup_websocket_connection_get_max_total_message_size (test->client) == (1000 * 1000 + 1)); ++ soup_websocket_connection_set_max_total_message_size (test->server, 1000 * 1000 + 1); ++ g_assert (soup_websocket_connection_get_max_total_message_size (test->server) == (1000 * 1000 + 1)); ++ + sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); + WAIT_UNTIL (received != NULL); +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch new file mode 100644 index 0000000000..29fb0d7ddb --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch @@ -0,0 +1,134 @@ +From 25616e1a958bc1503cc24d6845a6e80ffc287727 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro <mcatanzaro@redhat.com> +Date: Thu, 8 May 2025 16:16:25 -0500 +Subject: [PATCH] Set message size limit in SoupServer rather than + SoupWebsocketConnection + +We're not sure about the compatibility implications of having a default +size limit for clients. + +Also not sure whether the server limit is actually set appropriately, +but there is probably very little server usage of +SoupWebsocketConnection in the wild, so it's not so likely to break +things. + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/2df34d9544cabdbfdedd3b36f098cf69233b1df7] +CVE: CVE-2025-32049 + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + libsoup/server/soup-server.c | 24 +++++++++++++---- + libsoup/websocket/soup-websocket-connection.c | 26 +++++++++++++------ + 2 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c +index 6b486f5..c779f7d 100644 +--- a/libsoup/server/soup-server.c ++++ b/libsoup/server/soup-server.c +@@ -186,6 +186,16 @@ static GParamSpec *properties[LAST_PROPERTY] = { NULL, }; + + G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) + ++/* SoupWebsocketConnection by default limits only maximum packet size. But a ++ * message may consist of multiple packets, so SoupServer additionally restricts ++ * total message size to mitigate denial of service attacks on the server. ++ * SoupWebsocketConnection does not do this by default because I don't know ++ * whether that would or would not cause compatibility problems for websites. ++ * ++ * This size is in bytes and it is arbitrary. ++ */ ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 ++ + static void request_finished (SoupServerMessage *msg, + SoupMessageIOCompletion completion, + SoupServer *server); +@@ -937,11 +947,15 @@ complete_websocket_upgrade (SoupServer *server, + + g_object_ref (msg); + stream = soup_server_message_steal_connection (msg); +- conn = soup_websocket_connection_new (stream, uri, +- SOUP_WEBSOCKET_CONNECTION_SERVER, +- soup_message_headers_get_one_common (soup_server_message_get_request_headers (msg), SOUP_HEADER_ORIGIN), +- soup_message_headers_get_one_common (soup_server_message_get_response_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL), +- handler->websocket_extensions); ++ conn = SOUP_WEBSOCKET_CONNECTION (g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION, ++ "io-stream", stream, ++ "uri", uri, ++ "connection-type", SOUP_WEBSOCKET_CONNECTION_SERVER, ++ "origin", soup_message_headers_get_one_common (soup_server_message_get_request_headers (msg), SOUP_HEADER_ORIGIN), ++ "protocol", soup_message_headers_get_one_common (soup_server_message_get_response_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL), ++ "extensions", handler->websocket_extensions, ++ "max-total-message-size", (guint64)MAX_TOTAL_MESSAGE_SIZE_DEFAULT, ++ NULL)); + handler->websocket_extensions = NULL; + g_object_unref (stream); + +diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c +index 26476df..cbb1b72 100644 +--- a/libsoup/websocket/soup-websocket-connection.c ++++ b/libsoup/websocket/soup-websocket-connection.c +@@ -149,7 +149,6 @@ typedef struct { + } SoupWebsocketConnectionPrivate; + + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 +-#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 + #define READ_BUFFER_SIZE 1024 + #define MASK_LENGTH 4 + +@@ -1612,9 +1611,10 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + /** + * SoupWebsocketConnection:max-incoming-payload-size: + * +- * The maximum payload size for incoming packets. +- * +- * The protocol expects or 0 to not limit it. ++ * The maximum payload size for incoming packets, or 0 to not limit it. ++ * ++ * Each message may consist of multiple packets, so also refer to ++ * [property@WebSocketConnection:max-total-message-size]. + */ + properties[PROP_MAX_INCOMING_PAYLOAD_SIZE] = + g_param_spec_uint64 ("max-incoming-payload-size", +@@ -1662,9 +1662,19 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + /** + * SoupWebsocketConnection:max-total-message-size: + * +- * The total message size for incoming packets. ++ * The maximum size for incoming messages. ++ * ++ * Set to a value to limit the total message size, or 0 to not ++ * limit it. ++ * ++ * [method@Server.add_websocket_handler] will set this to a nonzero ++ * default value to mitigate denial of service attacks. Clients must ++ * choose their own default if they need to mitigate denial of service ++ * attacks. You also need to set your own default if creating your own ++ * server SoupWebsocketConnection without using SoupServer. + * +- * The protocol expects or 0 to not limit it. ++ * Each message may consist of multiple packets, so also refer to ++ * [property@WebSocketConnection:max-incoming-payload-size]. + * + * Since: 3.8 + */ +@@ -1674,7 +1684,7 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + "Max total message size ", + 0, + G_MAXUINT64, +- MAX_TOTAL_MESSAGE_SIZE_DEFAULT, ++ 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); +@@ -2164,7 +2174,7 @@ soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *s + { + SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); + +- g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0); + + return priv->max_total_message_size; + } +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch new file mode 100644 index 0000000000..6f391e98e2 --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch @@ -0,0 +1,292 @@ +From 3c87790a4ba141125e6ba165c478f0440e8e693e Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro <mcatanzaro@redhat.com> +Date: Fri, 16 May 2025 16:55:40 -0500 +Subject: [PATCH 4/4] Add tests for max-incoming-packet-size and + max-total-message-size + +An even better test would verify that it's possible to send big messages +containing small packets, but libsoup doesn't offer control over packet +size, and I don't want to take the time to learn how WebSockets work to +figure out how to do that manually. Instead, I just check that both +limits work, for both client and server. + +I didn't add deflate variants of these tests because I doubt that would +add valuable coverage. + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/4d00b45b7eebdcfa0706b58e34c40b8a0a16015b] +CVE: CVE-2025-32049 + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + tests/websocket-test.c | 214 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 197 insertions(+), 17 deletions(-) + +diff --git a/tests/websocket-test.c b/tests/websocket-test.c +index 827b041..ec1324c 100644 +--- a/tests/websocket-test.c ++++ b/tests/websocket-test.c +@@ -543,16 +543,9 @@ test_send_big_packets (Test *test, + { + GBytes *sent = NULL; + GBytes *received = NULL; ++ gulong signal_id; + +- g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received); +- +- sent = g_bytes_new_take (g_strnfill (400, '!'), 400); +- soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); +- WAIT_UNTIL (received != NULL); +- g_assert (g_bytes_equal (sent, received)); +- g_bytes_unref (sent); +- g_bytes_unref (received); +- received = NULL; ++ signal_id = g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received); + + sent = g_bytes_new_take (g_strnfill (100 * 1000, '?'), 100 * 1000); + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); +@@ -563,23 +556,174 @@ test_send_big_packets (Test *test, + received = NULL; + + soup_websocket_connection_set_max_incoming_payload_size (test->client, 1000 * 1000 + 1); +- g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->client) == (1000 * 1000 + 1)); ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 1000 * 1000 + 1); + soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1); +- g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1)); ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 1000 * 1000 + 1); + + soup_websocket_connection_set_max_total_message_size (test->client, 1000 * 1000 + 1); +- g_assert (soup_websocket_connection_get_max_total_message_size (test->client) == (1000 * 1000 + 1)); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 1000 * 1000 + 1); + soup_websocket_connection_set_max_total_message_size (test->server, 1000 * 1000 + 1); +- g_assert (soup_websocket_connection_get_max_total_message_size (test->server) == (1000 * 1000 + 1)); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 1000 * 1000 + 1); + + sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); + WAIT_UNTIL (received != NULL); + g_assert (g_bytes_equal (sent, received)); ++ g_bytes_unref (received); ++ received = NULL; ++ ++ /* Reverse the test and send the big message to the server. */ ++ g_signal_handler_disconnect (test->client, signal_id); ++ g_signal_connect (test->server, "message", G_CALLBACK (on_text_message), &received); ++ ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); ++ WAIT_UNTIL (received != NULL); ++ g_assert_true (g_bytes_equal (sent, received)); + g_bytes_unref (sent); + g_bytes_unref (received); + } + ++static void ++test_send_big_packets_direct (Test *test, ++ gconstpointer data) ++{ ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); ++ ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 0); ++ ++ test_send_big_packets (test, data); ++} ++ ++static void ++test_send_big_packets_soup (Test *test, ++ gconstpointer data) ++{ ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); ++ ++ /* Max total message size defaults to 0 (unlimited), but SoupServer applies its own limit by default. */ ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024); ++ ++ test_send_big_packets (test, data); ++} ++ ++static void ++test_send_exceeding_client_max_payload_size (Test *test, ++ gconstpointer data) ++{ ++ GBytes *sent = NULL; ++ GBytes *received = NULL; ++ gboolean close_event = FALSE; ++ GError *error = NULL; ++ ++ g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); ++ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); ++ ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); ++ ++ soup_websocket_connection_set_max_incoming_payload_size (test->server, 0); ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 0); ++ ++ /* The message to the client is dropped due to the client's limit. */ ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); ++ soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); ++ g_bytes_unref (sent); ++ WAIT_UNTIL (close_event); ++ g_assert_null (received); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); ++ g_assert_no_error (test->client_error); ++} ++ ++static void ++test_send_exceeding_server_max_payload_size (Test *test, ++ gconstpointer data) ++{ ++ GBytes *sent = NULL; ++ GBytes *received = NULL; ++ gboolean close_event = FALSE; ++ GError *error = NULL; ++ ++ g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error); ++ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_set_flag), &close_event); ++ ++ soup_websocket_connection_set_max_incoming_payload_size (test->client, 0); ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 0); ++ ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); ++ ++ /* The message to the server is dropped due to the server's limit. */ ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); ++ g_bytes_unref (sent); ++ WAIT_UNTIL (close_event); ++ g_assert_null (received); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); ++ g_assert_no_error (test->client_error); ++} ++ ++static void ++test_send_exceeding_client_max_message_size (Test *test, ++ gconstpointer data) ++{ ++ GBytes *sent = NULL; ++ GBytes *received = NULL; ++ gboolean close_event = FALSE; ++ GError *error = NULL; ++ ++ g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); ++ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); ++ ++ soup_websocket_connection_set_max_total_message_size (test->client, 128 * 1024); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 128 * 1024); ++ ++ soup_websocket_connection_set_max_total_message_size (test->server, 0); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 0); ++ ++ /* The message to the client is dropped due to the client's limit. */ ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); ++ soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); ++ g_bytes_unref (sent); ++ WAIT_UNTIL (close_event); ++ g_assert_null (received); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); ++ g_assert_no_error (test->client_error); ++} ++ ++static void ++test_send_exceeding_server_max_message_size (Test *test, ++ gconstpointer data) ++{ ++ GBytes *sent = NULL; ++ GBytes *received = NULL; ++ gboolean close_event = FALSE; ++ GError *error = NULL; ++ ++ g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error); ++ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_set_flag), &close_event); ++ ++ soup_websocket_connection_set_max_total_message_size (test->client, 0); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); ++ ++ /* Set the server message total message size manually, because its ++ * default is different for direct connection vs. soup connection. ++ */ ++ soup_websocket_connection_set_max_total_message_size (test->server, 128 * 1024); ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024); ++ ++ /* The message to the server is dropped due to the server's limit. */ ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); ++ g_bytes_unref (sent); ++ WAIT_UNTIL (close_event); ++ g_assert_null (received); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); ++ g_assert_no_error (test->client_error); ++} ++ ++ + static void + test_send_empty_packets (Test *test, + gconstpointer data) +@@ -2064,11 +2208,47 @@ main (int argc, + + g_test_add ("/websocket/direct/send-big-packets", Test, NULL, + setup_direct_connection, +- test_send_big_packets, ++ test_send_big_packets_direct, + teardown_direct_connection); + g_test_add ("/websocket/soup/send-big-packets", Test, NULL, + setup_soup_connection, +- test_send_big_packets, ++ test_send_big_packets_soup, ++ teardown_soup_connection); ++ ++ g_test_add ("/websocket/direct/send-exceeding-client-max-payload-size", Test, NULL, ++ setup_direct_connection, ++ test_send_exceeding_client_max_payload_size, ++ teardown_direct_connection); ++ g_test_add ("/websocket/soup/send-exceeding-client-max-payload-size", Test, NULL, ++ setup_soup_connection, ++ test_send_exceeding_client_max_payload_size, ++ teardown_soup_connection); ++ ++ g_test_add ("/websocket/direct/send-exceeding-server-max-payload-size", Test, NULL, ++ setup_direct_connection, ++ test_send_exceeding_server_max_payload_size, ++ teardown_direct_connection); ++ g_test_add ("/websocket/soup/send-exceeding-server-max-payload-size", Test, NULL, ++ setup_soup_connection, ++ test_send_exceeding_server_max_payload_size, ++ teardown_soup_connection); ++ ++ g_test_add ("/websocket/direct/send-exceeding-client-max-message-size", Test, NULL, ++ setup_direct_connection, ++ test_send_exceeding_client_max_message_size, ++ teardown_direct_connection); ++ g_test_add ("/websocket/soup/send-exceeding-client-max-message-size", Test, NULL, ++ setup_soup_connection, ++ test_send_exceeding_client_max_message_size, ++ teardown_soup_connection); ++ ++ g_test_add ("/websocket/direct/send-exceeding-server-max-message-size", Test, NULL, ++ setup_direct_connection, ++ test_send_exceeding_server_max_message_size, ++ teardown_direct_connection); ++ g_test_add ("/websocket/soup/send-exceeding-server-max-message-size", Test, NULL, ++ setup_soup_connection, ++ test_send_exceeding_server_max_message_size, + teardown_soup_connection); + + g_test_add ("/websocket/direct/send-empty-packets", Test, NULL, +@@ -2217,11 +2397,11 @@ main (int argc, + + g_test_add ("/websocket/direct/deflate-send-big-packets", Test, NULL, + setup_direct_connection_with_extensions, +- test_send_big_packets, ++ test_send_big_packets_direct, + teardown_direct_connection); + g_test_add ("/websocket/soup/deflate-send-big-packets", Test, NULL, + setup_soup_connection_with_extensions, +- test_send_big_packets, ++ test_send_big_packets_soup, + teardown_soup_connection); + + g_test_add ("/websocket/direct/deflate-send-empty-packets", Test, NULL, +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup_3.4.4.bb b/meta/recipes-support/libsoup/libsoup_3.4.4.bb index c09b06fec2..fc4a286dcf 100644 --- a/meta/recipes-support/libsoup/libsoup_3.4.4.bb +++ b/meta/recipes-support/libsoup/libsoup_3.4.4.bb @@ -46,6 +46,11 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ file://CVE-2025-2784.patch \ file://CVE-2025-4945.patch \ file://CVE-2025-12105.patch \ + file://CVE-2025-14523.patch \ + file://CVE-2025-32049-1.patch \ + file://CVE-2025-32049-2.patch \ + file://CVE-2025-32049-3.patch \ + file://CVE-2025-32049-4.patch \ " SRC_URI[sha256sum] = "291c67725f36ed90ea43efff25064b69c5a2d1981488477c05c481a3b4b0c5aa" -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 2026-04-09 6:16 ` [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 jinfeng.wang.cn @ 2026-04-23 17:09 ` Yoann Congal 2026-04-24 7:16 ` Li, Changqing 0 siblings, 1 reply; 23+ messages in thread From: Yoann Congal @ 2026-04-23 17:09 UTC (permalink / raw) To: Jinfeng.Wang.CN, openembedded-core On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Changqing Li <changqing.li@windriver.com> > > Refer: > https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 > https://gitlab.gnome.org/GNOME/libsoup/-/issues/390 > > Signed-off-by: Changqing Li <changqing.li@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- > .../libsoup-3.4.4/CVE-2025-14523.patch | 715 ++++++++++++++++++ > .../libsoup-3.4.4/CVE-2025-32049-1.patch | 229 ++++++ > .../libsoup-3.4.4/CVE-2025-32049-2.patch | 34 + > .../libsoup-3.4.4/CVE-2025-32049-3.patch | 134 ++++ > .../libsoup-3.4.4/CVE-2025-32049-4.patch | 292 +++++++ > meta/recipes-support/libsoup/libsoup_3.4.4.bb | 5 + > 6 files changed, 1409 insertions(+) > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch > > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch > new file mode 100644 > index 0000000000..b90f8bd29d > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch > @@ -0,0 +1,715 @@ > +From 70123da95418f5d6e00e8ac2d586fb6c5d02cdc6 Mon Sep 17 00:00:00 2001 > +From: Michael Catanzaro <mcatanzaro@redhat.com> > +Date: Wed, 7 Jan 2026 14:50:33 -0600 > +Subject: [PATCH] Reject duplicate Host headers > + > +RFC 9112 section 3.2 says: > + > +A server MUST respond with a 400 (Bad Request) status code to any > +HTTP/1.1 request message that lacks a Host header field and to any > +request message that contains more than one Host header field line or a > +Host header field with an invalid field value. > + > +In addition to rejecting a duplicate header when parsing headers, also > +reject attempts to add the duplicate header using the > +soup_message_headers_append() API, and add tests for both cases. > + > +These checks will also apply to HTTP/2. I'm not sure whether this is > +actually desired or not, but the header processing code is not aware of > +which HTTP version is in use. > + > +(Note that while SoupMessageHeaders does not require the Host header to > +be present in an HTTP/1.1 request, SoupServer itself does. So we can't > +test the case of missing Host header via the header parsing test, but it > +really is enforced.) > + > +Fixes #472 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/d3db5a6f8f03e1f0133754872877c92c0284c472] Sorry but I don't see this commit mentionned in (CVE-2025-14523) (#YWH-PGM9867-116) Lack of Duplicate Header Rejection in libsoup can lead to host header parsing discrepancy between libsoup server and proxy (#472) · Issue · GNOME/libsoup https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 I admit this commit looks related but I very much like a detailled trail between a trusted source (eg. NVD, debian security tracker or upstream) and the commit. Also, that commit is only in the "mcatanzaro/rhel9" branch, that would need some justification. This may apply to the other CVE. Finally, I'd rather have 1 CVE fix per commit, would it be possible to split the commit? Thanks! > +CVE: CVE-2025-14523 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-headers.c | 3 +- > + libsoup/soup-message-headers-private.h | 4 +- > + libsoup/soup-message-headers.c | 80 +++++++------ > + tests/header-parsing-test.c | 148 +++++++++++++++++-------- > + 4 files changed, 153 insertions(+), 82 deletions(-) > + > +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c > +index 155c11d..3fec9b3 100644 > +--- a/libsoup/soup-headers.c > ++++ b/libsoup/soup-headers.c > +@@ -139,7 +139,8 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) > + for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) > + *p = ' '; > + > +- soup_message_headers_append_untrusted_data (dest, name, value); > ++ if (!soup_message_headers_append_untrusted_data (dest, name, value)) > ++ goto done; > + } > + success = TRUE; > + > +diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h > +index 9815464..770f3ef 100644 > +--- a/libsoup/soup-message-headers-private.h > ++++ b/libsoup/soup-message-headers-private.h > +@@ -10,10 +10,10 @@ > + > + G_BEGIN_DECLS > + > +-void soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, > ++gboolean soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, > + const char *name, > + const char *value); > +-void soup_message_headers_append_common (SoupMessageHeaders *hdrs, > ++gboolean soup_message_headers_append_common (SoupMessageHeaders *hdrs, > + SoupHeaderName name, > + const char *value); > + const char *soup_message_headers_get_one_common (SoupMessageHeaders *hdrs, > +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c > +index d69d6e8..ce4b3b3 100644 > +--- a/libsoup/soup-message-headers.c > ++++ b/libsoup/soup-message-headers.c > +@@ -267,12 +267,16 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) > + soup_header_free_list (tokens); > + } > + > +-void > ++gboolean > + soup_message_headers_append_common (SoupMessageHeaders *hdrs, > + SoupHeaderName name, > + const char *value) > + { > + SoupCommonHeader header; > ++ if (name == SOUP_HEADER_HOST && soup_message_headers_get_one (hdrs, "Host")) { > ++ g_warning ("soup_message_headers_append_common: Rejecting duplicate Host header"); > ++ return FALSE; > ++ } > + > + if (!hdrs->common_headers) > + hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6); > +@@ -284,32 +288,18 @@ soup_message_headers_append_common (SoupMessageHeaders *hdrs, > + g_hash_table_remove (hdrs->common_concat, GUINT_TO_POINTER (header.name)); > + > + soup_message_headers_set (hdrs, name, value); > ++ return TRUE; > + } > + > +-/** > +- * soup_message_headers_append: > +- * @hdrs: a #SoupMessageHeaders > +- * @name: the header name to add > +- * @value: the new value of @name > +- * > +- * Appends a new header with name @name and value @value to @hdrs. > +- * > +- * (If there is an existing header with name @name, then this creates a second > +- * one, which is only allowed for list-valued headers; see also > +- * [method@MessageHeaders.replace].) > +- * > +- * The caller is expected to make sure that @name and @value are > +- * syntactically correct. > +- **/ > +-void > +-soup_message_headers_append (SoupMessageHeaders *hdrs, > +- const char *name, const char *value) > ++static gboolean > ++soup_message_headers_append_internal (SoupMessageHeaders *hdrs, > ++ const char *name, const char *value) > + { > + SoupUncommonHeader header; > + SoupHeaderName header_name; > + > +- g_return_if_fail (name != NULL); > +- g_return_if_fail (value != NULL); > ++ g_return_val_if_fail (name != NULL, FALSE); > ++ g_return_val_if_fail (value != NULL, FALSE); > + > + /* Setting a syntactically invalid header name or value is > + * considered to be a programming error. However, it can also > +@@ -317,23 +307,22 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, > + * compiled with G_DISABLE_CHECKS. > + */ > + #ifndef G_DISABLE_CHECKS > +- g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL); > +- g_return_if_fail (strpbrk (value, "\r\n") == NULL); > ++ g_return_val_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL, FALSE); > ++ g_return_val_if_fail (strpbrk (value, "\r\n") == NULL, FALSE); > + #else > + if (*name && strpbrk (name, " \t\r\n:")) { > +- g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name); > +- return; > ++ g_warning ("soup_message_headers_append: Rejecting bad name '%s'", name); > ++ return FALSE; > + } > + if (strpbrk (value, "\r\n")) { > +- g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value); > +- return; > ++ g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value); > ++ return FALSE; > + } > + #endif > + > + header_name = soup_header_name_from_string (name); > + if (header_name != SOUP_HEADER_UNKNOWN) { > +- soup_message_headers_append_common (hdrs, header_name, value); > +- return; > ++ return soup_message_headers_append_common (hdrs, header_name, value); > + } > + > + if (!hdrs->uncommon_headers) > +@@ -344,21 +333,48 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, > + g_array_append_val (hdrs->uncommon_headers, header); > + if (hdrs->uncommon_concat) > + g_hash_table_remove (hdrs->uncommon_concat, header.name); > ++ return TRUE; > ++} > ++ > ++/** > ++ * soup_message_headers_append: > ++ * @hdrs: a #SoupMessageHeaders > ++ * @name: the header name to add > ++ * @value: the new value of @name > ++ * > ++ * Appends a new header with name @name and value @value to @hdrs. > ++ * > ++ * (If there is an existing header with name @name, then this creates a second > ++ * one, which is only allowed for list-valued headers; see also > ++ * [method@MessageHeaders.replace].) > ++ * > ++ * The caller is expected to make sure that @name and @value are > ++ * syntactically correct. > ++ **/ > ++void > ++soup_message_headers_append (SoupMessageHeaders *hdrs, > ++ const char *name, const char *value) > ++{ > ++ soup_message_headers_append_internal (hdrs, name, value); > + } > + > + /* > +- * Appends a header value ensuring that it is valid UTF8. > ++ * Appends a header value ensuring that it is valid UTF-8, and also checking the > ++ * return value of soup_message_headers_append_internal() to report whether the > ++ * headers are invalid for various other reasons. > + */ > +-void > ++gboolean > + soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, > + const char *name, > + const char *value) > + { > + char *safe_value = g_utf8_make_valid (value, -1); > + char *safe_name = g_utf8_make_valid (name, -1); > +- soup_message_headers_append (hdrs, safe_name, safe_value); > ++ gboolean result = soup_message_headers_append_internal (hdrs, safe_name, safe_value); > ++ > + g_free (safe_value); > + g_free (safe_name); > ++ return result; > + } > + > + void > +diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c > +index 9490559..98a22a4 100644 > +--- a/tests/header-parsing-test.c > ++++ b/tests/header-parsing-test.c > +@@ -24,6 +24,7 @@ static struct RequestTest { > + const char *method, *path; > + SoupHTTPVersion version; > + Header headers[10]; > ++ GLogLevelFlags log_flags; > + } reqtests[] = { > + /**********************/ > + /*** VALID REQUESTS ***/ > +@@ -33,7 +34,7 @@ static struct RequestTest { > + "GET / HTTP/1.0\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "/", SOUP_HTTP_1_0, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Req w/ 1 header", NULL, > +@@ -42,7 +43,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, no leading whitespace", NULL, > +@@ -51,7 +52,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header including trailing whitespace", NULL, > +@@ -60,7 +61,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped", NULL, > +@@ -69,7 +70,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped with additional whitespace", NULL, > +@@ -78,7 +79,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped with tab", NULL, > +@@ -87,7 +88,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped before value", NULL, > +@@ -96,7 +97,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header with empty value", NULL, > +@@ -105,7 +106,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 2 headers", NULL, > +@@ -115,7 +116,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "Connection", "close" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers", NULL, > +@@ -126,7 +127,7 @@ static struct RequestTest { > + { "Connection", "close" }, > + { "Blah", "blah" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers, 1st wrapped", NULL, > +@@ -137,7 +138,7 @@ static struct RequestTest { > + { "Foo", "bar baz" }, > + { "Blah", "blah" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers, 2nd wrapped", NULL, > +@@ -148,7 +149,7 @@ static struct RequestTest { > + { "Blah", "blah" }, > + { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers, 3rd wrapped", NULL, > +@@ -159,7 +160,7 @@ static struct RequestTest { > + { "Blah", "blah" }, > + { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ same header multiple times", NULL, > +@@ -168,7 +169,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar, baz, quux" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Connection header on HTTP/1.0 message", NULL, > +@@ -178,21 +179,21 @@ static struct RequestTest { > + { { "Connection", "Bar, Quux" }, > + { "Foo", "bar" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "GET with full URI", "667637", > + "GET http://example.com HTTP/1.1\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "http://example.com", SOUP_HTTP_1_1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "GET with full URI in upper-case", "667637", > + "GET HTTP://example.com HTTP/1.1\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "HTTP://example.com", SOUP_HTTP_1_1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + /* It's better for this to be passed through: this means a SoupServer > +@@ -202,7 +203,7 @@ static struct RequestTest { > + "GET AbOuT: HTTP/1.1\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "AbOuT:", SOUP_HTTP_1_1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + /****************************/ > +@@ -217,7 +218,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /* RFC 2616 section 3.1 says we MUST accept this */ > +@@ -228,7 +229,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /* RFC 2616 section 19.3 says we SHOULD accept these */ > +@@ -240,7 +241,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "Connection", "close" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "LF instead of CRLF after Request-Line", NULL, > +@@ -249,7 +250,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Mixed CRLF/LF", "666316", > +@@ -261,7 +262,7 @@ static struct RequestTest { > + { "e", "f" }, > + { "g", "h" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ incorrect whitespace in Request-Line", NULL, > +@@ -270,7 +271,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ incorrect whitespace after Request-Line", "475169", > +@@ -279,7 +280,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /* If the request/status line is parseable, then we > +@@ -293,7 +294,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "Bar", "two" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "First header line is continuation", "666316", > +@@ -303,7 +304,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Zero-length header name", "666316", > +@@ -313,7 +314,7 @@ static struct RequestTest { > + { { "a", "b" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "CR in header name", "666316", > +@@ -323,7 +324,7 @@ static struct RequestTest { > + { { "a", "b" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "CR in header value", "666316", > +@@ -336,7 +337,7 @@ static struct RequestTest { > + { "s", "t" }, /* CR at end is ignored */ > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Tab in header name", "666316", > +@@ -351,7 +352,7 @@ static struct RequestTest { > + { "p", "q z: w" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Tab in header value", "666316", > +@@ -364,7 +365,7 @@ static struct RequestTest { > + { "z", "w" }, /* trailing tab ignored */ > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /************************/ > +@@ -375,77 +376,77 @@ static struct RequestTest { > + "GET /\r\n", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "HTTP 1.2 request (no such thing)", NULL, > + "GET / HTTP/1.2\r\n", -1, > + SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "HTTP 2000 request (no such thing)", NULL, > + "GET / HTTP/2000.0\r\n", -1, > + SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Long HTTP version terminating at missing minor version", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/404", > + unterminated_http_version, sizeof (unterminated_http_version), > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Non-HTTP request", NULL, > + "GET / SOUP/1.1\r\nHost: example.com\r\n", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Junk after Request-Line", NULL, > + "GET / HTTP/1.1 blah\r\nHost: example.com\r\n", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL in Method", NULL, > + "G\x00T / HTTP/1.1\r\nHost: example.com\r\n", 37, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL at beginning of Method", "666316", > + "\x00 / HTTP/1.1\r\nHost: example.com\r\n", 35, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL in Path", NULL, > + "GET /\x00 HTTP/1.1\r\nHost: example.com\r\n", 38, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "No terminating CRLF", NULL, > + "GET / HTTP/1.1\r\nHost: example.com", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Unrecognized expectation", NULL, > + "GET / HTTP/1.1\r\nHost: example.com\r\nExpect: the-impossible\r\n", -1, > + SOUP_STATUS_EXPECTATION_FAILED, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + // https://gitlab.gnome.org/GNOME/libsoup/-/issues/377 > +@@ -453,21 +454,40 @@ static struct RequestTest { > + "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL in header value", NULL, > + "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Only newlines", NULL, > + only_newlines, sizeof (only_newlines), > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > ++ }, > ++ { "Duplicate Host headers", > ++ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", > ++ "GET / HTTP/1.1\r\nHost: example.com\r\nHost: example.org\r\n", > ++ -1, > ++ SOUP_STATUS_BAD_REQUEST, > ++ NULL, NULL, -1, > ++ { { NULL } }, > ++ G_LOG_LEVEL_WARNING > ++ }, > ++ > ++ { "Duplicate Host headers, case insensitive", > ++ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", > ++ "GET / HTTP/1.1\r\nHost: example.com\r\nhost: example.org\r\n", > ++ -1, > ++ SOUP_STATUS_BAD_REQUEST, > ++ NULL, NULL, -1, > ++ { { NULL } }, > ++ G_LOG_LEVEL_WARNING > + } > + }; > + static const int num_reqtests = G_N_ELEMENTS (reqtests); > +@@ -915,10 +935,17 @@ do_request_tests (void) > + len = strlen (reqtests[i].request); > + else > + len = reqtests[i].length; > ++ > ++ if (reqtests[i].log_flags) > ++ g_test_expect_message ("libsoup", reqtests[i].log_flags, "*"); > ++ > + status = soup_headers_parse_request (reqtests[i].request, len, > + headers, &method, &path, > + &version); > + g_assert_cmpint (status, ==, reqtests[i].status); > ++ if (reqtests[i].log_flags) > ++ g_test_assert_expected_messages (); > ++ > + if (SOUP_STATUS_IS_SUCCESSFUL (status)) { > + g_assert_cmpstr (method, ==, reqtests[i].method); > + g_assert_cmpstr (path, ==, reqtests[i].path); > +@@ -1312,6 +1339,32 @@ do_bad_header_tests (void) > + soup_message_headers_unref (hdrs); > + } > + > ++static void > ++do_append_duplicate_host_test (void) > ++{ > ++ SoupMessageHeaders *hdrs; > ++ const char *list_value; > ++ > ++ hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); > ++ soup_message_headers_append (hdrs, "Host", "a"); > ++ > ++ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, > ++ "soup_message_headers_append_common: Rejecting duplicate Host header"); > ++ soup_message_headers_append (hdrs, "Host", "b"); > ++ g_test_assert_expected_messages (); > ++ > ++ /* Case insensitive */ > ++ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, > ++ "soup_message_headers_append_common: Rejecting duplicate Host header"); > ++ soup_message_headers_append (hdrs, "host", "b"); > ++ g_test_assert_expected_messages (); > ++ > ++ list_value = soup_message_headers_get_list (hdrs, "Host"); > ++ g_assert_cmpstr (list_value, ==, "a"); > ++ > ++ soup_message_headers_unref (hdrs); > ++} > ++ > + int > + main (int argc, char **argv) > + { > +@@ -1327,6 +1380,7 @@ main (int argc, char **argv) > + g_test_add_func ("/header-parsing/content-type", do_content_type_tests); > + g_test_add_func ("/header-parsing/append-param", do_append_param_tests); > + g_test_add_func ("/header-parsing/bad", do_bad_header_tests); > ++ g_test_add_func ("/header-parsing/append-duplicate-host", do_append_duplicate_host_test); > + > + ret = g_test_run (); > + > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch > new file mode 100644 > index 0000000000..0772c759dc > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch > @@ -0,0 +1,229 @@ > +From 176cb31003252a69d3fc7908e8f505c0ee006b7a Mon Sep 17 00:00:00 2001 > +From: Ignacio Casal Quinteiro <qignacio@amazon.com> > +Date: Wed, 24 Jul 2024 15:20:35 +0200 > +Subject: [PATCH 1/4] websocket: add a way to restrict the total message size > + > +Otherwise a client could send small packages smaller than > +total-incoming-payload-size but still to break the server > +with a big allocation > + > +Fixes: #390 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/db87805ab565d67533dfed2cb409dbfd63c7fdce] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/websocket/soup-websocket-connection.c | 107 +++++++++++++++++- > + libsoup/websocket/soup-websocket-connection.h | 7 ++ > + 2 files changed, 110 insertions(+), 4 deletions(-) > + > +diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c > +index 5eb8150..19bdd39 100644 > +--- a/libsoup/websocket/soup-websocket-connection.c > ++++ b/libsoup/websocket/soup-websocket-connection.c > +@@ -84,7 +84,7 @@ enum { > + PROP_MAX_INCOMING_PAYLOAD_SIZE, > + PROP_KEEPALIVE_INTERVAL, > + PROP_EXTENSIONS, > +- > ++ PROP_MAX_TOTAL_MESSAGE_SIZE, > + LAST_PROPERTY > + }; > + > +@@ -126,6 +126,7 @@ typedef struct { > + char *origin; > + char *protocol; > + guint64 max_incoming_payload_size; > ++ guint64 max_total_message_size; > + guint keepalive_interval; > + > + gushort peer_close_code; > +@@ -156,6 +157,7 @@ typedef struct { > + } SoupWebsocketConnectionPrivate; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -670,8 +672,8 @@ bad_data_error_and_close (SoupWebsocketConnection *self) > + } > + > + static void > +-too_big_error_and_close (SoupWebsocketConnection *self, > +- guint64 payload_len) > ++too_big_incoming_payload_error_and_close (SoupWebsocketConnection *self, > ++ guint64 payload_len) > + { > + SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > + GError *error; > +@@ -687,6 +689,24 @@ too_big_error_and_close (SoupWebsocketConnection *self, > + emit_error_and_close (self, error, TRUE); > + } > + > ++static void > ++too_big_message_error_and_close (SoupWebsocketConnection *self, > ++ guint64 len) > ++{ > ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > ++ GError *error; > ++ > ++ error = g_error_new_literal (SOUP_WEBSOCKET_ERROR, > ++ SOUP_WEBSOCKET_CLOSE_TOO_BIG, > ++ priv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? > ++ "Received WebSocket payload from the client larger than configured max-total-message-size" : > ++ "Received WebSocket payload from the server larger than configured max-total-message-size"); > ++ g_debug ("%s received message of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT, > ++ priv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client", > ++ len, priv->max_total_message_size); > ++ emit_error_and_close (self, error, TRUE); > ++} > ++ > + static void > + close_connection (SoupWebsocketConnection *self, > + gushort code, > +@@ -918,6 +938,12 @@ process_contents (SoupWebsocketConnection *self, > + switch (priv->message_opcode) { > + case 0x01: > + case 0x02: > ++ /* Safety valve */ > ++ if (priv->max_total_message_size > 0 && > ++ (priv->message_data->len + payload_len) > priv->max_total_message_size) { > ++ too_big_message_error_and_close (self, (priv->message_data->len + payload_len)); > ++ return; > ++ } > + g_byte_array_append (priv->message_data, payload, payload_len); > + break; > + default: > +@@ -1056,7 +1082,7 @@ process_frame (SoupWebsocketConnection *self) > + /* Safety valve */ > + if (priv->max_incoming_payload_size > 0 && > + payload_len > priv->max_incoming_payload_size) { > +- too_big_error_and_close (self, payload_len); > ++ too_big_incoming_payload_error_and_close (self, payload_len); > + return FALSE; > + } > + > +@@ -1363,6 +1389,10 @@ soup_websocket_connection_get_property (GObject *object, > + g_value_set_pointer (value, priv->extensions); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ g_value_set_uint64 (value, priv->max_total_message_size); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1416,6 +1446,10 @@ soup_websocket_connection_set_property (GObject *object, > + priv->extensions = g_value_get_pointer (value); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ priv->max_total_message_size = g_value_get_uint64 (value); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1628,6 +1662,26 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + G_PARAM_CONSTRUCT_ONLY | > + G_PARAM_STATIC_STRINGS); > + > ++ /** > ++ * SoupWebsocketConnection:max-total-message-size: > ++ * > ++ * The total message size for incoming packets. > ++ * > ++ * The protocol expects or 0 to not limit it. > ++ * > ++ * Since: 3.8 > ++ */ > ++ properties[PROP_MAX_TOTAL_MESSAGE_SIZE] = > ++ g_param_spec_uint64 ("max-total-message-size", > ++ "Max total message size", > ++ "Max total message size ", > ++ 0, > ++ G_MAXUINT64, > ++ MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ G_PARAM_READWRITE | > ++ G_PARAM_CONSTRUCT | > ++ G_PARAM_STATIC_STRINGS); > ++ > + g_object_class_install_properties (gobject_class, LAST_PROPERTY, properties); > + > + /** > +@@ -2111,6 +2165,51 @@ soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection > + } > + } > + > ++/** > ++ * soup_websocket_connection_get_max_total_message_size: > ++ * @self: the WebSocket > ++ * > ++ * Gets the maximum total message size allowed for packets. > ++ * > ++ * Returns: the maximum total message size. > ++ * > ++ * Since: 3.8 > ++ */ > ++guint64 > ++soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self) > ++{ > ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > ++ > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ > ++ return priv->max_total_message_size; > ++} > ++ > ++/** > ++ * soup_websocket_connection_set_max_total_message_size: > ++ * @self: the WebSocket > ++ * @max_total_message_size: the maximum total message size > ++ * > ++ * Sets the maximum total message size allowed for packets. > ++ * > ++ * It does not limit the outgoing packet size. > ++ * > ++ * Since: 3.8 > ++ */ > ++void > ++soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size) > ++{ > ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > ++ > ++ g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self)); > ++ > ++ if (priv->max_total_message_size != max_total_message_size) { > ++ priv->max_total_message_size = max_total_message_size; > ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_TOTAL_MESSAGE_SIZE]); > ++ } > ++} > ++ > + /** > + * soup_websocket_connection_get_keepalive_interval: > + * @self: the WebSocket > +diff --git a/libsoup/websocket/soup-websocket-connection.h b/libsoup/websocket/soup-websocket-connection.h > +index eeb093d..922de56 100644 > +--- a/libsoup/websocket/soup-websocket-connection.h > ++++ b/libsoup/websocket/soup-websocket-connection.h > +@@ -88,6 +88,13 @@ SOUP_AVAILABLE_IN_ALL > + void soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection *self, > + guint64 max_incoming_payload_size); > + > ++SOUP_AVAILABLE_IN_3_0 > ++guint64 soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self); > ++ > ++SOUP_AVAILABLE_IN_3_0 > ++void soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size); > ++ > + SOUP_AVAILABLE_IN_ALL > + guint soup_websocket_connection_get_keepalive_interval (SoupWebsocketConnection *self); > + > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch > new file mode 100644 > index 0000000000..6f00fabfdb > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch > @@ -0,0 +1,34 @@ > +From 81eb7cf7422878f0b78b833a3b741f734502921f Mon Sep 17 00:00:00 2001 > +From: Ignacio Casal Quinteiro <qignacio@amazon.com> > +Date: Fri, 20 Sep 2024 12:12:38 +0200 > +Subject: [PATCH 2/4] websocket-test: set the total message size > + > +This is required when sending a big amount of data > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/4904a46a2d9a014efa6be01a186ac353dbf5047b] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + tests/websocket-test.c | 5 +++++ > + 1 file changed, 5 insertions(+) > + > +diff --git a/tests/websocket-test.c b/tests/websocket-test.c > +index a0b8334..827b041 100644 > +--- a/tests/websocket-test.c > ++++ b/tests/websocket-test.c > +@@ -567,6 +567,11 @@ test_send_big_packets (Test *test, > + soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1); > + g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1)); > + > ++ soup_websocket_connection_set_max_total_message_size (test->client, 1000 * 1000 + 1); > ++ g_assert (soup_websocket_connection_get_max_total_message_size (test->client) == (1000 * 1000 + 1)); > ++ soup_websocket_connection_set_max_total_message_size (test->server, 1000 * 1000 + 1); > ++ g_assert (soup_websocket_connection_get_max_total_message_size (test->server) == (1000 * 1000 + 1)); > ++ > + sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > + WAIT_UNTIL (received != NULL); > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch > new file mode 100644 > index 0000000000..29fb0d7ddb > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch > @@ -0,0 +1,134 @@ > +From 25616e1a958bc1503cc24d6845a6e80ffc287727 Mon Sep 17 00:00:00 2001 > +From: Michael Catanzaro <mcatanzaro@redhat.com> > +Date: Thu, 8 May 2025 16:16:25 -0500 > +Subject: [PATCH] Set message size limit in SoupServer rather than > + SoupWebsocketConnection > + > +We're not sure about the compatibility implications of having a default > +size limit for clients. > + > +Also not sure whether the server limit is actually set appropriately, > +but there is probably very little server usage of > +SoupWebsocketConnection in the wild, so it's not so likely to break > +things. > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/2df34d9544cabdbfdedd3b36f098cf69233b1df7] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/server/soup-server.c | 24 +++++++++++++---- > + libsoup/websocket/soup-websocket-connection.c | 26 +++++++++++++------ > + 2 files changed, 37 insertions(+), 13 deletions(-) > + > +diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c > +index 6b486f5..c779f7d 100644 > +--- a/libsoup/server/soup-server.c > ++++ b/libsoup/server/soup-server.c > +@@ -186,6 +186,16 @@ static GParamSpec *properties[LAST_PROPERTY] = { NULL, }; > + > + G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) > + > ++/* SoupWebsocketConnection by default limits only maximum packet size. But a > ++ * message may consist of multiple packets, so SoupServer additionally restricts > ++ * total message size to mitigate denial of service attacks on the server. > ++ * SoupWebsocketConnection does not do this by default because I don't know > ++ * whether that would or would not cause compatibility problems for websites. > ++ * > ++ * This size is in bytes and it is arbitrary. > ++ */ > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > ++ > + static void request_finished (SoupServerMessage *msg, > + SoupMessageIOCompletion completion, > + SoupServer *server); > +@@ -937,11 +947,15 @@ complete_websocket_upgrade (SoupServer *server, > + > + g_object_ref (msg); > + stream = soup_server_message_steal_connection (msg); > +- conn = soup_websocket_connection_new (stream, uri, > +- SOUP_WEBSOCKET_CONNECTION_SERVER, > +- soup_message_headers_get_one_common (soup_server_message_get_request_headers (msg), SOUP_HEADER_ORIGIN), > +- soup_message_headers_get_one_common (soup_server_message_get_response_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL), > +- handler->websocket_extensions); > ++ conn = SOUP_WEBSOCKET_CONNECTION (g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION, > ++ "io-stream", stream, > ++ "uri", uri, > ++ "connection-type", SOUP_WEBSOCKET_CONNECTION_SERVER, > ++ "origin", soup_message_headers_get_one_common (soup_server_message_get_request_headers (msg), SOUP_HEADER_ORIGIN), > ++ "protocol", soup_message_headers_get_one_common (soup_server_message_get_response_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL), > ++ "extensions", handler->websocket_extensions, > ++ "max-total-message-size", (guint64)MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ NULL)); > + handler->websocket_extensions = NULL; > + g_object_unref (stream); > + > +diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c > +index 26476df..cbb1b72 100644 > +--- a/libsoup/websocket/soup-websocket-connection.c > ++++ b/libsoup/websocket/soup-websocket-connection.c > +@@ -149,7 +149,6 @@ typedef struct { > + } SoupWebsocketConnectionPrivate; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > +-#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -1612,9 +1611,10 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-incoming-payload-size: > + * > +- * The maximum payload size for incoming packets. > +- * > +- * The protocol expects or 0 to not limit it. > ++ * The maximum payload size for incoming packets, or 0 to not limit it. > ++ * > ++ * Each message may consist of multiple packets, so also refer to > ++ * [property@WebSocketConnection:max-total-message-size]. > + */ > + properties[PROP_MAX_INCOMING_PAYLOAD_SIZE] = > + g_param_spec_uint64 ("max-incoming-payload-size", > +@@ -1662,9 +1662,19 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-total-message-size: > + * > +- * The total message size for incoming packets. > ++ * The maximum size for incoming messages. > ++ * > ++ * Set to a value to limit the total message size, or 0 to not > ++ * limit it. > ++ * > ++ * [method@Server.add_websocket_handler] will set this to a nonzero > ++ * default value to mitigate denial of service attacks. Clients must > ++ * choose their own default if they need to mitigate denial of service > ++ * attacks. You also need to set your own default if creating your own > ++ * server SoupWebsocketConnection without using SoupServer. > + * > +- * The protocol expects or 0 to not limit it. > ++ * Each message may consist of multiple packets, so also refer to > ++ * [property@WebSocketConnection:max-incoming-payload-size]. > + * > + * Since: 3.8 > + */ > +@@ -1674,7 +1684,7 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + "Max total message size ", > + 0, > + G_MAXUINT64, > +- MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT | > + G_PARAM_STATIC_STRINGS); > +@@ -2164,7 +2174,7 @@ soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *s > + { > + SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > + > +- g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0); > + > + return priv->max_total_message_size; > + } > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch > new file mode 100644 > index 0000000000..6f391e98e2 > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch > @@ -0,0 +1,292 @@ > +From 3c87790a4ba141125e6ba165c478f0440e8e693e Mon Sep 17 00:00:00 2001 > +From: Michael Catanzaro <mcatanzaro@redhat.com> > +Date: Fri, 16 May 2025 16:55:40 -0500 > +Subject: [PATCH 4/4] Add tests for max-incoming-packet-size and > + max-total-message-size > + > +An even better test would verify that it's possible to send big messages > +containing small packets, but libsoup doesn't offer control over packet > +size, and I don't want to take the time to learn how WebSockets work to > +figure out how to do that manually. Instead, I just check that both > +limits work, for both client and server. > + > +I didn't add deflate variants of these tests because I doubt that would > +add valuable coverage. > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/4d00b45b7eebdcfa0706b58e34c40b8a0a16015b] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + tests/websocket-test.c | 214 +++++++++++++++++++++++++++++++++++++---- > + 1 file changed, 197 insertions(+), 17 deletions(-) > + > +diff --git a/tests/websocket-test.c b/tests/websocket-test.c > +index 827b041..ec1324c 100644 > +--- a/tests/websocket-test.c > ++++ b/tests/websocket-test.c > +@@ -543,16 +543,9 @@ test_send_big_packets (Test *test, > + { > + GBytes *sent = NULL; > + GBytes *received = NULL; > ++ gulong signal_id; > + > +- g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received); > +- > +- sent = g_bytes_new_take (g_strnfill (400, '!'), 400); > +- soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > +- WAIT_UNTIL (received != NULL); > +- g_assert (g_bytes_equal (sent, received)); > +- g_bytes_unref (sent); > +- g_bytes_unref (received); > +- received = NULL; > ++ signal_id = g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received); > + > + sent = g_bytes_new_take (g_strnfill (100 * 1000, '?'), 100 * 1000); > + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > +@@ -563,23 +556,174 @@ test_send_big_packets (Test *test, > + received = NULL; > + > + soup_websocket_connection_set_max_incoming_payload_size (test->client, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->client) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 1000 * 1000 + 1); > + soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 1000 * 1000 + 1); > + > + soup_websocket_connection_set_max_total_message_size (test->client, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_total_message_size (test->client) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 1000 * 1000 + 1); > + soup_websocket_connection_set_max_total_message_size (test->server, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_total_message_size (test->server) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 1000 * 1000 + 1); > + > + sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > + WAIT_UNTIL (received != NULL); > + g_assert (g_bytes_equal (sent, received)); > ++ g_bytes_unref (received); > ++ received = NULL; > ++ > ++ /* Reverse the test and send the big message to the server. */ > ++ g_signal_handler_disconnect (test->client, signal_id); > ++ g_signal_connect (test->server, "message", G_CALLBACK (on_text_message), &received); > ++ > ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); > ++ WAIT_UNTIL (received != NULL); > ++ g_assert_true (g_bytes_equal (sent, received)); > + g_bytes_unref (sent); > + g_bytes_unref (received); > + } > + > ++static void > ++test_send_big_packets_direct (Test *test, > ++ gconstpointer data) > ++{ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); > ++ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 0); > ++ > ++ test_send_big_packets (test, data); > ++} > ++ > ++static void > ++test_send_big_packets_soup (Test *test, > ++ gconstpointer data) > ++{ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); > ++ > ++ /* Max total message size defaults to 0 (unlimited), but SoupServer applies its own limit by default. */ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024); > ++ > ++ test_send_big_packets (test, data); > ++} > ++ > ++static void > ++test_send_exceeding_client_max_payload_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); > ++ > ++ soup_websocket_connection_set_max_incoming_payload_size (test->server, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 0); > ++ > ++ /* The message to the client is dropped due to the client's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++static void > ++test_send_exceeding_server_max_payload_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ soup_websocket_connection_set_max_incoming_payload_size (test->client, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 0); > ++ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); > ++ > ++ /* The message to the server is dropped due to the server's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++static void > ++test_send_exceeding_client_max_message_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ soup_websocket_connection_set_max_total_message_size (test->client, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 128 * 1024); > ++ > ++ soup_websocket_connection_set_max_total_message_size (test->server, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 0); > ++ > ++ /* The message to the client is dropped due to the client's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++static void > ++test_send_exceeding_server_max_message_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ soup_websocket_connection_set_max_total_message_size (test->client, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); > ++ > ++ /* Set the server message total message size manually, because its > ++ * default is different for direct connection vs. soup connection. > ++ */ > ++ soup_websocket_connection_set_max_total_message_size (test->server, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024); > ++ > ++ /* The message to the server is dropped due to the server's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++ > + static void > + test_send_empty_packets (Test *test, > + gconstpointer data) > +@@ -2064,11 +2208,47 @@ main (int argc, > + > + g_test_add ("/websocket/direct/send-big-packets", Test, NULL, > + setup_direct_connection, > +- test_send_big_packets, > ++ test_send_big_packets_direct, > + teardown_direct_connection); > + g_test_add ("/websocket/soup/send-big-packets", Test, NULL, > + setup_soup_connection, > +- test_send_big_packets, > ++ test_send_big_packets_soup, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-client-max-payload-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_client_max_payload_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-client-max-payload-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_client_max_payload_size, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-server-max-payload-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_server_max_payload_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-server-max-payload-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_server_max_payload_size, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-client-max-message-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_client_max_message_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-client-max-message-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_client_max_message_size, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-server-max-message-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_server_max_message_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-server-max-message-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_server_max_message_size, > + teardown_soup_connection); > + > + g_test_add ("/websocket/direct/send-empty-packets", Test, NULL, > +@@ -2217,11 +2397,11 @@ main (int argc, > + > + g_test_add ("/websocket/direct/deflate-send-big-packets", Test, NULL, > + setup_direct_connection_with_extensions, > +- test_send_big_packets, > ++ test_send_big_packets_direct, > + teardown_direct_connection); > + g_test_add ("/websocket/soup/deflate-send-big-packets", Test, NULL, > + setup_soup_connection_with_extensions, > +- test_send_big_packets, > ++ test_send_big_packets_soup, > + teardown_soup_connection); > + > + g_test_add ("/websocket/direct/deflate-send-empty-packets", Test, NULL, > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup_3.4.4.bb b/meta/recipes-support/libsoup/libsoup_3.4.4.bb > index c09b06fec2..fc4a286dcf 100644 > --- a/meta/recipes-support/libsoup/libsoup_3.4.4.bb > +++ b/meta/recipes-support/libsoup/libsoup_3.4.4.bb > @@ -46,6 +46,11 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ > file://CVE-2025-2784.patch \ > file://CVE-2025-4945.patch \ > file://CVE-2025-12105.patch \ > + file://CVE-2025-14523.patch \ > + file://CVE-2025-32049-1.patch \ > + file://CVE-2025-32049-2.patch \ > + file://CVE-2025-32049-3.patch \ > + file://CVE-2025-32049-4.patch \ > " > SRC_URI[sha256sum] = "291c67725f36ed90ea43efff25064b69c5a2d1981488477c05c481a3b4b0c5aa" > -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 2026-04-23 17:09 ` [OE-core] " Yoann Congal @ 2026-04-24 7:16 ` Li, Changqing 0 siblings, 0 replies; 23+ messages in thread From: Li, Changqing @ 2026-04-24 7:16 UTC (permalink / raw) To: Wang, Jinfeng (CN), openembedded-core@lists.openembedded.org, yoann.congal@smile.fr [-- Attachment #1: Type: text/plain, Size: 63809 bytes --] ________________________________ From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> on behalf of Yoann Congal via lists.openembedded.org <yoann.congal=smile.fr@lists.openembedded.org> Sent: Friday, April 24, 2026 1:09 AM To: Wang, Jinfeng (CN) <Jinfeng.Wang.CN@windriver.com>; openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> Subject: Re: [OE-core] [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 CAUTION: This email comes from a non Wind River email account! Do not click links or open attachments unless you recognize the sender and know the content is safe. On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Changqing Li <changqing.li@windriver.com> > > Refer: > https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 > https://gitlab.gnome.org/GNOME/libsoup/-/issues/390 > > Signed-off-by: Changqing Li <changqing.li@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- > .../libsoup-3.4.4/CVE-2025-14523.patch | 715 ++++++++++++++++++ > .../libsoup-3.4.4/CVE-2025-32049-1.patch | 229 ++++++ > .../libsoup-3.4.4/CVE-2025-32049-2.patch | 34 + > .../libsoup-3.4.4/CVE-2025-32049-3.patch | 134 ++++ > .../libsoup-3.4.4/CVE-2025-32049-4.patch | 292 +++++++ > meta/recipes-support/libsoup/libsoup_3.4.4.bb | 5 + > 6 files changed, 1409 insertions(+) > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch > > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch > new file mode 100644 > index 0000000000..b90f8bd29d > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-14523.patch > @@ -0,0 +1,715 @@ > +From 70123da95418f5d6e00e8ac2d586fb6c5d02cdc6 Mon Sep 17 00:00:00 2001 > +From: Michael Catanzaro <mcatanzaro@redhat.com> > +Date: Wed, 7 Jan 2026 14:50:33 -0600 > +Subject: [PATCH] Reject duplicate Host headers > + > +RFC 9112 section 3.2 says: > + > +A server MUST respond with a 400 (Bad Request) status code to any > +HTTP/1.1 request message that lacks a Host header field and to any > +request message that contains more than one Host header field line or a > +Host header field with an invalid field value. > + > +In addition to rejecting a duplicate header when parsing headers, also > +reject attempts to add the duplicate header using the > +soup_message_headers_append() API, and add tests for both cases. > + > +These checks will also apply to HTTP/2. I'm not sure whether this is > +actually desired or not, but the header processing code is not aware of > +which HTTP version is in use. > + > +(Note that while SoupMessageHeaders does not require the Host header to > +be present in an HTTP/1.1 request, SoupServer itself does. So we can't > +test the case of missing Host header via the header parsing test, but it > +really is enforced.) > + > +Fixes #472 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/d3db5a6f8f03e1f0133754872877c92c0284c472] Sorry but I don't see this commit mentionned in (CVE-2025-14523) (#YWH-PGM9867-116) Lack of Duplicate Header Rejection in libsoup can lead to host header parsing discrepancy between libsoup server and proxy (#472) · Issue · GNOME/libsoup https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 I admit this commit looks related but I very much like a detailled trail between a trusted source (eg. NVD, debian security tracker or upstream) and the commit. Also, that commit is only in the "mcatanzaro/rhel9" branch, that would need some justification. This may apply to the other CVE. I pasted the commit link for libsoup2 by accident, actually, this patch is from https://gitlab.gnome.org/GNOME/libsoup/-/commit/aecd8daadc110f8561fb2d6b2806a4cacf2e4c85, the link address in commit message need update. Finally, I'd rather have 1 CVE fix per commit, would it be possible to split the commit? Sure! Regards //Changqing Thanks! > +CVE: CVE-2025-14523 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-headers.c | 3 +- > + libsoup/soup-message-headers-private.h | 4 +- > + libsoup/soup-message-headers.c | 80 +++++++------ > + tests/header-parsing-test.c | 148 +++++++++++++++++-------- > + 4 files changed, 153 insertions(+), 82 deletions(-) > + > +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c > +index 155c11d..3fec9b3 100644 > +--- a/libsoup/soup-headers.c > ++++ b/libsoup/soup-headers.c > +@@ -139,7 +139,8 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) > + for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) > + *p = ' '; > + > +- soup_message_headers_append_untrusted_data (dest, name, value); > ++ if (!soup_message_headers_append_untrusted_data (dest, name, value)) > ++ goto done; > + } > + success = TRUE; > + > +diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h > +index 9815464..770f3ef 100644 > +--- a/libsoup/soup-message-headers-private.h > ++++ b/libsoup/soup-message-headers-private.h > +@@ -10,10 +10,10 @@ > + > + G_BEGIN_DECLS > + > +-void soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, > ++gboolean soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, > + const char *name, > + const char *value); > +-void soup_message_headers_append_common (SoupMessageHeaders *hdrs, > ++gboolean soup_message_headers_append_common (SoupMessageHeaders *hdrs, > + SoupHeaderName name, > + const char *value); > + const char *soup_message_headers_get_one_common (SoupMessageHeaders *hdrs, > +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c > +index d69d6e8..ce4b3b3 100644 > +--- a/libsoup/soup-message-headers.c > ++++ b/libsoup/soup-message-headers.c > +@@ -267,12 +267,16 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) > + soup_header_free_list (tokens); > + } > + > +-void > ++gboolean > + soup_message_headers_append_common (SoupMessageHeaders *hdrs, > + SoupHeaderName name, > + const char *value) > + { > + SoupCommonHeader header; > ++ if (name == SOUP_HEADER_HOST && soup_message_headers_get_one (hdrs, "Host")) { > ++ g_warning ("soup_message_headers_append_common: Rejecting duplicate Host header"); > ++ return FALSE; > ++ } > + > + if (!hdrs->common_headers) > + hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6); > +@@ -284,32 +288,18 @@ soup_message_headers_append_common (SoupMessageHeaders *hdrs, > + g_hash_table_remove (hdrs->common_concat, GUINT_TO_POINTER (header.name)); > + > + soup_message_headers_set (hdrs, name, value); > ++ return TRUE; > + } > + > +-/** > +- * soup_message_headers_append: > +- * @hdrs: a #SoupMessageHeaders > +- * @name: the header name to add > +- * @value: the new value of @name > +- * > +- * Appends a new header with name @name and value @value to @hdrs. > +- * > +- * (If there is an existing header with name @name, then this creates a second > +- * one, which is only allowed for list-valued headers; see also > +- * [method@MessageHeaders.replace].) > +- * > +- * The caller is expected to make sure that @name and @value are > +- * syntactically correct. > +- **/ > +-void > +-soup_message_headers_append (SoupMessageHeaders *hdrs, > +- const char *name, const char *value) > ++static gboolean > ++soup_message_headers_append_internal (SoupMessageHeaders *hdrs, > ++ const char *name, const char *value) > + { > + SoupUncommonHeader header; > + SoupHeaderName header_name; > + > +- g_return_if_fail (name != NULL); > +- g_return_if_fail (value != NULL); > ++ g_return_val_if_fail (name != NULL, FALSE); > ++ g_return_val_if_fail (value != NULL, FALSE); > + > + /* Setting a syntactically invalid header name or value is > + * considered to be a programming error. However, it can also > +@@ -317,23 +307,22 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, > + * compiled with G_DISABLE_CHECKS. > + */ > + #ifndef G_DISABLE_CHECKS > +- g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL); > +- g_return_if_fail (strpbrk (value, "\r\n") == NULL); > ++ g_return_val_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL, FALSE); > ++ g_return_val_if_fail (strpbrk (value, "\r\n") == NULL, FALSE); > + #else > + if (*name && strpbrk (name, " \t\r\n:")) { > +- g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name); > +- return; > ++ g_warning ("soup_message_headers_append: Rejecting bad name '%s'", name); > ++ return FALSE; > + } > + if (strpbrk (value, "\r\n")) { > +- g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value); > +- return; > ++ g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value); > ++ return FALSE; > + } > + #endif > + > + header_name = soup_header_name_from_string (name); > + if (header_name != SOUP_HEADER_UNKNOWN) { > +- soup_message_headers_append_common (hdrs, header_name, value); > +- return; > ++ return soup_message_headers_append_common (hdrs, header_name, value); > + } > + > + if (!hdrs->uncommon_headers) > +@@ -344,21 +333,48 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, > + g_array_append_val (hdrs->uncommon_headers, header); > + if (hdrs->uncommon_concat) > + g_hash_table_remove (hdrs->uncommon_concat, header.name); > ++ return TRUE; > ++} > ++ > ++/** > ++ * soup_message_headers_append: > ++ * @hdrs: a #SoupMessageHeaders > ++ * @name: the header name to add > ++ * @value: the new value of @name > ++ * > ++ * Appends a new header with name @name and value @value to @hdrs. > ++ * > ++ * (If there is an existing header with name @name, then this creates a second > ++ * one, which is only allowed for list-valued headers; see also > ++ * [method@MessageHeaders.replace].) > ++ * > ++ * The caller is expected to make sure that @name and @value are > ++ * syntactically correct. > ++ **/ > ++void > ++soup_message_headers_append (SoupMessageHeaders *hdrs, > ++ const char *name, const char *value) > ++{ > ++ soup_message_headers_append_internal (hdrs, name, value); > + } > + > + /* > +- * Appends a header value ensuring that it is valid UTF8. > ++ * Appends a header value ensuring that it is valid UTF-8, and also checking the > ++ * return value of soup_message_headers_append_internal() to report whether the > ++ * headers are invalid for various other reasons. > + */ > +-void > ++gboolean > + soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs, > + const char *name, > + const char *value) > + { > + char *safe_value = g_utf8_make_valid (value, -1); > + char *safe_name = g_utf8_make_valid (name, -1); > +- soup_message_headers_append (hdrs, safe_name, safe_value); > ++ gboolean result = soup_message_headers_append_internal (hdrs, safe_name, safe_value); > ++ > + g_free (safe_value); > + g_free (safe_name); > ++ return result; > + } > + > + void > +diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c > +index 9490559..98a22a4 100644 > +--- a/tests/header-parsing-test.c > ++++ b/tests/header-parsing-test.c > +@@ -24,6 +24,7 @@ static struct RequestTest { > + const char *method, *path; > + SoupHTTPVersion version; > + Header headers[10]; > ++ GLogLevelFlags log_flags; > + } reqtests[] = { > + /**********************/ > + /*** VALID REQUESTS ***/ > +@@ -33,7 +34,7 @@ static struct RequestTest { > + "GET / HTTP/1.0\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "/", SOUP_HTTP_1_0, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Req w/ 1 header", NULL, > +@@ -42,7 +43,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, no leading whitespace", NULL, > +@@ -51,7 +52,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header including trailing whitespace", NULL, > +@@ -60,7 +61,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped", NULL, > +@@ -69,7 +70,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped with additional whitespace", NULL, > +@@ -78,7 +79,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped with tab", NULL, > +@@ -87,7 +88,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header, wrapped before value", NULL, > +@@ -96,7 +97,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 1 header with empty value", NULL, > +@@ -105,7 +106,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 2 headers", NULL, > +@@ -115,7 +116,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "Connection", "close" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers", NULL, > +@@ -126,7 +127,7 @@ static struct RequestTest { > + { "Connection", "close" }, > + { "Blah", "blah" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers, 1st wrapped", NULL, > +@@ -137,7 +138,7 @@ static struct RequestTest { > + { "Foo", "bar baz" }, > + { "Blah", "blah" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers, 2nd wrapped", NULL, > +@@ -148,7 +149,7 @@ static struct RequestTest { > + { "Blah", "blah" }, > + { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ 3 headers, 3rd wrapped", NULL, > +@@ -159,7 +160,7 @@ static struct RequestTest { > + { "Blah", "blah" }, > + { "Foo", "bar baz" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ same header multiple times", NULL, > +@@ -168,7 +169,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Foo", "bar, baz, quux" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Connection header on HTTP/1.0 message", NULL, > +@@ -178,21 +179,21 @@ static struct RequestTest { > + { { "Connection", "Bar, Quux" }, > + { "Foo", "bar" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "GET with full URI", "667637", > + "GET http://example.com HTTP/1.1\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "http://example.com", SOUP_HTTP_1_1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "GET with full URI in upper-case", "667637", > + "GET HTTP://example.com HTTP/1.1\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "HTTP://example.com", SOUP_HTTP_1_1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + /* It's better for this to be passed through: this means a SoupServer > +@@ -202,7 +203,7 @@ static struct RequestTest { > + "GET AbOuT: HTTP/1.1\r\n", -1, > + SOUP_STATUS_OK, > + "GET", "AbOuT:", SOUP_HTTP_1_1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + /****************************/ > +@@ -217,7 +218,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /* RFC 2616 section 3.1 says we MUST accept this */ > +@@ -228,7 +229,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /* RFC 2616 section 19.3 says we SHOULD accept these */ > +@@ -240,7 +241,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "Connection", "close" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "LF instead of CRLF after Request-Line", NULL, > +@@ -249,7 +250,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Mixed CRLF/LF", "666316", > +@@ -261,7 +262,7 @@ static struct RequestTest { > + { "e", "f" }, > + { "g", "h" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ incorrect whitespace in Request-Line", NULL, > +@@ -270,7 +271,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Req w/ incorrect whitespace after Request-Line", "475169", > +@@ -279,7 +280,7 @@ static struct RequestTest { > + "GET", "/", SOUP_HTTP_1_1, > + { { "Host", "example.com" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /* If the request/status line is parseable, then we > +@@ -293,7 +294,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "Bar", "two" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "First header line is continuation", "666316", > +@@ -303,7 +304,7 @@ static struct RequestTest { > + { { "Host", "example.com" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Zero-length header name", "666316", > +@@ -313,7 +314,7 @@ static struct RequestTest { > + { { "a", "b" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "CR in header name", "666316", > +@@ -323,7 +324,7 @@ static struct RequestTest { > + { { "a", "b" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "CR in header value", "666316", > +@@ -336,7 +337,7 @@ static struct RequestTest { > + { "s", "t" }, /* CR at end is ignored */ > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Tab in header name", "666316", > +@@ -351,7 +352,7 @@ static struct RequestTest { > + { "p", "q z: w" }, > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + { "Tab in header value", "666316", > +@@ -364,7 +365,7 @@ static struct RequestTest { > + { "z", "w" }, /* trailing tab ignored */ > + { "c", "d" }, > + { NULL } > +- } > ++ }, 0 > + }, > + > + /************************/ > +@@ -375,77 +376,77 @@ static struct RequestTest { > + "GET /\r\n", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "HTTP 1.2 request (no such thing)", NULL, > + "GET / HTTP/1.2\r\n", -1, > + SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "HTTP 2000 request (no such thing)", NULL, > + "GET / HTTP/2000.0\r\n", -1, > + SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Long HTTP version terminating at missing minor version", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/404", > + unterminated_http_version, sizeof (unterminated_http_version), > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Non-HTTP request", NULL, > + "GET / SOUP/1.1\r\nHost: example.com\r\n", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Junk after Request-Line", NULL, > + "GET / HTTP/1.1 blah\r\nHost: example.com\r\n", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL in Method", NULL, > + "G\x00T / HTTP/1.1\r\nHost: example.com\r\n", 37, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL at beginning of Method", "666316", > + "\x00 / HTTP/1.1\r\nHost: example.com\r\n", 35, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL in Path", NULL, > + "GET /\x00 HTTP/1.1\r\nHost: example.com\r\n", 38, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "No terminating CRLF", NULL, > + "GET / HTTP/1.1\r\nHost: example.com", -1, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Unrecognized expectation", NULL, > + "GET / HTTP/1.1\r\nHost: example.com\r\nExpect: the-impossible\r\n", -1, > + SOUP_STATUS_EXPECTATION_FAILED, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + // https://gitlab.gnome.org/GNOME/libsoup/-/issues/377 > +@@ -453,21 +454,40 @@ static struct RequestTest { > + "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "NUL in header value", NULL, > + "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28, > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > + }, > + > + { "Only newlines", NULL, > + only_newlines, sizeof (only_newlines), > + SOUP_STATUS_BAD_REQUEST, > + NULL, NULL, -1, > +- { { NULL } } > ++ { { NULL } }, 0 > ++ }, > ++ { "Duplicate Host headers", > ++ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", > ++ "GET / HTTP/1.1\r\nHost: example.com\r\nHost: example.org\r\n", > ++ -1, > ++ SOUP_STATUS_BAD_REQUEST, > ++ NULL, NULL, -1, > ++ { { NULL } }, > ++ G_LOG_LEVEL_WARNING > ++ }, > ++ > ++ { "Duplicate Host headers, case insensitive", > ++ "https://gitlab.gnome.org/GNOME/libsoup/-/issues/472", > ++ "GET / HTTP/1.1\r\nHost: example.com\r\nhost: example.org\r\n", > ++ -1, > ++ SOUP_STATUS_BAD_REQUEST, > ++ NULL, NULL, -1, > ++ { { NULL } }, > ++ G_LOG_LEVEL_WARNING > + } > + }; > + static const int num_reqtests = G_N_ELEMENTS (reqtests); > +@@ -915,10 +935,17 @@ do_request_tests (void) > + len = strlen (reqtests[i].request); > + else > + len = reqtests[i].length; > ++ > ++ if (reqtests[i].log_flags) > ++ g_test_expect_message ("libsoup", reqtests[i].log_flags, "*"); > ++ > + status = soup_headers_parse_request (reqtests[i].request, len, > + headers, &method, &path, > + &version); > + g_assert_cmpint (status, ==, reqtests[i].status); > ++ if (reqtests[i].log_flags) > ++ g_test_assert_expected_messages (); > ++ > + if (SOUP_STATUS_IS_SUCCESSFUL (status)) { > + g_assert_cmpstr (method, ==, reqtests[i].method); > + g_assert_cmpstr (path, ==, reqtests[i].path); > +@@ -1312,6 +1339,32 @@ do_bad_header_tests (void) > + soup_message_headers_unref (hdrs); > + } > + > ++static void > ++do_append_duplicate_host_test (void) > ++{ > ++ SoupMessageHeaders *hdrs; > ++ const char *list_value; > ++ > ++ hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST); > ++ soup_message_headers_append (hdrs, "Host", "a"); > ++ > ++ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, > ++ "soup_message_headers_append_common: Rejecting duplicate Host header"); > ++ soup_message_headers_append (hdrs, "Host", "b"); > ++ g_test_assert_expected_messages (); > ++ > ++ /* Case insensitive */ > ++ g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING, > ++ "soup_message_headers_append_common: Rejecting duplicate Host header"); > ++ soup_message_headers_append (hdrs, "host", "b"); > ++ g_test_assert_expected_messages (); > ++ > ++ list_value = soup_message_headers_get_list (hdrs, "Host"); > ++ g_assert_cmpstr (list_value, ==, "a"); > ++ > ++ soup_message_headers_unref (hdrs); > ++} > ++ > + int > + main (int argc, char **argv) > + { > +@@ -1327,6 +1380,7 @@ main (int argc, char **argv) > + g_test_add_func ("/header-parsing/content-type", do_content_type_tests); > + g_test_add_func ("/header-parsing/append-param", do_append_param_tests); > + g_test_add_func ("/header-parsing/bad", do_bad_header_tests); > ++ g_test_add_func ("/header-parsing/append-duplicate-host", do_append_duplicate_host_test); > + > + ret = g_test_run (); > + > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch > new file mode 100644 > index 0000000000..0772c759dc > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-1.patch > @@ -0,0 +1,229 @@ > +From 176cb31003252a69d3fc7908e8f505c0ee006b7a Mon Sep 17 00:00:00 2001 > +From: Ignacio Casal Quinteiro <qignacio@amazon.com> > +Date: Wed, 24 Jul 2024 15:20:35 +0200 > +Subject: [PATCH 1/4] websocket: add a way to restrict the total message size > + > +Otherwise a client could send small packages smaller than > +total-incoming-payload-size but still to break the server > +with a big allocation > + > +Fixes: #390 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/db87805ab565d67533dfed2cb409dbfd63c7fdce] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/websocket/soup-websocket-connection.c | 107 +++++++++++++++++- > + libsoup/websocket/soup-websocket-connection.h | 7 ++ > + 2 files changed, 110 insertions(+), 4 deletions(-) > + > +diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c > +index 5eb8150..19bdd39 100644 > +--- a/libsoup/websocket/soup-websocket-connection.c > ++++ b/libsoup/websocket/soup-websocket-connection.c > +@@ -84,7 +84,7 @@ enum { > + PROP_MAX_INCOMING_PAYLOAD_SIZE, > + PROP_KEEPALIVE_INTERVAL, > + PROP_EXTENSIONS, > +- > ++ PROP_MAX_TOTAL_MESSAGE_SIZE, > + LAST_PROPERTY > + }; > + > +@@ -126,6 +126,7 @@ typedef struct { > + char *origin; > + char *protocol; > + guint64 max_incoming_payload_size; > ++ guint64 max_total_message_size; > + guint keepalive_interval; > + > + gushort peer_close_code; > +@@ -156,6 +157,7 @@ typedef struct { > + } SoupWebsocketConnectionPrivate; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -670,8 +672,8 @@ bad_data_error_and_close (SoupWebsocketConnection *self) > + } > + > + static void > +-too_big_error_and_close (SoupWebsocketConnection *self, > +- guint64 payload_len) > ++too_big_incoming_payload_error_and_close (SoupWebsocketConnection *self, > ++ guint64 payload_len) > + { > + SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > + GError *error; > +@@ -687,6 +689,24 @@ too_big_error_and_close (SoupWebsocketConnection *self, > + emit_error_and_close (self, error, TRUE); > + } > + > ++static void > ++too_big_message_error_and_close (SoupWebsocketConnection *self, > ++ guint64 len) > ++{ > ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > ++ GError *error; > ++ > ++ error = g_error_new_literal (SOUP_WEBSOCKET_ERROR, > ++ SOUP_WEBSOCKET_CLOSE_TOO_BIG, > ++ priv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? > ++ "Received WebSocket payload from the client larger than configured max-total-message-size" : > ++ "Received WebSocket payload from the server larger than configured max-total-message-size"); > ++ g_debug ("%s received message of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT, > ++ priv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client", > ++ len, priv->max_total_message_size); > ++ emit_error_and_close (self, error, TRUE); > ++} > ++ > + static void > + close_connection (SoupWebsocketConnection *self, > + gushort code, > +@@ -918,6 +938,12 @@ process_contents (SoupWebsocketConnection *self, > + switch (priv->message_opcode) { > + case 0x01: > + case 0x02: > ++ /* Safety valve */ > ++ if (priv->max_total_message_size > 0 && > ++ (priv->message_data->len + payload_len) > priv->max_total_message_size) { > ++ too_big_message_error_and_close (self, (priv->message_data->len + payload_len)); > ++ return; > ++ } > + g_byte_array_append (priv->message_data, payload, payload_len); > + break; > + default: > +@@ -1056,7 +1082,7 @@ process_frame (SoupWebsocketConnection *self) > + /* Safety valve */ > + if (priv->max_incoming_payload_size > 0 && > + payload_len > priv->max_incoming_payload_size) { > +- too_big_error_and_close (self, payload_len); > ++ too_big_incoming_payload_error_and_close (self, payload_len); > + return FALSE; > + } > + > +@@ -1363,6 +1389,10 @@ soup_websocket_connection_get_property (GObject *object, > + g_value_set_pointer (value, priv->extensions); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ g_value_set_uint64 (value, priv->max_total_message_size); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1416,6 +1446,10 @@ soup_websocket_connection_set_property (GObject *object, > + priv->extensions = g_value_get_pointer (value); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ priv->max_total_message_size = g_value_get_uint64 (value); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1628,6 +1662,26 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + G_PARAM_CONSTRUCT_ONLY | > + G_PARAM_STATIC_STRINGS); > + > ++ /** > ++ * SoupWebsocketConnection:max-total-message-size: > ++ * > ++ * The total message size for incoming packets. > ++ * > ++ * The protocol expects or 0 to not limit it. > ++ * > ++ * Since: 3.8 > ++ */ > ++ properties[PROP_MAX_TOTAL_MESSAGE_SIZE] = > ++ g_param_spec_uint64 ("max-total-message-size", > ++ "Max total message size", > ++ "Max total message size ", > ++ 0, > ++ G_MAXUINT64, > ++ MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ G_PARAM_READWRITE | > ++ G_PARAM_CONSTRUCT | > ++ G_PARAM_STATIC_STRINGS); > ++ > + g_object_class_install_properties (gobject_class, LAST_PROPERTY, properties); > + > + /** > +@@ -2111,6 +2165,51 @@ soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection > + } > + } > + > ++/** > ++ * soup_websocket_connection_get_max_total_message_size: > ++ * @self: the WebSocket > ++ * > ++ * Gets the maximum total message size allowed for packets. > ++ * > ++ * Returns: the maximum total message size. > ++ * > ++ * Since: 3.8 > ++ */ > ++guint64 > ++soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self) > ++{ > ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > ++ > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ > ++ return priv->max_total_message_size; > ++} > ++ > ++/** > ++ * soup_websocket_connection_set_max_total_message_size: > ++ * @self: the WebSocket > ++ * @max_total_message_size: the maximum total message size > ++ * > ++ * Sets the maximum total message size allowed for packets. > ++ * > ++ * It does not limit the outgoing packet size. > ++ * > ++ * Since: 3.8 > ++ */ > ++void > ++soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size) > ++{ > ++ SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > ++ > ++ g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self)); > ++ > ++ if (priv->max_total_message_size != max_total_message_size) { > ++ priv->max_total_message_size = max_total_message_size; > ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_TOTAL_MESSAGE_SIZE]); > ++ } > ++} > ++ > + /** > + * soup_websocket_connection_get_keepalive_interval: > + * @self: the WebSocket > +diff --git a/libsoup/websocket/soup-websocket-connection.h b/libsoup/websocket/soup-websocket-connection.h > +index eeb093d..922de56 100644 > +--- a/libsoup/websocket/soup-websocket-connection.h > ++++ b/libsoup/websocket/soup-websocket-connection.h > +@@ -88,6 +88,13 @@ SOUP_AVAILABLE_IN_ALL > + void soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection *self, > + guint64 max_incoming_payload_size); > + > ++SOUP_AVAILABLE_IN_3_0 > ++guint64 soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self); > ++ > ++SOUP_AVAILABLE_IN_3_0 > ++void soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size); > ++ > + SOUP_AVAILABLE_IN_ALL > + guint soup_websocket_connection_get_keepalive_interval (SoupWebsocketConnection *self); > + > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch > new file mode 100644 > index 0000000000..6f00fabfdb > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-2.patch > @@ -0,0 +1,34 @@ > +From 81eb7cf7422878f0b78b833a3b741f734502921f Mon Sep 17 00:00:00 2001 > +From: Ignacio Casal Quinteiro <qignacio@amazon.com> > +Date: Fri, 20 Sep 2024 12:12:38 +0200 > +Subject: [PATCH 2/4] websocket-test: set the total message size > + > +This is required when sending a big amount of data > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/4904a46a2d9a014efa6be01a186ac353dbf5047b] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + tests/websocket-test.c | 5 +++++ > + 1 file changed, 5 insertions(+) > + > +diff --git a/tests/websocket-test.c b/tests/websocket-test.c > +index a0b8334..827b041 100644 > +--- a/tests/websocket-test.c > ++++ b/tests/websocket-test.c > +@@ -567,6 +567,11 @@ test_send_big_packets (Test *test, > + soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1); > + g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1)); > + > ++ soup_websocket_connection_set_max_total_message_size (test->client, 1000 * 1000 + 1); > ++ g_assert (soup_websocket_connection_get_max_total_message_size (test->client) == (1000 * 1000 + 1)); > ++ soup_websocket_connection_set_max_total_message_size (test->server, 1000 * 1000 + 1); > ++ g_assert (soup_websocket_connection_get_max_total_message_size (test->server) == (1000 * 1000 + 1)); > ++ > + sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > + WAIT_UNTIL (received != NULL); > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch > new file mode 100644 > index 0000000000..29fb0d7ddb > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-3.patch > @@ -0,0 +1,134 @@ > +From 25616e1a958bc1503cc24d6845a6e80ffc287727 Mon Sep 17 00:00:00 2001 > +From: Michael Catanzaro <mcatanzaro@redhat.com> > +Date: Thu, 8 May 2025 16:16:25 -0500 > +Subject: [PATCH] Set message size limit in SoupServer rather than > + SoupWebsocketConnection > + > +We're not sure about the compatibility implications of having a default > +size limit for clients. > + > +Also not sure whether the server limit is actually set appropriately, > +but there is probably very little server usage of > +SoupWebsocketConnection in the wild, so it's not so likely to break > +things. > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/2df34d9544cabdbfdedd3b36f098cf69233b1df7] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/server/soup-server.c | 24 +++++++++++++---- > + libsoup/websocket/soup-websocket-connection.c | 26 +++++++++++++------ > + 2 files changed, 37 insertions(+), 13 deletions(-) > + > +diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c > +index 6b486f5..c779f7d 100644 > +--- a/libsoup/server/soup-server.c > ++++ b/libsoup/server/soup-server.c > +@@ -186,6 +186,16 @@ static GParamSpec *properties[LAST_PROPERTY] = { NULL, }; > + > + G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) > + > ++/* SoupWebsocketConnection by default limits only maximum packet size. But a > ++ * message may consist of multiple packets, so SoupServer additionally restricts > ++ * total message size to mitigate denial of service attacks on the server. > ++ * SoupWebsocketConnection does not do this by default because I don't know > ++ * whether that would or would not cause compatibility problems for websites. > ++ * > ++ * This size is in bytes and it is arbitrary. > ++ */ > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > ++ > + static void request_finished (SoupServerMessage *msg, > + SoupMessageIOCompletion completion, > + SoupServer *server); > +@@ -937,11 +947,15 @@ complete_websocket_upgrade (SoupServer *server, > + > + g_object_ref (msg); > + stream = soup_server_message_steal_connection (msg); > +- conn = soup_websocket_connection_new (stream, uri, > +- SOUP_WEBSOCKET_CONNECTION_SERVER, > +- soup_message_headers_get_one_common (soup_server_message_get_request_headers (msg), SOUP_HEADER_ORIGIN), > +- soup_message_headers_get_one_common (soup_server_message_get_response_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL), > +- handler->websocket_extensions); > ++ conn = SOUP_WEBSOCKET_CONNECTION (g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION, > ++ "io-stream", stream, > ++ "uri", uri, > ++ "connection-type", SOUP_WEBSOCKET_CONNECTION_SERVER, > ++ "origin", soup_message_headers_get_one_common (soup_server_message_get_request_headers (msg), SOUP_HEADER_ORIGIN), > ++ "protocol", soup_message_headers_get_one_common (soup_server_message_get_response_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL), > ++ "extensions", handler->websocket_extensions, > ++ "max-total-message-size", (guint64)MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ NULL)); > + handler->websocket_extensions = NULL; > + g_object_unref (stream); > + > +diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c > +index 26476df..cbb1b72 100644 > +--- a/libsoup/websocket/soup-websocket-connection.c > ++++ b/libsoup/websocket/soup-websocket-connection.c > +@@ -149,7 +149,6 @@ typedef struct { > + } SoupWebsocketConnectionPrivate; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > +-#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -1612,9 +1611,10 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-incoming-payload-size: > + * > +- * The maximum payload size for incoming packets. > +- * > +- * The protocol expects or 0 to not limit it. > ++ * The maximum payload size for incoming packets, or 0 to not limit it. > ++ * > ++ * Each message may consist of multiple packets, so also refer to > ++ * [property@WebSocketConnection:max-total-message-size]. > + */ > + properties[PROP_MAX_INCOMING_PAYLOAD_SIZE] = > + g_param_spec_uint64 ("max-incoming-payload-size", > +@@ -1662,9 +1662,19 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-total-message-size: > + * > +- * The total message size for incoming packets. > ++ * The maximum size for incoming messages. > ++ * > ++ * Set to a value to limit the total message size, or 0 to not > ++ * limit it. > ++ * > ++ * [method@Server.add_websocket_handler] will set this to a nonzero > ++ * default value to mitigate denial of service attacks. Clients must > ++ * choose their own default if they need to mitigate denial of service > ++ * attacks. You also need to set your own default if creating your own > ++ * server SoupWebsocketConnection without using SoupServer. > + * > +- * The protocol expects or 0 to not limit it. > ++ * Each message may consist of multiple packets, so also refer to > ++ * [property@WebSocketConnection:max-incoming-payload-size]. > + * > + * Since: 3.8 > + */ > +@@ -1674,7 +1684,7 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + "Max total message size ", > + 0, > + G_MAXUINT64, > +- MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT | > + G_PARAM_STATIC_STRINGS); > +@@ -2164,7 +2174,7 @@ soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *s > + { > + SoupWebsocketConnectionPrivate *priv = soup_websocket_connection_get_instance_private (self); > + > +- g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0); > + > + return priv->max_total_message_size; > + } > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch > new file mode 100644 > index 0000000000..6f391e98e2 > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-32049-4.patch > @@ -0,0 +1,292 @@ > +From 3c87790a4ba141125e6ba165c478f0440e8e693e Mon Sep 17 00:00:00 2001 > +From: Michael Catanzaro <mcatanzaro@redhat.com> > +Date: Fri, 16 May 2025 16:55:40 -0500 > +Subject: [PATCH 4/4] Add tests for max-incoming-packet-size and > + max-total-message-size > + > +An even better test would verify that it's possible to send big messages > +containing small packets, but libsoup doesn't offer control over packet > +size, and I don't want to take the time to learn how WebSockets work to > +figure out how to do that manually. Instead, I just check that both > +limits work, for both client and server. > + > +I didn't add deflate variants of these tests because I doubt that would > +add valuable coverage. > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/4d00b45b7eebdcfa0706b58e34c40b8a0a16015b] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + tests/websocket-test.c | 214 +++++++++++++++++++++++++++++++++++++---- > + 1 file changed, 197 insertions(+), 17 deletions(-) > + > +diff --git a/tests/websocket-test.c b/tests/websocket-test.c > +index 827b041..ec1324c 100644 > +--- a/tests/websocket-test.c > ++++ b/tests/websocket-test.c > +@@ -543,16 +543,9 @@ test_send_big_packets (Test *test, > + { > + GBytes *sent = NULL; > + GBytes *received = NULL; > ++ gulong signal_id; > + > +- g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received); > +- > +- sent = g_bytes_new_take (g_strnfill (400, '!'), 400); > +- soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > +- WAIT_UNTIL (received != NULL); > +- g_assert (g_bytes_equal (sent, received)); > +- g_bytes_unref (sent); > +- g_bytes_unref (received); > +- received = NULL; > ++ signal_id = g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received); > + > + sent = g_bytes_new_take (g_strnfill (100 * 1000, '?'), 100 * 1000); > + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > +@@ -563,23 +556,174 @@ test_send_big_packets (Test *test, > + received = NULL; > + > + soup_websocket_connection_set_max_incoming_payload_size (test->client, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->client) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 1000 * 1000 + 1); > + soup_websocket_connection_set_max_incoming_payload_size (test->server, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_incoming_payload_size (test->server) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 1000 * 1000 + 1); > + > + soup_websocket_connection_set_max_total_message_size (test->client, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_total_message_size (test->client) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 1000 * 1000 + 1); > + soup_websocket_connection_set_max_total_message_size (test->server, 1000 * 1000 + 1); > +- g_assert (soup_websocket_connection_get_max_total_message_size (test->server) == (1000 * 1000 + 1)); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 1000 * 1000 + 1); > + > + sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > + soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > + WAIT_UNTIL (received != NULL); > + g_assert (g_bytes_equal (sent, received)); > ++ g_bytes_unref (received); > ++ received = NULL; > ++ > ++ /* Reverse the test and send the big message to the server. */ > ++ g_signal_handler_disconnect (test->client, signal_id); > ++ g_signal_connect (test->server, "message", G_CALLBACK (on_text_message), &received); > ++ > ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); > ++ WAIT_UNTIL (received != NULL); > ++ g_assert_true (g_bytes_equal (sent, received)); > + g_bytes_unref (sent); > + g_bytes_unref (received); > + } > + > ++static void > ++test_send_big_packets_direct (Test *test, > ++ gconstpointer data) > ++{ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); > ++ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 0); > ++ > ++ test_send_big_packets (test, data); > ++} > ++ > ++static void > ++test_send_big_packets_soup (Test *test, > ++ gconstpointer data) > ++{ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); > ++ > ++ /* Max total message size defaults to 0 (unlimited), but SoupServer applies its own limit by default. */ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024); > ++ > ++ test_send_big_packets (test, data); > ++} > ++ > ++static void > ++test_send_exceeding_client_max_payload_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024); > ++ > ++ soup_websocket_connection_set_max_incoming_payload_size (test->server, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 0); > ++ > ++ /* The message to the client is dropped due to the client's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++static void > ++test_send_exceeding_server_max_payload_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ soup_websocket_connection_set_max_incoming_payload_size (test->client, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 0); > ++ > ++ g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024); > ++ > ++ /* The message to the server is dropped due to the server's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++static void > ++test_send_exceeding_client_max_message_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ soup_websocket_connection_set_max_total_message_size (test->client, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 128 * 1024); > ++ > ++ soup_websocket_connection_set_max_total_message_size (test->server, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 0); > ++ > ++ /* The message to the client is dropped due to the client's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->server, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++static void > ++test_send_exceeding_server_max_message_size (Test *test, > ++ gconstpointer data) > ++{ > ++ GBytes *sent = NULL; > ++ GBytes *received = NULL; > ++ gboolean close_event = FALSE; > ++ GError *error = NULL; > ++ > ++ g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error); > ++ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_set_flag), &close_event); > ++ > ++ soup_websocket_connection_set_max_total_message_size (test->client, 0); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0); > ++ > ++ /* Set the server message total message size manually, because its > ++ * default is different for direct connection vs. soup connection. > ++ */ > ++ soup_websocket_connection_set_max_total_message_size (test->server, 128 * 1024); > ++ g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024); > ++ > ++ /* The message to the server is dropped due to the server's limit. */ > ++ sent = g_bytes_new_take (g_strnfill (1000 * 1000, '?'), 1000 * 1000); > ++ soup_websocket_connection_send_text (test->client, g_bytes_get_data (sent, NULL)); > ++ g_bytes_unref (sent); > ++ WAIT_UNTIL (close_event); > ++ g_assert_null (received); > ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED); > ++ g_assert_no_error (test->client_error); > ++} > ++ > ++ > + static void > + test_send_empty_packets (Test *test, > + gconstpointer data) > +@@ -2064,11 +2208,47 @@ main (int argc, > + > + g_test_add ("/websocket/direct/send-big-packets", Test, NULL, > + setup_direct_connection, > +- test_send_big_packets, > ++ test_send_big_packets_direct, > + teardown_direct_connection); > + g_test_add ("/websocket/soup/send-big-packets", Test, NULL, > + setup_soup_connection, > +- test_send_big_packets, > ++ test_send_big_packets_soup, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-client-max-payload-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_client_max_payload_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-client-max-payload-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_client_max_payload_size, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-server-max-payload-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_server_max_payload_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-server-max-payload-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_server_max_payload_size, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-client-max-message-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_client_max_message_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-client-max-message-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_client_max_message_size, > ++ teardown_soup_connection); > ++ > ++ g_test_add ("/websocket/direct/send-exceeding-server-max-message-size", Test, NULL, > ++ setup_direct_connection, > ++ test_send_exceeding_server_max_message_size, > ++ teardown_direct_connection); > ++ g_test_add ("/websocket/soup/send-exceeding-server-max-message-size", Test, NULL, > ++ setup_soup_connection, > ++ test_send_exceeding_server_max_message_size, > + teardown_soup_connection); > + > + g_test_add ("/websocket/direct/send-empty-packets", Test, NULL, > +@@ -2217,11 +2397,11 @@ main (int argc, > + > + g_test_add ("/websocket/direct/deflate-send-big-packets", Test, NULL, > + setup_direct_connection_with_extensions, > +- test_send_big_packets, > ++ test_send_big_packets_direct, > + teardown_direct_connection); > + g_test_add ("/websocket/soup/deflate-send-big-packets", Test, NULL, > + setup_soup_connection_with_extensions, > +- test_send_big_packets, > ++ test_send_big_packets_soup, > + teardown_soup_connection); > + > + g_test_add ("/websocket/direct/deflate-send-empty-packets", Test, NULL, > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup_3.4.4.bb b/meta/recipes-support/libsoup/libsoup_3.4.4.bb > index c09b06fec2..fc4a286dcf 100644 > --- a/meta/recipes-support/libsoup/libsoup_3.4.4.bb > +++ b/meta/recipes-support/libsoup/libsoup_3.4.4.bb > @@ -46,6 +46,11 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ > file://CVE-2025-2784.patch \ > file://CVE-2025-4945.patch \ > file://CVE-2025-12105.patch \ > + file://CVE-2025-14523.patch \ > + file://CVE-2025-32049-1.patch \ > + file://CVE-2025-32049-2.patch \ > + file://CVE-2025-32049-3.patch \ > + file://CVE-2025-32049-4.patch \ > " > SRC_URI[sha256sum] = "291c67725f36ed90ea43efff25064b69c5a2d1981488477c05c481a3b4b0c5aa" > -- Yoann Congal Smile ECS [-- Attachment #2: Type: text/html, Size: 119960 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 03/12] libsoup-2.4: fix CVE-2025-14523/CVE-2025-32049 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 01/12] gi-docgen: fix CVE-2025-11687 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-23 17:13 ` [OE-core] " Yoann Congal 2026-04-09 6:16 ` [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 jinfeng.wang.cn ` (8 subsequent siblings) 11 siblings, 1 reply; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Changqing Li <changqing.li@windriver.com> Refer: https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 https://gitlab.gnome.org/GNOME/libsoup/-/issues/390 Signed-off-by: Changqing Li <changqing.li@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../libsoup/libsoup-2.4/CVE-2025-14523.patch | 52 ++++ .../libsoup-2.4/CVE-2025-32049-1.patch | 229 ++++++++++++++++++ .../libsoup-2.4/CVE-2025-32049-2.patch | 131 ++++++++++ .../libsoup/libsoup-2.4_2.74.3.bb | 3 + 4 files changed, 415 insertions(+) create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch new file mode 100644 index 0000000000..7815dba55a --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch @@ -0,0 +1,52 @@ +From d6028a6e6a8417b7fb6c89f6c10fb94781435ee6 Mon Sep 17 00:00:00 2001 +From: Changqing Li <changqing.li@windriver.com> +Date: Wed, 4 Feb 2026 15:08:50 +0800 +Subject: [PATCH] Reject duplicate Host headers (for libsoup 2) + +This is a simplified version of my patch for libsoup 3: + +!491 + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/d3db5a6f8f03e1f0133754872877c92c0284c472] +CVE: CVE-2025-14523 + +This patch is a MR for branch 2-74, but not merged yet, maybe it will +not be merged. + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + libsoup/soup-headers.c | 3 +++ + libsoup/soup-message-headers.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c +index ea2f986..6cd3dad 100644 +--- a/libsoup/soup-headers.c ++++ b/libsoup/soup-headers.c +@@ -138,6 +138,9 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) + for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) + *p = ' '; + ++ if (g_ascii_strcasecmp (name, "Host") == 0 && soup_message_headers_get_one (dest, "Host")) ++ goto done; ++ + soup_message_headers_append (dest, name, value); + } + success = TRUE; +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c +index f612bff..bb20bbb 100644 +--- a/libsoup/soup-message-headers.c ++++ b/libsoup/soup-message-headers.c +@@ -220,6 +220,9 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, + } + #endif + ++ if (g_ascii_strcasecmp (name, "Host") == 0 && soup_message_headers_get_one (hdrs, "Host")) ++ return; ++ + header.name = intern_header_name (name, &setter); + header.value = g_strdup (value); + g_array_append_val (hdrs->array, header); +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch new file mode 100644 index 0000000000..64e87cb1ec --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch @@ -0,0 +1,229 @@ +From c574e659c41c18fad3973bbaa3b3ec75664b3137 Mon Sep 17 00:00:00 2001 +From: Changqing Li <changqing.li@windriver.com> +Date: Thu, 5 Feb 2026 16:20:02 +0800 +Subject: [PATCH 1/2] websocket: add a way to restrict the total message size + +Otherwise a client could send small packages smaller than +total-incoming-payload-size but still to break the server +with a big allocation + +Fixes: #390 + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/db87805ab565d67533dfed2cb409dbfd63c7fdce] +CVE: CVE-2025-32049 + +libsoup2 is not maintained, the patch is backported from libsoup3, and +change accordingly + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + libsoup/soup-websocket-connection.c | 104 ++++++++++++++++++++++++++-- + libsoup/soup-websocket-connection.h | 7 ++ + 2 files changed, 107 insertions(+), 4 deletions(-) + +diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c +index 9d5f4f8..3dad477 100644 +--- a/libsoup/soup-websocket-connection.c ++++ b/libsoup/soup-websocket-connection.c +@@ -85,7 +85,8 @@ enum { + PROP_STATE, + PROP_MAX_INCOMING_PAYLOAD_SIZE, + PROP_KEEPALIVE_INTERVAL, +- PROP_EXTENSIONS ++ PROP_EXTENSIONS, ++ PROP_MAX_TOTAL_MESSAGE_SIZE, + }; + + enum { +@@ -120,6 +121,7 @@ struct _SoupWebsocketConnectionPrivate { + char *origin; + char *protocol; + guint64 max_incoming_payload_size; ++ guint64 max_total_message_size; + guint keepalive_interval; + + gushort peer_close_code; +@@ -152,6 +154,7 @@ struct _SoupWebsocketConnectionPrivate { + }; + + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 + #define READ_BUFFER_SIZE 1024 + #define MASK_LENGTH 4 + +@@ -664,7 +667,7 @@ bad_data_error_and_close (SoupWebsocketConnection *self) + } + + static void +-too_big_error_and_close (SoupWebsocketConnection *self, ++too_big_incoming_payload_error_and_close (SoupWebsocketConnection *self, + guint64 payload_len) + { + GError *error; +@@ -680,6 +683,23 @@ too_big_error_and_close (SoupWebsocketConnection *self, + emit_error_and_close (self, error, TRUE); + } + ++static void ++too_big_message_error_and_close (SoupWebsocketConnection *self, ++ guint64 len) ++{ ++ GError *error; ++ ++ error = g_error_new_literal (SOUP_WEBSOCKET_ERROR, ++ SOUP_WEBSOCKET_CLOSE_TOO_BIG, ++ self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? ++ "Received WebSocket payload from the client larger than configured max-total-message-size" : ++ "Received WebSocket payload from the server larger than configured max-total-message-size"); ++ g_debug ("%s received message of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT, ++ self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client", ++ len, self->pv->max_total_message_size); ++ emit_error_and_close (self, error, TRUE); ++} ++ + static void + close_connection (SoupWebsocketConnection *self, + gushort code, +@@ -913,6 +933,12 @@ process_contents (SoupWebsocketConnection *self, + switch (pv->message_opcode) { + case 0x01: + case 0x02: ++ /* Safety valve */ ++ if (pv->max_total_message_size > 0 && ++ (pv->message_data->len + payload_len) > pv->max_total_message_size) { ++ too_big_message_error_and_close (self, (pv->message_data->len + payload_len)); ++ return; ++ } + g_byte_array_append (pv->message_data, payload, payload_len); + break; + default: +@@ -1050,7 +1076,7 @@ process_frame (SoupWebsocketConnection *self) + /* Safety valve */ + if (self->pv->max_incoming_payload_size > 0 && + payload_len >= self->pv->max_incoming_payload_size) { +- too_big_error_and_close (self, payload_len); ++ too_big_incoming_payload_error_and_close (self, payload_len); + return FALSE; + } + +@@ -1357,6 +1383,10 @@ soup_websocket_connection_get_property (GObject *object, + g_value_set_pointer (value, pv->extensions); + break; + ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: ++ g_value_set_uint64 (value, pv->max_total_message_size); ++ break; ++ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -1410,6 +1440,10 @@ soup_websocket_connection_set_property (GObject *object, + pv->extensions = g_value_get_pointer (value); + break; + ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: ++ pv->max_total_message_size = g_value_get_uint64 (value); ++ break; ++ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; +@@ -1631,7 +1665,24 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +- ++ /** ++ * SoupWebsocketConnection:max-total-message-size: ++ * ++ * The total message size for incoming packets. ++ * ++ * The protocol expects or 0 to not limit it. ++ * ++ */ ++ g_object_class_install_property (gobject_class, PROP_MAX_TOTAL_MESSAGE_SIZE, ++ g_param_spec_uint64 ("max-total-message-size", ++ "Max total message size", ++ "Max total message size ", ++ 0, ++ G_MAXUINT64, ++ MAX_TOTAL_MESSAGE_SIZE_DEFAULT, ++ G_PARAM_READWRITE | ++ G_PARAM_CONSTRUCT | ++ G_PARAM_STATIC_STRINGS)); + /** + * SoupWebsocketConnection::message: + * @self: the WebSocket +@@ -2145,6 +2196,51 @@ soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection + } + } + ++/** ++ * soup_websocket_connection_get_max_total_message_size: ++ * @self: the WebSocket ++ * ++ * Gets the maximum total message size allowed for packets. ++ * ++ * Returns: the maximum total message size. ++ * ++ */ ++guint64 ++soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self) ++{ ++ SoupWebsocketConnectionPrivate *pv; ++ ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); ++ pv = self->pv; ++ ++ return pv->max_total_message_size; ++} ++ ++/** ++ * soup_websocket_connection_set_max_total_message_size: ++ * @self: the WebSocket ++ * @max_total_message_size: the maximum total message size ++ * ++ * Sets the maximum total message size allowed for packets. ++ * ++ * It does not limit the outgoing packet size. ++ * ++ */ ++void ++soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, ++ guint64 max_total_message_size) ++{ ++ SoupWebsocketConnectionPrivate *pv; ++ ++ g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self)); ++ pv = self->pv; ++ ++ if (pv->max_total_message_size != max_total_message_size) { ++ pv->max_total_message_size = max_total_message_size; ++ g_object_notify (G_OBJECT (self), "max-total-message-size"); ++ } ++} ++ + /** + * soup_websocket_connection_get_keepalive_interval: + * @self: the WebSocket +diff --git a/libsoup/soup-websocket-connection.h b/libsoup/soup-websocket-connection.h +index f82d723..d2a60e9 100644 +--- a/libsoup/soup-websocket-connection.h ++++ b/libsoup/soup-websocket-connection.h +@@ -136,6 +136,13 @@ SOUP_AVAILABLE_IN_2_58 + void soup_websocket_connection_set_keepalive_interval (SoupWebsocketConnection *self, + guint interval); + ++SOUP_AVAILABLE_IN_2_72 ++guint64 soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self); ++ ++SOUP_AVAILABLE_IN_2_72 ++void soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, ++ guint64 max_total_message_size); ++ + G_END_DECLS + + #endif /* __SOUP_WEBSOCKET_CONNECTION_H__ */ +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch new file mode 100644 index 0000000000..f9c894aaec --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch @@ -0,0 +1,131 @@ +From 0bfc66f1082f5d47df99b6fc03f742ef7fa1051e Mon Sep 17 00:00:00 2001 +From: Changqing Li <changqing.li@windriver.com> +Date: Thu, 5 Feb 2026 17:19:51 +0800 +Subject: [PATCH] Set message size limit in SoupServer rather than + SoupWebsocketConnection + +We're not sure about the compatibility implications of having a default +size limit for clients. + +Also not sure whether the server limit is actually set appropriately, +but there is probably very little server usage of +SoupWebsocketConnection in the wild, so it's not so likely to break +things. + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/2df34d9544cabdbfdedd3b36f098cf69233b1df7] +CVE: CVE-2025-32049 + +Signed-off-by: Changqing Li <changqing.li@windriver.com> +--- + libsoup/soup-server.c | 24 +++++++++++++++++++----- + libsoup/soup-websocket-connection.c | 23 ++++++++++++++++------- + 2 files changed, 35 insertions(+), 12 deletions(-) + +diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c +index 63875f3..a3f8597 100644 +--- a/libsoup/soup-server.c ++++ b/libsoup/soup-server.c +@@ -216,6 +216,16 @@ enum { + + G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) + ++/* SoupWebsocketConnection by default limits only maximum packet size. But a ++ * message may consist of multiple packets, so SoupServer additionally restricts ++ * total message size to mitigate denial of service attacks on the server. ++ * SoupWebsocketConnection does not do this by default because I don't know ++ * whether that would or would not cause compatibility problems for websites. ++ * ++ * This size is in bytes and it is arbitrary. ++ */ ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 ++ + static SoupClientContext *soup_client_context_ref (SoupClientContext *client); + static void soup_client_context_unref (SoupClientContext *client); + +@@ -1445,11 +1455,15 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data) + + soup_client_context_ref (client); + stream = soup_client_context_steal_connection (client); +- conn = soup_websocket_connection_new_with_extensions (stream, uri, +- SOUP_WEBSOCKET_CONNECTION_SERVER, +- soup_message_headers_get_one (msg->request_headers, "Origin"), +- soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), +- handler->websocket_extensions); ++ conn = SOUP_WEBSOCKET_CONNECTION (g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION, ++ "io-stream", stream, ++ "uri", uri, ++ "connection-type", SOUP_WEBSOCKET_CONNECTION_SERVER, ++ "origin", soup_message_headers_get_one (msg->request_headers, "Origin"), ++ "protocol", soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), ++ "extensions", handler->websocket_extensions, ++ "max-total-message-size", (guint64)MAX_TOTAL_MESSAGE_SIZE_DEFAULT, ++ NULL)); + handler->websocket_extensions = NULL; + g_object_unref (stream); + soup_client_context_unref (client); +diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c +index 3dad477..e7fa9b7 100644 +--- a/libsoup/soup-websocket-connection.c ++++ b/libsoup/soup-websocket-connection.c +@@ -154,7 +154,6 @@ struct _SoupWebsocketConnectionPrivate { + }; + + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 +-#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 + #define READ_BUFFER_SIZE 1024 + #define MASK_LENGTH 4 + +@@ -1615,8 +1614,9 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + /** + * SoupWebsocketConnection:max-incoming-payload-size: + * +- * The maximum payload size for incoming packets the protocol expects +- * or 0 to not limit it. ++ * The maximum payload size for incoming packets, or 0 to not limit it. ++ * Each message may consist of multiple packets, so also refer to ++ * [property@WebSocketConnection:max-total-message-size]. + * + * Since: 2.56 + */ +@@ -1668,9 +1668,18 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + /** + * SoupWebsocketConnection:max-total-message-size: + * +- * The total message size for incoming packets. ++ * The maximum size for incoming messages. ++ * Set to a value to limit the total message size, or 0 to not ++ * limit it. + * +- * The protocol expects or 0 to not limit it. ++ * [method@Server.add_websocket_handler] will set this to a nonzero ++ * default value to mitigate denial of service attacks. Clients must ++ * choose their own default if they need to mitigate denial of service ++ * attacks. You also need to set your own default if creating your own ++ * server SoupWebsocketConnection without using SoupServer. ++ * ++ * Each message may consist of multiple packets, so also refer to ++ *[property@WebSocketConnection:max-incoming-payload-size]. + * + */ + g_object_class_install_property (gobject_class, PROP_MAX_TOTAL_MESSAGE_SIZE, +@@ -1679,7 +1688,7 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) + "Max total message size ", + 0, + G_MAXUINT64, +- MAX_TOTAL_MESSAGE_SIZE_DEFAULT, ++ 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); +@@ -2210,7 +2219,7 @@ soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *s + { + SoupWebsocketConnectionPrivate *pv; + +- g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0); + pv = self->pv; + + return pv->max_total_message_size; +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb b/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb index 7e00cd678a..915d735da3 100644 --- a/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb +++ b/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb @@ -41,6 +41,9 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ file://CVE-2025-4476.patch \ file://CVE-2025-2784.patch \ file://CVE-2025-4945.patch \ + file://CVE-2025-14523.patch \ + file://CVE-2025-32049-1.patch \ + file://CVE-2025-32049-2.patch \ " SRC_URI[sha256sum] = "e4b77c41cfc4c8c5a035fcdc320c7bc6cfb75ef7c5a034153df1413fa1d92f13" -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 03/12] libsoup-2.4: fix CVE-2025-14523/CVE-2025-32049 2026-04-09 6:16 ` [scarthgap][PATCH 03/12] libsoup-2.4: " jinfeng.wang.cn @ 2026-04-23 17:13 ` Yoann Congal 2026-04-24 7:37 ` Li, Changqing 0 siblings, 1 reply; 23+ messages in thread From: Yoann Congal @ 2026-04-23 17:13 UTC (permalink / raw) To: Jinfeng.Wang.CN, openembedded-core On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Changqing Li <changqing.li@windriver.com> > > Refer: > https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 > https://gitlab.gnome.org/GNOME/libsoup/-/issues/390 > > Signed-off-by: Changqing Li <changqing.li@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- > .../libsoup/libsoup-2.4/CVE-2025-14523.patch | 52 ++++ > .../libsoup-2.4/CVE-2025-32049-1.patch | 229 ++++++++++++++++++ > .../libsoup-2.4/CVE-2025-32049-2.patch | 131 ++++++++++ > .../libsoup/libsoup-2.4_2.74.3.bb | 3 + > 4 files changed, 415 insertions(+) > create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch > > diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch > new file mode 100644 > index 0000000000..7815dba55a > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch > @@ -0,0 +1,52 @@ > +From d6028a6e6a8417b7fb6c89f6c10fb94781435ee6 Mon Sep 17 00:00:00 2001 > +From: Changqing Li <changqing.li@windriver.com> > +Date: Wed, 4 Feb 2026 15:08:50 +0800 > +Subject: [PATCH] Reject duplicate Host headers (for libsoup 2) > + > +This is a simplified version of my patch for libsoup 3: > + > +!491 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/d3db5a6f8f03e1f0133754872877c92c0284c472] > +CVE: CVE-2025-14523 See remarks made to 02/12 patch, they should apply here. > +This patch is a MR for branch 2-74, but not merged yet, maybe it will > +not be merged. ... then you can't mark the patch as "Upstream-Status: Backport". Maybe the "Submitted" status is more apropriate. But, then, do we really want to use an unmerged patch? Regards, > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-headers.c | 3 +++ > + libsoup/soup-message-headers.c | 3 +++ > + 2 files changed, 6 insertions(+) > + > +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c > +index ea2f986..6cd3dad 100644 > +--- a/libsoup/soup-headers.c > ++++ b/libsoup/soup-headers.c > +@@ -138,6 +138,9 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) > + for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) > + *p = ' '; > + > ++ if (g_ascii_strcasecmp (name, "Host") == 0 && soup_message_headers_get_one (dest, "Host")) > ++ goto done; > ++ > + soup_message_headers_append (dest, name, value); > + } > + success = TRUE; > +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c > +index f612bff..bb20bbb 100644 > +--- a/libsoup/soup-message-headers.c > ++++ b/libsoup/soup-message-headers.c > +@@ -220,6 +220,9 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, > + } > + #endif > + > ++ if (g_ascii_strcasecmp (name, "Host") == 0 && soup_message_headers_get_one (hdrs, "Host")) > ++ return; > ++ > + header.name = intern_header_name (name, &setter); > + header.value = g_strdup (value); > + g_array_append_val (hdrs->array, header); > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch > new file mode 100644 > index 0000000000..64e87cb1ec > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch > @@ -0,0 +1,229 @@ > +From c574e659c41c18fad3973bbaa3b3ec75664b3137 Mon Sep 17 00:00:00 2001 > +From: Changqing Li <changqing.li@windriver.com> > +Date: Thu, 5 Feb 2026 16:20:02 +0800 > +Subject: [PATCH 1/2] websocket: add a way to restrict the total message size > + > +Otherwise a client could send small packages smaller than > +total-incoming-payload-size but still to break the server > +with a big allocation > + > +Fixes: #390 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/db87805ab565d67533dfed2cb409dbfd63c7fdce] > +CVE: CVE-2025-32049 > + > +libsoup2 is not maintained, the patch is backported from libsoup3, and > +change accordingly > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-websocket-connection.c | 104 ++++++++++++++++++++++++++-- > + libsoup/soup-websocket-connection.h | 7 ++ > + 2 files changed, 107 insertions(+), 4 deletions(-) > + > +diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c > +index 9d5f4f8..3dad477 100644 > +--- a/libsoup/soup-websocket-connection.c > ++++ b/libsoup/soup-websocket-connection.c > +@@ -85,7 +85,8 @@ enum { > + PROP_STATE, > + PROP_MAX_INCOMING_PAYLOAD_SIZE, > + PROP_KEEPALIVE_INTERVAL, > +- PROP_EXTENSIONS > ++ PROP_EXTENSIONS, > ++ PROP_MAX_TOTAL_MESSAGE_SIZE, > + }; > + > + enum { > +@@ -120,6 +121,7 @@ struct _SoupWebsocketConnectionPrivate { > + char *origin; > + char *protocol; > + guint64 max_incoming_payload_size; > ++ guint64 max_total_message_size; > + guint keepalive_interval; > + > + gushort peer_close_code; > +@@ -152,6 +154,7 @@ struct _SoupWebsocketConnectionPrivate { > + }; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -664,7 +667,7 @@ bad_data_error_and_close (SoupWebsocketConnection *self) > + } > + > + static void > +-too_big_error_and_close (SoupWebsocketConnection *self, > ++too_big_incoming_payload_error_and_close (SoupWebsocketConnection *self, > + guint64 payload_len) > + { > + GError *error; > +@@ -680,6 +683,23 @@ too_big_error_and_close (SoupWebsocketConnection *self, > + emit_error_and_close (self, error, TRUE); > + } > + > ++static void > ++too_big_message_error_and_close (SoupWebsocketConnection *self, > ++ guint64 len) > ++{ > ++ GError *error; > ++ > ++ error = g_error_new_literal (SOUP_WEBSOCKET_ERROR, > ++ SOUP_WEBSOCKET_CLOSE_TOO_BIG, > ++ self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? > ++ "Received WebSocket payload from the client larger than configured max-total-message-size" : > ++ "Received WebSocket payload from the server larger than configured max-total-message-size"); > ++ g_debug ("%s received message of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT, > ++ self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client", > ++ len, self->pv->max_total_message_size); > ++ emit_error_and_close (self, error, TRUE); > ++} > ++ > + static void > + close_connection (SoupWebsocketConnection *self, > + gushort code, > +@@ -913,6 +933,12 @@ process_contents (SoupWebsocketConnection *self, > + switch (pv->message_opcode) { > + case 0x01: > + case 0x02: > ++ /* Safety valve */ > ++ if (pv->max_total_message_size > 0 && > ++ (pv->message_data->len + payload_len) > pv->max_total_message_size) { > ++ too_big_message_error_and_close (self, (pv->message_data->len + payload_len)); > ++ return; > ++ } > + g_byte_array_append (pv->message_data, payload, payload_len); > + break; > + default: > +@@ -1050,7 +1076,7 @@ process_frame (SoupWebsocketConnection *self) > + /* Safety valve */ > + if (self->pv->max_incoming_payload_size > 0 && > + payload_len >= self->pv->max_incoming_payload_size) { > +- too_big_error_and_close (self, payload_len); > ++ too_big_incoming_payload_error_and_close (self, payload_len); > + return FALSE; > + } > + > +@@ -1357,6 +1383,10 @@ soup_websocket_connection_get_property (GObject *object, > + g_value_set_pointer (value, pv->extensions); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ g_value_set_uint64 (value, pv->max_total_message_size); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1410,6 +1440,10 @@ soup_websocket_connection_set_property (GObject *object, > + pv->extensions = g_value_get_pointer (value); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ pv->max_total_message_size = g_value_get_uint64 (value); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1631,7 +1665,24 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT_ONLY | > + G_PARAM_STATIC_STRINGS)); > +- > ++ /** > ++ * SoupWebsocketConnection:max-total-message-size: > ++ * > ++ * The total message size for incoming packets. > ++ * > ++ * The protocol expects or 0 to not limit it. > ++ * > ++ */ > ++ g_object_class_install_property (gobject_class, PROP_MAX_TOTAL_MESSAGE_SIZE, > ++ g_param_spec_uint64 ("max-total-message-size", > ++ "Max total message size", > ++ "Max total message size ", > ++ 0, > ++ G_MAXUINT64, > ++ MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ G_PARAM_READWRITE | > ++ G_PARAM_CONSTRUCT | > ++ G_PARAM_STATIC_STRINGS)); > + /** > + * SoupWebsocketConnection::message: > + * @self: the WebSocket > +@@ -2145,6 +2196,51 @@ soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection > + } > + } > + > ++/** > ++ * soup_websocket_connection_get_max_total_message_size: > ++ * @self: the WebSocket > ++ * > ++ * Gets the maximum total message size allowed for packets. > ++ * > ++ * Returns: the maximum total message size. > ++ * > ++ */ > ++guint64 > ++soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self) > ++{ > ++ SoupWebsocketConnectionPrivate *pv; > ++ > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ pv = self->pv; > ++ > ++ return pv->max_total_message_size; > ++} > ++ > ++/** > ++ * soup_websocket_connection_set_max_total_message_size: > ++ * @self: the WebSocket > ++ * @max_total_message_size: the maximum total message size > ++ * > ++ * Sets the maximum total message size allowed for packets. > ++ * > ++ * It does not limit the outgoing packet size. > ++ * > ++ */ > ++void > ++soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size) > ++{ > ++ SoupWebsocketConnectionPrivate *pv; > ++ > ++ g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self)); > ++ pv = self->pv; > ++ > ++ if (pv->max_total_message_size != max_total_message_size) { > ++ pv->max_total_message_size = max_total_message_size; > ++ g_object_notify (G_OBJECT (self), "max-total-message-size"); > ++ } > ++} > ++ > + /** > + * soup_websocket_connection_get_keepalive_interval: > + * @self: the WebSocket > +diff --git a/libsoup/soup-websocket-connection.h b/libsoup/soup-websocket-connection.h > +index f82d723..d2a60e9 100644 > +--- a/libsoup/soup-websocket-connection.h > ++++ b/libsoup/soup-websocket-connection.h > +@@ -136,6 +136,13 @@ SOUP_AVAILABLE_IN_2_58 > + void soup_websocket_connection_set_keepalive_interval (SoupWebsocketConnection *self, > + guint interval); > + > ++SOUP_AVAILABLE_IN_2_72 > ++guint64 soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self); > ++ > ++SOUP_AVAILABLE_IN_2_72 > ++void soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size); > ++ > + G_END_DECLS > + > + #endif /* __SOUP_WEBSOCKET_CONNECTION_H__ */ > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch > new file mode 100644 > index 0000000000..f9c894aaec > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch > @@ -0,0 +1,131 @@ > +From 0bfc66f1082f5d47df99b6fc03f742ef7fa1051e Mon Sep 17 00:00:00 2001 > +From: Changqing Li <changqing.li@windriver.com> > +Date: Thu, 5 Feb 2026 17:19:51 +0800 > +Subject: [PATCH] Set message size limit in SoupServer rather than > + SoupWebsocketConnection > + > +We're not sure about the compatibility implications of having a default > +size limit for clients. > + > +Also not sure whether the server limit is actually set appropriately, > +but there is probably very little server usage of > +SoupWebsocketConnection in the wild, so it's not so likely to break > +things. > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/2df34d9544cabdbfdedd3b36f098cf69233b1df7] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-server.c | 24 +++++++++++++++++++----- > + libsoup/soup-websocket-connection.c | 23 ++++++++++++++++------- > + 2 files changed, 35 insertions(+), 12 deletions(-) > + > +diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c > +index 63875f3..a3f8597 100644 > +--- a/libsoup/soup-server.c > ++++ b/libsoup/soup-server.c > +@@ -216,6 +216,16 @@ enum { > + > + G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) > + > ++/* SoupWebsocketConnection by default limits only maximum packet size. But a > ++ * message may consist of multiple packets, so SoupServer additionally restricts > ++ * total message size to mitigate denial of service attacks on the server. > ++ * SoupWebsocketConnection does not do this by default because I don't know > ++ * whether that would or would not cause compatibility problems for websites. > ++ * > ++ * This size is in bytes and it is arbitrary. > ++ */ > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > ++ > + static SoupClientContext *soup_client_context_ref (SoupClientContext *client); > + static void soup_client_context_unref (SoupClientContext *client); > + > +@@ -1445,11 +1455,15 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data) > + > + soup_client_context_ref (client); > + stream = soup_client_context_steal_connection (client); > +- conn = soup_websocket_connection_new_with_extensions (stream, uri, > +- SOUP_WEBSOCKET_CONNECTION_SERVER, > +- soup_message_headers_get_one (msg->request_headers, "Origin"), > +- soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), > +- handler->websocket_extensions); > ++ conn = SOUP_WEBSOCKET_CONNECTION (g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION, > ++ "io-stream", stream, > ++ "uri", uri, > ++ "connection-type", SOUP_WEBSOCKET_CONNECTION_SERVER, > ++ "origin", soup_message_headers_get_one (msg->request_headers, "Origin"), > ++ "protocol", soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), > ++ "extensions", handler->websocket_extensions, > ++ "max-total-message-size", (guint64)MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ NULL)); > + handler->websocket_extensions = NULL; > + g_object_unref (stream); > + soup_client_context_unref (client); > +diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c > +index 3dad477..e7fa9b7 100644 > +--- a/libsoup/soup-websocket-connection.c > ++++ b/libsoup/soup-websocket-connection.c > +@@ -154,7 +154,6 @@ struct _SoupWebsocketConnectionPrivate { > + }; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > +-#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -1615,8 +1614,9 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-incoming-payload-size: > + * > +- * The maximum payload size for incoming packets the protocol expects > +- * or 0 to not limit it. > ++ * The maximum payload size for incoming packets, or 0 to not limit it. > ++ * Each message may consist of multiple packets, so also refer to > ++ * [property@WebSocketConnection:max-total-message-size]. > + * > + * Since: 2.56 > + */ > +@@ -1668,9 +1668,18 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-total-message-size: > + * > +- * The total message size for incoming packets. > ++ * The maximum size for incoming messages. > ++ * Set to a value to limit the total message size, or 0 to not > ++ * limit it. > + * > +- * The protocol expects or 0 to not limit it. > ++ * [method@Server.add_websocket_handler] will set this to a nonzero > ++ * default value to mitigate denial of service attacks. Clients must > ++ * choose their own default if they need to mitigate denial of service > ++ * attacks. You also need to set your own default if creating your own > ++ * server SoupWebsocketConnection without using SoupServer. > ++ * > ++ * Each message may consist of multiple packets, so also refer to > ++ *[property@WebSocketConnection:max-incoming-payload-size]. > + * > + */ > + g_object_class_install_property (gobject_class, PROP_MAX_TOTAL_MESSAGE_SIZE, > +@@ -1679,7 +1688,7 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + "Max total message size ", > + 0, > + G_MAXUINT64, > +- MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT | > + G_PARAM_STATIC_STRINGS)); > +@@ -2210,7 +2219,7 @@ soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *s > + { > + SoupWebsocketConnectionPrivate *pv; > + > +- g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0); > + pv = self->pv; > + > + return pv->max_total_message_size; > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb b/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb > index 7e00cd678a..915d735da3 100644 > --- a/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb > +++ b/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb > @@ -41,6 +41,9 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ > file://CVE-2025-4476.patch \ > file://CVE-2025-2784.patch \ > file://CVE-2025-4945.patch \ > + file://CVE-2025-14523.patch \ > + file://CVE-2025-32049-1.patch \ > + file://CVE-2025-32049-2.patch \ > " > SRC_URI[sha256sum] = "e4b77c41cfc4c8c5a035fcdc320c7bc6cfb75ef7c5a034153df1413fa1d92f13" > -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 03/12] libsoup-2.4: fix CVE-2025-14523/CVE-2025-32049 2026-04-23 17:13 ` [OE-core] " Yoann Congal @ 2026-04-24 7:37 ` Li, Changqing 0 siblings, 0 replies; 23+ messages in thread From: Li, Changqing @ 2026-04-24 7:37 UTC (permalink / raw) To: Wang, Jinfeng (CN), openembedded-core@lists.openembedded.org, yoann.congal@smile.fr [-- Attachment #1: Type: text/plain, Size: 23059 bytes --] ________________________________ From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> on behalf of Yoann Congal via lists.openembedded.org <yoann.congal=smile.fr@lists.openembedded.org> Sent: Friday, April 24, 2026 1:13 AM To: Wang, Jinfeng (CN) <Jinfeng.Wang.CN@windriver.com>; openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> Subject: Re: [OE-core] [scarthgap][PATCH 03/12] libsoup-2.4: fix CVE-2025-14523/CVE-2025-32049 CAUTION: This email comes from a non Wind River email account! Do not click links or open attachments unless you recognize the sender and know the content is safe. On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Changqing Li <changqing.li@windriver.com> > > Refer: > https://gitlab.gnome.org/GNOME/libsoup/-/issues/472 > https://gitlab.gnome.org/GNOME/libsoup/-/issues/390 > > Signed-off-by: Changqing Li <changqing.li@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- > .../libsoup/libsoup-2.4/CVE-2025-14523.patch | 52 ++++ > .../libsoup-2.4/CVE-2025-32049-1.patch | 229 ++++++++++++++++++ > .../libsoup-2.4/CVE-2025-32049-2.patch | 131 ++++++++++ > .../libsoup/libsoup-2.4_2.74.3.bb | 3 + > 4 files changed, 415 insertions(+) > create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch > create mode 100644 meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch > > diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch > new file mode 100644 > index 0000000000..7815dba55a > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-14523.patch > @@ -0,0 +1,52 @@ > +From d6028a6e6a8417b7fb6c89f6c10fb94781435ee6 Mon Sep 17 00:00:00 2001 > +From: Changqing Li <changqing.li@windriver.com> > +Date: Wed, 4 Feb 2026 15:08:50 +0800 > +Subject: [PATCH] Reject duplicate Host headers (for libsoup 2) > + > +This is a simplified version of my patch for libsoup 3: > + > +!491 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/d3db5a6f8f03e1f0133754872877c92c0284c472] > +CVE: CVE-2025-14523 See remarks made to 02/12 patch, they should apply here. This commit link is right for this patch. > +This patch is a MR for branch 2-74, but not merged yet, maybe it will > +not be merged. ... then you can't mark the patch as "Upstream-Status: Backport". Maybe the "Submitted" status is more apropriate. Yes, Submiitted is more apropriate. But, then, do we really want to use an unmerged patch? It is a bit long time since I made this patch, I remembered that I checked the related code logic, seems reasonable, but I am not expert at this software. and I remembered that I had test with the POC in issue https://gitlab.gnome.org/GNOME/libsoup/-/issues/472. I need to double check this when I split the commit per CVE as you suggest in 02/12 patch. What is your opinion? I am also ok that it is better not use the unmerged patch. Regards, > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-headers.c | 3 +++ > + libsoup/soup-message-headers.c | 3 +++ > + 2 files changed, 6 insertions(+) > + > +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c > +index ea2f986..6cd3dad 100644 > +--- a/libsoup/soup-headers.c > ++++ b/libsoup/soup-headers.c > +@@ -138,6 +138,9 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest) > + for (p = strchr (value, '\r'); p; p = strchr (p, '\r')) > + *p = ' '; > + > ++ if (g_ascii_strcasecmp (name, "Host") == 0 && soup_message_headers_get_one (dest, "Host")) > ++ goto done; > ++ > + soup_message_headers_append (dest, name, value); > + } > + success = TRUE; > +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c > +index f612bff..bb20bbb 100644 > +--- a/libsoup/soup-message-headers.c > ++++ b/libsoup/soup-message-headers.c > +@@ -220,6 +220,9 @@ soup_message_headers_append (SoupMessageHeaders *hdrs, > + } > + #endif > + > ++ if (g_ascii_strcasecmp (name, "Host") == 0 && soup_message_headers_get_one (hdrs, "Host")) > ++ return; > ++ > + header.name = intern_header_name (name, &setter); > + header.value = g_strdup (value); > + g_array_append_val (hdrs->array, header); > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch > new file mode 100644 > index 0000000000..64e87cb1ec > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-1.patch > @@ -0,0 +1,229 @@ > +From c574e659c41c18fad3973bbaa3b3ec75664b3137 Mon Sep 17 00:00:00 2001 > +From: Changqing Li <changqing.li@windriver.com> > +Date: Thu, 5 Feb 2026 16:20:02 +0800 > +Subject: [PATCH 1/2] websocket: add a way to restrict the total message size > + > +Otherwise a client could send small packages smaller than > +total-incoming-payload-size but still to break the server > +with a big allocation > + > +Fixes: #390 > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/db87805ab565d67533dfed2cb409dbfd63c7fdce] > +CVE: CVE-2025-32049 > + > +libsoup2 is not maintained, the patch is backported from libsoup3, and > +change accordingly > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-websocket-connection.c | 104 ++++++++++++++++++++++++++-- > + libsoup/soup-websocket-connection.h | 7 ++ > + 2 files changed, 107 insertions(+), 4 deletions(-) > + > +diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c > +index 9d5f4f8..3dad477 100644 > +--- a/libsoup/soup-websocket-connection.c > ++++ b/libsoup/soup-websocket-connection.c > +@@ -85,7 +85,8 @@ enum { > + PROP_STATE, > + PROP_MAX_INCOMING_PAYLOAD_SIZE, > + PROP_KEEPALIVE_INTERVAL, > +- PROP_EXTENSIONS > ++ PROP_EXTENSIONS, > ++ PROP_MAX_TOTAL_MESSAGE_SIZE, > + }; > + > + enum { > +@@ -120,6 +121,7 @@ struct _SoupWebsocketConnectionPrivate { > + char *origin; > + char *protocol; > + guint64 max_incoming_payload_size; > ++ guint64 max_total_message_size; > + guint keepalive_interval; > + > + gushort peer_close_code; > +@@ -152,6 +154,7 @@ struct _SoupWebsocketConnectionPrivate { > + }; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -664,7 +667,7 @@ bad_data_error_and_close (SoupWebsocketConnection *self) > + } > + > + static void > +-too_big_error_and_close (SoupWebsocketConnection *self, > ++too_big_incoming_payload_error_and_close (SoupWebsocketConnection *self, > + guint64 payload_len) > + { > + GError *error; > +@@ -680,6 +683,23 @@ too_big_error_and_close (SoupWebsocketConnection *self, > + emit_error_and_close (self, error, TRUE); > + } > + > ++static void > ++too_big_message_error_and_close (SoupWebsocketConnection *self, > ++ guint64 len) > ++{ > ++ GError *error; > ++ > ++ error = g_error_new_literal (SOUP_WEBSOCKET_ERROR, > ++ SOUP_WEBSOCKET_CLOSE_TOO_BIG, > ++ self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? > ++ "Received WebSocket payload from the client larger than configured max-total-message-size" : > ++ "Received WebSocket payload from the server larger than configured max-total-message-size"); > ++ g_debug ("%s received message of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT, > ++ self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client", > ++ len, self->pv->max_total_message_size); > ++ emit_error_and_close (self, error, TRUE); > ++} > ++ > + static void > + close_connection (SoupWebsocketConnection *self, > + gushort code, > +@@ -913,6 +933,12 @@ process_contents (SoupWebsocketConnection *self, > + switch (pv->message_opcode) { > + case 0x01: > + case 0x02: > ++ /* Safety valve */ > ++ if (pv->max_total_message_size > 0 && > ++ (pv->message_data->len + payload_len) > pv->max_total_message_size) { > ++ too_big_message_error_and_close (self, (pv->message_data->len + payload_len)); > ++ return; > ++ } > + g_byte_array_append (pv->message_data, payload, payload_len); > + break; > + default: > +@@ -1050,7 +1076,7 @@ process_frame (SoupWebsocketConnection *self) > + /* Safety valve */ > + if (self->pv->max_incoming_payload_size > 0 && > + payload_len >= self->pv->max_incoming_payload_size) { > +- too_big_error_and_close (self, payload_len); > ++ too_big_incoming_payload_error_and_close (self, payload_len); > + return FALSE; > + } > + > +@@ -1357,6 +1383,10 @@ soup_websocket_connection_get_property (GObject *object, > + g_value_set_pointer (value, pv->extensions); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ g_value_set_uint64 (value, pv->max_total_message_size); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1410,6 +1440,10 @@ soup_websocket_connection_set_property (GObject *object, > + pv->extensions = g_value_get_pointer (value); > + break; > + > ++ case PROP_MAX_TOTAL_MESSAGE_SIZE: > ++ pv->max_total_message_size = g_value_get_uint64 (value); > ++ break; > ++ > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); > + break; > +@@ -1631,7 +1665,24 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT_ONLY | > + G_PARAM_STATIC_STRINGS)); > +- > ++ /** > ++ * SoupWebsocketConnection:max-total-message-size: > ++ * > ++ * The total message size for incoming packets. > ++ * > ++ * The protocol expects or 0 to not limit it. > ++ * > ++ */ > ++ g_object_class_install_property (gobject_class, PROP_MAX_TOTAL_MESSAGE_SIZE, > ++ g_param_spec_uint64 ("max-total-message-size", > ++ "Max total message size", > ++ "Max total message size ", > ++ 0, > ++ G_MAXUINT64, > ++ MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ G_PARAM_READWRITE | > ++ G_PARAM_CONSTRUCT | > ++ G_PARAM_STATIC_STRINGS)); > + /** > + * SoupWebsocketConnection::message: > + * @self: the WebSocket > +@@ -2145,6 +2196,51 @@ soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection > + } > + } > + > ++/** > ++ * soup_websocket_connection_get_max_total_message_size: > ++ * @self: the WebSocket > ++ * > ++ * Gets the maximum total message size allowed for packets. > ++ * > ++ * Returns: the maximum total message size. > ++ * > ++ */ > ++guint64 > ++soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self) > ++{ > ++ SoupWebsocketConnectionPrivate *pv; > ++ > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ pv = self->pv; > ++ > ++ return pv->max_total_message_size; > ++} > ++ > ++/** > ++ * soup_websocket_connection_set_max_total_message_size: > ++ * @self: the WebSocket > ++ * @max_total_message_size: the maximum total message size > ++ * > ++ * Sets the maximum total message size allowed for packets. > ++ * > ++ * It does not limit the outgoing packet size. > ++ * > ++ */ > ++void > ++soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size) > ++{ > ++ SoupWebsocketConnectionPrivate *pv; > ++ > ++ g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self)); > ++ pv = self->pv; > ++ > ++ if (pv->max_total_message_size != max_total_message_size) { > ++ pv->max_total_message_size = max_total_message_size; > ++ g_object_notify (G_OBJECT (self), "max-total-message-size"); > ++ } > ++} > ++ > + /** > + * soup_websocket_connection_get_keepalive_interval: > + * @self: the WebSocket > +diff --git a/libsoup/soup-websocket-connection.h b/libsoup/soup-websocket-connection.h > +index f82d723..d2a60e9 100644 > +--- a/libsoup/soup-websocket-connection.h > ++++ b/libsoup/soup-websocket-connection.h > +@@ -136,6 +136,13 @@ SOUP_AVAILABLE_IN_2_58 > + void soup_websocket_connection_set_keepalive_interval (SoupWebsocketConnection *self, > + guint interval); > + > ++SOUP_AVAILABLE_IN_2_72 > ++guint64 soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *self); > ++ > ++SOUP_AVAILABLE_IN_2_72 > ++void soup_websocket_connection_set_max_total_message_size (SoupWebsocketConnection *self, > ++ guint64 max_total_message_size); > ++ > + G_END_DECLS > + > + #endif /* __SOUP_WEBSOCKET_CONNECTION_H__ */ > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch > new file mode 100644 > index 0000000000..f9c894aaec > --- /dev/null > +++ b/meta/recipes-support/libsoup/libsoup-2.4/CVE-2025-32049-2.patch > @@ -0,0 +1,131 @@ > +From 0bfc66f1082f5d47df99b6fc03f742ef7fa1051e Mon Sep 17 00:00:00 2001 > +From: Changqing Li <changqing.li@windriver.com> > +Date: Thu, 5 Feb 2026 17:19:51 +0800 > +Subject: [PATCH] Set message size limit in SoupServer rather than > + SoupWebsocketConnection > + > +We're not sure about the compatibility implications of having a default > +size limit for clients. > + > +Also not sure whether the server limit is actually set appropriately, > +but there is probably very little server usage of > +SoupWebsocketConnection in the wild, so it's not so likely to break > +things. > + > +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/2df34d9544cabdbfdedd3b36f098cf69233b1df7] > +CVE: CVE-2025-32049 > + > +Signed-off-by: Changqing Li <changqing.li@windriver.com> > +--- > + libsoup/soup-server.c | 24 +++++++++++++++++++----- > + libsoup/soup-websocket-connection.c | 23 ++++++++++++++++------- > + 2 files changed, 35 insertions(+), 12 deletions(-) > + > +diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c > +index 63875f3..a3f8597 100644 > +--- a/libsoup/soup-server.c > ++++ b/libsoup/soup-server.c > +@@ -216,6 +216,16 @@ enum { > + > + G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT) > + > ++/* SoupWebsocketConnection by default limits only maximum packet size. But a > ++ * message may consist of multiple packets, so SoupServer additionally restricts > ++ * total message size to mitigate denial of service attacks on the server. > ++ * SoupWebsocketConnection does not do this by default because I don't know > ++ * whether that would or would not cause compatibility problems for websites. > ++ * > ++ * This size is in bytes and it is arbitrary. > ++ */ > ++#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > ++ > + static SoupClientContext *soup_client_context_ref (SoupClientContext *client); > + static void soup_client_context_unref (SoupClientContext *client); > + > +@@ -1445,11 +1455,15 @@ complete_websocket_upgrade (SoupMessage *msg, gpointer user_data) > + > + soup_client_context_ref (client); > + stream = soup_client_context_steal_connection (client); > +- conn = soup_websocket_connection_new_with_extensions (stream, uri, > +- SOUP_WEBSOCKET_CONNECTION_SERVER, > +- soup_message_headers_get_one (msg->request_headers, "Origin"), > +- soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), > +- handler->websocket_extensions); > ++ conn = SOUP_WEBSOCKET_CONNECTION (g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION, > ++ "io-stream", stream, > ++ "uri", uri, > ++ "connection-type", SOUP_WEBSOCKET_CONNECTION_SERVER, > ++ "origin", soup_message_headers_get_one (msg->request_headers, "Origin"), > ++ "protocol", soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"), > ++ "extensions", handler->websocket_extensions, > ++ "max-total-message-size", (guint64)MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ NULL)); > + handler->websocket_extensions = NULL; > + g_object_unref (stream); > + soup_client_context_unref (client); > +diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c > +index 3dad477..e7fa9b7 100644 > +--- a/libsoup/soup-websocket-connection.c > ++++ b/libsoup/soup-websocket-connection.c > +@@ -154,7 +154,6 @@ struct _SoupWebsocketConnectionPrivate { > + }; > + > + #define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024 > +-#define MAX_TOTAL_MESSAGE_SIZE_DEFAULT 128 * 1024 > + #define READ_BUFFER_SIZE 1024 > + #define MASK_LENGTH 4 > + > +@@ -1615,8 +1614,9 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-incoming-payload-size: > + * > +- * The maximum payload size for incoming packets the protocol expects > +- * or 0 to not limit it. > ++ * The maximum payload size for incoming packets, or 0 to not limit it. > ++ * Each message may consist of multiple packets, so also refer to > ++ * [property@WebSocketConnection:max-total-message-size]. > + * > + * Since: 2.56 > + */ > +@@ -1668,9 +1668,18 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + /** > + * SoupWebsocketConnection:max-total-message-size: > + * > +- * The total message size for incoming packets. > ++ * The maximum size for incoming messages. > ++ * Set to a value to limit the total message size, or 0 to not > ++ * limit it. > + * > +- * The protocol expects or 0 to not limit it. > ++ * [method@Server.add_websocket_handler] will set this to a nonzero > ++ * default value to mitigate denial of service attacks. Clients must > ++ * choose their own default if they need to mitigate denial of service > ++ * attacks. You also need to set your own default if creating your own > ++ * server SoupWebsocketConnection without using SoupServer. > ++ * > ++ * Each message may consist of multiple packets, so also refer to > ++ *[property@WebSocketConnection:max-incoming-payload-size]. > + * > + */ > + g_object_class_install_property (gobject_class, PROP_MAX_TOTAL_MESSAGE_SIZE, > +@@ -1679,7 +1688,7 @@ soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass) > + "Max total message size ", > + 0, > + G_MAXUINT64, > +- MAX_TOTAL_MESSAGE_SIZE_DEFAULT, > ++ 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT | > + G_PARAM_STATIC_STRINGS)); > +@@ -2210,7 +2219,7 @@ soup_websocket_connection_get_max_total_message_size (SoupWebsocketConnection *s > + { > + SoupWebsocketConnectionPrivate *pv; > + > +- g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_TOTAL_MESSAGE_SIZE_DEFAULT); > ++ g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0); > + pv = self->pv; > + > + return pv->max_total_message_size; > +-- > +2.34.1 > + > diff --git a/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb b/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb > index 7e00cd678a..915d735da3 100644 > --- a/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb > +++ b/meta/recipes-support/libsoup/libsoup-2.4_2.74.3.bb > @@ -41,6 +41,9 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ > file://CVE-2025-4476.patch \ > file://CVE-2025-2784.patch \ > file://CVE-2025-4945.patch \ > + file://CVE-2025-14523.patch \ > + file://CVE-2025-32049-1.patch \ > + file://CVE-2025-32049-2.patch \ > " > SRC_URI[sha256sum] = "e4b77c41cfc4c8c5a035fcdc320c7bc6cfb75ef7c5a034153df1413fa1d92f13" > -- Yoann Congal Smile ECS [-- Attachment #2: Type: text/html, Size: 47297 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (2 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 03/12] libsoup-2.4: " jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-24 6:45 ` [OE-core] " Yoann Congal 2026-04-09 6:16 ` [scarthgap][PATCH 05/12] python3-pyasn1: fix CVE-2026-23490 jinfeng.wang.cn ` (7 subsequent siblings) 11 siblings, 1 reply; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Libo Chen <libo.chen.cn@windriver.com> According to [1], An undocumented and unsafe feature in the PLY (Python Lex-Yacc) library 3.11 allows Remote Code Execution (RCE) via the `picklefile` parameter in the `yacc()` function. This parameter accepts a `.pkl` file that is deserialized with `pickle.load()` without validation. Because `pickle` allows execution of embedded code via `__reduce__()`, an attacker can achieve code execution by passing a malicious pickle file. The parameter is not mentioned in official documentation or the GitHub repository, yet it is active in the PyPI version. This introduces a stealthy backdoor and persistence risk. [1] https://nvd.nist.gov/vuln/detail/CVE-2025-56005 Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../python/python3-ply/CVE-2025-56005.patch | 125 ++++++++++++++++++ .../python/python3-ply_3.11.bb | 4 + 2 files changed, 129 insertions(+) create mode 100644 meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch diff --git a/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch b/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch new file mode 100644 index 0000000000..3f1e62b766 --- /dev/null +++ b/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch @@ -0,0 +1,125 @@ +From bfaebcc33a5af77f2701581638aa31a1bf918302 Mon Sep 17 00:00:00 2001 +From: Libo Chen <libo.chen.cn@windriver.com> +Date: Tue, 27 Jan 2026 13:58:57 +0800 +Subject: [PATCH] python3-ply: fix CVE-2025-56005 + +Deprecate and disable the unsafe picklefile parameter and related +pickle serialization/deserialization functions to prevent RCE attacks. + +The picklefile parameter in yacc() now issues a DeprecationWarning +and is ignored. The read_pickle() and pickle_table() methods are +stubbed out to issue warnings and raise NotImplementedError, following +Python's standard practice for security-deprecated APIs. + +CVE: CVE-2025-56005 + +Upstream-Status: Inactive-Upstream + +Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> +--- + ply/yacc.py | 72 +++++++++++++++++++++-------------------------------- + 1 file changed, 28 insertions(+), 44 deletions(-) + +diff --git a/ply/yacc.py b/ply/yacc.py +index 88188a1..5103566 100644 +--- a/ply/yacc.py ++++ b/ply/yacc.py +@@ -1998,31 +1998,15 @@ class LRTable(object): + return parsetab._lr_signature + + def read_pickle(self, filename): +- try: +- import cPickle as pickle +- except ImportError: +- import pickle +- +- if not os.path.exists(filename): +- raise ImportError +- +- in_f = open(filename, 'rb') +- +- tabversion = pickle.load(in_f) +- if tabversion != __tabversion__: +- raise VersionError('yacc table file version is out of date') +- self.lr_method = pickle.load(in_f) +- signature = pickle.load(in_f) +- self.lr_action = pickle.load(in_f) +- self.lr_goto = pickle.load(in_f) +- productions = pickle.load(in_f) +- +- self.lr_productions = [] +- for p in productions: +- self.lr_productions.append(MiniProduction(*p)) +- +- in_f.close() +- return signature ++ import warnings ++ warnings.warn( ++ "read_pickle() is deprecated and disabled due to security vulnerability CVE-2025-56005. " ++ "Pickle deserialization can lead to arbitrary code execution. " ++ "This function is no longer supported.", ++ DeprecationWarning, ++ stacklevel=2 ++ ) ++ raise NotImplementedError("read_pickle() is disabled for security reasons (CVE-2025-56005)") + + # Bind all production function names to callable objects in pdict + def bind_callables(self, pdict): +@@ -2845,27 +2829,19 @@ del _lr_goto_items + # pickle_table() + # + # This function pickles the LR parsing tables to a supplied file object ++ # DEPRECATED: Disabled due to CVE-2025-56005 + # ----------------------------------------------------------------------------- + + def pickle_table(self, filename, signature=''): +- try: +- import cPickle as pickle +- except ImportError: +- import pickle +- with open(filename, 'wb') as outf: +- pickle.dump(__tabversion__, outf, pickle_protocol) +- pickle.dump(self.lr_method, outf, pickle_protocol) +- pickle.dump(signature, outf, pickle_protocol) +- pickle.dump(self.lr_action, outf, pickle_protocol) +- pickle.dump(self.lr_goto, outf, pickle_protocol) +- +- outp = [] +- for p in self.lr_productions: +- if p.func: +- outp.append((p.str, p.name, p.len, p.func, os.path.basename(p.file), p.line)) +- else: +- outp.append((str(p), p.name, p.len, None, None, None)) +- pickle.dump(outp, outf, pickle_protocol) ++ import warnings ++ warnings.warn( ++ "pickle_table() is deprecated and disabled due to security vulnerability CVE-2025-56005. " ++ "Pickle serialization can lead to arbitrary code execution when deserialized. " ++ "This function is no longer supported.", ++ DeprecationWarning, ++ stacklevel=2 ++ ) ++ raise NotImplementedError("pickle_table() is disabled for security reasons (CVE-2025-56005)") + + # ----------------------------------------------------------------------------- + # === INTROSPECTION === +@@ -3225,7 +3201,15 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star + + # If pickling is enabled, table files are not created + if picklefile: +- write_tables = 0 ++ import warnings ++ warnings.warn( ++ "The 'picklefile' parameter is deprecated and disabled due to security vulnerability CVE-2025-56005. " ++ "Pickle deserialization can lead to arbitrary code execution. " ++ "The parameter will be ignored and standard table files will be used instead.", ++ DeprecationWarning, ++ stacklevel=2 ++ ) ++ picklefile = None + + if errorlog is None: + errorlog = PlyLogger(sys.stderr) +-- +2.34.1 + diff --git a/meta/recipes-devtools/python/python3-ply_3.11.bb b/meta/recipes-devtools/python/python3-ply_3.11.bb index a05bd6702d..41bcac2be8 100644 --- a/meta/recipes-devtools/python/python3-ply_3.11.bb +++ b/meta/recipes-devtools/python/python3-ply_3.11.bb @@ -8,6 +8,10 @@ LIC_FILES_CHKSUM = "file://README.md;beginline=5;endline=32;md5=f5ee5c355c0e6719 SRC_URI[md5sum] = "6465f602e656455affcd7c5734c638f8" SRC_URI[sha256sum] = "00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3" +SRC_URI += " \ + file://CVE-2025-56005.patch \ +" + inherit pypi setuptools3 RDEPENDS:${PN}:class-target += "\ -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 2026-04-09 6:16 ` [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 jinfeng.wang.cn @ 2026-04-24 6:45 ` Yoann Congal 2026-04-27 6:20 ` Chen, Libo (CN) 0 siblings, 1 reply; 23+ messages in thread From: Yoann Congal @ 2026-04-24 6:45 UTC (permalink / raw) To: Jinfeng.Wang.CN, openembedded-core On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Libo Chen <libo.chen.cn@windriver.com> > > According to [1], An undocumented and unsafe feature in the PLY (Python > Lex-Yacc) library 3.11 allows Remote Code Execution (RCE) via the > `picklefile` parameter in the `yacc()` function. This parameter accepts > a `.pkl` file that is deserialized with `pickle.load()` without > validation. Because `pickle` allows execution of embedded code via > `__reduce__()`, an attacker can achieve code execution by passing a > malicious pickle file. The parameter is not mentioned in official > documentation or the GitHub repository, yet it is active in the PyPI > version. This introduces a stealthy backdoor and persistence risk. > > [1] https://nvd.nist.gov/vuln/detail/CVE-2025-56005 > > Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- > .../python/python3-ply/CVE-2025-56005.patch | 125 ++++++++++++++++++ > .../python/python3-ply_3.11.bb | 4 + > 2 files changed, 129 insertions(+) > create mode 100644 meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch > > diff --git a/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch b/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch > new file mode 100644 > index 0000000000..3f1e62b766 > --- /dev/null > +++ b/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch > @@ -0,0 +1,125 @@ > +From bfaebcc33a5af77f2701581638aa31a1bf918302 Mon Sep 17 00:00:00 2001 > +From: Libo Chen <libo.chen.cn@windriver.com> > +Date: Tue, 27 Jan 2026 13:58:57 +0800 > +Subject: [PATCH] python3-ply: fix CVE-2025-56005 > + > +Deprecate and disable the unsafe picklefile parameter and related > +pickle serialization/deserialization functions to prevent RCE attacks. > + > +The picklefile parameter in yacc() now issues a DeprecationWarning > +and is ignored. The read_pickle() and pickle_table() methods are > +stubbed out to issue warnings and raise NotImplementedError, following > +Python's standard practice for security-deprecated APIs. > + > +CVE: CVE-2025-56005 > + > +Upstream-Status: Inactive-Upstream > + > +Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> Hello, The status of this patch is not clear: It is not mentionned in the NVD report you linked. And there is an argument to reject the CVE: https://github.com/tom025/ply_exploit_rejection/blob/main/README.md In doubt (such as this), I'd rather leave the CVE applicable and let downstream users that uses impacted code decide for themselves how they want to handle this CVE. > +--- > + ply/yacc.py | 72 +++++++++++++++++++++-------------------------------- > + 1 file changed, 28 insertions(+), 44 deletions(-) > + > +diff --git a/ply/yacc.py b/ply/yacc.py > +index 88188a1..5103566 100644 > +--- a/ply/yacc.py > ++++ b/ply/yacc.py > +@@ -1998,31 +1998,15 @@ class LRTable(object): > + return parsetab._lr_signature > + > + def read_pickle(self, filename): > +- try: > +- import cPickle as pickle > +- except ImportError: > +- import pickle > +- > +- if not os.path.exists(filename): > +- raise ImportError > +- > +- in_f = open(filename, 'rb') > +- > +- tabversion = pickle.load(in_f) > +- if tabversion != __tabversion__: > +- raise VersionError('yacc table file version is out of date') > +- self.lr_method = pickle.load(in_f) > +- signature = pickle.load(in_f) > +- self.lr_action = pickle.load(in_f) > +- self.lr_goto = pickle.load(in_f) > +- productions = pickle.load(in_f) > +- > +- self.lr_productions = [] > +- for p in productions: > +- self.lr_productions.append(MiniProduction(*p)) > +- > +- in_f.close() > +- return signature > ++ import warnings > ++ warnings.warn( > ++ "read_pickle() is deprecated and disabled due to security vulnerability CVE-2025-56005. " > ++ "Pickle deserialization can lead to arbitrary code execution. " > ++ "This function is no longer supported.", > ++ DeprecationWarning, > ++ stacklevel=2 > ++ ) > ++ raise NotImplementedError("read_pickle() is disabled for security reasons (CVE-2025-56005)") And, also, this is quite a breaking change for a stable user using this feature. So, I can't accept this one. Sorry. > + > + # Bind all production function names to callable objects in pdict > + def bind_callables(self, pdict): > +@@ -2845,27 +2829,19 @@ del _lr_goto_items > + # pickle_table() > + # > + # This function pickles the LR parsing tables to a supplied file object > ++ # DEPRECATED: Disabled due to CVE-2025-56005 > + # ----------------------------------------------------------------------------- > + > + def pickle_table(self, filename, signature=''): > +- try: > +- import cPickle as pickle > +- except ImportError: > +- import pickle > +- with open(filename, 'wb') as outf: > +- pickle.dump(__tabversion__, outf, pickle_protocol) > +- pickle.dump(self.lr_method, outf, pickle_protocol) > +- pickle.dump(signature, outf, pickle_protocol) > +- pickle.dump(self.lr_action, outf, pickle_protocol) > +- pickle.dump(self.lr_goto, outf, pickle_protocol) > +- > +- outp = [] > +- for p in self.lr_productions: > +- if p.func: > +- outp.append((p.str, p.name, p.len, p.func, os.path.basename(p.file), p.line)) > +- else: > +- outp.append((str(p), p.name, p.len, None, None, None)) > +- pickle.dump(outp, outf, pickle_protocol) > ++ import warnings > ++ warnings.warn( > ++ "pickle_table() is deprecated and disabled due to security vulnerability CVE-2025-56005. " > ++ "Pickle serialization can lead to arbitrary code execution when deserialized. " > ++ "This function is no longer supported.", > ++ DeprecationWarning, > ++ stacklevel=2 > ++ ) > ++ raise NotImplementedError("pickle_table() is disabled for security reasons (CVE-2025-56005)") > + > + # ----------------------------------------------------------------------------- > + # === INTROSPECTION === > +@@ -3225,7 +3201,15 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star > + > + # If pickling is enabled, table files are not created > + if picklefile: > +- write_tables = 0 > ++ import warnings > ++ warnings.warn( > ++ "The 'picklefile' parameter is deprecated and disabled due to security vulnerability CVE-2025-56005. " > ++ "Pickle deserialization can lead to arbitrary code execution. " > ++ "The parameter will be ignored and standard table files will be used instead.", > ++ DeprecationWarning, > ++ stacklevel=2 > ++ ) > ++ picklefile = None > + > + if errorlog is None: > + errorlog = PlyLogger(sys.stderr) > +-- > +2.34.1 > + > diff --git a/meta/recipes-devtools/python/python3-ply_3.11.bb b/meta/recipes-devtools/python/python3-ply_3.11.bb > index a05bd6702d..41bcac2be8 100644 > --- a/meta/recipes-devtools/python/python3-ply_3.11.bb > +++ b/meta/recipes-devtools/python/python3-ply_3.11.bb > @@ -8,6 +8,10 @@ LIC_FILES_CHKSUM = "file://README.md;beginline=5;endline=32;md5=f5ee5c355c0e6719 > SRC_URI[md5sum] = "6465f602e656455affcd7c5734c638f8" > SRC_URI[sha256sum] = "00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3" > > +SRC_URI += " \ > + file://CVE-2025-56005.patch \ > +" > + > inherit pypi setuptools3 > > RDEPENDS:${PN}:class-target += "\ -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [OE-core] [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 2026-04-24 6:45 ` [OE-core] " Yoann Congal @ 2026-04-27 6:20 ` Chen, Libo (CN) 0 siblings, 0 replies; 23+ messages in thread From: Chen, Libo (CN) @ 2026-04-27 6:20 UTC (permalink / raw) To: yoann.congal@smile.fr, Wang, Jinfeng (CN), openembedded-core@lists.openembedded.org >-----Original Message----- >From: openembedded-core@lists.openembedded.org ><openembedded-core@lists.openembedded.org> On Behalf Of Yoann Congal via >lists.openembedded.org >Sent: Friday, April 24, 2026 2:45 PM >To: Wang, Jinfeng (CN) <Jinfeng.Wang.CN@windriver.com>; >openembedded-core@lists.openembedded.org >Subject: Re: [OE-core] [scarthgap][PATCH 04/12] python3-ply: fix >CVE-2025-56005 > >CAUTION: This email comes from a non Wind River email account! >Do not click links or open attachments unless you recognize the sender and know >the content is safe. > >On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org >Wang wrote: >> From: Libo Chen <libo.chen.cn@windriver.com> >> >> According to [1], An undocumented and unsafe feature in the PLY >> (Python >> Lex-Yacc) library 3.11 allows Remote Code Execution (RCE) via the >> `picklefile` parameter in the `yacc()` function. This parameter >> accepts a `.pkl` file that is deserialized with `pickle.load()` >> without validation. Because `pickle` allows execution of embedded code >> via `__reduce__()`, an attacker can achieve code execution by passing >> a malicious pickle file. The parameter is not mentioned in official >> documentation or the GitHub repository, yet it is active in the PyPI >> version. This introduces a stealthy backdoor and persistence risk. >> >> [1] https://nvd.nist.gov/vuln/detail/CVE-2025-56005 >> >> Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> >> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> >> --- >> .../python/python3-ply/CVE-2025-56005.patch | 125 >++++++++++++++++++ >> .../python/python3-ply_3.11.bb | 4 + >> 2 files changed, 129 insertions(+) >> create mode 100644 >> meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch >> >> diff --git >> a/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch >> b/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch >> new file mode 100644 >> index 0000000000..3f1e62b766 >> --- /dev/null >> +++ b/meta/recipes-devtools/python/python3-ply/CVE-2025-56005.patch >> @@ -0,0 +1,125 @@ >> +From bfaebcc33a5af77f2701581638aa31a1bf918302 Mon Sep 17 00:00:00 >> +2001 >> +From: Libo Chen <libo.chen.cn@windriver.com> >> +Date: Tue, 27 Jan 2026 13:58:57 +0800 >> +Subject: [PATCH] python3-ply: fix CVE-2025-56005 >> + >> +Deprecate and disable the unsafe picklefile parameter and related >> +pickle serialization/deserialization functions to prevent RCE attacks. >> + >> +The picklefile parameter in yacc() now issues a DeprecationWarning >> +and is ignored. The read_pickle() and pickle_table() methods are >> +stubbed out to issue warnings and raise NotImplementedError, >> +following Python's standard practice for security-deprecated APIs. >> + >> +CVE: CVE-2025-56005 >> + >> +Upstream-Status: Inactive-Upstream >> + >> +Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> > >Hello, > >The status of this patch is not clear: It is not mentionned in the NVD report you >linked. The upstream https://github.com/dabeaz/ply was archived by the owner on Dec 22, 2025. It is now read-only. So I could not submit my patch to the upstream and only mark it as "Upstream-Status: Inactive-Upstream" >And there is an argument to reject the CVE: >https://github.com/tom025/ply_exploit_rejection/blob/main/README.md I can reproduce this CVE. Here're my steps: 1) copy the source code from https://github.com/bohmiiidd/Undocumented-RCE-in-PLY/ to a python script ply-bug.py 2) set up a uv environment. Here's the configuration: [xyz/temp/ply-poc]$ cat /buildarea1/xyz/opt/pyenv/pyproject.toml [project] name = "pyenv" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.14.2" dependencies = [ "ply==3.11", ] [xyz/temp/ply-poc]$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal 3) run the python script ply-bug.py [xyz/temp/ply-poc]$ ls -l /tmp/pwned && cat /tmp/pwned ls: cannot access '/tmp/pwned': No such file or directory [xyz/temp/ply-poc]$ uv --directory /buildarea1/xyz/opt/pyenv run python /buildarea1/xyz/temp/ply-poc/ply-bug.py WARNING: yacc table file version is out of date WARNING: no p_error() function is defined Traceback (most recent call last): File "/buildarea1/xyz/temp/ply-poc/ply-bug.py", line 35, in <module> parser.parse('example') ~~~~~~~~~~~~^^^^^^^^^^^ File "/buildarea1/xyz/opt/pyenv/.venv/lib/python3.14/site-packages/ply/yacc.py", line 333, in parse return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc) ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/buildarea1/xyz/opt/pyenv/.venv/lib/python3.14/site-packages/ply/yacc.py", line 1018, in parseopt_notrack lexer = lex.lexer ^^^^^^^^^ AttributeError: module 'ply.lex' has no attribute 'lexer'. Did you mean: 'Lexer'? [xyz/temp/ply-poc]$ ls -l /tmp/pwned && cat /tmp/pwned -rw-r--r-- 1 xyz users 11 Apr 27 13:46 /tmp/pwned VULNERABLE > >In doubt (such as this), I'd rather leave the CVE applicable and let downstream >users that uses impacted code decide for themselves how they want to handle >this CVE. > >> +--- >> + ply/yacc.py | 72 >> ++++++++++++++++++++++-------------------------------- >> + 1 file changed, 28 insertions(+), 44 deletions(-) >> + >> +diff --git a/ply/yacc.py b/ply/yacc.py index 88188a1..5103566 100644 >> +--- a/ply/yacc.py >> ++++ b/ply/yacc.py >> +@@ -1998,31 +1998,15 @@ class LRTable(object): >> + return parsetab._lr_signature >> + >> + def read_pickle(self, filename): >> +- try: >> +- import cPickle as pickle >> +- except ImportError: >> +- import pickle >> +- >> +- if not os.path.exists(filename): >> +- raise ImportError >> +- >> +- in_f = open(filename, 'rb') >> +- >> +- tabversion = pickle.load(in_f) >> +- if tabversion != __tabversion__: >> +- raise VersionError('yacc table file version is out of date') >> +- self.lr_method = pickle.load(in_f) >> +- signature = pickle.load(in_f) >> +- self.lr_action = pickle.load(in_f) >> +- self.lr_goto = pickle.load(in_f) >> +- productions = pickle.load(in_f) >> +- >> +- self.lr_productions = [] >> +- for p in productions: >> +- self.lr_productions.append(MiniProduction(*p)) >> +- >> +- in_f.close() >> +- return signature >> ++ import warnings >> ++ warnings.warn( >> ++ "read_pickle() is deprecated and disabled due to security >vulnerability CVE-2025-56005. " >> ++ "Pickle deserialization can lead to arbitrary code execution. " >> ++ "This function is no longer supported.", >> ++ DeprecationWarning, >> ++ stacklevel=2 >> ++ ) >> ++ raise NotImplementedError("read_pickle() is disabled for >> ++ security reasons (CVE-2025-56005)") > >And, also, this is quite a breaking change for a stable user using this feature. > >So, I can't accept this one. Sorry. > >> + >> + # Bind all production function names to callable objects in pdict >> + def bind_callables(self, pdict): >> +@@ -2845,27 +2829,19 @@ del _lr_goto_items >> + # pickle_table() >> + # >> + # This function pickles the LR parsing tables to a supplied file >> +object >> ++ # DEPRECATED: Disabled due to CVE-2025-56005 >> + # >> + -------------------------------------------------------------------- >> + --------- >> + >> + def pickle_table(self, filename, signature=''): >> +- try: >> +- import cPickle as pickle >> +- except ImportError: >> +- import pickle >> +- with open(filename, 'wb') as outf: >> +- pickle.dump(__tabversion__, outf, pickle_protocol) >> +- pickle.dump(self.lr_method, outf, pickle_protocol) >> +- pickle.dump(signature, outf, pickle_protocol) >> +- pickle.dump(self.lr_action, outf, pickle_protocol) >> +- pickle.dump(self.lr_goto, outf, pickle_protocol) >> +- >> +- outp = [] >> +- for p in self.lr_productions: >> +- if p.func: >> +- outp.append((p.str, p.name, p.len, p.func, >os.path.basename(p.file), p.line)) >> +- else: >> +- outp.append((str(p), p.name, p.len, None, None, >None)) >> +- pickle.dump(outp, outf, pickle_protocol) >> ++ import warnings >> ++ warnings.warn( >> ++ "pickle_table() is deprecated and disabled due to security >vulnerability CVE-2025-56005. " >> ++ "Pickle serialization can lead to arbitrary code execution when >deserialized. " >> ++ "This function is no longer supported.", >> ++ DeprecationWarning, >> ++ stacklevel=2 >> ++ ) >> ++ raise NotImplementedError("pickle_table() is disabled for >> ++ security reasons (CVE-2025-56005)") >> + >> + # ----------------------------------------------------------------------------- >> + # === INTROSPECTION === >> +@@ -3225,7 +3201,15 @@ def yacc(method='LALR', debug=yaccdebug, >> +module=None, tabmodule=tab_module, star >> + >> + # If pickling is enabled, table files are not created >> + if picklefile: >> +- write_tables = 0 >> ++ import warnings >> ++ warnings.warn( >> ++ "The 'picklefile' parameter is deprecated and disabled due to >security vulnerability CVE-2025-56005. " >> ++ "Pickle deserialization can lead to arbitrary code execution. " >> ++ "The parameter will be ignored and standard table files will be >used instead.", >> ++ DeprecationWarning, >> ++ stacklevel=2 >> ++ ) >> ++ picklefile = None >> + >> + if errorlog is None: >> + errorlog = PlyLogger(sys.stderr) >> +-- >> +2.34.1 >> + >> diff --git a/meta/recipes-devtools/python/python3-ply_3.11.bb >> b/meta/recipes-devtools/python/python3-ply_3.11.bb >> index a05bd6702d..41bcac2be8 100644 >> --- a/meta/recipes-devtools/python/python3-ply_3.11.bb >> +++ b/meta/recipes-devtools/python/python3-ply_3.11.bb >> @@ -8,6 +8,10 @@ LIC_FILES_CHKSUM = >> "file://README.md;beginline=5;endline=32;md5=f5ee5c355c0e6719 >> SRC_URI[md5sum] = "6465f602e656455affcd7c5734c638f8" >> SRC_URI[sha256sum] = >"00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3" >> >> +SRC_URI += " \ >> + file://CVE-2025-56005.patch \ >> +" >> + >> inherit pypi setuptools3 >> >> RDEPENDS:${PN}:class-target += "\ > > >-- >Yoann Congal >Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 05/12] python3-pyasn1: fix CVE-2026-23490 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (3 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 06/12] python3-wheel: fix CVE-2026-24049 jinfeng.wang.cn ` (6 subsequent siblings) 11 siblings, 0 replies; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Jiaying Song <jiaying.song.cn@windriver.com> pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.2, a Denial-of-Service issue has been found that leads to memory exhaustion from malformed RELATIVE-OID with excessive continuation octets. This vulnerability is fixed in 0.6.2. References: https://nvd.nist.gov/vuln/detail/CVE-2026-23490 Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../recipes-devtools/python/python-pyasn1.inc | 3 +- .../python3-pyasn1/CVE-2026-23490.patch | 136 ++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 meta/recipes-devtools/python/python3-pyasn1/CVE-2026-23490.patch diff --git a/meta/recipes-devtools/python/python-pyasn1.inc b/meta/recipes-devtools/python/python-pyasn1.inc index 530ff1c7c3..96b4a3b52a 100644 --- a/meta/recipes-devtools/python/python-pyasn1.inc +++ b/meta/recipes-devtools/python/python-pyasn1.inc @@ -18,7 +18,8 @@ inherit ptest SRC_URI += " \ file://run-ptest \ - " + file://CVE-2026-23490.patch \ +" RDEPENDS:${PN}-ptest += " \ python3-pytest \ diff --git a/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-23490.patch b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-23490.patch new file mode 100644 index 0000000000..a79774003b --- /dev/null +++ b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-23490.patch @@ -0,0 +1,136 @@ +From d98d7bc91864e1e368d4849c26568e33c0dd0e27 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin <simon.pichugin@gmail.com> +Date: Wed, 28 Jan 2026 16:31:29 +0800 +Subject: [PATCH] Merge commit from fork + +Add limit of 20 continuation octets per OID arc to prevent a potential +memory exhaustion from excessive continuation bytes input. + +CVE: CVE-2026-23490 + +Upstream-Status: Backport [https://github.com/pyasn1/pyasn1/commit/3908f14422] + +Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> +--- + pyasn1/codec/ber/decoder.py | 13 ++++++- + tests/codec/ber/test_decoder.py | 65 +++++++++++++++++++++++++++++++++ + 2 files changed, 77 insertions(+), 1 deletion(-) + +diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py +index 7cc863d..be8ba65 100644 +--- a/pyasn1/codec/ber/decoder.py ++++ b/pyasn1/codec/ber/decoder.py +@@ -35,6 +35,10 @@ noValue = base.noValue + + SubstrateUnderrunError = error.SubstrateUnderrunError + ++# Maximum number of continuation octets (high-bit set) allowed per OID arc. ++# 20 octets allows up to 140-bit integers, supporting UUID-based OIDs ++MAX_OID_ARC_CONTINUATION_OCTETS = 20 ++ + + class AbstractPayloadDecoder(object): + protoComponent = None +@@ -431,7 +435,14 @@ class ObjectIdentifierPayloadDecoder(AbstractSimplePayloadDecoder): + # Construct subid from a number of octets + nextSubId = subId + subId = 0 ++ continuationOctetCount = 0 + while nextSubId >= 128: ++ continuationOctetCount += 1 ++ if continuationOctetCount > MAX_OID_ARC_CONTINUATION_OCTETS: ++ raise error.PyAsn1Error( ++ 'OID arc exceeds maximum continuation octets limit (%d) ' ++ 'at position %d' % (MAX_OID_ARC_CONTINUATION_OCTETS, index) ++ ) + subId = (subId << 7) + (nextSubId & 0x7F) + if index >= substrateLen: + raise error.SubstrateUnderrunError( +@@ -1872,7 +1883,7 @@ class StreamingDecoder(object): + :py:class:`~pyasn1.error.SubstrateUnderrunError` object indicating + insufficient BER/CER/DER serialization on input to fully recover ASN.1 + objects from it. +- ++ + In the latter case the caller is advised to ensure some more data in + the input stream, then call the iterator again. The decoder will resume + the decoding process using the newly arrived data. +diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py +index 3b97ce4..f033dfd 100644 +--- a/tests/codec/ber/test_decoder.py ++++ b/tests/codec/ber/test_decoder.py +@@ -450,6 +450,71 @@ class ObjectIdentifierDecoderTestCase(BaseTestCase): + ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47)) + ) == ((2, 999, 18446744073709551535184467440737095), null) + ++ def testExcessiveContinuationOctets(self): ++ """Test that OID arcs with excessive continuation octets are rejected.""" ++ # Create a payload with 25 continuation octets (exceeds 20 limit) ++ # 0x81 bytes are continuation octets, 0x01 terminates ++ malicious_payload = bytes([0x06, 26]) + bytes([0x81] * 25) + bytes([0x01]) ++ try: ++ decoder.decode(malicious_payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert 0, 'Excessive continuation octets tolerated' ++ ++ def testMaxAllowedContinuationOctets(self): ++ """Test that OID arcs at the maximum continuation octets limit work.""" ++ # Create a payload with exactly 20 continuation octets (at limit) ++ # This should succeed ++ payload = bytes([0x06, 21]) + bytes([0x81] * 20) + bytes([0x01]) ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ assert 0, 'Valid OID with 20 continuation octets rejected' ++ ++ def testOneOverContinuationLimit(self): ++ """Test boundary: 21 continuation octets (one over limit) is rejected.""" ++ payload = bytes([0x06, 22]) + bytes([0x81] * 21) + bytes([0x01]) ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert 0, '21 continuation octets tolerated (should be rejected)' ++ ++ def testExcessiveContinuationInSecondArc(self): ++ """Test that limit applies to subsequent arcs, not just the first.""" ++ # First arc: valid simple byte (0x55 = 85, decodes to arc 2.5) ++ # Second arc: excessive continuation octets ++ payload = bytes([0x06, 27]) + bytes([0x55]) + bytes([0x81] * 25) + bytes([0x01]) ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert 0, 'Excessive continuation in second arc tolerated' ++ ++ def testMultipleArcsAtLimit(self): ++ """Test multiple arcs each at the continuation limit work correctly.""" ++ # Two arcs, each with 20 continuation octets (both at limit) ++ arc1 = bytes([0x81] * 20) + bytes([0x01]) # 21 bytes ++ arc2 = bytes([0x81] * 20) + bytes([0x01]) # 21 bytes ++ payload = bytes([0x06, 42]) + arc1 + arc2 ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ assert 0, 'Multiple valid arcs at limit rejected' ++ ++ def testExcessiveContinuationWithMaxBytes(self): ++ """Test with 0xFF continuation bytes (maximum value, not just 0x81).""" ++ # 0xFF bytes are also continuation octets (high bit set) ++ malicious_payload = bytes([0x06, 26]) + bytes([0xFF] * 25) + bytes([0x01]) ++ try: ++ decoder.decode(malicious_payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert 0, 'Excessive 0xFF continuation octets tolerated' + + class RealDecoderTestCase(BaseTestCase): + def testChar(self): +-- +2.34.1 + -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 06/12] python3-wheel: fix CVE-2026-24049 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (4 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 05/12] python3-pyasn1: fix CVE-2026-23490 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 07/12] gnupg: fix CVE-2026-24882 jinfeng.wang.cn ` (5 subsequent siblings) 11 siblings, 0 replies; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Guocai He <guocai.he.cn@windriver.com> Backport patch to fix CVE-2026-24049 per reference [1] [2]. [1] https://security-tracker.debian.org/tracker/CVE-2026-24049 [2] https://github.com/pypa/wheel/commit/7a7d2de96b Signed-off-by: Guocai He <guocai.he.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../python/python3-wheel/CVE-2026-24049.patch | 73 +++++++++++++++++++ .../python/python3-wheel_0.42.0.bb | 2 + 2 files changed, 75 insertions(+) create mode 100644 meta/recipes-devtools/python/python3-wheel/CVE-2026-24049.patch diff --git a/meta/recipes-devtools/python/python3-wheel/CVE-2026-24049.patch b/meta/recipes-devtools/python/python3-wheel/CVE-2026-24049.patch new file mode 100644 index 0000000000..89a848c100 --- /dev/null +++ b/meta/recipes-devtools/python/python3-wheel/CVE-2026-24049.patch @@ -0,0 +1,73 @@ +From 363aef740d670c37d76b6fd86e2a28886de23f45 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi> +Date: Thu, 22 Jan 2026 01:41:14 +0200 +Subject: [PATCH] Fixed security issue around wheel unpack (#675) + +A maliciously crafted wheel could cause the permissions of a file outside the unpack tree to be altered. + +Fixes CVE-2026-24049. + +CVE: CVE-2026-24049 + +In test case, the API "run_command" is not defined and use "unpack" directly. + +Upstream-Status: Backport [https://github.com/pypa/wheel/commit/7a7d2de96b] + +Signed-off-by: Guocai He <guocai.he.cn@windriver.com> +--- + src/wheel/cli/unpack.py | 4 ++-- + tests/cli/test_unpack.py | 22 ++++++++++++++++++++++ + 2 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/src/wheel/cli/unpack.py b/src/wheel/cli/unpack.py +index d48840e..83dc742 100644 +--- a/src/wheel/cli/unpack.py ++++ b/src/wheel/cli/unpack.py +@@ -19,12 +19,12 @@ def unpack(path: str, dest: str = ".") -> None: + destination = Path(dest) / namever + print(f"Unpacking to: {destination}...", end="", flush=True) + for zinfo in wf.filelist: +- wf.extract(zinfo, destination) ++ target_path = Path(wf.extract(zinfo, destination)) + + # Set permissions to the same values as they were set in the archive + # We have to do this manually due to + # https://github.com/python/cpython/issues/59999 + permissions = zinfo.external_attr >> 16 & 0o777 +- destination.joinpath(zinfo.filename).chmod(permissions) ++ target_path.chmod(permissions) + + print("OK") +diff --git a/tests/cli/test_unpack.py b/tests/cli/test_unpack.py +index ae584af..96d1391 100644 +--- a/tests/cli/test_unpack.py ++++ b/tests/cli/test_unpack.py +@@ -34,3 +34,25 @@ def test_unpack_executable_bit(tmp_path): + unpack(str(wheel_path), str(tmp_path)) + assert not script_path.is_dir() + assert stat.S_IMODE(script_path.stat().st_mode) == 0o755 ++ ++@pytest.mark.skipif( ++ platform.system() == "Windows", reason="Windows does not support chmod()" ++) ++def test_chmod_outside_unpack_tree(tmp_path_factory: TempPathFactory) -> None: ++ wheel_path = tmp_path_factory.mktemp("build") / "test-1.0-py3-none-any.whl" ++ with WheelFile(wheel_path, "w") as wf: ++ wf.writestr( ++ "test-1.0.dist-info/METADATA", ++ "Metadata-Version: 2.4\nName: test\nVersion: 1.0\n", ++ ) ++ wf.writestr("../../system-file", b"malicious data") ++ ++ extract_root_path = tmp_path_factory.mktemp("extract") ++ system_file = extract_root_path / "system-file" ++ extract_path = extract_root_path / "subdir" ++ system_file.write_bytes(b"important data") ++ system_file.chmod(0o755) ++ unpack(str(wheel_path), str(extract_path)) ++ ++ assert system_file.read_bytes() == b"important data" ++ assert stat.S_IMODE(system_file.stat().st_mode) == 0o755 +-- +2.34.1 + diff --git a/meta/recipes-devtools/python/python3-wheel_0.42.0.bb b/meta/recipes-devtools/python/python3-wheel_0.42.0.bb index 807888e6c0..934f258a93 100644 --- a/meta/recipes-devtools/python/python3-wheel_0.42.0.bb +++ b/meta/recipes-devtools/python/python3-wheel_0.42.0.bb @@ -8,6 +8,8 @@ SRC_URI[sha256sum] = "c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7cee inherit python_flit_core pypi +SRC_URI += "file://CVE-2026-24049.patch" + BBCLASSEXTEND = "native nativesdk" # This used to use the bootstrap install which didn't compile. Until we bump the -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 07/12] gnupg: fix CVE-2026-24882 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (5 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 06/12] python3-wheel: fix CVE-2026-24049 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 08/12] libxml2: Fix CVE-2026-1757 jinfeng.wang.cn ` (4 subsequent siblings) 11 siblings, 0 replies; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Guocai He <guocai.he.cn@windriver.com> Backport patch to fix CVE-2026-24882 per reference [1] [2]. [1] https://security-tracker.debian.org/tracker/CVE-2026-24882 [2] https://dev.gnupg.org/T8045 Signed-off-by: Guocai He <guocai.he.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../gnupg/gnupg/CVE-2026-24882-0001.patch | 70 +++++++++++++++++++ .../gnupg/gnupg/CVE-2026-24882-0002.patch | 47 +++++++++++++ meta/recipes-support/gnupg/gnupg_2.4.8.bb | 2 + 3 files changed, 119 insertions(+) create mode 100644 meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0001.patch create mode 100644 meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0002.patch diff --git a/meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0001.patch b/meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0001.patch new file mode 100644 index 0000000000..6e6d44c372 --- /dev/null +++ b/meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0001.patch @@ -0,0 +1,70 @@ +From d07e2f19134129d59014fe181642cd122dc2e29f Mon Sep 17 00:00:00 2001 +From: Werner Koch <wk@gnupg.org> +Date: Mon, 26 Jan 2026 11:13:44 +0100 +Subject: [PATCH 1/2] tpm: Fix possible buffer overflow in PKDECRYPT + +* tpm2d/tpm2.c (tpm2_ecc_decrypt): Bail out on too long CIPHERTEXT. +(tpm2_rsa_decrypt): Ditto. +-- + +Cherry pick master commit of: + 93fa34d9a346020355cd51d54102d30d4f177323 + +GnuPG-bug-id: 8045 +Co-authored-by: NIIBE Yutaka <gniibe@fsij.org> +Reported-by: OpenAI Security Research + +CVE: CVE-2026-24882 +Upstream-Status: Backport [https://github.com/gpg/gnupg/commit/01c130031] + +Signed-off-by: Guocai He <guocai.he.cn@windriver.com> +--- + tpm2d/tpm2.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/tpm2d/tpm2.c b/tpm2d/tpm2.c +index 3e908dd..cd0347c 100644 +--- a/tpm2d/tpm2.c ++++ b/tpm2d/tpm2.c +@@ -917,10 +917,20 @@ tpm2_ecc_decrypt (ctrl_t ctrl, TSS_CONTEXT *tssc, TPM_HANDLE key, + size_t len; + int ret; + ++#if defined(TPM2_MAX_ECC_KEY_BYTES) /* Intel stack */ ++ if (ciphertext_len > 2*TPM2_MAX_ECC_KEY_BYTES + 1) ++ return GPG_ERR_TOO_LARGE; ++#elif defined(MAX_ECC_KEY_BYTES) /* IBM stack */ ++ if (ciphertext_len > 2*MAX_ECC_KEY_BYTES + 1) ++ return GPG_ERR_TOO_LARGE; ++#else ++# error TMP2 header are not correctly installed ++#endif ++ + /* This isn't really a decryption per se. The ciphertext actually + * contains an EC Point which we must multiply by the private key number. + * +- * The reason is to generate a diffe helman agreement on a shared ++ * The reason is to generate a diffie-hellman agreement on a shared + * point. This shared point is then used to generate the per + * session encryption key. + */ +@@ -976,6 +986,16 @@ tpm2_rsa_decrypt (ctrl_t ctrl, TSS_CONTEXT *tssc, TPM_HANDLE key, + TPM_HANDLE ah; + char *auth; + ++#if defined(TPM2_MAX_RSA_KEY_BYTES) /* Intel stack */ ++ if (ciphertext_len > TPM2_MAX_RSA_KEY_BYTES) ++ return GPG_ERR_TOO_LARGE; ++#elif defined(MAX_RSA_KEY_BYTES) /* IBM stack */ ++ if (ciphertext_len > MAX_RSA_KEY_BYTES) ++ return GPG_ERR_TOO_LARGE; ++#else ++# error TMP2 header are not correctly installed ++#endif ++ + inScheme.scheme = TPM_ALG_RSAES; + /* + * apparent gcrypt error: occasionally rsa ciphertext will +-- +2.34.1 + diff --git a/meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0002.patch b/meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0002.patch new file mode 100644 index 0000000000..2e872ea491 --- /dev/null +++ b/meta/recipes-support/gnupg/gnupg/CVE-2026-24882-0002.patch @@ -0,0 +1,47 @@ +From e8eaa9bf018d3276d613f371207c91c1ffa3e16c Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka <gniibe@fsij.org> +Date: Thu, 12 Feb 2026 11:51:17 +0900 +Subject: [PATCH 2/2] agent: Fix the regression in pkdecrypt with TPM RSA. + +* agent/divert-tpm2.c (divert_tpm2_pkdecrypt): Care about additional +0x00. + +-- + +Cherry pick master commit of: + 6eed3959303c81c9699fe9273030e480732f72be + +GnuPG-bug-id: 8045 +Signed-off-by: NIIBE Yutaka <gniibe@fsij.org> + +CVE: CVE-2026-24882 +Upstream-Status: Backport [https://github.com/gpg/gnupg/commit/555a9f5b3] + +Signed-off-by: Guocai He <guocai.he.cn@windriver.com> +--- + agent/divert-tpm2.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/agent/divert-tpm2.c b/agent/divert-tpm2.c +index 2496d09..5b5bd14 100644 +--- a/agent/divert-tpm2.c ++++ b/agent/divert-tpm2.c +@@ -135,6 +135,15 @@ divert_tpm2_pkdecrypt (ctrl_t ctrl, + if (!smatch (&s, n, "a")) + return gpg_error (GPG_ERR_UNKNOWN_SEXP); + n = snext (&s); ++ /* NOTE: gpg-agent protocol uses signed integer for RSA (%m in ++ * MPI), where 0x00 is added when the MSB is 1. TPM2 uses ++ * unsigned integer. We need to remove this 0x00, or else ++ * it may result GPG_ERR_TOO_LARGE in tpm2daemon. */ ++ if (!*s && (n&1)) ++ { ++ s++; ++ n--; ++ } + } + else if (smatch (&s, n, "ecdh")) + { +-- +2.34.1 + diff --git a/meta/recipes-support/gnupg/gnupg_2.4.8.bb b/meta/recipes-support/gnupg/gnupg_2.4.8.bb index 2d27f4454e..6a865ed57d 100644 --- a/meta/recipes-support/gnupg/gnupg_2.4.8.bb +++ b/meta/recipes-support/gnupg/gnupg_2.4.8.bb @@ -19,6 +19,8 @@ SRC_URI = "${GNUPG_MIRROR}/${BPN}/${BPN}-${PV}.tar.bz2 \ file://0004-autogen.sh-fix-find-version-for-beta-checking.patch \ file://0001-Woverride-init-is-not-needed-with-gcc-9.patch \ file://CVE-2025-68973.patch \ + file://CVE-2026-24882-0001.patch \ + file://CVE-2026-24882-0002.patch \ " SRC_URI:append:class-native = " file://0001-configure.ac-use-a-custom-value-for-the-location-of-.patch \ file://relocate.patch" -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 08/12] libxml2: Fix CVE-2026-1757 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (6 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 07/12] gnupg: fix CVE-2026-24882 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 jinfeng.wang.cn ` (3 subsequent siblings) 11 siblings, 0 replies; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Mingli Yu <mingli.yu@windriver.com> Backport patch [1] to fix CVE-2026-1757. The shell is refactored [2], so backport the related code from shell.c to debugXML.c. [1] https://gitlab.gnome.org/GNOME/libxml2/-/commit/160c8a43 [2] https://gitlab.gnome.org/GNOME/libxml2/-/commit/1341deac Signed-off-by: Mingli Yu <mingli.yu@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../libxml/libxml2/CVE-2026-1757.patch | 49 +++++++++++++++++++ meta/recipes-core/libxml/libxml2_2.12.10.bb | 1 + 2 files changed, 50 insertions(+) create mode 100644 meta/recipes-core/libxml/libxml2/CVE-2026-1757.patch diff --git a/meta/recipes-core/libxml/libxml2/CVE-2026-1757.patch b/meta/recipes-core/libxml/libxml2/CVE-2026-1757.patch new file mode 100644 index 0000000000..b6e6373ab0 --- /dev/null +++ b/meta/recipes-core/libxml/libxml2/CVE-2026-1757.patch @@ -0,0 +1,49 @@ +From bbe186902eddca01cc2049780a1d1a37937d3862 Mon Sep 17 00:00:00 2001 +From: Mingli Yu <mingli.yu@windriver.com> +Date: Wed, 25 Feb 2026 16:16:14 +0800 +Subject: [PATCH] shell: free cmdline before continue + +This patch frees the cmdline when it's not empty but it doesn't contain +any actual character. + +If the cmdline is just whitespaces or \r and \n, the loop continues +without freeing the cmdline string, so it's a leak. + +Fix #1009 + +Reference https://gitlab.gnome.org/GNOME/libxml2/-/commit/160c8a43 + +CVE: CVE-2026-1757 + +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxml2/-/commit/160c8a43] + +The shell is refactored [1], so backport the related code from shell.c +to debugXML.c. + +[1] https://gitlab.gnome.org/GNOME/libxml2/-/commit/1341deac + +Signed-off-by: Mingli Yu <mingli.yu@windriver.com> +--- + debugXML.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/debugXML.c b/debugXML.c +index 9d9618f..2d5c99d 100644 +--- a/debugXML.c ++++ b/debugXML.c +@@ -2866,8 +2866,11 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, + command[i++] = *cur++; + } + command[i] = 0; +- if (i == 0) ++ if (i == 0) { ++ free(cmdline); ++ cmdline = NULL; + continue; ++ } + + /* + * Parse the argument +-- +2.34.1 + diff --git a/meta/recipes-core/libxml/libxml2_2.12.10.bb b/meta/recipes-core/libxml/libxml2_2.12.10.bb index 25da11bd2d..2bfa78324f 100644 --- a/meta/recipes-core/libxml/libxml2_2.12.10.bb +++ b/meta/recipes-core/libxml/libxml2_2.12.10.bb @@ -30,6 +30,7 @@ SRC_URI += "http://www.w3.org/XML/Test/xmlts20130923.tar;subdir=${BP};name=testt file://CVE-2026-0992-01.patch \ file://CVE-2026-0992-02.patch \ file://CVE-2026-0992-03.patch \ + file://CVE-2026-1757.patch \ " SRC_URI[archive.sha256sum] = "c3d8c0c34aa39098f66576fe51969db12a5100b956233dc56506f7a8679be995" -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (7 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 08/12] libxml2: Fix CVE-2026-1757 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-24 7:36 ` [OE-core] " Yoann Congal 2026-04-09 6:16 ` [scarthgap][PATCH 10/12] busybox: fix CVE-2026-26157 and CVE-2026-26158 jinfeng.wang.cn ` (2 subsequent siblings) 11 siblings, 1 reply; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Jiaying Song <jiaying.song.cn@windriver.com> pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.3, the `pyasn1` library is vulnerable to a Denial of Service (DoS) attack caused by uncontrolled recursion when decoding ASN.1 data with deeply nested structures. An attacker can supply a crafted payload containing thousands of nested `SEQUENCE` (`0x30`) or `SET` (`0x31`) tags with "Indefinite Length" (`0x80`) markers. This forces the decoder to recursively call itself until the Python interpreter crashes with a `RecursionError` or consumes all available memory (OOM), crashing the host application. This is a distinct vulnerability from CVE-2026-23490 (which addressed integer overflows in OID decoding). The fix for CVE-2026-23490 (`MAX_OID_ARC_CONTINUATION_OCTETS`) does not mitigate this recursion issue. Version 0.6.3 fixes this specific issue. References: https://nvd.nist.gov/vuln/detail/CVE-2026-30922 Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../recipes-devtools/python/python-pyasn1.inc | 1 + .../python3-pyasn1/CVE-2026-30922.patch | 257 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch diff --git a/meta/recipes-devtools/python/python-pyasn1.inc b/meta/recipes-devtools/python/python-pyasn1.inc index 96b4a3b52a..d69cdf8877 100644 --- a/meta/recipes-devtools/python/python-pyasn1.inc +++ b/meta/recipes-devtools/python/python-pyasn1.inc @@ -19,6 +19,7 @@ inherit ptest SRC_URI += " \ file://run-ptest \ file://CVE-2026-23490.patch \ + file://CVE-2026-30922.patch \ " RDEPENDS:${PN}-ptest += " \ diff --git a/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch new file mode 100644 index 0000000000..7eceaa2595 --- /dev/null +++ b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch @@ -0,0 +1,257 @@ +From 85e901d1dacdcd17363cc2dd18a91cfb72363eeb Mon Sep 17 00:00:00 2001 +From: Simon Pichugin <simon.pichugin@gmail.com> +Date: Thu, 19 Mar 2026 17:11:40 +0800 +Subject: [PATCH] Merge commit from fork + +CVE: CVE-2026-30922 + +Upstream-Status: Backport [https://github.com/pyasn1/pyasn1/commit/25ad481c19] + +Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> +--- + pyasn1/codec/ber/decoder.py | 10 +++ + tests/codec/ber/test_decoder.py | 114 ++++++++++++++++++++++++++++++++ + tests/codec/cer/test_decoder.py | 22 ++++++ + tests/codec/der/test_decoder.py | 40 +++++++++++ + 4 files changed, 186 insertions(+) + +diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py +index be8ba65..da2a048 100644 +--- a/pyasn1/codec/ber/decoder.py ++++ b/pyasn1/codec/ber/decoder.py +@@ -38,6 +38,7 @@ SubstrateUnderrunError = error.SubstrateUnderrunError + # Maximum number of continuation octets (high-bit set) allowed per OID arc. + # 20 octets allows up to 140-bit integers, supporting UUID-based OIDs + MAX_OID_ARC_CONTINUATION_OCTETS = 20 ++MAX_NESTING_DEPTH = 100 + + + class AbstractPayloadDecoder(object): +@@ -1515,6 +1516,15 @@ class SingleItemDecoder(object): + decodeFun=None, substrateFun=None, + **options): + ++ _nestingLevel = options.get('_nestingLevel', 0) ++ ++ if _nestingLevel > MAX_NESTING_DEPTH: ++ raise error.PyAsn1Error( ++ 'ASN.1 structure nesting depth exceeds limit (%d)' % MAX_NESTING_DEPTH ++ ) ++ ++ options['_nestingLevel'] = _nestingLevel + 1 ++ + allowEoo = options.pop('allowEoo', False) + + if LOG: +diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py +index f033dfd..226381a 100644 +--- a/tests/codec/ber/test_decoder.py ++++ b/tests/codec/ber/test_decoder.py +@@ -1987,6 +1987,120 @@ class CompressedFilesTestCase(BaseTestCase): + finally: + os.remove(path) + ++class NestingDepthLimitTestCase(BaseTestCase): ++ """Test protection against deeply nested ASN.1 structures (CVE prevention).""" ++ ++ def testIndefLenSequenceNesting(self): ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" ++ # Each \x30\x80 opens a new indefinite-length SEQUENCE ++ payload = b'\x30\x80' * 200 ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' ++ ++ def testIndefLenSetNesting(self): ++ """Deeply nested indefinite-length SETs must raise PyAsn1Error.""" ++ # Each \x31\x80 opens a new indefinite-length SET ++ payload = b'\x31\x80' * 200 ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert False, 'Deeply nested indef-length SETs not rejected' ++ ++ def testDefiniteLenNesting(self): ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" ++ inner = b'\x05\x00' # NULL ++ for _ in range(200): ++ length = len(inner) ++ if length < 128: ++ inner = b'\x30' + bytes([length]) + inner ++ else: ++ length_bytes = length.to_bytes( ++ (length.bit_length() + 7) // 8, 'big') ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ ++ length_bytes + inner ++ try: ++ decoder.decode(inner) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' ++ ++ def testNestingUnderLimitWorks(self): ++ """Nesting within the limit must decode successfully.""" ++ inner = b'\x05\x00' # NULL ++ for _ in range(50): ++ length = len(inner) ++ if length < 128: ++ inner = b'\x30' + bytes([length]) + inner ++ else: ++ length_bytes = length.to_bytes( ++ (length.bit_length() + 7) // 8, 'big') ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ ++ length_bytes + inner ++ asn1Object, _ = decoder.decode(inner) ++ assert asn1Object is not None, 'Valid nested structure rejected' ++ ++ def testSiblingsDontIncreaseDepth(self): ++ """Sibling elements at the same level must not inflate depth count.""" ++ # SEQUENCE containing 200 INTEGER siblings - should decode fine ++ components = b'\x02\x01\x01' * 200 # 200 x INTEGER(1) ++ length = len(components) ++ length_bytes = length.to_bytes( ++ (length.bit_length() + 7) // 8, 'big') ++ payload = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ ++ length_bytes + components ++ asn1Object, _ = decoder.decode(payload) ++ assert asn1Object is not None, 'Siblings incorrectly rejected' ++ ++ def testErrorMessageContainsLimit(self): ++ """Error message must indicate the nesting depth limit.""" ++ payload = b'\x30\x80' * 200 ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error as exc: ++ assert 'nesting depth' in str(exc).lower(), \ ++ 'Error message missing depth info: %s' % exc ++ else: ++ assert False, 'Expected PyAsn1Error' ++ ++ def testNoRecursionError(self): ++ """Must raise PyAsn1Error, not RecursionError.""" ++ payload = b'\x30\x80' * 50000 ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ pass ++ except RecursionError: ++ assert False, 'Got RecursionError instead of PyAsn1Error' ++ ++ def testMixedNesting(self): ++ """Mixed SEQUENCE and SET nesting must be caught.""" ++ # Alternate SEQUENCE (0x30) and SET (0x31) with indef length ++ payload = b'' ++ for i in range(200): ++ payload += b'\x30\x80' if i % 2 == 0 else b'\x31\x80' ++ try: ++ decoder.decode(payload) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert False, 'Mixed nesting not rejected' ++ ++ def testWithSchema(self): ++ """Deeply nested structures must be caught even with schema.""" ++ payload = b'\x30\x80' * 200 ++ try: ++ decoder.decode(payload, asn1Spec=univ.Sequence()) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert False, 'Deeply nested with schema not rejected' + + class NonStreamingCompatibilityTestCase(BaseTestCase): + def setUp(self): +diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py +index 133affd..fbb1145 100644 +--- a/tests/codec/cer/test_decoder.py ++++ b/tests/codec/cer/test_decoder.py +@@ -363,6 +363,28 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): + assert s[0] == 3 + assert s[1][0] == univ.OctetString(hexValue='02010C') + ++class NestingDepthLimitTestCase(BaseTestCase): ++ """Test CER decoder protection against deeply nested structures.""" ++ ++ def testIndefLenNesting(self): ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" ++ payload = b'\x30\x80' * 200 ++ try: ++ decoder.decode(payload) ++ except PyAsn1Error: ++ pass ++ else: ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' ++ ++ def testNoRecursionError(self): ++ """Must raise PyAsn1Error, not RecursionError.""" ++ payload = b'\x30\x80' * 50000 ++ try: ++ decoder.decode(payload) ++ except PyAsn1Error: ++ pass ++ except RecursionError: ++ assert False, 'Got RecursionError instead of PyAsn1Error' + + suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py +index 5bc9deb..b0fa867 100644 +--- a/tests/codec/der/test_decoder.py ++++ b/tests/codec/der/test_decoder.py +@@ -361,6 +361,46 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): + assert s[0] == 3 + assert s[1][0] == univ.OctetString(hexValue='02010C') + ++class NestingDepthLimitTestCase(BaseTestCase): ++ """Test DER decoder protection against deeply nested structures.""" ++ ++ def testDefiniteLenNesting(self): ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" ++ inner = b'\x05\x00' # NULL ++ for _ in range(200): ++ length = len(inner) ++ if length < 128: ++ inner = b'\x30' + bytes([length]) + inner ++ else: ++ length_bytes = length.to_bytes( ++ (length.bit_length() + 7) // 8, 'big') ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ ++ length_bytes + inner ++ try: ++ decoder.decode(inner) ++ except PyAsn1Error: ++ pass ++ else: ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' ++ ++ def testNoRecursionError(self): ++ """Must raise PyAsn1Error, not RecursionError.""" ++ inner = b'\x05\x00' ++ for _ in range(200): ++ length = len(inner) ++ if length < 128: ++ inner = b'\x30' + bytes([length]) + inner ++ else: ++ length_bytes = length.to_bytes( ++ (length.bit_length() + 7) // 8, 'big') ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ ++ length_bytes + inner ++ try: ++ decoder.decode(inner) ++ except PyAsn1Error: ++ pass ++ except RecursionError: ++ assert False, 'Got RecursionError instead of PyAsn1Error' + + suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +-- +2.34.1 + -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 2026-04-09 6:16 ` [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 jinfeng.wang.cn @ 2026-04-24 7:36 ` Yoann Congal 2026-04-27 6:04 ` Song, Jiaying (CN) 0 siblings, 1 reply; 23+ messages in thread From: Yoann Congal @ 2026-04-24 7:36 UTC (permalink / raw) To: Jinfeng.Wang.CN, openembedded-core On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Jiaying Song <jiaying.song.cn@windriver.com> > > pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.3, the > `pyasn1` library is vulnerable to a Denial of Service (DoS) attack > caused by uncontrolled recursion when decoding ASN.1 data with deeply > nested structures. An attacker can supply a crafted payload containing > thousands of nested `SEQUENCE` (`0x30`) or `SET` (`0x31`) tags with > "Indefinite Length" (`0x80`) markers. This forces the decoder to > recursively call itself until the Python interpreter crashes with a > `RecursionError` or consumes all available memory (OOM), crashing the > host application. This is a distinct vulnerability from CVE-2026-23490 > (which addressed integer overflows in OID decoding). The fix for > CVE-2026-23490 (`MAX_OID_ARC_CONTINUATION_OCTETS`) does not mitigate > this recursion issue. Version 0.6.3 fixes this specific issue. > > References: > https://nvd.nist.gov/vuln/detail/CVE-2026-30922 > > Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- AFAIK, this CVE also apply to master (I'm not sure why it does not appear on https://valkyrie.yocto.io/pub/non-release/patchmetrics/) I'll hold this patch until "python3-pyasn1: upgrade 0.6.2 -> 0.6.3" merges. > .../recipes-devtools/python/python-pyasn1.inc | 1 + > .../python3-pyasn1/CVE-2026-30922.patch | 257 ++++++++++++++++++ > 2 files changed, 258 insertions(+) > create mode 100644 meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > > diff --git a/meta/recipes-devtools/python/python-pyasn1.inc b/meta/recipes-devtools/python/python-pyasn1.inc > index 96b4a3b52a..d69cdf8877 100644 > --- a/meta/recipes-devtools/python/python-pyasn1.inc > +++ b/meta/recipes-devtools/python/python-pyasn1.inc > @@ -19,6 +19,7 @@ inherit ptest > SRC_URI += " \ > file://run-ptest \ > file://CVE-2026-23490.patch \ > + file://CVE-2026-30922.patch \ > " > > RDEPENDS:${PN}-ptest += " \ > diff --git a/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > new file mode 100644 > index 0000000000..7eceaa2595 > --- /dev/null > +++ b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > @@ -0,0 +1,257 @@ > +From 85e901d1dacdcd17363cc2dd18a91cfb72363eeb Mon Sep 17 00:00:00 2001 > +From: Simon Pichugin <simon.pichugin@gmail.com> > +Date: Thu, 19 Mar 2026 17:11:40 +0800 > +Subject: [PATCH] Merge commit from fork > + > +CVE: CVE-2026-30922 > + > +Upstream-Status: Backport [https://github.com/pyasn1/pyasn1/commit/25ad481c19] > + > +Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> > +--- > + pyasn1/codec/ber/decoder.py | 10 +++ > + tests/codec/ber/test_decoder.py | 114 ++++++++++++++++++++++++++++++++ > + tests/codec/cer/test_decoder.py | 22 ++++++ > + tests/codec/der/test_decoder.py | 40 +++++++++++ > + 4 files changed, 186 insertions(+) > + > +diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py > +index be8ba65..da2a048 100644 > +--- a/pyasn1/codec/ber/decoder.py > ++++ b/pyasn1/codec/ber/decoder.py > +@@ -38,6 +38,7 @@ SubstrateUnderrunError = error.SubstrateUnderrunError > + # Maximum number of continuation octets (high-bit set) allowed per OID arc. > + # 20 octets allows up to 140-bit integers, supporting UUID-based OIDs > + MAX_OID_ARC_CONTINUATION_OCTETS = 20 > ++MAX_NESTING_DEPTH = 100 > + > + > + class AbstractPayloadDecoder(object): > +@@ -1515,6 +1516,15 @@ class SingleItemDecoder(object): > + decodeFun=None, substrateFun=None, > + **options): > + > ++ _nestingLevel = options.get('_nestingLevel', 0) > ++ > ++ if _nestingLevel > MAX_NESTING_DEPTH: > ++ raise error.PyAsn1Error( > ++ 'ASN.1 structure nesting depth exceeds limit (%d)' % MAX_NESTING_DEPTH > ++ ) > ++ > ++ options['_nestingLevel'] = _nestingLevel + 1 > ++ > + allowEoo = options.pop('allowEoo', False) > + > + if LOG: > +diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py > +index f033dfd..226381a 100644 > +--- a/tests/codec/ber/test_decoder.py > ++++ b/tests/codec/ber/test_decoder.py > +@@ -1987,6 +1987,120 @@ class CompressedFilesTestCase(BaseTestCase): > + finally: > + os.remove(path) > + > ++class NestingDepthLimitTestCase(BaseTestCase): > ++ """Test protection against deeply nested ASN.1 structures (CVE prevention).""" > ++ > ++ def testIndefLenSequenceNesting(self): > ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" > ++ # Each \x30\x80 opens a new indefinite-length SEQUENCE > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' > ++ > ++ def testIndefLenSetNesting(self): > ++ """Deeply nested indefinite-length SETs must raise PyAsn1Error.""" > ++ # Each \x31\x80 opens a new indefinite-length SET > ++ payload = b'\x31\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested indef-length SETs not rejected' > ++ > ++ def testDefiniteLenNesting(self): > ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" > ++ inner = b'\x05\x00' # NULL > ++ for _ in range(200): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ try: > ++ decoder.decode(inner) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' > ++ > ++ def testNestingUnderLimitWorks(self): > ++ """Nesting within the limit must decode successfully.""" > ++ inner = b'\x05\x00' # NULL > ++ for _ in range(50): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ asn1Object, _ = decoder.decode(inner) > ++ assert asn1Object is not None, 'Valid nested structure rejected' > ++ > ++ def testSiblingsDontIncreaseDepth(self): > ++ """Sibling elements at the same level must not inflate depth count.""" > ++ # SEQUENCE containing 200 INTEGER siblings - should decode fine > ++ components = b'\x02\x01\x01' * 200 # 200 x INTEGER(1) > ++ length = len(components) > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ payload = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + components > ++ asn1Object, _ = decoder.decode(payload) > ++ assert asn1Object is not None, 'Siblings incorrectly rejected' > ++ > ++ def testErrorMessageContainsLimit(self): > ++ """Error message must indicate the nesting depth limit.""" > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error as exc: > ++ assert 'nesting depth' in str(exc).lower(), \ > ++ 'Error message missing depth info: %s' % exc > ++ else: > ++ assert False, 'Expected PyAsn1Error' > ++ > ++ def testNoRecursionError(self): > ++ """Must raise PyAsn1Error, not RecursionError.""" > ++ payload = b'\x30\x80' * 50000 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ except RecursionError: > ++ assert False, 'Got RecursionError instead of PyAsn1Error' > ++ > ++ def testMixedNesting(self): > ++ """Mixed SEQUENCE and SET nesting must be caught.""" > ++ # Alternate SEQUENCE (0x30) and SET (0x31) with indef length > ++ payload = b'' > ++ for i in range(200): > ++ payload += b'\x30\x80' if i % 2 == 0 else b'\x31\x80' > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Mixed nesting not rejected' > ++ > ++ def testWithSchema(self): > ++ """Deeply nested structures must be caught even with schema.""" > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload, asn1Spec=univ.Sequence()) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested with schema not rejected' > + > + class NonStreamingCompatibilityTestCase(BaseTestCase): > + def setUp(self): > +diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py > +index 133affd..fbb1145 100644 > +--- a/tests/codec/cer/test_decoder.py > ++++ b/tests/codec/cer/test_decoder.py > +@@ -363,6 +363,28 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): > + assert s[0] == 3 > + assert s[1][0] == univ.OctetString(hexValue='02010C') > + > ++class NestingDepthLimitTestCase(BaseTestCase): > ++ """Test CER decoder protection against deeply nested structures.""" > ++ > ++ def testIndefLenNesting(self): > ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' > ++ > ++ def testNoRecursionError(self): > ++ """Must raise PyAsn1Error, not RecursionError.""" > ++ payload = b'\x30\x80' * 50000 > ++ try: > ++ decoder.decode(payload) > ++ except PyAsn1Error: > ++ pass > ++ except RecursionError: > ++ assert False, 'Got RecursionError instead of PyAsn1Error' > + > + suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) > + > +diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py > +index 5bc9deb..b0fa867 100644 > +--- a/tests/codec/der/test_decoder.py > ++++ b/tests/codec/der/test_decoder.py > +@@ -361,6 +361,46 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): > + assert s[0] == 3 > + assert s[1][0] == univ.OctetString(hexValue='02010C') > + > ++class NestingDepthLimitTestCase(BaseTestCase): > ++ """Test DER decoder protection against deeply nested structures.""" > ++ > ++ def testDefiniteLenNesting(self): > ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" > ++ inner = b'\x05\x00' # NULL > ++ for _ in range(200): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ try: > ++ decoder.decode(inner) > ++ except PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' > ++ > ++ def testNoRecursionError(self): > ++ """Must raise PyAsn1Error, not RecursionError.""" > ++ inner = b'\x05\x00' > ++ for _ in range(200): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ try: > ++ decoder.decode(inner) > ++ except PyAsn1Error: > ++ pass > ++ except RecursionError: > ++ assert False, 'Got RecursionError instead of PyAsn1Error' > + > + suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) > + > +-- > +2.34.1 > + -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [OE-core] [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 2026-04-24 7:36 ` [OE-core] " Yoann Congal @ 2026-04-27 6:04 ` Song, Jiaying (CN) 0 siblings, 0 replies; 23+ messages in thread From: Song, Jiaying (CN) @ 2026-04-27 6:04 UTC (permalink / raw) To: yoann.congal@smile.fr, Wang, Jinfeng (CN), openembedded-core@lists.openembedded.org Hi Yoann, This patch is for scarthgap where pyasn1 is at 0.5.1. The 0.6.2 -> 0.6.3 upgrade would only apply to master. According to https://github.com/pyasn1/pyasn1/security/advisories/GHSA-jr27-m4p2-rc6r , all versions <= 0.6.2 are affected, so for scarthgap, this patch is still needed to fix the CVE. Best regards, Jiaying. -----Original Message----- From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> On Behalf Of Yoann Congal via lists.openembedded.org Sent: Friday, April 24, 2026 3:36 PM To: Wang, Jinfeng (CN) <Jinfeng.Wang.CN@windriver.com>; openembedded-core@lists.openembedded.org Subject: Re: [OE-core] [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 CAUTION: This email comes from a non Wind River email account! Do not click links or open attachments unless you recognize the sender and know the content is safe. On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Jiaying Song <jiaying.song.cn@windriver.com> > > pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.3, the > `pyasn1` library is vulnerable to a Denial of Service (DoS) attack > caused by uncontrolled recursion when decoding ASN.1 data with deeply > nested structures. An attacker can supply a crafted payload containing > thousands of nested `SEQUENCE` (`0x30`) or `SET` (`0x31`) tags with > "Indefinite Length" (`0x80`) markers. This forces the decoder to > recursively call itself until the Python interpreter crashes with a > `RecursionError` or consumes all available memory (OOM), crashing the > host application. This is a distinct vulnerability from CVE-2026-23490 > (which addressed integer overflows in OID decoding). The fix for > CVE-2026-23490 (`MAX_OID_ARC_CONTINUATION_OCTETS`) does not mitigate > this recursion issue. Version 0.6.3 fixes this specific issue. > > References: > https://nvd.nist.gov/vuln/detail/CVE-2026-30922 > > Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- AFAIK, this CVE also apply to master (I'm not sure why it does not appear on https://valkyrie.yocto.io/pub/non-release/patchmetrics/) I'll hold this patch until "python3-pyasn1: upgrade 0.6.2 -> 0.6.3" merges. > .../recipes-devtools/python/python-pyasn1.inc | 1 + > .../python3-pyasn1/CVE-2026-30922.patch | 257 ++++++++++++++++++ > 2 files changed, 258 insertions(+) > create mode 100644 > meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > > diff --git a/meta/recipes-devtools/python/python-pyasn1.inc > b/meta/recipes-devtools/python/python-pyasn1.inc > index 96b4a3b52a..d69cdf8877 100644 > --- a/meta/recipes-devtools/python/python-pyasn1.inc > +++ b/meta/recipes-devtools/python/python-pyasn1.inc > @@ -19,6 +19,7 @@ inherit ptest > SRC_URI += " \ > file://run-ptest \ > file://CVE-2026-23490.patch \ > + file://CVE-2026-30922.patch \ > " > > RDEPENDS:${PN}-ptest += " \ > diff --git > a/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > new file mode 100644 > index 0000000000..7eceaa2595 > --- /dev/null > +++ b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch > @@ -0,0 +1,257 @@ > +From 85e901d1dacdcd17363cc2dd18a91cfb72363eeb Mon Sep 17 00:00:00 > +2001 > +From: Simon Pichugin <simon.pichugin@gmail.com> > +Date: Thu, 19 Mar 2026 17:11:40 +0800 > +Subject: [PATCH] Merge commit from fork > + > +CVE: CVE-2026-30922 > + > +Upstream-Status: Backport > +[https://github.com/pyasn1/pyasn1/commit/25ad481c19] > + > +Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> > +--- > + pyasn1/codec/ber/decoder.py | 10 +++ > + tests/codec/ber/test_decoder.py | 114 > +++++++++++++++++++++++++++++++++ tests/codec/cer/test_decoder.py | > +22 ++++++ tests/codec/der/test_decoder.py | 40 +++++++++++ > + 4 files changed, 186 insertions(+) > + > +diff --git a/pyasn1/codec/ber/decoder.py > +b/pyasn1/codec/ber/decoder.py index be8ba65..da2a048 100644 > +--- a/pyasn1/codec/ber/decoder.py > ++++ b/pyasn1/codec/ber/decoder.py > +@@ -38,6 +38,7 @@ SubstrateUnderrunError = > +error.SubstrateUnderrunError # Maximum number of continuation octets (high-bit set) allowed per OID arc. > + # 20 octets allows up to 140-bit integers, supporting UUID-based > +OIDs MAX_OID_ARC_CONTINUATION_OCTETS = 20 > ++MAX_NESTING_DEPTH = 100 > + > + > + class AbstractPayloadDecoder(object): > +@@ -1515,6 +1516,15 @@ class SingleItemDecoder(object): > + decodeFun=None, substrateFun=None, > + **options): > + > ++ _nestingLevel = options.get('_nestingLevel', 0) > ++ > ++ if _nestingLevel > MAX_NESTING_DEPTH: > ++ raise error.PyAsn1Error( > ++ 'ASN.1 structure nesting depth exceeds limit (%d)' % MAX_NESTING_DEPTH > ++ ) > ++ > ++ options['_nestingLevel'] = _nestingLevel + 1 > ++ > + allowEoo = options.pop('allowEoo', False) > + > + if LOG: > +diff --git a/tests/codec/ber/test_decoder.py > +b/tests/codec/ber/test_decoder.py index f033dfd..226381a 100644 > +--- a/tests/codec/ber/test_decoder.py > ++++ b/tests/codec/ber/test_decoder.py > +@@ -1987,6 +1987,120 @@ class CompressedFilesTestCase(BaseTestCase): > + finally: > + os.remove(path) > + > ++class NestingDepthLimitTestCase(BaseTestCase): > ++ """Test protection against deeply nested ASN.1 structures (CVE prevention).""" > ++ > ++ def testIndefLenSequenceNesting(self): > ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" > ++ # Each \x30\x80 opens a new indefinite-length SEQUENCE > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' > ++ > ++ def testIndefLenSetNesting(self): > ++ """Deeply nested indefinite-length SETs must raise PyAsn1Error.""" > ++ # Each \x31\x80 opens a new indefinite-length SET > ++ payload = b'\x31\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested indef-length SETs not rejected' > ++ > ++ def testDefiniteLenNesting(self): > ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" > ++ inner = b'\x05\x00' # NULL > ++ for _ in range(200): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ try: > ++ decoder.decode(inner) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' > ++ > ++ def testNestingUnderLimitWorks(self): > ++ """Nesting within the limit must decode successfully.""" > ++ inner = b'\x05\x00' # NULL > ++ for _ in range(50): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ asn1Object, _ = decoder.decode(inner) > ++ assert asn1Object is not None, 'Valid nested structure rejected' > ++ > ++ def testSiblingsDontIncreaseDepth(self): > ++ """Sibling elements at the same level must not inflate depth count.""" > ++ # SEQUENCE containing 200 INTEGER siblings - should decode fine > ++ components = b'\x02\x01\x01' * 200 # 200 x INTEGER(1) > ++ length = len(components) > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ payload = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + components > ++ asn1Object, _ = decoder.decode(payload) > ++ assert asn1Object is not None, 'Siblings incorrectly rejected' > ++ > ++ def testErrorMessageContainsLimit(self): > ++ """Error message must indicate the nesting depth limit.""" > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error as exc: > ++ assert 'nesting depth' in str(exc).lower(), \ > ++ 'Error message missing depth info: %s' % exc > ++ else: > ++ assert False, 'Expected PyAsn1Error' > ++ > ++ def testNoRecursionError(self): > ++ """Must raise PyAsn1Error, not RecursionError.""" > ++ payload = b'\x30\x80' * 50000 > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ except RecursionError: > ++ assert False, 'Got RecursionError instead of PyAsn1Error' > ++ > ++ def testMixedNesting(self): > ++ """Mixed SEQUENCE and SET nesting must be caught.""" > ++ # Alternate SEQUENCE (0x30) and SET (0x31) with indef length > ++ payload = b'' > ++ for i in range(200): > ++ payload += b'\x30\x80' if i % 2 == 0 else b'\x31\x80' > ++ try: > ++ decoder.decode(payload) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Mixed nesting not rejected' > ++ > ++ def testWithSchema(self): > ++ """Deeply nested structures must be caught even with schema.""" > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload, asn1Spec=univ.Sequence()) > ++ except error.PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested with schema not rejected' > + > + class NonStreamingCompatibilityTestCase(BaseTestCase): > + def setUp(self): > +diff --git a/tests/codec/cer/test_decoder.py > +b/tests/codec/cer/test_decoder.py index 133affd..fbb1145 100644 > +--- a/tests/codec/cer/test_decoder.py > ++++ b/tests/codec/cer/test_decoder.py > +@@ -363,6 +363,28 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): > + assert s[0] == 3 > + assert s[1][0] == univ.OctetString(hexValue='02010C') > + > ++class NestingDepthLimitTestCase(BaseTestCase): > ++ """Test CER decoder protection against deeply nested structures.""" > ++ > ++ def testIndefLenNesting(self): > ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" > ++ payload = b'\x30\x80' * 200 > ++ try: > ++ decoder.decode(payload) > ++ except PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' > ++ > ++ def testNoRecursionError(self): > ++ """Must raise PyAsn1Error, not RecursionError.""" > ++ payload = b'\x30\x80' * 50000 > ++ try: > ++ decoder.decode(payload) > ++ except PyAsn1Error: > ++ pass > ++ except RecursionError: > ++ assert False, 'Got RecursionError instead of PyAsn1Error' > + > + suite = > + unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) > + > +diff --git a/tests/codec/der/test_decoder.py > +b/tests/codec/der/test_decoder.py index 5bc9deb..b0fa867 100644 > +--- a/tests/codec/der/test_decoder.py > ++++ b/tests/codec/der/test_decoder.py > +@@ -361,6 +361,46 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): > + assert s[0] == 3 > + assert s[1][0] == univ.OctetString(hexValue='02010C') > + > ++class NestingDepthLimitTestCase(BaseTestCase): > ++ """Test DER decoder protection against deeply nested structures.""" > ++ > ++ def testDefiniteLenNesting(self): > ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" > ++ inner = b'\x05\x00' # NULL > ++ for _ in range(200): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ try: > ++ decoder.decode(inner) > ++ except PyAsn1Error: > ++ pass > ++ else: > ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' > ++ > ++ def testNoRecursionError(self): > ++ """Must raise PyAsn1Error, not RecursionError.""" > ++ inner = b'\x05\x00' > ++ for _ in range(200): > ++ length = len(inner) > ++ if length < 128: > ++ inner = b'\x30' + bytes([length]) + inner > ++ else: > ++ length_bytes = length.to_bytes( > ++ (length.bit_length() + 7) // 8, 'big') > ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ > ++ length_bytes + inner > ++ try: > ++ decoder.decode(inner) > ++ except PyAsn1Error: > ++ pass > ++ except RecursionError: > ++ assert False, 'Got RecursionError instead of PyAsn1Error' > + > + suite = > + unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) > + > +-- > +2.34.1 > + -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 10/12] busybox: fix CVE-2026-26157 and CVE-2026-26158 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (8 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 jinfeng.wang.cn 11 siblings, 0 replies; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Chen Qi <Qi.Chen@windriver.com> Backport patches to fix these two CVEs. Signed-off-by: Chen Qi <Qi.Chen@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- ...-hardlink-components-GNU-tar-does-th.patch | 201 ++++++++++++++++++ ...nsafe-components-from-hardlinks-not-.patch | 39 ++++ meta/recipes-core/busybox/busybox_1.36.1.bb | 2 + 3 files changed, 242 insertions(+) create mode 100644 meta/recipes-core/busybox/busybox/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch create mode 100644 meta/recipes-core/busybox/busybox/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch diff --git a/meta/recipes-core/busybox/busybox/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch b/meta/recipes-core/busybox/busybox/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch new file mode 100644 index 0000000000..2071703f35 --- /dev/null +++ b/meta/recipes-core/busybox/busybox/0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch @@ -0,0 +1,201 @@ +From cc7952a6da0eab6ffc6a98db4e0c9892c5c5ca53 Mon Sep 17 00:00:00 2001 +From: Denys Vlasenko <vda.linux@googlemail.com> +Date: Thu, 29 Jan 2026 11:48:02 +0100 +Subject: [PATCH 1/2] tar: strip unsafe hardlink components - GNU tar does the + same + +Defends against files like these (python reproducer): + +import tarfile +ti = tarfile.TarInfo("leak_hosts") +ti.type = tarfile.LNKTYPE +ti.linkname = "/etc/hosts" # or "../etc/hosts" or ".." +ti.size = 0 +with tarfile.open("/tmp/hardlink.tar", "w") as t: + t.addfile(ti) + +function old new delta +skip_unsafe_prefix - 127 +127 +get_header_tar 1752 1754 +2 +.rodata 106861 106856 -5 +unzip_main 2715 2706 -9 +strip_unsafe_prefix 102 18 -84 +------------------------------------------------------------------------------ +(add/remove: 1/0 grow/shrink: 1/3 up/down: 129/-98) Total: 31 bytes + +Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> + +CVE: CVE-2026-26157 +CVE: CVE-2026-26158 + +Upstream-Status: Backport [https://git.busybox.net/busybox/commit/archival?id=3fb6b31c716669e12f75a2accd31bb7685b1a1cb] + +Signed-off-by: Chen Qi <Qi.Chen@windriver.com> +--- + archival/libarchive/data_extract_all.c | 7 +++-- + archival/libarchive/get_header_tar.c | 11 ++++++-- + archival/libarchive/unsafe_prefix.c | 30 +++++++++++++++++---- + archival/libarchive/unsafe_symlink_target.c | 1 + + archival/tar.c | 2 +- + archival/unzip.c | 2 +- + include/bb_archive.h | 3 ++- + 7 files changed, 42 insertions(+), 14 deletions(-) + +diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c +index 8a69711c1..b84b960c4 100644 +--- a/archival/libarchive/data_extract_all.c ++++ b/archival/libarchive/data_extract_all.c +@@ -66,8 +66,8 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) + } + #endif + #if ENABLE_FEATURE_PATH_TRAVERSAL_PROTECTION +- /* Strip leading "/" and up to last "/../" path component */ +- dst_name = (char *)strip_unsafe_prefix(dst_name); ++ /* Skip leading "/" and past last ".." path component */ ++ dst_name = (char *)skip_unsafe_prefix(dst_name); + #endif + // ^^^ This may be a problem if some applets do need to extract absolute names. + // (Probably will need to invent ARCHIVE_ALLOW_UNSAFE_NAME flag). +@@ -185,8 +185,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) + + /* To avoid a directory traversal attack via symlinks, + * do not restore symlinks with ".." components +- * or symlinks starting with "/", unless a magic +- * envvar is set. ++ * or symlinks starting with "/" + * + * For example, consider a .tar created via: + * $ tar cvf bug.tar anything.txt +diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c +index cc6f3f0ad..1c40ecedb 100644 +--- a/archival/libarchive/get_header_tar.c ++++ b/archival/libarchive/get_header_tar.c +@@ -454,8 +454,15 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) + #endif + + /* Everything up to and including last ".." component is stripped */ +- overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name)); +-//TODO: do the same for file_header->link_target? ++ strip_unsafe_prefix(file_header->name); ++ if (file_header->link_target) { ++ /* GNU tar 1.34 examples: ++ * tar: Removing leading '/' from hard link targets ++ * tar: Removing leading '../' from hard link targets ++ * tar: Removing leading 'etc/../' from hard link targets ++ */ ++ strip_unsafe_prefix(file_header->link_target); ++ } + + /* Strip trailing '/' in directories */ + /* Must be done after mode is set as '/' is used to check if it's a directory */ +diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c +index 667081195..89a371a7f 100644 +--- a/archival/libarchive/unsafe_prefix.c ++++ b/archival/libarchive/unsafe_prefix.c +@@ -5,11 +5,11 @@ + #include "libbb.h" + #include "bb_archive.h" + +-const char* FAST_FUNC strip_unsafe_prefix(const char *str) ++const char* FAST_FUNC skip_unsafe_prefix(const char *str) + { + const char *cp = str; + while (1) { +- char *cp2; ++ const char *cp2; + if (*cp == '/') { + cp++; + continue; +@@ -22,10 +22,25 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) + cp += 3; + continue; + } +- cp2 = strstr(cp, "/../"); ++ cp2 = cp; ++ find_dotdot: ++ cp2 = strstr(cp2, "/.."); + if (!cp2) +- break; +- cp = cp2 + 4; ++ break; /* No (more) malicious components */ ++ ++ /* We found "/..something" */ ++ cp2 += 3; ++ if (*cp2 != '/') { ++ if (*cp2 == '\0') { ++ /* Trailing "/..": malicious, return "" */ ++ /* (causes harmless errors trying to create or hardlink a file named "") */ ++ return cp2; ++ } ++ /* "/..name" is not malicious, look for next "/.." */ ++ goto find_dotdot; ++ } ++ /* Found "/../": malicious, advance past it */ ++ cp = cp2 + 1; + } + if (cp != str) { + static smallint warned = 0; +@@ -37,3 +52,8 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) + } + return cp; + } ++ ++void FAST_FUNC strip_unsafe_prefix(char *str) ++{ ++ overlapping_strcpy(str, skip_unsafe_prefix(str)); ++} +diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c +index f8dc8033d..d764c89ab 100644 +--- a/archival/libarchive/unsafe_symlink_target.c ++++ b/archival/libarchive/unsafe_symlink_target.c +@@ -36,6 +36,7 @@ void FAST_FUNC create_links_from_list(llist_t *list) + *list->data ? "hard" : "sym", + list->data + 1, target + ); ++ /* Note: GNU tar 1.34 errors out only _after_ all links are (attempted to be) created */ + } + list = list->link; + } +diff --git a/archival/tar.c b/archival/tar.c +index 9de37592e..cf8c2d1f6 100644 +--- a/archival/tar.c ++++ b/archival/tar.c +@@ -475,7 +475,7 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state, + DBG("writeFileToTarball('%s')", fileName); + + /* Strip leading '/' and such (must be before memorizing hardlink's name) */ +- header_name = strip_unsafe_prefix(fileName); ++ header_name = skip_unsafe_prefix(fileName); + + if (header_name[0] == '\0') + return TRUE; +diff --git a/archival/unzip.c b/archival/unzip.c +index 691a2d81b..58442150b 100644 +--- a/archival/unzip.c ++++ b/archival/unzip.c +@@ -853,7 +853,7 @@ int unzip_main(int argc, char **argv) + unzip_skip(zip.fmt.extra_len); + + /* Guard against "/abspath", "/../" and similar attacks */ +- overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); ++ strip_unsafe_prefix(dst_fn); + + /* Filter zip entries */ + if (find_list_entry(zreject, dst_fn) +diff --git a/include/bb_archive.h b/include/bb_archive.h +index e0ef8fc4e..1dc77f31d 100644 +--- a/include/bb_archive.h ++++ b/include/bb_archive.h +@@ -202,7 +202,8 @@ char get_header_tar_xz(archive_handle_t *archive_handle) FAST_FUNC; + void seek_by_jump(int fd, off_t amount) FAST_FUNC; + void seek_by_read(int fd, off_t amount) FAST_FUNC; + +-const char *strip_unsafe_prefix(const char *str) FAST_FUNC; ++const char *skip_unsafe_prefix(const char *str) FAST_FUNC; ++void strip_unsafe_prefix(char *str) FAST_FUNC; + void create_or_remember_link(llist_t **link_placeholders, + const char *target, + const char *linkname, +-- +2.34.1 + diff --git a/meta/recipes-core/busybox/busybox/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch b/meta/recipes-core/busybox/busybox/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch new file mode 100644 index 0000000000..d79f2a259a --- /dev/null +++ b/meta/recipes-core/busybox/busybox/0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch @@ -0,0 +1,39 @@ +From c70673fad2b317cfaed2d1da98c5dfe0fedd9be0 Mon Sep 17 00:00:00 2001 +From: Radoslav Kolev <radoslav.kolev@suse.com> +Date: Mon, 16 Feb 2026 11:50:04 +0200 +Subject: [PATCH 2/2] tar: only strip unsafe components from hardlinks, not + symlinks + +commit 3fb6b31c7 introduced a check for unsafe components in +tar archive hardlinks, but it was being applied to symlinks too +which broke "Symlinks and hardlinks coexist" tar test. + +Signed-off-by: Radoslav Kolev <radoslav.kolev@suse.com> +Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> + +CVE: CVE-2026-26157 +CVE: CVE-2026-26158 + +Upstream-Status: Backport [https://git.busybox.net/busybox/commit/archival?id=599f5dd8fac390c18b79cba4c14c334957605dae] + +Signed-off-by: Chen Qi <Qi.Chen@windriver.com> +--- + archival/libarchive/get_header_tar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c +index 1c40ecedb..606d8067f 100644 +--- a/archival/libarchive/get_header_tar.c ++++ b/archival/libarchive/get_header_tar.c +@@ -455,7 +455,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) + + /* Everything up to and including last ".." component is stripped */ + strip_unsafe_prefix(file_header->name); +- if (file_header->link_target) { ++ if (file_header->link_target && !S_ISLNK(file_header->mode)) { + /* GNU tar 1.34 examples: + * tar: Removing leading '/' from hard link targets + * tar: Removing leading '../' from hard link targets +-- +2.34.1 + diff --git a/meta/recipes-core/busybox/busybox_1.36.1.bb b/meta/recipes-core/busybox/busybox_1.36.1.bb index d870e2ee10..dc162882e9 100644 --- a/meta/recipes-core/busybox/busybox_1.36.1.bb +++ b/meta/recipes-core/busybox/busybox_1.36.1.bb @@ -62,6 +62,8 @@ SRC_URI = "https://busybox.net/downloads/busybox-${PV}.tar.bz2;name=tarball \ file://CVE-2025-46394-01.patch \ file://CVE-2025-46394-02.patch \ file://CVE-2025-60876.patch \ + file://0001-tar-strip-unsafe-hardlink-components-GNU-tar-does-th.patch \ + file://0002-tar-only-strip-unsafe-components-from-hardlinks-not-.patch \ " SRC_URI:append:libc-musl = " file://musl.cfg " # TODO http://lists.busybox.net/pipermail/busybox/2023-January/090078.html -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (9 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 10/12] busybox: fix CVE-2026-26157 and CVE-2026-26158 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-24 8:10 ` [OE-core] " Yoann Congal 2026-04-09 6:16 ` [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 jinfeng.wang.cn 11 siblings, 1 reply; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Liyin Zhang <liyin.zhang.cn@windriver.com> Upgrade zlib from 1.3.1 to 1.3.2 to fix CVE-2026-27171. And delete patches included in this version. Reference: [https://nvd.nist.gov/vuln/detail/CVE-2026-27171] [https://git.openembedded.org/openembedded-core/commit/meta/recipes-core/zlib?id=af357536104e918aefbb2a2cb835c45eed690e88] Signed-off-by: Liyin Zhang <liyin.zhang.cn@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- ...configure-Pass-LDFLAGS-to-link-tests.patch | 78 ------------------- .../zlib/zlib/CVE-2026-27171.patch | 63 --------------- .../zlib/{zlib_1.3.1.bb => zlib_1.3.2.bb} | 4 +- 3 files changed, 1 insertion(+), 144 deletions(-) delete mode 100644 meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch delete mode 100644 meta/recipes-core/zlib/zlib/CVE-2026-27171.patch rename meta/recipes-core/zlib/{zlib_1.3.1.bb => zlib_1.3.2.bb} (87%) diff --git a/meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch b/meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch deleted file mode 100644 index 07b2cd3879..0000000000 --- a/meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch +++ /dev/null @@ -1,78 +0,0 @@ -Upstream-Status: Submitted [https://github.com/madler/zlib/pull/599] -Signed-off-by: Ross Burton <ross.burton@arm.com> - -From ea77f1f003a4d18b23cca703f3c824942863a1b4 Mon Sep 17 00:00:00 2001 -From: Khem Raj <raj.khem@gmail.com> -Date: Tue, 8 Mar 2022 22:38:47 -0800 -Subject: [PATCH] configure: Pass LDFLAGS to link tests - -LDFLAGS can contain critical flags without which linking wont succeed -therefore ensure that all configure tests involving link time checks are -using LDFLAGS on compiler commandline along with CFLAGS to ensure the -tests perform correctly. Without this some tests may fail resulting in -wrong confgure result, ending in miscompiling the package - -Signed-off-by: Khem Raj <raj.khem@gmail.com> - ---- - configure | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/configure b/configure -index c55098a..a7c6d72 100755 ---- a/configure -+++ b/configure -@@ -443,7 +443,7 @@ if test $shared -eq 1; then - echo Checking for shared library support... | tee -a configure.log - # we must test in two steps (cc then ld), required at least on SunOS 4.x - if try $CC -c $SFLAGS $test.c && -- try $LDSHARED $SFLAGS -o $test$shared_ext $test.o; then -+ try $LDSHARED $SFLAGS $LDFLAGS -o $test$shared_ext $test.o; then - echo Building shared library $SHAREDLIBV with $CC. | tee -a configure.log - elif test -z "$old_cc" -a -z "$old_cflags"; then - echo No shared library support. | tee -a configure.log -@@ -505,7 +505,7 @@ int main(void) { - } - EOF - fi -- if try $CC $CFLAGS -o $test $test.c; then -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then - sizet=`./$test` - echo "Checking for a pointer-size integer type..." $sizet"." | tee -a configure.log - CFLAGS="${CFLAGS} -DNO_SIZE_T=${sizet}" -@@ -539,7 +539,7 @@ int main(void) { - return 0; - } - EOF -- if try $CC $CFLAGS -o $test $test.c; then -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then - echo "Checking for fseeko... Yes." | tee -a configure.log - else - CFLAGS="${CFLAGS} -DNO_FSEEKO" -@@ -556,7 +556,7 @@ cat > $test.c <<EOF - #include <errno.h> - int main() { return strlen(strerror(errno)); } - EOF --if try $CC $CFLAGS -o $test $test.c; then -+if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then - echo "Checking for strerror... Yes." | tee -a configure.log - else - CFLAGS="${CFLAGS} -DNO_STRERROR" -@@ -663,7 +663,7 @@ int main() - return (mytest("Hello%d\n", 1)); - } - EOF -- if try $CC $CFLAGS -o $test $test.c; then -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then - echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log - - echo >> configure.log -@@ -753,7 +753,7 @@ int main() - } - EOF - -- if try $CC $CFLAGS -o $test $test.c; then -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then - echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log - - echo >> configure.log diff --git a/meta/recipes-core/zlib/zlib/CVE-2026-27171.patch b/meta/recipes-core/zlib/zlib/CVE-2026-27171.patch deleted file mode 100644 index e6a8a3eac5..0000000000 --- a/meta/recipes-core/zlib/zlib/CVE-2026-27171.patch +++ /dev/null @@ -1,63 +0,0 @@ -From f234bdf5c0f94b681312452fcd5e36968221fa04 Mon Sep 17 00:00:00 2001 -From: Mark Adler <git@madler.net> -Date: Sun, 21 Dec 2025 18:17:56 -0800 -Subject: [PATCH] Check for negative lengths in crc32_combine functions. - -Though zlib.h says that len2 must be non-negative, this avoids the -possibility of an accidental infinite loop. - -Upstream-Status: Backport [https://github.com/madler/zlib/commit/ba829a458576d1ff0f26fc7230c6de816d1f6a77] -CVE: CVE-2026-27171 - -Signed-off-by: Hugo SIMELIERE <hsimeliere.opensource@witekio.com> ---- - crc32.c | 4 ++++ - zlib.h | 4 ++-- - 2 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/crc32.c b/crc32.c -index 6c38f5c..33d8c79 100644 ---- a/crc32.c -+++ b/crc32.c -@@ -1019,6 +1019,8 @@ unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, - - /* ========================================================================= */ - uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { -+ if (len2 < 0) -+ return 0; - #ifdef DYNAMIC_CRC_TABLE - once(&made, make_crc_table); - #endif /* DYNAMIC_CRC_TABLE */ -@@ -1032,6 +1034,8 @@ uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { - - /* ========================================================================= */ - uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { -+ if (len2 < 0) -+ return 0; - #ifdef DYNAMIC_CRC_TABLE - once(&made, make_crc_table); - #endif /* DYNAMIC_CRC_TABLE */ -diff --git a/zlib.h b/zlib.h -index 8d4b932..8c7f8ac 100644 ---- a/zlib.h -+++ b/zlib.h -@@ -1758,14 +1758,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and -- len2. len2 must be non-negative. -+ len2. len2 must be non-negative, otherwise zero is returned. - */ - - /* - ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); - - Return the operator corresponding to length len2, to be used with -- crc32_combine_op(). len2 must be non-negative. -+ crc32_combine_op(). len2 must be non-negative, otherwise zero is returned. - */ - - ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); --- -2.43.0 - diff --git a/meta/recipes-core/zlib/zlib_1.3.1.bb b/meta/recipes-core/zlib/zlib_1.3.2.bb similarity index 87% rename from meta/recipes-core/zlib/zlib_1.3.1.bb rename to meta/recipes-core/zlib/zlib_1.3.2.bb index e42578fd7e..c7d59fdf78 100644 --- a/meta/recipes-core/zlib/zlib_1.3.1.bb +++ b/meta/recipes-core/zlib/zlib_1.3.2.bb @@ -8,13 +8,11 @@ LIC_FILES_CHKSUM = "file://zlib.h;beginline=6;endline=23;md5=5377232268e952e9ef6 # The source tarball needs to be .gz as only the .gz ends up in fossils/ SRC_URI = "https://zlib.net/${BP}.tar.gz \ - file://0001-configure-Pass-LDFLAGS-to-link-tests.patch \ file://run-ptest \ - file://CVE-2026-27171.patch \ " UPSTREAM_CHECK_URI = "http://zlib.net/" -SRC_URI[sha256sum] = "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23" +SRC_URI[sha256sum] = "bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16" # When a new release is made the previous release is moved to fossils/, so add this # to PREMIRRORS so it is also searched automatically. -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 2026-04-09 6:16 ` [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 jinfeng.wang.cn @ 2026-04-24 8:10 ` Yoann Congal 0 siblings, 0 replies; 23+ messages in thread From: Yoann Congal @ 2026-04-24 8:10 UTC (permalink / raw) To: Jinfeng.Wang.CN, openembedded-core On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Liyin Zhang <liyin.zhang.cn@windriver.com> > > Upgrade zlib from 1.3.1 to 1.3.2 to fix CVE-2026-27171. > And delete patches included in this version. > > Reference: > [https://nvd.nist.gov/vuln/detail/CVE-2026-27171] > [https://git.openembedded.org/openembedded-core/commit/meta/recipes-core/zlib?id=af357536104e918aefbb2a2cb835c45eed690e88] > > Signed-off-by: Liyin Zhang <liyin.zhang.cn@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- Please add the changelog (either by URL or spelt out) to commit message when sending an upgrade: I need to review it for stability. If this is a cherry-pick from master, keep the original commit message and add the backporting comments at the end. In this case, there are changes in this upgrade that do not look compatible with our stable policy: * Complete rewrite of cmake support. * Remove untgz from contrib. * Add zipAlreadyThere() to minizip zip.c to help avoid duplicates. * Add deflateUsed() function to get the used bits in the last byte. * Add a "G" option to force gzip, disabling transparency in gzread(). * Return all available uncompressed data on error in gzread.c. * Support non-blocking devices in the gz* routines. Either justify that none of the upgrade changes break anything or only backport the CVE patches. Regards, > ...configure-Pass-LDFLAGS-to-link-tests.patch | 78 ------------------- > .../zlib/zlib/CVE-2026-27171.patch | 63 --------------- > .../zlib/{zlib_1.3.1.bb => zlib_1.3.2.bb} | 4 +- > 3 files changed, 1 insertion(+), 144 deletions(-) > delete mode 100644 meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch > delete mode 100644 meta/recipes-core/zlib/zlib/CVE-2026-27171.patch > rename meta/recipes-core/zlib/{zlib_1.3.1.bb => zlib_1.3.2.bb} (87%) > > diff --git a/meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch b/meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch > deleted file mode 100644 > index 07b2cd3879..0000000000 > --- a/meta/recipes-core/zlib/zlib/0001-configure-Pass-LDFLAGS-to-link-tests.patch > +++ /dev/null > @@ -1,78 +0,0 @@ > -Upstream-Status: Submitted [https://github.com/madler/zlib/pull/599] > -Signed-off-by: Ross Burton <ross.burton@arm.com> > - > -From ea77f1f003a4d18b23cca703f3c824942863a1b4 Mon Sep 17 00:00:00 2001 > -From: Khem Raj <raj.khem@gmail.com> > -Date: Tue, 8 Mar 2022 22:38:47 -0800 > -Subject: [PATCH] configure: Pass LDFLAGS to link tests > - > -LDFLAGS can contain critical flags without which linking wont succeed > -therefore ensure that all configure tests involving link time checks are > -using LDFLAGS on compiler commandline along with CFLAGS to ensure the > -tests perform correctly. Without this some tests may fail resulting in > -wrong confgure result, ending in miscompiling the package > - > -Signed-off-by: Khem Raj <raj.khem@gmail.com> > - > ---- > - configure | 12 ++++++------ > - 1 file changed, 6 insertions(+), 6 deletions(-) > - > -diff --git a/configure b/configure > -index c55098a..a7c6d72 100755 > ---- a/configure > -+++ b/configure > -@@ -443,7 +443,7 @@ if test $shared -eq 1; then > - echo Checking for shared library support... | tee -a configure.log > - # we must test in two steps (cc then ld), required at least on SunOS 4.x > - if try $CC -c $SFLAGS $test.c && > -- try $LDSHARED $SFLAGS -o $test$shared_ext $test.o; then > -+ try $LDSHARED $SFLAGS $LDFLAGS -o $test$shared_ext $test.o; then > - echo Building shared library $SHAREDLIBV with $CC. | tee -a configure.log > - elif test -z "$old_cc" -a -z "$old_cflags"; then > - echo No shared library support. | tee -a configure.log > -@@ -505,7 +505,7 @@ int main(void) { > - } > - EOF > - fi > -- if try $CC $CFLAGS -o $test $test.c; then > -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then > - sizet=`./$test` > - echo "Checking for a pointer-size integer type..." $sizet"." | tee -a configure.log > - CFLAGS="${CFLAGS} -DNO_SIZE_T=${sizet}" > -@@ -539,7 +539,7 @@ int main(void) { > - return 0; > - } > - EOF > -- if try $CC $CFLAGS -o $test $test.c; then > -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then > - echo "Checking for fseeko... Yes." | tee -a configure.log > - else > - CFLAGS="${CFLAGS} -DNO_FSEEKO" > -@@ -556,7 +556,7 @@ cat > $test.c <<EOF > - #include <errno.h> > - int main() { return strlen(strerror(errno)); } > - EOF > --if try $CC $CFLAGS -o $test $test.c; then > -+if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then > - echo "Checking for strerror... Yes." | tee -a configure.log > - else > - CFLAGS="${CFLAGS} -DNO_STRERROR" > -@@ -663,7 +663,7 @@ int main() > - return (mytest("Hello%d\n", 1)); > - } > - EOF > -- if try $CC $CFLAGS -o $test $test.c; then > -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then > - echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log > - > - echo >> configure.log > -@@ -753,7 +753,7 @@ int main() > - } > - EOF > - > -- if try $CC $CFLAGS -o $test $test.c; then > -+ if try $CC $CFLAGS $LDFLAGS -o $test $test.c; then > - echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log > - > - echo >> configure.log > diff --git a/meta/recipes-core/zlib/zlib/CVE-2026-27171.patch b/meta/recipes-core/zlib/zlib/CVE-2026-27171.patch > deleted file mode 100644 > index e6a8a3eac5..0000000000 > --- a/meta/recipes-core/zlib/zlib/CVE-2026-27171.patch > +++ /dev/null > @@ -1,63 +0,0 @@ > -From f234bdf5c0f94b681312452fcd5e36968221fa04 Mon Sep 17 00:00:00 2001 > -From: Mark Adler <git@madler.net> > -Date: Sun, 21 Dec 2025 18:17:56 -0800 > -Subject: [PATCH] Check for negative lengths in crc32_combine functions. > - > -Though zlib.h says that len2 must be non-negative, this avoids the > -possibility of an accidental infinite loop. > - > -Upstream-Status: Backport [https://github.com/madler/zlib/commit/ba829a458576d1ff0f26fc7230c6de816d1f6a77] > -CVE: CVE-2026-27171 > - > -Signed-off-by: Hugo SIMELIERE <hsimeliere.opensource@witekio.com> > ---- > - crc32.c | 4 ++++ > - zlib.h | 4 ++-- > - 2 files changed, 6 insertions(+), 2 deletions(-) > - > -diff --git a/crc32.c b/crc32.c > -index 6c38f5c..33d8c79 100644 > ---- a/crc32.c > -+++ b/crc32.c > -@@ -1019,6 +1019,8 @@ unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, > - > - /* ========================================================================= */ > - uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { > -+ if (len2 < 0) > -+ return 0; > - #ifdef DYNAMIC_CRC_TABLE > - once(&made, make_crc_table); > - #endif /* DYNAMIC_CRC_TABLE */ > -@@ -1032,6 +1034,8 @@ uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { > - > - /* ========================================================================= */ > - uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { > -+ if (len2 < 0) > -+ return 0; > - #ifdef DYNAMIC_CRC_TABLE > - once(&made, make_crc_table); > - #endif /* DYNAMIC_CRC_TABLE */ > -diff --git a/zlib.h b/zlib.h > -index 8d4b932..8c7f8ac 100644 > ---- a/zlib.h > -+++ b/zlib.h > -@@ -1758,14 +1758,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); > - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were > - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 > - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and > -- len2. len2 must be non-negative. > -+ len2. len2 must be non-negative, otherwise zero is returned. > - */ > - > - /* > - ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); > - > - Return the operator corresponding to length len2, to be used with > -- crc32_combine_op(). len2 must be non-negative. > -+ crc32_combine_op(). len2 must be non-negative, otherwise zero is returned. > - */ > - > - ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); > --- > -2.43.0 > - > diff --git a/meta/recipes-core/zlib/zlib_1.3.1.bb b/meta/recipes-core/zlib/zlib_1.3.2.bb > similarity index 87% > rename from meta/recipes-core/zlib/zlib_1.3.1.bb > rename to meta/recipes-core/zlib/zlib_1.3.2.bb > index e42578fd7e..c7d59fdf78 100644 > --- a/meta/recipes-core/zlib/zlib_1.3.1.bb > +++ b/meta/recipes-core/zlib/zlib_1.3.2.bb > @@ -8,13 +8,11 @@ LIC_FILES_CHKSUM = "file://zlib.h;beginline=6;endline=23;md5=5377232268e952e9ef6 > > # The source tarball needs to be .gz as only the .gz ends up in fossils/ > SRC_URI = "https://zlib.net/${BP}.tar.gz \ > - file://0001-configure-Pass-LDFLAGS-to-link-tests.patch \ > file://run-ptest \ > - file://CVE-2026-27171.patch \ > " > UPSTREAM_CHECK_URI = "http://zlib.net/" > > -SRC_URI[sha256sum] = "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23" > +SRC_URI[sha256sum] = "bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16" > > # When a new release is made the previous release is moved to fossils/, so add this > # to PREMIRRORS so it is also searched automatically. -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
* [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn ` (10 preceding siblings ...) 2026-04-09 6:16 ` [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 jinfeng.wang.cn @ 2026-04-09 6:16 ` jinfeng.wang.cn 2026-04-24 8:21 ` [OE-core] " Yoann Congal 11 siblings, 1 reply; 23+ messages in thread From: jinfeng.wang.cn @ 2026-04-09 6:16 UTC (permalink / raw) To: openembedded-core From: Kai Kang <kai.kang@windriver.com> Upgrade libpcap from 1.10.4 to 1.10.6 which includes fix for CVEs. Remove backported patches which have been incorporated in 1.10.6: * CVE-2023-7256-pre1.patch * CVE-2023-7256.patch * CVE-2024-8006.patch * CVE-2025-11961-01.patch * CVE-2025-11961-02.patch * CVE-2025-11964.patch [1]: https://nvd.nist.gov/vuln/detail/CVE-2025-11961 [2]: https://nvd.nist.gov/vuln/detail/CVE-2025-11964 Signed-off-by: Kai Kang <kai.kang@windriver.com> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> --- .../libpcap/libpcap/CVE-2023-7256-pre1.patch | 37 -- .../libpcap/libpcap/CVE-2023-7256.patch | 365 --------------- .../libpcap/libpcap/CVE-2024-8006.patch | 42 -- .../libpcap/libpcap/CVE-2025-11961-01.patch | 38 -- .../libpcap/libpcap/CVE-2025-11961-02.patch | 433 ------------------ .../libpcap/libpcap/CVE-2025-11964.patch | 33 -- .../{libpcap_1.10.4.bb => libpcap_1.10.6.bb} | 8 +- 7 files changed, 1 insertion(+), 955 deletions(-) delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch rename meta/recipes-connectivity/libpcap/{libpcap_1.10.4.bb => libpcap_1.10.6.bb} (83%) diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch deleted file mode 100644 index 64abfb85cd..0000000000 --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 73da0d4d65ef0925772b7b7f82a5fbb3ff2c5e4f Mon Sep 17 00:00:00 2001 -From: Rose <83477269+AtariDreams@users.noreply.github.com> -Date: Tue, 16 May 2023 12:37:11 -0400 -Subject: [PATCH] Remove unused variable retval in sock_present2network - -This quiets the compiler since it is not even returned anyway, and is a misleading variable name. - -(cherry picked from commit c7b90298984c46d820d3cee79a96d24870b5f200) - -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/73da0d4d65ef0925772b7b7f82a5fbb3ff2c5e4f] -CVE: CVE-2023-7256 #Dependency Patch -Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> ---- - sockutils.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/sockutils.c b/sockutils.c -index 1c07f76fd1..6752f296af 100644 ---- a/sockutils.c -+++ b/sockutils.c -@@ -2082,7 +2082,6 @@ int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *addres - */ - int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen) - { -- int retval; - struct addrinfo *addrinfo; - struct addrinfo hints; - -@@ -2090,7 +2089,7 @@ int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, - - hints.ai_family = addr_family; - -- if ((retval = sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen)) == -1) -+ if (sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen) == -1) - return 0; - - if (addrinfo->ai_family == PF_INET) diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch deleted file mode 100644 index fffcb2704a..0000000000 --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch +++ /dev/null @@ -1,365 +0,0 @@ -From 2aa69b04d8173b18a0e3492e0c8f2f7fabdf642d Mon Sep 17 00:00:00 2001 -From: Guy Harris <gharris@sonic.net> -Date: Thu, 28 Sep 2023 00:37:57 -0700 -Subject: [PATCH] Have sock_initaddress() return the list of addrinfo - structures or NULL. - -Its return address is currently 0 for success and -1 for failure, with a -pointer to the first element of the list of struct addrinfos returned -through a pointer on success; change it to return that pointer on -success and NULL on failure. - -That way, we don't have to worry about what happens to the pointer -pointeed to by the argument in question on failure; we know that we got -NULL back if no struct addrinfos were found because getaddrinfo() -failed. Thus, we know that we have something to free iff -sock_initaddress() returned a pointer to that something rather than -returning NULL. - -This avoids a double-free in some cases. - -This is apparently CVE-2023-40400. - -(backported from commit 262e4f34979872d822ccedf9f318ed89c4d31c03) - -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/2aa69b04d8173b18a0e3492e0c8f2f7fabdf642d] -CVE: CVE-2023-7256 -Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> ---- - pcap-rpcap.c | 48 ++++++++++++++++++++-------------------- - rpcapd/daemon.c | 8 +++++-- - rpcapd/rpcapd.c | 8 +++++-- - sockutils.c | 58 ++++++++++++++++++++++++++++--------------------- - sockutils.h | 5 ++--- - 5 files changed, 72 insertions(+), 55 deletions(-) - -diff --git a/pcap-rpcap.c b/pcap-rpcap.c -index ef0cd6e49c..f1992e4aea 100644 ---- a/pcap-rpcap.c -+++ b/pcap-rpcap.c -@@ -1024,7 +1024,6 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf) - { - struct activehosts *temp; /* temp var needed to scan the host list chain */ - struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ -- int retval; - - /* retrieve the network address corresponding to 'host' */ - addrinfo = NULL; -@@ -1032,9 +1031,9 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf) - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - -- retval = sock_initaddress(host, NULL, &hints, &addrinfo, errbuf, -+ addrinfo = sock_initaddress(host, NULL, &hints, errbuf, - PCAP_ERRBUF_SIZE); -- if (retval != 0) -+ if (addrinfo == NULL) - { - *error = 1; - return NULL; -@@ -1186,7 +1185,9 @@ static int pcap_startcapture_remote(pcap_t *fp) - hints.ai_flags = AI_PASSIVE; /* Data connection is opened by the server toward the client */ - - /* Let's the server pick up a free network port for us */ -- if (sock_initaddress(NULL, NULL, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) -+ addrinfo = sock_initaddress(NULL, NULL, &hints, fp->errbuf, -+ PCAP_ERRBUF_SIZE); -+ if (addrinfo == NULL) - goto error_nodiscard; - - if ((sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, -@@ -1311,7 +1312,9 @@ static int pcap_startcapture_remote(pcap_t *fp) - snprintf(portstring, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata)); - - /* Let's the server pick up a free network port for us */ -- if (sock_initaddress(host, portstring, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) -+ addrinfo = sock_initaddress(host, portstring, &hints, -+ fp->errbuf, PCAP_ERRBUF_SIZE); -+ if (addrinfo == NULL) - goto error; - - if ((sockdata = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) -@@ -2340,16 +2343,16 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, - if (port[0] == 0) - { - /* the user chose not to specify the port */ -- if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, -- &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) -- return -1; -+ addrinfo = sock_initaddress(host, RPCAP_DEFAULT_NETPORT, -+ &hints, errbuf, PCAP_ERRBUF_SIZE); - } - else - { -- if (sock_initaddress(host, port, &hints, &addrinfo, -- errbuf, PCAP_ERRBUF_SIZE) == -1) -- return -1; -+ addrinfo = sock_initaddress(host, port, &hints, -+ errbuf, PCAP_ERRBUF_SIZE); - } -+ if (addrinfo == NULL) -+ return -1; - - if ((*sockctrlp = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, - errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) -@@ -2950,19 +2953,19 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha - /* Do the work */ - if ((port == NULL) || (port[0] == 0)) - { -- if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) -- { -- return (SOCKET)-2; -- } -+ addrinfo = sock_initaddress(address, -+ RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, errbuf, -+ PCAP_ERRBUF_SIZE); - } - else - { -- if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) -- { -- return (SOCKET)-2; -- } -+ addrinfo = sock_initaddress(address, port, &hints, errbuf, -+ PCAP_ERRBUF_SIZE); -+ } -+ if (addrinfo == NULL) -+ { -+ return (SOCKET)-2; - } -- - - if ((sockmain = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) - { -@@ -3122,7 +3125,6 @@ int pcap_remoteact_close(const char *host, char *errbuf) - { - struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */ - struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ -- int retval; - - temp = activeHosts; - prev = NULL; -@@ -3133,9 +3135,9 @@ int pcap_remoteact_close(const char *host, char *errbuf) - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - -- retval = sock_initaddress(host, NULL, &hints, &addrinfo, errbuf, -+ addrinfo = sock_initaddress(host, NULL, &hints, errbuf, - PCAP_ERRBUF_SIZE); -- if (retval != 0) -+ if (addrinfo == NULL) - { - return -1; - } -diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c -index 8d620dd604..b04b29f107 100644 ---- a/rpcapd/daemon.c -+++ b/rpcapd/daemon.c -@@ -2085,7 +2085,9 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, - goto error; - } - -- if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) -+ addrinfo = sock_initaddress(peerhost, portdata, &hints, -+ errmsgbuf, PCAP_ERRBUF_SIZE); -+ if (addrinfo == NULL) - goto error; - - if ((session->sockdata = sock_open(peerhost, addrinfo, SOCKOPEN_CLIENT, 0, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) -@@ -2096,7 +2098,9 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, - hints.ai_flags = AI_PASSIVE; - - // Make the server socket pick up a free network port for us -- if (sock_initaddress(NULL, NULL, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) -+ addrinfo = sock_initaddress(NULL, NULL, &hints, errmsgbuf, -+ PCAP_ERRBUF_SIZE); -+ if (addrinfo == NULL) - goto error; - - if ((session->sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) -diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c -index e1f3f05299..d166522c9f 100644 ---- a/rpcapd/rpcapd.c -+++ b/rpcapd/rpcapd.c -@@ -611,7 +611,9 @@ void main_startup(void) - // - // Get a list of sockets on which to listen. - // -- if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) -+ addrinfo = sock_initaddress((address[0]) ? address : NULL, -+ port, &mainhints, errbuf, PCAP_ERRBUF_SIZE); -+ if (addrinfo == NULL) - { - rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); - return; -@@ -1350,7 +1352,9 @@ main_active(void *ptr) - memset(errbuf, 0, sizeof(errbuf)); - - // Do the work -- if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) -+ addrinfo = sock_initaddress(activepars->address, activepars->port, -+ &hints, errbuf, PCAP_ERRBUF_SIZE); -+ if (addrinfo == NULL) - { - rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); - return 0; -diff --git a/sockutils.c b/sockutils.c -index a1bfa1b5e2..823c2363e0 100644 ---- a/sockutils.c -+++ b/sockutils.c -@@ -1069,20 +1069,21 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, - * \param errbuflen: length of the buffer that will contains the error. The error message cannot be - * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. - * -- * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned -- * in the 'errbuf' variable. The addrinfo variable that has to be used in the following sockets calls is -- * returned into the addrinfo parameter. -+ * \return a pointer to the first element in a list of addrinfo structures -+ * if everything is fine, NULL if some errors occurred. The error message -+ * is returned in the 'errbuf' variable. - * -- * \warning The 'addrinfo' variable has to be deleted by the programmer by calling freeaddrinfo() when -- * it is no longer needed. -+ * \warning The list of addrinfo structures returned has to be deleted by -+ * the programmer by calling freeaddrinfo() when it is no longer needed. - * - * \warning This function requires the 'hints' variable as parameter. The semantic of this variable is the same - * of the one of the corresponding variable used into the standard getaddrinfo() socket function. We suggest - * the programmer to look at that function in order to set the 'hints' variable appropriately. - */ --int sock_initaddress(const char *host, const char *port, -- struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf, int errbuflen) -+struct addrinfo *sock_initaddress(const char *host, const char *port, -+ struct addrinfo *hints, char *errbuf, int errbuflen) - { -+ struct addrinfo *addrinfo; - int retval; - - /* -@@ -1094,9 +1095,13 @@ int sock_initaddress(const char *host, const char *port, - * as those messages won't talk about a problem with the port if - * no port was specified. - */ -- retval = getaddrinfo(host, port == NULL ? "0" : port, hints, addrinfo); -+ retval = getaddrinfo(host, port == NULL ? "0" : port, hints, &addrinfo); - if (retval != 0) - { -+ /* -+ * That call failed. -+ * Determine whether the problem is that the host is bad. -+ */ - if (errbuf) - { - if (host != NULL && port != NULL) { -@@ -1108,7 +1113,7 @@ int sock_initaddress(const char *host, const char *port, - int try_retval; - - try_retval = getaddrinfo(host, NULL, hints, -- addrinfo); -+ &addrinfo); - if (try_retval == 0) { - /* - * Worked with just the host, -@@ -1117,14 +1122,16 @@ int sock_initaddress(const char *host, const char *port, - * - * Free up the address info first. - */ -- freeaddrinfo(*addrinfo); -+ freeaddrinfo(addrinfo); - get_gai_errstring(errbuf, errbuflen, - "", retval, NULL, port); - } else { - /* - * Didn't work with just the host, - * so assume the problem is -- * with the host. -+ * with the host; we assume -+ * the original error indicates -+ * the underlying problem. - */ - get_gai_errstring(errbuf, errbuflen, - "", retval, host, NULL); -@@ -1132,13 +1139,14 @@ int sock_initaddress(const char *host, const char *port, - } else { - /* - * Either the host or port was null, so -- * there's nothing to determine. -+ * there's nothing to determine; report -+ * the error from the original call. - */ - get_gai_errstring(errbuf, errbuflen, "", - retval, host, port); - } - } -- return -1; -+ return NULL; - } - /* - * \warning SOCKET: I should check all the accept() in order to bind to all addresses in case -@@ -1153,30 +1161,28 @@ int sock_initaddress(const char *host, const char *port, - * ignore all addresses that are neither? (What, no IPX - * support? :-)) - */ -- if (((*addrinfo)->ai_family != PF_INET) && -- ((*addrinfo)->ai_family != PF_INET6)) -+ if ((addrinfo->ai_family != PF_INET) && -+ (addrinfo->ai_family != PF_INET6)) - { - if (errbuf) - snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported"); -- freeaddrinfo(*addrinfo); -- *addrinfo = NULL; -- return -1; -+ freeaddrinfo(addrinfo); -+ return NULL; - } - - /* - * You can't do multicast (or broadcast) TCP. - */ -- if (((*addrinfo)->ai_socktype == SOCK_STREAM) && -- (sock_ismcastaddr((*addrinfo)->ai_addr) == 0)) -+ if ((addrinfo->ai_socktype == SOCK_STREAM) && -+ (sock_ismcastaddr(addrinfo->ai_addr) == 0)) - { - if (errbuf) - snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams"); -- freeaddrinfo(*addrinfo); -- *addrinfo = NULL; -- return -1; -+ freeaddrinfo(addrinfo); -+ return NULL; - } - -- return 0; -+ return addrinfo; - } - - /* -@@ -2089,7 +2095,9 @@ int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, - - hints.ai_family = addr_family; - -- if (sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen) == -1) -+ addrinfo = sock_initaddress(address, "22222" /* fake port */, &hints, -+ errbuf, errbuflen); -+ if (addrinfo == NULL) - return 0; - - if (addrinfo->ai_family == PF_INET) -diff --git a/sockutils.h b/sockutils.h -index a488d8fcb4..30b8cfe0b7 100644 ---- a/sockutils.h -+++ b/sockutils.h -@@ -138,9 +138,8 @@ void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, - PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(4, 5); - void sock_geterrmsg(char *errbuf, size_t errbuflen, - PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(3, 4); --int sock_initaddress(const char *address, const char *port, -- struct addrinfo *hints, struct addrinfo **addrinfo, -- char *errbuf, int errbuflen); -+struct addrinfo *sock_initaddress(const char *address, const char *port, -+ struct addrinfo *hints, char *errbuf, int errbuflen); - int sock_recv(SOCKET sock, SSL *, void *buffer, size_t size, int receiveall, - char *errbuf, int errbuflen); - int sock_recv_dgram(SOCKET sock, SSL *, void *buffer, size_t size, diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch deleted file mode 100644 index 6819aedd20..0000000000 --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 8a633ee5b9ecd9d38a587ac9b204e2380713b0d6 Mon Sep 17 00:00:00 2001 -From: Nicolas Badoux <n.badoux@hotmail.com> -Date: Mon, 19 Aug 2024 12:31:53 +0200 -Subject: [PATCH] makes pcap_findalldevs_ex errors out if the directory does - not exist - -(backported from commit 0f8a103469ce87d2b8d68c5130a46ddb7fb5eb29) - -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/8a633ee5b9ecd9d38a587ac9b204e2380713b0d6] -CVE: CVE-2024-8006 -Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> ---- - pcap-new.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/pcap-new.c b/pcap-new.c -index be91b3f8db..d449ee623c 100644 ---- a/pcap-new.c -+++ b/pcap-new.c -@@ -230,6 +230,13 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t - #else - /* opening the folder */ - unixdir= opendir(path); -+ if (unixdir == NULL) { -+ DIAG_OFF_FORMAT_TRUNCATION -+ snprintf(errbuf, PCAP_ERRBUF_SIZE, -+ "Error when listing files: does folder '%s' exist?", path); -+ DIAG_ON_FORMAT_TRUNCATION -+ return -1; -+ } - - /* get the first file into it */ - filedata= readdir(unixdir); -@@ -237,7 +244,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t - if (filedata == NULL) - { - DIAG_OFF_FORMAT_TRUNCATION -- snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); -+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' contain files?", path); - DIAG_ON_FORMAT_TRUNCATION - closedir(unixdir); - return -1; diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch deleted file mode 100644 index 73c3ab3f5c..0000000000 --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 7224be0fe2f4beb916b7b69141f478facd0f0634 Mon Sep 17 00:00:00 2001 -From: Denis Ovsienko <denis@ovsienko.info> -Date: Sat, 27 Dec 2025 21:36:11 +0000 -Subject: [PATCH] Rename one of the xdtoi() copies to simplify backporting. - -CVE: CVE-2025-11961 -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7224be0fe2f4beb916b7b69141f478facd0f0634] -Signed-off-by: Peter Marko <peter.marko@siemens.com> ---- - nametoaddr.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/nametoaddr.c b/nametoaddr.c -index dc75495c..bdaacbf1 100644 ---- a/nametoaddr.c -+++ b/nametoaddr.c -@@ -646,7 +646,7 @@ pcap_nametollc(const char *s) - - /* Hex digit to 8-bit unsigned integer. */ - static inline u_char --xdtoi(u_char c) -+pcapint_xdtoi(u_char c) - { - if (c >= '0' && c <= '9') - return (u_char)(c - '0'); -@@ -728,10 +728,10 @@ pcap_ether_aton(const char *s) - while (*s) { - if (*s == ':' || *s == '.' || *s == '-') - s += 1; -- d = xdtoi(*s++); -+ d = pcapint_xdtoi(*s++); - if (PCAP_ISXDIGIT(*s)) { - d <<= 4; -- d |= xdtoi(*s++); -+ d |= pcapint_xdtoi(*s++); - } - *ep++ = d; - } diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch deleted file mode 100644 index 2dca7908ef..0000000000 --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch +++ /dev/null @@ -1,433 +0,0 @@ -From b2d2f9a9a0581c40780bde509f7cc715920f1c02 Mon Sep 17 00:00:00 2001 -From: Denis Ovsienko <denis@ovsienko.info> -Date: Fri, 19 Dec 2025 17:31:13 +0000 -Subject: [PATCH] CVE-2025-11961: Fix OOBR and OOBW in pcap_ether_aton(). - -pcap_ether_aton() has for a long time required its string argument to be -a well-formed MAC-48 address, which is always the case when the argument -comes from other libpcap code, so the function has never validated the -input and used a simple loop to parse any of the three common MAC-48 -address formats. However, the function has also been a part of the -public API, so calling it directly with a malformed address can cause -the loop to read beyond the end of the input string and/or to write -beyond the end of the allocated output buffer. - -To handle invalid input more appropriately, replace the simple loop with -new functions and require the input to match a supported address format. - -This problem was reported by Jin Wei, Kunwei Qian and Ping Chen. - -(backported from commit dd08e53e9380e217ae7c7768da9cc3d7bf37bf83) - -CVE: CVE-2025-11961 -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/b2d2f9a9a0581c40780bde509f7cc715920f1c02] -Signed-off-by: Peter Marko <peter.marko@siemens.com> ---- - gencode.c | 5 + - nametoaddr.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++---- - 2 files changed, 349 insertions(+), 23 deletions(-) - -diff --git a/gencode.c b/gencode.c -index 3ddd15f8..76fb2d82 100644 ---- a/gencode.c -+++ b/gencode.c -@@ -7228,6 +7228,11 @@ gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) - return (NULL); - - if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { -+ /* -+ * Because the lexer guards the input string format, in this -+ * context the function returns NULL iff the implicit malloc() -+ * has failed. -+ */ - cstate->e = pcap_ether_aton(s); - if (cstate->e == NULL) - bpf_error(cstate, "malloc"); -diff --git a/nametoaddr.c b/nametoaddr.c -index f9fcd288..f50d0da5 100644 ---- a/nametoaddr.c -+++ b/nametoaddr.c -@@ -703,39 +703,360 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr) - return(32); - } - -+// Man page: "xxxxxxxxxxxx", regexp: "^[0-9a-fA-F]{12}$". -+static u_char -+pcapint_atomac48_xxxxxxxxxxxx(const char *s, uint8_t *addr) -+{ -+ if (strlen(s) == 12 && -+ PCAP_ISXDIGIT(s[0]) && -+ PCAP_ISXDIGIT(s[1]) && -+ PCAP_ISXDIGIT(s[2]) && -+ PCAP_ISXDIGIT(s[3]) && -+ PCAP_ISXDIGIT(s[4]) && -+ PCAP_ISXDIGIT(s[5]) && -+ PCAP_ISXDIGIT(s[6]) && -+ PCAP_ISXDIGIT(s[7]) && -+ PCAP_ISXDIGIT(s[8]) && -+ PCAP_ISXDIGIT(s[9]) && -+ PCAP_ISXDIGIT(s[10]) && -+ PCAP_ISXDIGIT(s[11])) { -+ addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); -+ addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); -+ addr[2] = pcapint_xdtoi(s[4]) << 4 | pcapint_xdtoi(s[5]); -+ addr[3] = pcapint_xdtoi(s[6]) << 4 | pcapint_xdtoi(s[7]); -+ addr[4] = pcapint_xdtoi(s[8]) << 4 | pcapint_xdtoi(s[9]); -+ addr[5] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); -+ return 1; -+ } -+ return 0; -+} -+ -+// Man page: "xxxx.xxxx.xxxx", regexp: "^[0-9a-fA-F]{4}(\.[0-9a-fA-F]{4}){2}$". -+static u_char -+pcapint_atomac48_xxxx_3_times(const char *s, uint8_t *addr) -+{ -+ const char sep = '.'; -+ if (strlen(s) == 14 && -+ PCAP_ISXDIGIT(s[0]) && -+ PCAP_ISXDIGIT(s[1]) && -+ PCAP_ISXDIGIT(s[2]) && -+ PCAP_ISXDIGIT(s[3]) && -+ s[4] == sep && -+ PCAP_ISXDIGIT(s[5]) && -+ PCAP_ISXDIGIT(s[6]) && -+ PCAP_ISXDIGIT(s[7]) && -+ PCAP_ISXDIGIT(s[8]) && -+ s[9] == sep && -+ PCAP_ISXDIGIT(s[10]) && -+ PCAP_ISXDIGIT(s[11]) && -+ PCAP_ISXDIGIT(s[12]) && -+ PCAP_ISXDIGIT(s[13])) { -+ addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); -+ addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); -+ addr[2] = pcapint_xdtoi(s[5]) << 4 | pcapint_xdtoi(s[6]); -+ addr[3] = pcapint_xdtoi(s[7]) << 4 | pcapint_xdtoi(s[8]); -+ addr[4] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); -+ addr[5] = pcapint_xdtoi(s[12]) << 4 | pcapint_xdtoi(s[13]); -+ return 1; -+ } -+ return 0; -+} -+ - /* -- * Convert 's', which can have the one of the forms: -+ * Man page: "xx:xx:xx:xx:xx:xx", regexp: "^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$". -+ * Man page: "xx-xx-xx-xx-xx-xx", regexp: "^[0-9a-fA-F]{1,2}(-[0-9a-fA-F]{1,2}){5}$". -+ * Man page: "xx.xx.xx.xx.xx.xx", regexp: "^[0-9a-fA-F]{1,2}(\.[0-9a-fA-F]{1,2}){5}$". -+ * (Any "xx" above can be "x", which is equivalent to "0x".) - * -- * "xx:xx:xx:xx:xx:xx" -- * "xx.xx.xx.xx.xx.xx" -- * "xx-xx-xx-xx-xx-xx" -- * "xxxx.xxxx.xxxx" -- * "xxxxxxxxxxxx" -+ * An equivalent (and parametrisable for EUI-64) FSM could be implemented using -+ * a smaller graph, but that graph would be neither acyclic nor planar nor -+ * trivial to verify. - * -- * (or various mixes of ':', '.', and '-') into a new -- * ethernet address. Assumes 's' is well formed. -+ * | -+ * [.] v -+ * +<---------- START -+ * | | -+ * | | [0-9a-fA-F] -+ * | [.] v -+ * +<--------- BYTE0_X ----------+ -+ * | | | -+ * | | [0-9a-fA-F] | -+ * | [.] v | -+ * +<--------- BYTE0_XX | [:\.-] -+ * | | | -+ * | | [:\.-] | -+ * | [.] v | -+ * +<----- BYTE0_SEP_BYTE1 <-----+ -+ * | | -+ * | | [0-9a-fA-F] -+ * | [.] v -+ * +<--------- BYTE1_X ----------+ -+ * | | | -+ * | | [0-9a-fA-F] | -+ * | [.] v | -+ * +<--------- BYTE1_XX | <sep> -+ * | | | -+ * | | <sep> | -+ * | [.] v | -+ * +<----- BYTE1_SEP_BYTE2 <-----+ -+ * | | -+ * | | [0-9a-fA-F] -+ * | [.] v -+ * +<--------- BYTE2_X ----------+ -+ * | | | -+ * | | [0-9a-fA-F] | -+ * | [.] v | -+ * +<--------- BYTE2_XX | <sep> -+ * | | | -+ * | | <sep> | -+ * | [.] v | -+ * +<----- BYTE2_SEP_BYTE3 <-----+ -+ * | | -+ * | | [0-9a-fA-F] -+ * | [.] v -+ * +<--------- BYTE3_X ----------+ -+ * | | | -+ * | | [0-9a-fA-F] | -+ * | [.] v | -+ * +<--------- BYTE3_XX | <sep> -+ * | | | -+ * | | <sep> | -+ * | [.] v | -+ * +<----- BYTE3_SEP_BYTE4 <-----+ -+ * | | -+ * | | [0-9a-fA-F] -+ * | [.] v -+ * +<--------- BYTE4_X ----------+ -+ * | | | -+ * | | [0-9a-fA-F] | -+ * | [.] v | -+ * +<--------- BYTE4_XX | <sep> -+ * | | | -+ * | | <sep> | -+ * | [.] v | -+ * +<----- BYTE4_SEP_BYTE5 <-----+ -+ * | | -+ * | | [0-9a-fA-F] -+ * | [.] v -+ * +<--------- BYTE5_X ----------+ -+ * | | | -+ * | | [0-9a-fA-F] | -+ * | [.] v | -+ * +<--------- BYTE5_XX | \0 -+ * | | | -+ * | | \0 | -+ * | | v -+ * +--> (reject) +---------> (accept) -+ * -+ */ -+static u_char -+pcapint_atomac48_x_xx_6_times(const char *s, uint8_t *addr) -+{ -+ enum { -+ START, -+ BYTE0_X, -+ BYTE0_XX, -+ BYTE0_SEP_BYTE1, -+ BYTE1_X, -+ BYTE1_XX, -+ BYTE1_SEP_BYTE2, -+ BYTE2_X, -+ BYTE2_XX, -+ BYTE2_SEP_BYTE3, -+ BYTE3_X, -+ BYTE3_XX, -+ BYTE3_SEP_BYTE4, -+ BYTE4_X, -+ BYTE4_XX, -+ BYTE4_SEP_BYTE5, -+ BYTE5_X, -+ BYTE5_XX, -+ } fsm_state = START; -+ uint8_t buf[6]; -+ const char *seplist = ":.-"; -+ char sep; -+ -+ while (*s) { -+ switch (fsm_state) { -+ case START: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[0] = pcapint_xdtoi(*s); -+ fsm_state = BYTE0_X; -+ break; -+ } -+ goto reject; -+ case BYTE0_X: -+ if (strchr(seplist, *s)) { -+ sep = *s; -+ fsm_state = BYTE0_SEP_BYTE1; -+ break; -+ } -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[0] = buf[0] << 4 | pcapint_xdtoi(*s); -+ fsm_state = BYTE0_XX; -+ break; -+ } -+ goto reject; -+ case BYTE0_XX: -+ if (strchr(seplist, *s)) { -+ sep = *s; -+ fsm_state = BYTE0_SEP_BYTE1; -+ break; -+ } -+ goto reject; -+ case BYTE0_SEP_BYTE1: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[1] = pcapint_xdtoi(*s); -+ fsm_state = BYTE1_X; -+ break; -+ } -+ goto reject; -+ case BYTE1_X: -+ if (*s == sep) { -+ fsm_state = BYTE1_SEP_BYTE2; -+ break; -+ } -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[1] = buf[1] << 4 | pcapint_xdtoi(*s); -+ fsm_state = BYTE1_XX; -+ break; -+ } -+ goto reject; -+ case BYTE1_XX: -+ if (*s == sep) { -+ fsm_state = BYTE1_SEP_BYTE2; -+ break; -+ } -+ goto reject; -+ case BYTE1_SEP_BYTE2: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[2] = pcapint_xdtoi(*s); -+ fsm_state = BYTE2_X; -+ break; -+ } -+ goto reject; -+ case BYTE2_X: -+ if (*s == sep) { -+ fsm_state = BYTE2_SEP_BYTE3; -+ break; -+ } -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[2] = buf[2] << 4 | pcapint_xdtoi(*s); -+ fsm_state = BYTE2_XX; -+ break; -+ } -+ goto reject; -+ case BYTE2_XX: -+ if (*s == sep) { -+ fsm_state = BYTE2_SEP_BYTE3; -+ break; -+ } -+ goto reject; -+ case BYTE2_SEP_BYTE3: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[3] = pcapint_xdtoi(*s); -+ fsm_state = BYTE3_X; -+ break; -+ } -+ goto reject; -+ case BYTE3_X: -+ if (*s == sep) { -+ fsm_state = BYTE3_SEP_BYTE4; -+ break; -+ } -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[3] = buf[3] << 4 | pcapint_xdtoi(*s); -+ fsm_state = BYTE3_XX; -+ break; -+ } -+ goto reject; -+ case BYTE3_XX: -+ if (*s == sep) { -+ fsm_state = BYTE3_SEP_BYTE4; -+ break; -+ } -+ goto reject; -+ case BYTE3_SEP_BYTE4: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[4] = pcapint_xdtoi(*s); -+ fsm_state = BYTE4_X; -+ break; -+ } -+ goto reject; -+ case BYTE4_X: -+ if (*s == sep) { -+ fsm_state = BYTE4_SEP_BYTE5; -+ break; -+ } -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[4] = buf[4] << 4 | pcapint_xdtoi(*s); -+ fsm_state = BYTE4_XX; -+ break; -+ } -+ goto reject; -+ case BYTE4_XX: -+ if (*s == sep) { -+ fsm_state = BYTE4_SEP_BYTE5; -+ break; -+ } -+ goto reject; -+ case BYTE4_SEP_BYTE5: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[5] = pcapint_xdtoi(*s); -+ fsm_state = BYTE5_X; -+ break; -+ } -+ goto reject; -+ case BYTE5_X: -+ if (PCAP_ISXDIGIT(*s)) { -+ buf[5] = buf[5] << 4 | pcapint_xdtoi(*s); -+ fsm_state = BYTE5_XX; -+ break; -+ } -+ goto reject; -+ case BYTE5_XX: -+ goto reject; -+ } // switch -+ s++; -+ } // while -+ -+ if (fsm_state == BYTE5_X || fsm_state == BYTE5_XX) { -+ // accept -+ memcpy(addr, buf, sizeof(buf)); -+ return 1; -+ } -+ -+reject: -+ return 0; -+} -+ -+// The 'addr' argument must point to an array of at least 6 elements. -+static int -+pcapint_atomac48(const char *s, uint8_t *addr) -+{ -+ return s && ( -+ pcapint_atomac48_xxxxxxxxxxxx(s, addr) || -+ pcapint_atomac48_xxxx_3_times(s, addr) || -+ pcapint_atomac48_x_xx_6_times(s, addr) -+ ); -+} -+ -+/* -+ * If 's' is a MAC-48 address in one of the forms documented in pcap-filter(7) -+ * for "ether host", return a pointer to an allocated buffer with the binary -+ * value of the address. Return NULL on any error. - */ - u_char * - pcap_ether_aton(const char *s) - { -- register u_char *ep, *e; -- register u_char d; -+ uint8_t tmp[6]; -+ if (! pcapint_atomac48(s, tmp)) -+ return (NULL); - -- e = ep = (u_char *)malloc(6); -+ u_char *e = malloc(6); - if (e == NULL) - return (NULL); -- -- while (*s) { -- if (*s == ':' || *s == '.' || *s == '-') -- s += 1; -- d = pcapint_xdtoi(*s++); -- if (PCAP_ISXDIGIT(*s)) { -- d <<= 4; -- d |= pcapint_xdtoi(*s++); -- } -- *ep++ = d; -- } -- -+ memcpy(e, tmp, sizeof(tmp)); - return (e); - } - diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch deleted file mode 100644 index 003d21fb1f..0000000000 --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 7fabf607f2319a36a0bd78444247180acb838e69 Mon Sep 17 00:00:00 2001 -From: Guy Harris <gharris@sonic.net> -Date: Sun, 7 Sep 2025 12:51:56 -0700 -Subject: [PATCH] Fix a copy-and-pasteo in utf_16le_to_utf_8_truncated(). - -For the four octets of UTF-8 case, it was decrementing the remaining -buffer length by 3, not 4. - -Thanks to a team of developers from the Univesity of Waterloo for -reporting this. - -(cherry picked from commit aebfca1aea2fc8c177760a26e8f4de27b51d1b3b) - -CVE: CVE-2025-11964 -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7fabf607f2319a36a0bd78444247180acb838e69] -Signed-off-by: Peter Marko <peter.marko@siemens.com> ---- - fmtutils.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/fmtutils.c b/fmtutils.c -index a5a4fe62..78a0f8b7 100644 ---- a/fmtutils.c -+++ b/fmtutils.c -@@ -235,7 +235,7 @@ utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8, - *utf_8++ = ((uc >> 12) & 0x3F) | 0x80; - *utf_8++ = ((uc >> 6) & 0x3F) | 0x80; - *utf_8++ = ((uc >> 0) & 0x3F) | 0x80; -- utf_8_len -= 3; -+ utf_8_len -= 4; - } - } - diff --git a/meta/recipes-connectivity/libpcap/libpcap_1.10.4.bb b/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb similarity index 83% rename from meta/recipes-connectivity/libpcap/libpcap_1.10.4.bb rename to meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb index ee7d7540f6..5cba790012 100644 --- a/meta/recipes-connectivity/libpcap/libpcap_1.10.4.bb +++ b/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb @@ -11,15 +11,9 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=5eb289217c160e2920d2e35bddc36453 \ DEPENDS = "flex-native bison-native" SRC_URI = "https://www.tcpdump.org/release/${BP}.tar.gz \ - file://CVE-2023-7256-pre1.patch \ - file://CVE-2023-7256.patch \ - file://CVE-2024-8006.patch \ - file://CVE-2025-11961-01.patch \ - file://CVE-2025-11961-02.patch \ - file://CVE-2025-11964.patch \ " -SRC_URI[sha256sum] = "ed19a0383fad72e3ad435fd239d7cd80d64916b87269550159d20e47160ebe5f" +SRC_URI[sha256sum] = "872dd11337fe1ab02ad9d4fee047c9da244d695c6ddf34e2ebb733efd4ed8aa9" inherit autotools binconfig-disabled pkgconfig -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [OE-core] [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 2026-04-09 6:16 ` [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 jinfeng.wang.cn @ 2026-04-24 8:21 ` Yoann Congal 0 siblings, 0 replies; 23+ messages in thread From: Yoann Congal @ 2026-04-24 8:21 UTC (permalink / raw) To: Jinfeng.Wang.CN, openembedded-core On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote: > From: Kai Kang <kai.kang@windriver.com> > > Upgrade libpcap from 1.10.4 to 1.10.6 which includes fix for CVEs. > > Remove backported patches which have been incorporated in 1.10.6: > > * CVE-2023-7256-pre1.patch > * CVE-2023-7256.patch > * CVE-2024-8006.patch > * CVE-2025-11961-01.patch > * CVE-2025-11961-02.patch > * CVE-2025-11964.patch > > [1]: https://nvd.nist.gov/vuln/detail/CVE-2025-11961 > [2]: https://nvd.nist.gov/vuln/detail/CVE-2025-11964 > > Signed-off-by: Kai Kang <kai.kang@windriver.com> > Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com> > --- (Same as the zlib patch) Please add the changelog: https://github.com/the-tcpdump-group/libpcap/blob/libpcap-1.10.6/CHANGES#L1-L271 In this release, I see: * a lot of "Add <new link type>" => sounds like new features * Some API changes: pcap: make the seconds and microseconds/nanoseconds fields unsigned. Rename helper routines for pcap modules to have names beginning with pcapint_, to avoid namespace collisions for code linking statically with libpcap. Sorry, I don't think I can accept this upgrade. > .../libpcap/libpcap/CVE-2023-7256-pre1.patch | 37 -- > .../libpcap/libpcap/CVE-2023-7256.patch | 365 --------------- > .../libpcap/libpcap/CVE-2024-8006.patch | 42 -- > .../libpcap/libpcap/CVE-2025-11961-01.patch | 38 -- > .../libpcap/libpcap/CVE-2025-11961-02.patch | 433 ------------------ > .../libpcap/libpcap/CVE-2025-11964.patch | 33 -- > .../{libpcap_1.10.4.bb => libpcap_1.10.6.bb} | 8 +- > 7 files changed, 1 insertion(+), 955 deletions(-) > delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch > delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch > delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch > delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch > delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch > delete mode 100644 meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch > rename meta/recipes-connectivity/libpcap/{libpcap_1.10.4.bb => libpcap_1.10.6.bb} (83%) > > diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch > deleted file mode 100644 > index 64abfb85cd..0000000000 > --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256-pre1.patch > +++ /dev/null > @@ -1,37 +0,0 @@ > -From 73da0d4d65ef0925772b7b7f82a5fbb3ff2c5e4f Mon Sep 17 00:00:00 2001 > -From: Rose <83477269+AtariDreams@users.noreply.github.com> > -Date: Tue, 16 May 2023 12:37:11 -0400 > -Subject: [PATCH] Remove unused variable retval in sock_present2network > - > -This quiets the compiler since it is not even returned anyway, and is a misleading variable name. > - > -(cherry picked from commit c7b90298984c46d820d3cee79a96d24870b5f200) > - > -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/73da0d4d65ef0925772b7b7f82a5fbb3ff2c5e4f] > -CVE: CVE-2023-7256 #Dependency Patch > -Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> > ---- > - sockutils.c | 3 +-- > - 1 file changed, 1 insertion(+), 2 deletions(-) > - > -diff --git a/sockutils.c b/sockutils.c > -index 1c07f76fd1..6752f296af 100644 > ---- a/sockutils.c > -+++ b/sockutils.c > -@@ -2082,7 +2082,6 @@ int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *addres > - */ > - int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen) > - { > -- int retval; > - struct addrinfo *addrinfo; > - struct addrinfo hints; > - > -@@ -2090,7 +2089,7 @@ int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, > - > - hints.ai_family = addr_family; > - > -- if ((retval = sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen)) == -1) > -+ if (sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen) == -1) > - return 0; > - > - if (addrinfo->ai_family == PF_INET) > diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch > deleted file mode 100644 > index fffcb2704a..0000000000 > --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2023-7256.patch > +++ /dev/null > @@ -1,365 +0,0 @@ > -From 2aa69b04d8173b18a0e3492e0c8f2f7fabdf642d Mon Sep 17 00:00:00 2001 > -From: Guy Harris <gharris@sonic.net> > -Date: Thu, 28 Sep 2023 00:37:57 -0700 > -Subject: [PATCH] Have sock_initaddress() return the list of addrinfo > - structures or NULL. > - > -Its return address is currently 0 for success and -1 for failure, with a > -pointer to the first element of the list of struct addrinfos returned > -through a pointer on success; change it to return that pointer on > -success and NULL on failure. > - > -That way, we don't have to worry about what happens to the pointer > -pointeed to by the argument in question on failure; we know that we got > -NULL back if no struct addrinfos were found because getaddrinfo() > -failed. Thus, we know that we have something to free iff > -sock_initaddress() returned a pointer to that something rather than > -returning NULL. > - > -This avoids a double-free in some cases. > - > -This is apparently CVE-2023-40400. > - > -(backported from commit 262e4f34979872d822ccedf9f318ed89c4d31c03) > - > -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/2aa69b04d8173b18a0e3492e0c8f2f7fabdf642d] > -CVE: CVE-2023-7256 > -Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> > ---- > - pcap-rpcap.c | 48 ++++++++++++++++++++-------------------- > - rpcapd/daemon.c | 8 +++++-- > - rpcapd/rpcapd.c | 8 +++++-- > - sockutils.c | 58 ++++++++++++++++++++++++++++--------------------- > - sockutils.h | 5 ++--- > - 5 files changed, 72 insertions(+), 55 deletions(-) > - > -diff --git a/pcap-rpcap.c b/pcap-rpcap.c > -index ef0cd6e49c..f1992e4aea 100644 > ---- a/pcap-rpcap.c > -+++ b/pcap-rpcap.c > -@@ -1024,7 +1024,6 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf) > - { > - struct activehosts *temp; /* temp var needed to scan the host list chain */ > - struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ > -- int retval; > - > - /* retrieve the network address corresponding to 'host' */ > - addrinfo = NULL; > -@@ -1032,9 +1031,9 @@ rpcap_remoteact_getsock(const char *host, int *error, char *errbuf) > - hints.ai_family = PF_UNSPEC; > - hints.ai_socktype = SOCK_STREAM; > - > -- retval = sock_initaddress(host, NULL, &hints, &addrinfo, errbuf, > -+ addrinfo = sock_initaddress(host, NULL, &hints, errbuf, > - PCAP_ERRBUF_SIZE); > -- if (retval != 0) > -+ if (addrinfo == NULL) > - { > - *error = 1; > - return NULL; > -@@ -1186,7 +1185,9 @@ static int pcap_startcapture_remote(pcap_t *fp) > - hints.ai_flags = AI_PASSIVE; /* Data connection is opened by the server toward the client */ > - > - /* Let's the server pick up a free network port for us */ > -- if (sock_initaddress(NULL, NULL, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) > -+ addrinfo = sock_initaddress(NULL, NULL, &hints, fp->errbuf, > -+ PCAP_ERRBUF_SIZE); > -+ if (addrinfo == NULL) > - goto error_nodiscard; > - > - if ((sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, > -@@ -1311,7 +1312,9 @@ static int pcap_startcapture_remote(pcap_t *fp) > - snprintf(portstring, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata)); > - > - /* Let's the server pick up a free network port for us */ > -- if (sock_initaddress(host, portstring, &hints, &addrinfo, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) > -+ addrinfo = sock_initaddress(host, portstring, &hints, > -+ fp->errbuf, PCAP_ERRBUF_SIZE); > -+ if (addrinfo == NULL) > - goto error; > - > - if ((sockdata = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) > -@@ -2340,16 +2343,16 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, > - if (port[0] == 0) > - { > - /* the user chose not to specify the port */ > -- if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, > -- &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) > -- return -1; > -+ addrinfo = sock_initaddress(host, RPCAP_DEFAULT_NETPORT, > -+ &hints, errbuf, PCAP_ERRBUF_SIZE); > - } > - else > - { > -- if (sock_initaddress(host, port, &hints, &addrinfo, > -- errbuf, PCAP_ERRBUF_SIZE) == -1) > -- return -1; > -+ addrinfo = sock_initaddress(host, port, &hints, > -+ errbuf, PCAP_ERRBUF_SIZE); > - } > -+ if (addrinfo == NULL) > -+ return -1; > - > - if ((*sockctrlp = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, > - errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) > -@@ -2950,19 +2953,19 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha > - /* Do the work */ > - if ((port == NULL) || (port[0] == 0)) > - { > -- if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) > -- { > -- return (SOCKET)-2; > -- } > -+ addrinfo = sock_initaddress(address, > -+ RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, errbuf, > -+ PCAP_ERRBUF_SIZE); > - } > - else > - { > -- if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) > -- { > -- return (SOCKET)-2; > -- } > -+ addrinfo = sock_initaddress(address, port, &hints, errbuf, > -+ PCAP_ERRBUF_SIZE); > -+ } > -+ if (addrinfo == NULL) > -+ { > -+ return (SOCKET)-2; > - } > -- > - > - if ((sockmain = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) > - { > -@@ -3122,7 +3125,6 @@ int pcap_remoteact_close(const char *host, char *errbuf) > - { > - struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */ > - struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ > -- int retval; > - > - temp = activeHosts; > - prev = NULL; > -@@ -3133,9 +3135,9 @@ int pcap_remoteact_close(const char *host, char *errbuf) > - hints.ai_family = PF_UNSPEC; > - hints.ai_socktype = SOCK_STREAM; > - > -- retval = sock_initaddress(host, NULL, &hints, &addrinfo, errbuf, > -+ addrinfo = sock_initaddress(host, NULL, &hints, errbuf, > - PCAP_ERRBUF_SIZE); > -- if (retval != 0) > -+ if (addrinfo == NULL) > - { > - return -1; > - } > -diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c > -index 8d620dd604..b04b29f107 100644 > ---- a/rpcapd/daemon.c > -+++ b/rpcapd/daemon.c > -@@ -2085,7 +2085,9 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, > - goto error; > - } > - > -- if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) > -+ addrinfo = sock_initaddress(peerhost, portdata, &hints, > -+ errmsgbuf, PCAP_ERRBUF_SIZE); > -+ if (addrinfo == NULL) > - goto error; > - > - if ((session->sockdata = sock_open(peerhost, addrinfo, SOCKOPEN_CLIENT, 0, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) > -@@ -2096,7 +2098,9 @@ daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, > - hints.ai_flags = AI_PASSIVE; > - > - // Make the server socket pick up a free network port for us > -- if (sock_initaddress(NULL, NULL, &hints, &addrinfo, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) > -+ addrinfo = sock_initaddress(NULL, NULL, &hints, errmsgbuf, > -+ PCAP_ERRBUF_SIZE); > -+ if (addrinfo == NULL) > - goto error; > - > - if ((session->sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) > -diff --git a/rpcapd/rpcapd.c b/rpcapd/rpcapd.c > -index e1f3f05299..d166522c9f 100644 > ---- a/rpcapd/rpcapd.c > -+++ b/rpcapd/rpcapd.c > -@@ -611,7 +611,9 @@ void main_startup(void) > - // > - // Get a list of sockets on which to listen. > - // > -- if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) > -+ addrinfo = sock_initaddress((address[0]) ? address : NULL, > -+ port, &mainhints, errbuf, PCAP_ERRBUF_SIZE); > -+ if (addrinfo == NULL) > - { > - rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); > - return; > -@@ -1350,7 +1352,9 @@ main_active(void *ptr) > - memset(errbuf, 0, sizeof(errbuf)); > - > - // Do the work > -- if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) > -+ addrinfo = sock_initaddress(activepars->address, activepars->port, > -+ &hints, errbuf, PCAP_ERRBUF_SIZE); > -+ if (addrinfo == NULL) > - { > - rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); > - return 0; > -diff --git a/sockutils.c b/sockutils.c > -index a1bfa1b5e2..823c2363e0 100644 > ---- a/sockutils.c > -+++ b/sockutils.c > -@@ -1069,20 +1069,21 @@ get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, > - * \param errbuflen: length of the buffer that will contains the error. The error message cannot be > - * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. > - * > -- * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned > -- * in the 'errbuf' variable. The addrinfo variable that has to be used in the following sockets calls is > -- * returned into the addrinfo parameter. > -+ * \return a pointer to the first element in a list of addrinfo structures > -+ * if everything is fine, NULL if some errors occurred. The error message > -+ * is returned in the 'errbuf' variable. > - * > -- * \warning The 'addrinfo' variable has to be deleted by the programmer by calling freeaddrinfo() when > -- * it is no longer needed. > -+ * \warning The list of addrinfo structures returned has to be deleted by > -+ * the programmer by calling freeaddrinfo() when it is no longer needed. > - * > - * \warning This function requires the 'hints' variable as parameter. The semantic of this variable is the same > - * of the one of the corresponding variable used into the standard getaddrinfo() socket function. We suggest > - * the programmer to look at that function in order to set the 'hints' variable appropriately. > - */ > --int sock_initaddress(const char *host, const char *port, > -- struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf, int errbuflen) > -+struct addrinfo *sock_initaddress(const char *host, const char *port, > -+ struct addrinfo *hints, char *errbuf, int errbuflen) > - { > -+ struct addrinfo *addrinfo; > - int retval; > - > - /* > -@@ -1094,9 +1095,13 @@ int sock_initaddress(const char *host, const char *port, > - * as those messages won't talk about a problem with the port if > - * no port was specified. > - */ > -- retval = getaddrinfo(host, port == NULL ? "0" : port, hints, addrinfo); > -+ retval = getaddrinfo(host, port == NULL ? "0" : port, hints, &addrinfo); > - if (retval != 0) > - { > -+ /* > -+ * That call failed. > -+ * Determine whether the problem is that the host is bad. > -+ */ > - if (errbuf) > - { > - if (host != NULL && port != NULL) { > -@@ -1108,7 +1113,7 @@ int sock_initaddress(const char *host, const char *port, > - int try_retval; > - > - try_retval = getaddrinfo(host, NULL, hints, > -- addrinfo); > -+ &addrinfo); > - if (try_retval == 0) { > - /* > - * Worked with just the host, > -@@ -1117,14 +1122,16 @@ int sock_initaddress(const char *host, const char *port, > - * > - * Free up the address info first. > - */ > -- freeaddrinfo(*addrinfo); > -+ freeaddrinfo(addrinfo); > - get_gai_errstring(errbuf, errbuflen, > - "", retval, NULL, port); > - } else { > - /* > - * Didn't work with just the host, > - * so assume the problem is > -- * with the host. > -+ * with the host; we assume > -+ * the original error indicates > -+ * the underlying problem. > - */ > - get_gai_errstring(errbuf, errbuflen, > - "", retval, host, NULL); > -@@ -1132,13 +1139,14 @@ int sock_initaddress(const char *host, const char *port, > - } else { > - /* > - * Either the host or port was null, so > -- * there's nothing to determine. > -+ * there's nothing to determine; report > -+ * the error from the original call. > - */ > - get_gai_errstring(errbuf, errbuflen, "", > - retval, host, port); > - } > - } > -- return -1; > -+ return NULL; > - } > - /* > - * \warning SOCKET: I should check all the accept() in order to bind to all addresses in case > -@@ -1153,30 +1161,28 @@ int sock_initaddress(const char *host, const char *port, > - * ignore all addresses that are neither? (What, no IPX > - * support? :-)) > - */ > -- if (((*addrinfo)->ai_family != PF_INET) && > -- ((*addrinfo)->ai_family != PF_INET6)) > -+ if ((addrinfo->ai_family != PF_INET) && > -+ (addrinfo->ai_family != PF_INET6)) > - { > - if (errbuf) > - snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported"); > -- freeaddrinfo(*addrinfo); > -- *addrinfo = NULL; > -- return -1; > -+ freeaddrinfo(addrinfo); > -+ return NULL; > - } > - > - /* > - * You can't do multicast (or broadcast) TCP. > - */ > -- if (((*addrinfo)->ai_socktype == SOCK_STREAM) && > -- (sock_ismcastaddr((*addrinfo)->ai_addr) == 0)) > -+ if ((addrinfo->ai_socktype == SOCK_STREAM) && > -+ (sock_ismcastaddr(addrinfo->ai_addr) == 0)) > - { > - if (errbuf) > - snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams"); > -- freeaddrinfo(*addrinfo); > -- *addrinfo = NULL; > -- return -1; > -+ freeaddrinfo(addrinfo); > -+ return NULL; > - } > - > -- return 0; > -+ return addrinfo; > - } > - > - /* > -@@ -2089,7 +2095,9 @@ int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, > - > - hints.ai_family = addr_family; > - > -- if (sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen) == -1) > -+ addrinfo = sock_initaddress(address, "22222" /* fake port */, &hints, > -+ errbuf, errbuflen); > -+ if (addrinfo == NULL) > - return 0; > - > - if (addrinfo->ai_family == PF_INET) > -diff --git a/sockutils.h b/sockutils.h > -index a488d8fcb4..30b8cfe0b7 100644 > ---- a/sockutils.h > -+++ b/sockutils.h > -@@ -138,9 +138,8 @@ void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, > - PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(4, 5); > - void sock_geterrmsg(char *errbuf, size_t errbuflen, > - PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(3, 4); > --int sock_initaddress(const char *address, const char *port, > -- struct addrinfo *hints, struct addrinfo **addrinfo, > -- char *errbuf, int errbuflen); > -+struct addrinfo *sock_initaddress(const char *address, const char *port, > -+ struct addrinfo *hints, char *errbuf, int errbuflen); > - int sock_recv(SOCKET sock, SSL *, void *buffer, size_t size, int receiveall, > - char *errbuf, int errbuflen); > - int sock_recv_dgram(SOCKET sock, SSL *, void *buffer, size_t size, > diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch > deleted file mode 100644 > index 6819aedd20..0000000000 > --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2024-8006.patch > +++ /dev/null > @@ -1,42 +0,0 @@ > -From 8a633ee5b9ecd9d38a587ac9b204e2380713b0d6 Mon Sep 17 00:00:00 2001 > -From: Nicolas Badoux <n.badoux@hotmail.com> > -Date: Mon, 19 Aug 2024 12:31:53 +0200 > -Subject: [PATCH] makes pcap_findalldevs_ex errors out if the directory does > - not exist > - > -(backported from commit 0f8a103469ce87d2b8d68c5130a46ddb7fb5eb29) > - > -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/8a633ee5b9ecd9d38a587ac9b204e2380713b0d6] > -CVE: CVE-2024-8006 > -Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> > ---- > - pcap-new.c | 9 ++++++++- > - 1 file changed, 8 insertions(+), 1 deletion(-) > - > -diff --git a/pcap-new.c b/pcap-new.c > -index be91b3f8db..d449ee623c 100644 > ---- a/pcap-new.c > -+++ b/pcap-new.c > -@@ -230,6 +230,13 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t > - #else > - /* opening the folder */ > - unixdir= opendir(path); > -+ if (unixdir == NULL) { > -+ DIAG_OFF_FORMAT_TRUNCATION > -+ snprintf(errbuf, PCAP_ERRBUF_SIZE, > -+ "Error when listing files: does folder '%s' exist?", path); > -+ DIAG_ON_FORMAT_TRUNCATION > -+ return -1; > -+ } > - > - /* get the first file into it */ > - filedata= readdir(unixdir); > -@@ -237,7 +244,7 @@ int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t > - if (filedata == NULL) > - { > - DIAG_OFF_FORMAT_TRUNCATION > -- snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); > -+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' contain files?", path); > - DIAG_ON_FORMAT_TRUNCATION > - closedir(unixdir); > - return -1; > diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch > deleted file mode 100644 > index 73c3ab3f5c..0000000000 > --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch > +++ /dev/null > @@ -1,38 +0,0 @@ > -From 7224be0fe2f4beb916b7b69141f478facd0f0634 Mon Sep 17 00:00:00 2001 > -From: Denis Ovsienko <denis@ovsienko.info> > -Date: Sat, 27 Dec 2025 21:36:11 +0000 > -Subject: [PATCH] Rename one of the xdtoi() copies to simplify backporting. > - > -CVE: CVE-2025-11961 > -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7224be0fe2f4beb916b7b69141f478facd0f0634] > -Signed-off-by: Peter Marko <peter.marko@siemens.com> > ---- > - nametoaddr.c | 6 +++--- > - 1 file changed, 3 insertions(+), 3 deletions(-) > - > -diff --git a/nametoaddr.c b/nametoaddr.c > -index dc75495c..bdaacbf1 100644 > ---- a/nametoaddr.c > -+++ b/nametoaddr.c > -@@ -646,7 +646,7 @@ pcap_nametollc(const char *s) > - > - /* Hex digit to 8-bit unsigned integer. */ > - static inline u_char > --xdtoi(u_char c) > -+pcapint_xdtoi(u_char c) > - { > - if (c >= '0' && c <= '9') > - return (u_char)(c - '0'); > -@@ -728,10 +728,10 @@ pcap_ether_aton(const char *s) > - while (*s) { > - if (*s == ':' || *s == '.' || *s == '-') > - s += 1; > -- d = xdtoi(*s++); > -+ d = pcapint_xdtoi(*s++); > - if (PCAP_ISXDIGIT(*s)) { > - d <<= 4; > -- d |= xdtoi(*s++); > -+ d |= pcapint_xdtoi(*s++); > - } > - *ep++ = d; > - } > diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch > deleted file mode 100644 > index 2dca7908ef..0000000000 > --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch > +++ /dev/null > @@ -1,433 +0,0 @@ > -From b2d2f9a9a0581c40780bde509f7cc715920f1c02 Mon Sep 17 00:00:00 2001 > -From: Denis Ovsienko <denis@ovsienko.info> > -Date: Fri, 19 Dec 2025 17:31:13 +0000 > -Subject: [PATCH] CVE-2025-11961: Fix OOBR and OOBW in pcap_ether_aton(). > - > -pcap_ether_aton() has for a long time required its string argument to be > -a well-formed MAC-48 address, which is always the case when the argument > -comes from other libpcap code, so the function has never validated the > -input and used a simple loop to parse any of the three common MAC-48 > -address formats. However, the function has also been a part of the > -public API, so calling it directly with a malformed address can cause > -the loop to read beyond the end of the input string and/or to write > -beyond the end of the allocated output buffer. > - > -To handle invalid input more appropriately, replace the simple loop with > -new functions and require the input to match a supported address format. > - > -This problem was reported by Jin Wei, Kunwei Qian and Ping Chen. > - > -(backported from commit dd08e53e9380e217ae7c7768da9cc3d7bf37bf83) > - > -CVE: CVE-2025-11961 > -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/b2d2f9a9a0581c40780bde509f7cc715920f1c02] > -Signed-off-by: Peter Marko <peter.marko@siemens.com> > ---- > - gencode.c | 5 + > - nametoaddr.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++---- > - 2 files changed, 349 insertions(+), 23 deletions(-) > - > -diff --git a/gencode.c b/gencode.c > -index 3ddd15f8..76fb2d82 100644 > ---- a/gencode.c > -+++ b/gencode.c > -@@ -7228,6 +7228,11 @@ gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) > - return (NULL); > - > - if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { > -+ /* > -+ * Because the lexer guards the input string format, in this > -+ * context the function returns NULL iff the implicit malloc() > -+ * has failed. > -+ */ > - cstate->e = pcap_ether_aton(s); > - if (cstate->e == NULL) > - bpf_error(cstate, "malloc"); > -diff --git a/nametoaddr.c b/nametoaddr.c > -index f9fcd288..f50d0da5 100644 > ---- a/nametoaddr.c > -+++ b/nametoaddr.c > -@@ -703,39 +703,360 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr) > - return(32); > - } > - > -+// Man page: "xxxxxxxxxxxx", regexp: "^[0-9a-fA-F]{12}$". > -+static u_char > -+pcapint_atomac48_xxxxxxxxxxxx(const char *s, uint8_t *addr) > -+{ > -+ if (strlen(s) == 12 && > -+ PCAP_ISXDIGIT(s[0]) && > -+ PCAP_ISXDIGIT(s[1]) && > -+ PCAP_ISXDIGIT(s[2]) && > -+ PCAP_ISXDIGIT(s[3]) && > -+ PCAP_ISXDIGIT(s[4]) && > -+ PCAP_ISXDIGIT(s[5]) && > -+ PCAP_ISXDIGIT(s[6]) && > -+ PCAP_ISXDIGIT(s[7]) && > -+ PCAP_ISXDIGIT(s[8]) && > -+ PCAP_ISXDIGIT(s[9]) && > -+ PCAP_ISXDIGIT(s[10]) && > -+ PCAP_ISXDIGIT(s[11])) { > -+ addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); > -+ addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); > -+ addr[2] = pcapint_xdtoi(s[4]) << 4 | pcapint_xdtoi(s[5]); > -+ addr[3] = pcapint_xdtoi(s[6]) << 4 | pcapint_xdtoi(s[7]); > -+ addr[4] = pcapint_xdtoi(s[8]) << 4 | pcapint_xdtoi(s[9]); > -+ addr[5] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); > -+ return 1; > -+ } > -+ return 0; > -+} > -+ > -+// Man page: "xxxx.xxxx.xxxx", regexp: "^[0-9a-fA-F]{4}(\.[0-9a-fA-F]{4}){2}$". > -+static u_char > -+pcapint_atomac48_xxxx_3_times(const char *s, uint8_t *addr) > -+{ > -+ const char sep = '.'; > -+ if (strlen(s) == 14 && > -+ PCAP_ISXDIGIT(s[0]) && > -+ PCAP_ISXDIGIT(s[1]) && > -+ PCAP_ISXDIGIT(s[2]) && > -+ PCAP_ISXDIGIT(s[3]) && > -+ s[4] == sep && > -+ PCAP_ISXDIGIT(s[5]) && > -+ PCAP_ISXDIGIT(s[6]) && > -+ PCAP_ISXDIGIT(s[7]) && > -+ PCAP_ISXDIGIT(s[8]) && > -+ s[9] == sep && > -+ PCAP_ISXDIGIT(s[10]) && > -+ PCAP_ISXDIGIT(s[11]) && > -+ PCAP_ISXDIGIT(s[12]) && > -+ PCAP_ISXDIGIT(s[13])) { > -+ addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); > -+ addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); > -+ addr[2] = pcapint_xdtoi(s[5]) << 4 | pcapint_xdtoi(s[6]); > -+ addr[3] = pcapint_xdtoi(s[7]) << 4 | pcapint_xdtoi(s[8]); > -+ addr[4] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); > -+ addr[5] = pcapint_xdtoi(s[12]) << 4 | pcapint_xdtoi(s[13]); > -+ return 1; > -+ } > -+ return 0; > -+} > -+ > - /* > -- * Convert 's', which can have the one of the forms: > -+ * Man page: "xx:xx:xx:xx:xx:xx", regexp: "^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$". > -+ * Man page: "xx-xx-xx-xx-xx-xx", regexp: "^[0-9a-fA-F]{1,2}(-[0-9a-fA-F]{1,2}){5}$". > -+ * Man page: "xx.xx.xx.xx.xx.xx", regexp: "^[0-9a-fA-F]{1,2}(\.[0-9a-fA-F]{1,2}){5}$". > -+ * (Any "xx" above can be "x", which is equivalent to "0x".) > - * > -- * "xx:xx:xx:xx:xx:xx" > -- * "xx.xx.xx.xx.xx.xx" > -- * "xx-xx-xx-xx-xx-xx" > -- * "xxxx.xxxx.xxxx" > -- * "xxxxxxxxxxxx" > -+ * An equivalent (and parametrisable for EUI-64) FSM could be implemented using > -+ * a smaller graph, but that graph would be neither acyclic nor planar nor > -+ * trivial to verify. > - * > -- * (or various mixes of ':', '.', and '-') into a new > -- * ethernet address. Assumes 's' is well formed. > -+ * | > -+ * [.] v > -+ * +<---------- START > -+ * | | > -+ * | | [0-9a-fA-F] > -+ * | [.] v > -+ * +<--------- BYTE0_X ----------+ > -+ * | | | > -+ * | | [0-9a-fA-F] | > -+ * | [.] v | > -+ * +<--------- BYTE0_XX | [:\.-] > -+ * | | | > -+ * | | [:\.-] | > -+ * | [.] v | > -+ * +<----- BYTE0_SEP_BYTE1 <-----+ > -+ * | | > -+ * | | [0-9a-fA-F] > -+ * | [.] v > -+ * +<--------- BYTE1_X ----------+ > -+ * | | | > -+ * | | [0-9a-fA-F] | > -+ * | [.] v | > -+ * +<--------- BYTE1_XX | <sep> > -+ * | | | > -+ * | | <sep> | > -+ * | [.] v | > -+ * +<----- BYTE1_SEP_BYTE2 <-----+ > -+ * | | > -+ * | | [0-9a-fA-F] > -+ * | [.] v > -+ * +<--------- BYTE2_X ----------+ > -+ * | | | > -+ * | | [0-9a-fA-F] | > -+ * | [.] v | > -+ * +<--------- BYTE2_XX | <sep> > -+ * | | | > -+ * | | <sep> | > -+ * | [.] v | > -+ * +<----- BYTE2_SEP_BYTE3 <-----+ > -+ * | | > -+ * | | [0-9a-fA-F] > -+ * | [.] v > -+ * +<--------- BYTE3_X ----------+ > -+ * | | | > -+ * | | [0-9a-fA-F] | > -+ * | [.] v | > -+ * +<--------- BYTE3_XX | <sep> > -+ * | | | > -+ * | | <sep> | > -+ * | [.] v | > -+ * +<----- BYTE3_SEP_BYTE4 <-----+ > -+ * | | > -+ * | | [0-9a-fA-F] > -+ * | [.] v > -+ * +<--------- BYTE4_X ----------+ > -+ * | | | > -+ * | | [0-9a-fA-F] | > -+ * | [.] v | > -+ * +<--------- BYTE4_XX | <sep> > -+ * | | | > -+ * | | <sep> | > -+ * | [.] v | > -+ * +<----- BYTE4_SEP_BYTE5 <-----+ > -+ * | | > -+ * | | [0-9a-fA-F] > -+ * | [.] v > -+ * +<--------- BYTE5_X ----------+ > -+ * | | | > -+ * | | [0-9a-fA-F] | > -+ * | [.] v | > -+ * +<--------- BYTE5_XX | \0 > -+ * | | | > -+ * | | \0 | > -+ * | | v > -+ * +--> (reject) +---------> (accept) > -+ * > -+ */ > -+static u_char > -+pcapint_atomac48_x_xx_6_times(const char *s, uint8_t *addr) > -+{ > -+ enum { > -+ START, > -+ BYTE0_X, > -+ BYTE0_XX, > -+ BYTE0_SEP_BYTE1, > -+ BYTE1_X, > -+ BYTE1_XX, > -+ BYTE1_SEP_BYTE2, > -+ BYTE2_X, > -+ BYTE2_XX, > -+ BYTE2_SEP_BYTE3, > -+ BYTE3_X, > -+ BYTE3_XX, > -+ BYTE3_SEP_BYTE4, > -+ BYTE4_X, > -+ BYTE4_XX, > -+ BYTE4_SEP_BYTE5, > -+ BYTE5_X, > -+ BYTE5_XX, > -+ } fsm_state = START; > -+ uint8_t buf[6]; > -+ const char *seplist = ":.-"; > -+ char sep; > -+ > -+ while (*s) { > -+ switch (fsm_state) { > -+ case START: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[0] = pcapint_xdtoi(*s); > -+ fsm_state = BYTE0_X; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE0_X: > -+ if (strchr(seplist, *s)) { > -+ sep = *s; > -+ fsm_state = BYTE0_SEP_BYTE1; > -+ break; > -+ } > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[0] = buf[0] << 4 | pcapint_xdtoi(*s); > -+ fsm_state = BYTE0_XX; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE0_XX: > -+ if (strchr(seplist, *s)) { > -+ sep = *s; > -+ fsm_state = BYTE0_SEP_BYTE1; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE0_SEP_BYTE1: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[1] = pcapint_xdtoi(*s); > -+ fsm_state = BYTE1_X; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE1_X: > -+ if (*s == sep) { > -+ fsm_state = BYTE1_SEP_BYTE2; > -+ break; > -+ } > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[1] = buf[1] << 4 | pcapint_xdtoi(*s); > -+ fsm_state = BYTE1_XX; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE1_XX: > -+ if (*s == sep) { > -+ fsm_state = BYTE1_SEP_BYTE2; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE1_SEP_BYTE2: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[2] = pcapint_xdtoi(*s); > -+ fsm_state = BYTE2_X; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE2_X: > -+ if (*s == sep) { > -+ fsm_state = BYTE2_SEP_BYTE3; > -+ break; > -+ } > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[2] = buf[2] << 4 | pcapint_xdtoi(*s); > -+ fsm_state = BYTE2_XX; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE2_XX: > -+ if (*s == sep) { > -+ fsm_state = BYTE2_SEP_BYTE3; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE2_SEP_BYTE3: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[3] = pcapint_xdtoi(*s); > -+ fsm_state = BYTE3_X; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE3_X: > -+ if (*s == sep) { > -+ fsm_state = BYTE3_SEP_BYTE4; > -+ break; > -+ } > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[3] = buf[3] << 4 | pcapint_xdtoi(*s); > -+ fsm_state = BYTE3_XX; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE3_XX: > -+ if (*s == sep) { > -+ fsm_state = BYTE3_SEP_BYTE4; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE3_SEP_BYTE4: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[4] = pcapint_xdtoi(*s); > -+ fsm_state = BYTE4_X; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE4_X: > -+ if (*s == sep) { > -+ fsm_state = BYTE4_SEP_BYTE5; > -+ break; > -+ } > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[4] = buf[4] << 4 | pcapint_xdtoi(*s); > -+ fsm_state = BYTE4_XX; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE4_XX: > -+ if (*s == sep) { > -+ fsm_state = BYTE4_SEP_BYTE5; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE4_SEP_BYTE5: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[5] = pcapint_xdtoi(*s); > -+ fsm_state = BYTE5_X; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE5_X: > -+ if (PCAP_ISXDIGIT(*s)) { > -+ buf[5] = buf[5] << 4 | pcapint_xdtoi(*s); > -+ fsm_state = BYTE5_XX; > -+ break; > -+ } > -+ goto reject; > -+ case BYTE5_XX: > -+ goto reject; > -+ } // switch > -+ s++; > -+ } // while > -+ > -+ if (fsm_state == BYTE5_X || fsm_state == BYTE5_XX) { > -+ // accept > -+ memcpy(addr, buf, sizeof(buf)); > -+ return 1; > -+ } > -+ > -+reject: > -+ return 0; > -+} > -+ > -+// The 'addr' argument must point to an array of at least 6 elements. > -+static int > -+pcapint_atomac48(const char *s, uint8_t *addr) > -+{ > -+ return s && ( > -+ pcapint_atomac48_xxxxxxxxxxxx(s, addr) || > -+ pcapint_atomac48_xxxx_3_times(s, addr) || > -+ pcapint_atomac48_x_xx_6_times(s, addr) > -+ ); > -+} > -+ > -+/* > -+ * If 's' is a MAC-48 address in one of the forms documented in pcap-filter(7) > -+ * for "ether host", return a pointer to an allocated buffer with the binary > -+ * value of the address. Return NULL on any error. > - */ > - u_char * > - pcap_ether_aton(const char *s) > - { > -- register u_char *ep, *e; > -- register u_char d; > -+ uint8_t tmp[6]; > -+ if (! pcapint_atomac48(s, tmp)) > -+ return (NULL); > - > -- e = ep = (u_char *)malloc(6); > -+ u_char *e = malloc(6); > - if (e == NULL) > - return (NULL); > -- > -- while (*s) { > -- if (*s == ':' || *s == '.' || *s == '-') > -- s += 1; > -- d = pcapint_xdtoi(*s++); > -- if (PCAP_ISXDIGIT(*s)) { > -- d <<= 4; > -- d |= pcapint_xdtoi(*s++); > -- } > -- *ep++ = d; > -- } > -- > -+ memcpy(e, tmp, sizeof(tmp)); > - return (e); > - } > - > diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch > deleted file mode 100644 > index 003d21fb1f..0000000000 > --- a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch > +++ /dev/null > @@ -1,33 +0,0 @@ > -From 7fabf607f2319a36a0bd78444247180acb838e69 Mon Sep 17 00:00:00 2001 > -From: Guy Harris <gharris@sonic.net> > -Date: Sun, 7 Sep 2025 12:51:56 -0700 > -Subject: [PATCH] Fix a copy-and-pasteo in utf_16le_to_utf_8_truncated(). > - > -For the four octets of UTF-8 case, it was decrementing the remaining > -buffer length by 3, not 4. > - > -Thanks to a team of developers from the Univesity of Waterloo for > -reporting this. > - > -(cherry picked from commit aebfca1aea2fc8c177760a26e8f4de27b51d1b3b) > - > -CVE: CVE-2025-11964 > -Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7fabf607f2319a36a0bd78444247180acb838e69] > -Signed-off-by: Peter Marko <peter.marko@siemens.com> > ---- > - fmtutils.c | 2 +- > - 1 file changed, 1 insertion(+), 1 deletion(-) > - > -diff --git a/fmtutils.c b/fmtutils.c > -index a5a4fe62..78a0f8b7 100644 > ---- a/fmtutils.c > -+++ b/fmtutils.c > -@@ -235,7 +235,7 @@ utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8, > - *utf_8++ = ((uc >> 12) & 0x3F) | 0x80; > - *utf_8++ = ((uc >> 6) & 0x3F) | 0x80; > - *utf_8++ = ((uc >> 0) & 0x3F) | 0x80; > -- utf_8_len -= 3; > -+ utf_8_len -= 4; > - } > - } > - > diff --git a/meta/recipes-connectivity/libpcap/libpcap_1.10.4.bb b/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb > similarity index 83% > rename from meta/recipes-connectivity/libpcap/libpcap_1.10.4.bb > rename to meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb > index ee7d7540f6..5cba790012 100644 > --- a/meta/recipes-connectivity/libpcap/libpcap_1.10.4.bb > +++ b/meta/recipes-connectivity/libpcap/libpcap_1.10.6.bb > @@ -11,15 +11,9 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=5eb289217c160e2920d2e35bddc36453 \ > DEPENDS = "flex-native bison-native" > > SRC_URI = "https://www.tcpdump.org/release/${BP}.tar.gz \ > - file://CVE-2023-7256-pre1.patch \ > - file://CVE-2023-7256.patch \ > - file://CVE-2024-8006.patch \ > - file://CVE-2025-11961-01.patch \ > - file://CVE-2025-11961-02.patch \ > - file://CVE-2025-11964.patch \ > " > > -SRC_URI[sha256sum] = "ed19a0383fad72e3ad435fd239d7cd80d64916b87269550159d20e47160ebe5f" > +SRC_URI[sha256sum] = "872dd11337fe1ab02ad9d4fee047c9da244d695c6ddf34e2ebb733efd4ed8aa9" > > inherit autotools binconfig-disabled pkgconfig > -- Yoann Congal Smile ECS ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2026-04-27 6:20 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 01/12] gi-docgen: fix CVE-2025-11687 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 jinfeng.wang.cn 2026-04-23 17:09 ` [OE-core] " Yoann Congal 2026-04-24 7:16 ` Li, Changqing 2026-04-09 6:16 ` [scarthgap][PATCH 03/12] libsoup-2.4: " jinfeng.wang.cn 2026-04-23 17:13 ` [OE-core] " Yoann Congal 2026-04-24 7:37 ` Li, Changqing 2026-04-09 6:16 ` [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 jinfeng.wang.cn 2026-04-24 6:45 ` [OE-core] " Yoann Congal 2026-04-27 6:20 ` Chen, Libo (CN) 2026-04-09 6:16 ` [scarthgap][PATCH 05/12] python3-pyasn1: fix CVE-2026-23490 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 06/12] python3-wheel: fix CVE-2026-24049 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 07/12] gnupg: fix CVE-2026-24882 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 08/12] libxml2: Fix CVE-2026-1757 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 jinfeng.wang.cn 2026-04-24 7:36 ` [OE-core] " Yoann Congal 2026-04-27 6:04 ` Song, Jiaying (CN) 2026-04-09 6:16 ` [scarthgap][PATCH 10/12] busybox: fix CVE-2026-26157 and CVE-2026-26158 jinfeng.wang.cn 2026-04-09 6:16 ` [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 jinfeng.wang.cn 2026-04-24 8:10 ` [OE-core] " Yoann Congal 2026-04-09 6:16 ` [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 jinfeng.wang.cn 2026-04-24 8:21 ` [OE-core] " Yoann Congal
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox