Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions SPECS/libsoup/CVE-2026-0716.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
From 88ed9cc700ff5d1a40b1e09918c6f09d435da76b Mon Sep 17 00:00:00 2001
From: Mike Gorse <mgorse@suse.com>
Date: Mon, 2 Feb 2026 10:46:00 -0600
Subject: [PATCH] websocket: Fix out-of-bounds read in process_frame

If the maximum incoming payload size is unset, then a malicious frame could
cause an overflow when calculating the needed amount of data, leading to an
out-of-bounds read later.

This is CVE-2026-0716.

Closes #476

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/494.patch
---
libsoup/websocket/soup-websocket-connection.c | 6 +++
tests/websocket-test.c | 44 +++++++++++++++++++
2 files changed, 50 insertions(+)

diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c
index ef54ab6..5d14006 100644
--- a/libsoup/websocket/soup-websocket-connection.c
+++ b/libsoup/websocket/soup-websocket-connection.c
@@ -1096,6 +1096,12 @@ process_frame (SoupWebsocketConnection *self)
payload += 4;
at += 4;

+ /* at has a maximum value of 10 + 4 = 14 */
+ if (payload_len > G_MAXSIZE - 14) {
+ bad_data_error_and_close (self);
+ return FALSE;
+ }
+
if (len < at + payload_len)
return FALSE; /* need more data */

diff --git a/tests/websocket-test.c b/tests/websocket-test.c
index a7fc7e9..bd866d4 100644
--- a/tests/websocket-test.c
+++ b/tests/websocket-test.c
@@ -2170,6 +2170,41 @@ test_connection_error (void)
soup_test_session_abort_unref (session);
}

