diff --git a/ef6c4bf6.patch b/ef6c4bf6.patch index 6198224..2788bd1 100644 --- a/ef6c4bf6.patch +++ b/ef6c4bf6.patch @@ -11,7 +11,7 @@ CVE-2025-2784 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libsoup/soup-content-sniffer.c b/libsoup/soup-content-sniffer.c -index 967ec6141..4c8134a7f 100644 +index 967ec614..4c8134a7 100644 --- a/libsoup/soup-content-sniffer.c +++ b/libsoup/soup-content-sniffer.c @@ -642,7 +642,7 @@ sniff_feed_or_html (SoupContentSniffer *sniffer, SoupBuffer *buffer) @@ -24,7 +24,7 @@ index 967ec6141..4c8134a7f 100644 if (skip_insignificant_space (resource, &pos, resource_length)) diff --git a/tests/sniffing-test.c b/tests/sniffing-test.c -index d2aa86b9d..0a4569a43 100644 +index d2aa86b9..0a4569a4 100644 --- a/tests/sniffing-test.c +++ b/tests/sniffing-test.c @@ -605,6 +605,11 @@ main (int argc, char **argv) @@ -40,7 +40,7 @@ index d2aa86b9d..0a4569a43 100644 g_test_add_data_func ("/sniffing/disabled", "/text_or_binary/home.gif", diff --git a/tests/soup-tests.gresource.xml b/tests/soup-tests.gresource.xml -index 9c08d170e..cbef1d402 100644 +index 9c08d170..cbef1d40 100644 --- a/tests/soup-tests.gresource.xml +++ b/tests/soup-tests.gresource.xml @@ -25,5 +25,6 @@ diff --git a/libsoup2-CVE-2025-14523.patch b/libsoup2-CVE-2025-14523.patch new file mode 100644 index 0000000..a3457df --- /dev/null +++ b/libsoup2-CVE-2025-14523.patch @@ -0,0 +1,125 @@ +From ff8829d85b5903d16c4b284ccc75977af20da9ba Mon Sep 17 00:00:00 2001 +From: Alynx Zhou +Date: Thu, 8 Jan 2026 13:05:33 +0800 +Subject: [PATCH] Reject duplicate Host headers + +--- + libsoup/soup-headers.c | 4 +++- + libsoup/soup-message-headers-private.h | 10 ++++++++++ + libsoup/soup-message-headers.c | 27 ++++++++++++++++++++------ + 3 files changed, 34 insertions(+), 7 deletions(-) + create mode 100644 libsoup/soup-message-headers-private.h + +diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c +index cc481cfa..b58f3855 100644 +--- a/libsoup/soup-headers.c ++++ b/libsoup/soup-headers.c +@@ -14,6 +14,7 @@ + + #include "soup-headers.h" + #include "soup.h" ++#include "soup-message-headers-private.h" + + /** + * soup_headers_parse: +@@ -138,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 (dest, name, value); ++ if (!soup_message_headers_append_internal (dest, name, value)) ++ goto done; + } + success = TRUE; + +diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h +new file mode 100644 +index 00000000..62a4e511 +--- /dev/null ++++ b/libsoup/soup-message-headers-private.h +@@ -0,0 +1,10 @@ ++#ifndef __SOUP_MESSAGE_HEADERS_PRIVATE_H__ ++#define __SOUP_MESSAGE_HEADERS_PRIVATE_H__ 1 ++ ++#include "soup-message-headers.h" ++ ++gboolean ++soup_message_headers_append_internal (SoupMessageHeaders *hdrs, ++ const char *name, const char *value); ++ ++#endif +diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c +index 39ad14a0..160a52dc 100644 +--- a/libsoup/soup-message-headers.c ++++ b/libsoup/soup-message-headers.c +@@ -13,6 +13,7 @@ + + #include "soup-message-headers.h" + #include "soup.h" ++#include "soup-message-headers-private.h" + #include "soup-misc-private.h" + + /** +@@ -194,12 +195,20 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs) + void + soup_message_headers_append (SoupMessageHeaders *hdrs, + const char *name, const char *value) ++{ ++ soup_message_headers_append_internal (hdrs, name, value); ++} ++ ++gboolean ++soup_message_headers_append_internal (SoupMessageHeaders *hdrs, ++ const char *name, const char *value) + { + SoupHeader header; + SoupHeaderSetter setter; ++ const char *interned_host = intern_header_name ("Host", NULL); + +- 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 +@@ -207,26 +216,32 @@ 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; ++ return FALSE; + } + if (strpbrk (value, "\r\n")) { + g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value); +- return; ++ return FALSE; + } + #endif + + header.name = intern_header_name (name, &setter); ++ if (header.name == interned_host && soup_message_headers_get_one(hdrs, "Host")) { ++ g_warning ("Attempted to add duplicate Host header to a SoupMessageHeaders that already contains a Host header"); ++ return FALSE; ++ } + header.value = g_strdup (value); + g_array_append_val (hdrs->array, header); + if (hdrs->concat) + g_hash_table_remove (hdrs->concat, header.name); + if (setter) + setter (hdrs, header.value); ++ ++ return TRUE; + } + + /** +-- +2.52.0 + diff --git a/libsoup2-CVE-2026-0716.patch b/libsoup2-CVE-2026-0716.patch new file mode 100644 index 0000000..15d7857 --- /dev/null +++ b/libsoup2-CVE-2026-0716.patch @@ -0,0 +1,77 @@ +diff -urp libsoup-2.74.3.orig/libsoup/soup-websocket-connection.c libsoup-2.74.3/libsoup/soup-websocket-connection.c +--- libsoup-2.74.3.orig/libsoup/soup-websocket-connection.c 2022-10-11 13:27:22.000000000 -0500 ++++ libsoup-2.74.3/libsoup/soup-websocket-connection.c 2026-02-06 12:46:44.372111863 -0600 +@@ -1064,6 +1064,12 @@ process_frame (SoupWebsocketConnection * + 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 -urp libsoup-2.74.3.orig/tests/websocket-test.c libsoup-2.74.3/tests/websocket-test.c +--- libsoup-2.74.3.orig/tests/websocket-test.c 2022-10-11 13:27:22.000000000 -0500 ++++ libsoup-2.74.3/tests/websocket-test.c 2026-02-06 12:46:44.372679228 -0600 +@@ -1861,6 +1861,41 @@ test_cookies_in_response (Test *test, + soup_cookie_free (cookie); + } + ++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[]) +@@ -2094,6 +2129,15 @@ main (int argc, + test_cookies_in_response, + teardown_soup_connection); + ++ 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 (); diff --git a/libsoup2-CVE-2026-0719.patch b/libsoup2-CVE-2026-0719.patch new file mode 100644 index 0000000..38e7dc9 --- /dev/null +++ b/libsoup2-CVE-2026-0719.patch @@ -0,0 +1,50 @@ +diff --unified --recursive --text --new-file --color libsoup-2.74.3/libsoup/soup-auth-ntlm.c libsoup-2.74.3.new/libsoup/soup-auth-ntlm.c +--- libsoup-2.74.3/libsoup/soup-auth-ntlm.c 2022-10-12 02:27:22.000000000 +0800 ++++ libsoup-2.74.3.new/libsoup/soup-auth-ntlm.c 2026-01-12 10:26:03.168118541 +0800 +@@ -594,7 +594,7 @@ + } + + static void md4sum (const unsigned char *in, +- int nbytes, ++ size_t nbytes, + unsigned char digest[16]); + + typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */ +@@ -640,7 +640,7 @@ + { + unsigned char *buf, *p; + +- p = buf = g_malloc (strlen (password) * 2); ++ p = buf = g_malloc_n (strlen (password), 2); + + while (*password) { + *p++ = *password++; +@@ -1079,15 +1079,16 @@ + #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) ) + + static void +-md4sum (const unsigned char *in, int nbytes, unsigned char digest[16]) ++md4sum (const unsigned char *in, size_t nbytes, unsigned char digest[16]) + { + unsigned char *M; + guint32 A, B, C, D, AA, BB, CC, DD, X[16]; +- int pbytes, nbits = nbytes * 8, i, j; ++ size_t pbytes, nbits = nbytes * 8; ++ int i, j; + + /* There is *always* padding of at least one bit. */ + pbytes = ((119 - (nbytes % 64)) % 64) + 1; +- M = alloca (nbytes + pbytes + 8); ++ M = g_malloc (nbytes + pbytes + 8); + memcpy (M, in, nbytes); + memset (M + nbytes, 0, pbytes + 8); + M[nbytes] = 0x80; +@@ -1187,6 +1188,8 @@ + digest[13] = (D >> 8) & 0xFF; + digest[14] = (D >> 16) & 0xFF; + digest[15] = (D >> 24) & 0xFF; ++ ++ g_free (M); + } + + diff --git a/libsoup2-CVE-2026-1761.patch b/libsoup2-CVE-2026-1761.patch new file mode 100644 index 0000000..3c77592 --- /dev/null +++ b/libsoup2-CVE-2026-1761.patch @@ -0,0 +1,12 @@ +Index: libsoup-2.74.3/libsoup/soup-filter-input-stream.c +=================================================================== +--- libsoup-2.74.3.orig/libsoup/soup-filter-input-stream.c ++++ libsoup-2.74.3/libsoup/soup-filter-input-stream.c +@@ -272,6 +272,6 @@ soup_filter_input_stream_read_until (Sou + if (eof && !*got_boundary) + read_length = MIN (fstream->priv->buf->len, length); + else +- read_length = p - buf; ++ read_length = MIN ((gsize)(p - buf), length); + return read_from_buf (fstream, buffer, read_length); + } diff --git a/libsoup2.changes b/libsoup2.changes index ebe27e9..cc1ce2a 100644 --- a/libsoup2.changes +++ b/libsoup2.changes @@ -1,3 +1,29 @@ +------------------------------------------------------------------- +Fri Feb 6 18:52:17 UTC 2026 - Michael Gorse + +- Add libsoup2-CVE-2026-0716.patch: Fix out-of-bounds read for + websocket (bsc#1256418, CVE-2026-0716, glgo#GNOME/libsoup!494). + +------------------------------------------------------------------- +Tue Feb 3 01:52:48 UTC 2026 - Jonathan Kang + +- Add libsoup2-CVE-2026-1761.patch: multipart: check length of bytes + read soup_filter_input_stream_read_until() + (bsc#1257598, CVE-2026-1761, glgo#GNOME/libsoup!496). +- Refresh ef6c4bf6.patch from upstream git. + +------------------------------------------------------------------- +Fri Jan 9 02:52:21 UTC 2026 - Alynx Zhou + +- Add libsoup2-CVE-2026-0719.patch: Fix overflow for password + md4sum (bsc#1256399, CVE-2026-0719, glgo#GNOME/libsoup!493). + +------------------------------------------------------------------- +Thu Jan 8 05:11:30 UTC 2026 - Alynx Zhou + +- Add libsoup2-CVE-2025-14523.patch: Reject duplicated Host in + headers (bsc#1254876, CVE-2025-14523, glgo#GNOME/libsoup!491). + ------------------------------------------------------------------- Wed Jun 18 16:47:42 UTC 2025 - Michael Gorse diff --git a/libsoup2.spec b/libsoup2.spec index 4351c49..9f644e9 100644 --- a/libsoup2.spec +++ b/libsoup2.spec @@ -1,7 +1,7 @@ # # spec file for package libsoup2 # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -80,6 +80,14 @@ Patch25: libsoup-CVE-2025-4948.patch Patch26: libsoup-CVE-2025-4969.patch # PATCH-FIX-UPSTREAM libsoup-CVE-2025-4945.patch boo#1243314 mgorse@suse.com -- add value checks for date/time parsing. Patch27: libsoup-CVE-2025-4945.patch +# PATCH-FIX-UPSTREAM libsoup2-CVE-2025-14523.patch bsc#1254876, CVE-2025-14523, glgo#GNOME/libsoup!491 alynx.zhou@suse.com -- Reject duplicated Host in headers +Patch28: libsoup2-CVE-2025-14523.patch +# PATCH-FIX-UPSTREAM libsoup2-CVE-2026-0719.patch bsc#1256399, CVE-2026-0719, glgo#GNOME/libsoup!493 alynx.zhou@suse.com -- Fix overflow for password md4sum +Patch29: libsoup2-CVE-2026-0719.patch +# PATCH-FIX-UPSTREAM libsoup2-CVE-2026-1761.patch bsc#1257598, CVE-2026-1761, glgo#GNOME/libsoup!496 sckang@suse.com -- multipart: check length of bytes read soup_filter_input_stream_read_until() +Patch30: libsoup2-CVE-2026-1761.patch +# PATCH-FIX-UPSTREAM libsoup2-CVE-2026-0716.patch bsc#1256418, CVE-2026-0716, glgo#GNOME/libsoup!494 mgorse@suse.com -- Fix out-of-bounds read for websocket +Patch31: libsoup2-CVE-2026-0716.patch BuildRequires: glib-networking BuildRequires: meson >= 0.50