+static void
+test_cve_2026_0716 (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ GIOStream *io;
+ gsize written;
+ const char *frame;
+ gboolean close_event = FALSE;
+
+ g_signal_handlers_disconnect_by_func (test->server, on_error_not_reached, 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);
+
+ io = soup_websocket_connection_get_io_stream (test->client);
+
+ soup_websocket_connection_set_max_incoming_payload_size (test->server, 0);
+
+ // Malicious masked frame header (10-byte header + 4-byte mask) */
+ frame = "\x82\xff\xff\xff\xff\xff\xff\xff\xff\xf6\xaa\xbb\xcc\xdd";
+ if (!g_output_stream_write_all (g_io_stream_get_output_stream (io),
+ frame, 14, &written, NULL, NULL))
+ g_assert_cmpstr ("This code", ==, "should not be reached");
+ g_assert_cmpuint (written, ==, 14);
+
+ WAIT_UNTIL (error != NULL);
+ g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_BAD_DATA);
+ g_clear_error (&error);
+
+ WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
+ g_assert_true (close_event);
+
+ g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, SOUP_WEBSOCKET_CLOSE_BAD_DATA);
+}
+
int
main (int argc,
char *argv[])
@@ -2441,6 +2476,15 @@ main (int argc,

g_test_add_func ("/websocket/soup/connection-error", test_connection_error);

+ g_test_add ("/websocket/direct/cve-2026-0716", Test, NULL,
+ setup_direct_connection,
+ test_cve_2026_0716,
+ teardown_direct_connection);
+ g_test_add ("/websocket/soup/cve-2026-0716", Test, NULL,
+ setup_soup_connection,
+ test_cve_2026_0716,
+ teardown_soup_connection);
+
ret = g_test_run ();

test_cleanup ();
--
2.45.4

159 changes: 159 additions & 0 deletions SPECS/libsoup/CVE-2026-1760.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
From 88e2c97ac8bd202de4a8b8357fe88e7e4d5afe66 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Tue, 17 Feb 2026 02:44:11 +0000
Subject: [PATCH] server: close the connection after responsing a request
containing Content-Length and Transfer-Encoding

Closes #475

- Recompute encoding lazily prioritizing Transfer-Encoding over Content-Length.
- Ensure server closes connection when both headers are present by setting Connection: close.

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport from existing Build 1050366 of https://gitlab.gnome.org/GNOME/libsoup/-/commit/30b682af333402eeef4fad3acbc865771f85281a.patch
---
libsoup/server/soup-server-io.c | 9 ++++
libsoup/soup-message-headers.c | 88 +++++++++++++++------------------
2 files changed, 50 insertions(+), 47 deletions(-)

diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c
index 7e9cc45..0efb9b7 100644
--- a/libsoup/server/soup-server-io.c
+++ b/libsoup/server/soup-server-io.c
@@ -599,6 +599,15 @@ parse_headers (SoupServerMessage *msg,
return SOUP_STATUS_BAD_REQUEST;
}

+ /* A server MAY reject a request that contains both Content-Length and
+ * Transfer-Encoding or process such a request in accordance with the
+ * Transfer-Encoding alone. Regardless, the server MUST close the connection
+ * after responding to such a request to avoid the potential attacks
+ */
+ if (*encoding == SOUP_ENCODING_CHUNKED && soup_message_headers_get_one_common (request_headers, SOUP_HEADER_CONTENT_LENGTH))
+ soup_message_headers_replace_common (request_headers, SOUP_HEADER_CONNECTION, "close", TRUE);
+
+
/* Generate correct context for request */
req_host = soup_message_headers_get_one_common (request_headers, SOUP_HEADER_HOST);
if (req_host && strchr (req_host, '/')) {
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index d71a2cf..1a6be25 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -155,19 +155,8 @@ soup_message_headers_set (SoupMessageHeaders *hdrs,
{
switch (name) {
case SOUP_HEADER_CONTENT_LENGTH:
- if (hdrs->encoding == SOUP_ENCODING_CHUNKED)
- return;
-
- if (value) {
- char *end;
-
- hdrs->content_length = g_ascii_strtoull (value, &end, 10);
- if (*end)
- hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
- else
- hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
- } else
- hdrs->encoding = -1;
+ case SOUP_HEADER_TRANSFER_ENCODING:
+ hdrs->encoding = -1;
break;
case SOUP_HEADER_CONTENT_TYPE:
g_clear_pointer (&hdrs->content_type, g_free);
@@ -193,21 +182,7 @@ soup_message_headers_set (SoupMessageHeaders *hdrs,
} else
hdrs->expectations = 0;
break;
- case SOUP_HEADER_TRANSFER_ENCODING:
- if (value) {
- /* "identity" is a wrong value according to RFC errata 408,
- * and RFC 7230 does not list it as valid transfer-coding.
- * Nevertheless, the obsolete RFC 2616 stated "identity"
- * as valid, so we can't handle it as unrecognized here
- * for compatibility reasons.
- */
- if (g_ascii_strcasecmp (value, "chunked") == 0)
- hdrs->encoding = SOUP_ENCODING_CHUNKED;
- else if (g_ascii_strcasecmp (value, "identity") != 0)
- hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
- } else
- hdrs->encoding = -1;
- break;
+ /* SOUP_HEADER_TRANSFER_ENCODING handled by recomputing encoding lazily */
default:
break;
}
@@ -951,30 +926,49 @@ soup_message_headers_foreach (SoupMessageHeaders *hdrs,
SoupEncoding
soup_message_headers_get_encoding (SoupMessageHeaders *hdrs)
{
- const char *header;
+ const char *content_length;
+ const char *transfer_encoding;

if (hdrs->encoding != -1)
return hdrs->encoding;

- /* If Transfer-Encoding was set, hdrs->encoding would already
- * be set. So we don't need to check that possibility.
- */
- header = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
- if (header) {
- soup_message_headers_set (hdrs, SOUP_HEADER_CONTENT_LENGTH, header);
- if (hdrs->encoding != -1)
- return hdrs->encoding;
- }
+ /* Transfer-Encoding is checked first because it overrides the Content-Length */
+ transfer_encoding = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING);
+ if (transfer_encoding) {
+ /* "identity" is a wrong value according to RFC errata 408,
+ * and RFC 7230 does not list it as valid transfer-coding.
+ * Nevertheless, the obsolete RFC 2616 stated "identity"
+ * as valid, so we can't handle it as unrecognized here
+ * for compatibility reasons.
+ */
+ if (g_ascii_strcasecmp (transfer_encoding, "chunked") == 0)
+ hdrs->encoding = SOUP_ENCODING_CHUNKED;
+ else if (g_ascii_strcasecmp (transfer_encoding, "identity") != 0)
+ hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
+ } else {
+ content_length = soup_message_headers_get_one_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
+ if (content_length) {
+ char *end;

- /* Per RFC 2616 4.4, a response body that doesn't indicate its
- * encoding otherwise is terminated by connection close, and a
- * request that doesn't indicate otherwise has no body. Note
- * that SoupMessage calls soup_message_headers_set_encoding()
- * to override the response body default for our own
- * server-side messages.
- */
- hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
- SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
+ hdrs->content_length = g_ascii_strtoull (content_length, &end, 10);
+ if (*end)
+ hdrs->encoding = SOUP_ENCODING_UNRECOGNIZED;
+ else
+ hdrs->encoding = SOUP_ENCODING_CONTENT_LENGTH;
+ }
+ }
+
+ if (hdrs->encoding == -1) {
+ /* Per RFC 2616 4.4, a response body that doesn't indicate its
+ * encoding otherwise is terminated by connection close, and a
+ * request that doesn't indicate otherwise has no body. Note
+ * that SoupMessage calls soup_message_headers_set_encoding()
+ * to override the response body default for our own
+ * server-side messages.
+ */
+ hdrs->encoding = (hdrs->type == SOUP_MESSAGE_HEADERS_RESPONSE) ?
+ SOUP_ENCODING_EOF : SOUP_ENCODING_NONE;
+ }
return hdrs->encoding;
}

--
2.45.4

7 changes: 6 additions & 1 deletion SPECS/libsoup/libsoup.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Summary: libsoup HTTP client/server library
Name: libsoup
Version: %{BaseVersion}.4
Release: 11%{?dist}
Release: 12%{?dist}
License: GPLv2
Vendor: Microsoft Corporation
Distribution: Mariner
Expand Down Expand Up @@ -38,6 +38,8 @@ Patch19: CVE-2025-4969.patch
Patch20: CVE-2025-11021.patch
Patch21: CVE-2025-32049.patch
Patch22: CVE-2026-1536.patch
Patch23: CVE-2026-0716.patch
Patch24: CVE-2026-1760.patch


BuildRequires: meson
Expand Down Expand Up @@ -150,6 +152,9 @@ find %{buildroot} -type f -name "*.la" -delete -print
%defattr(-,root,root)

%changelog
* Tue Feb 17 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.0.4-12
- Patch for CVE-2026-1760, CVE-2026-0716

* Thu Feb 12 2026 Jyoti Kanase <v-jykanase@microsoft.com> - 3.0.4-11
- Patch for CVE-2025-32049, CVE-2025-1536

Expand Down
Loading