From 65b4782edd27092616d23530a089d75e7be88830 Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Mon, 11 May 2026 11:42:23 -0400 Subject: [PATCH] import UBI libsoup3-3.6.5-3.el10_1.11 --- CVE-2026-4271.patch | 361 ++++++++++++++++++++++++++++++++++++++++++++ CVE-2026-5119.patch | 120 +++++++++++++++ libsoup3.spec | 11 +- 3 files changed, 490 insertions(+), 2 deletions(-) create mode 100644 CVE-2026-4271.patch create mode 100644 CVE-2026-5119.patch diff --git a/CVE-2026-4271.patch b/CVE-2026-4271.patch new file mode 100644 index 0000000..1d4a6cb --- /dev/null +++ b/CVE-2026-4271.patch @@ -0,0 +1,361 @@ +From 2da78194fff0775a6cec51799a4aedf5aee7618a Mon Sep 17 00:00:00 2001 +From: Carlos Garcia Campos +Date: Mon, 16 Feb 2026 12:09:08 +0100 +Subject: [PATCH] server: protect message io while reading and writing + +Ensure the nghttp2 session is not destroyed while being used. + +Closes #496 +--- + .../http2/soup-server-message-io-http2.c | 117 +++++++++++++----- + tests/http2-test.c | 54 ++++++++ + 2 files changed, 141 insertions(+), 30 deletions(-) + +diff --git a/libsoup/server/http2/soup-server-message-io-http2.c b/libsoup/server/http2/soup-server-message-io-http2.c +index 913afb46..6f8d1bb6 100644 +--- a/libsoup/server/http2/soup-server-message-io-http2.c ++++ b/libsoup/server/http2/soup-server-message-io-http2.c +@@ -69,6 +69,8 @@ typedef struct { + GHashTable *messages; + + guint in_callback; ++ guint protected; ++ gboolean destroyed; + } SoupServerMessageIOHTTP2; + + static void soup_server_message_io_http2_send_response (SoupServerMessageIOHTTP2 *io, +@@ -146,6 +148,8 @@ soup_server_message_io_http2_destroy (SoupServerMessageIO *iface) + { + SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)iface; + ++ io->destroyed = TRUE; ++ + if (io->read_source) { + g_source_destroy (io->read_source); + g_source_unref (io->read_source); +@@ -160,10 +164,14 @@ soup_server_message_io_http2_destroy (SoupServerMessageIO *iface) + } + + g_clear_object (&io->iostream); +- g_clear_pointer (&io->session, nghttp2_session_del); +- g_clear_pointer (&io->messages, g_hash_table_unref); ++ io->istream = NULL; ++ io->ostream = NULL; + +- g_free (io); ++ if (io->protected == 0) { ++ g_clear_pointer (&io->session, nghttp2_session_del); ++ g_clear_pointer (&io->messages, g_hash_table_unref); ++ g_free (io); ++ } + } + + static void +@@ -321,7 +329,33 @@ static const SoupServerMessageIOFuncs io_funcs = { + soup_server_message_io_http2_is_paused + }; + ++static void ++soup_server_message_io_http2_protect (SoupServerMessageIOHTTP2 *io) ++{ ++ io->protected++; ++ g_object_ref (io->conn); ++} ++ + static gboolean ++soup_server_message_io_http2_unprotect (SoupServerMessageIOHTTP2 *io) ++{ ++ g_object_unref (io->conn); ++ ++ if (--io->protected > 0) ++ return FALSE; ++ ++ if (io->destroyed) { ++ g_clear_pointer (&io->session, nghttp2_session_del); ++ g_clear_pointer (&io->messages, g_hash_table_unref); ++ g_free (io); ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void + io_write (SoupServerMessageIOHTTP2 *io, + GError **error) + { +@@ -336,51 +370,57 @@ io_write (SoupServerMessageIOHTTP2 *io, + if (io->write_buffer_size == 0) { + /* Done */ + io->write_buffer = NULL; +- return TRUE; ++ return; + } + } + ++ if (!io->ostream) ++ return; ++ + gssize ret = g_pollable_stream_write (io->ostream, + io->write_buffer + io->written_bytes, + io->write_buffer_size - io->written_bytes, + FALSE, NULL, error); +- if (ret < 0) +- return FALSE; +- +- io->written_bytes += ret; +- return TRUE; ++ if (ret > 0) ++ io->written_bytes += ret; + } + + static gboolean + io_write_ready (GObject *stream, + SoupServerMessageIOHTTP2 *io) + { +- SoupServerConnection *conn = io->conn; + GError *error = NULL; + +- g_object_ref (conn); ++ soup_server_message_io_http2_protect (io); ++ ++ while (!error) { ++ if (io->destroyed) ++ break; ++ ++ if (!nghttp2_session_want_write (io->session)) ++ break; + +- while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && nghttp2_session_want_write (io->session)) + io_write (io, &error); ++ } + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + g_error_free (error); +- g_object_unref (conn); ++ soup_server_message_io_http2_unprotect (io); + return G_SOURCE_CONTINUE; + } + +- if (soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) { ++ if (!io->destroyed) { + if (error) + h2_debug (io, NULL, "[SESSION] IO error: %s", error->message); + + g_clear_pointer (&io->write_source, g_source_unref); + + if (error || (!nghttp2_session_want_read (io->session) && !nghttp2_session_want_write (io->session))) +- soup_server_connection_disconnect (conn); ++ soup_server_connection_disconnect (io->conn); + } + + g_clear_error (&error); +- g_object_unref (conn); ++ soup_server_message_io_http2_unprotect (io); + + return G_SOURCE_REMOVE; + } +@@ -390,13 +430,12 @@ static gboolean io_write_idle_cb (SoupServerMessageIOHTTP2* io); + static void + io_try_write (SoupServerMessageIOHTTP2 *io) + { +- SoupServerConnection *conn = io->conn; + GError *error = NULL; + + if (io->write_source) + return; + +- if (io->in_callback && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) { ++ if (io->in_callback && !io->destroyed) { + if (!nghttp2_session_want_write (io->session)) + return; + +@@ -416,12 +455,19 @@ io_try_write (SoupServerMessageIOHTTP2 *io) + g_clear_pointer (&io->write_idle_source, g_source_unref); + } + +- g_object_ref (conn); ++ soup_server_message_io_http2_protect (io); ++ ++ while (!error) { ++ if (io->destroyed) ++ break; ++ ++ if (!nghttp2_session_want_write (io->session)) ++ break; + +- while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && !io->in_callback && nghttp2_session_want_write (io->session)) + io_write (io, &error); ++ } + +- if (soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) { ++ if (!io->destroyed) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + g_clear_error (&error); + io->write_source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (io->ostream), NULL); +@@ -434,11 +480,11 @@ io_try_write (SoupServerMessageIOHTTP2 *io) + h2_debug (io, NULL, "[SESSION] IO error: %s", error->message); + + if (error || (!nghttp2_session_want_read (io->session) && !nghttp2_session_want_write (io->session))) +- soup_server_connection_disconnect (conn); ++ soup_server_connection_disconnect (io->conn); + } + + g_clear_error (&error); +- g_object_unref (conn); ++ soup_server_message_io_http2_unprotect (io); + } + + static gboolean +@@ -481,31 +527,37 @@ static gboolean + io_read_ready (GObject *stream, + SoupServerMessageIOHTTP2 *io) + { +- SoupServerConnection *conn = io->conn; + gboolean progress = TRUE; + GError *error = NULL; + +- g_object_ref (conn); ++ soup_server_message_io_http2_protect (io); ++ ++ while (progress) { ++ if (io->destroyed) ++ break; ++ ++ if (!nghttp2_session_want_read (io->session)) ++ break; + +- while (progress && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && nghttp2_session_want_read (io->session)) + progress = io_read (io, &error); ++ } + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + g_error_free (error); +- g_object_unref (conn); ++ soup_server_message_io_http2_unprotect (io); + return G_SOURCE_CONTINUE; + } + +- if (soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io) { ++ if (!io->destroyed) { + if (error) + h2_debug (io, NULL, "[SESSION] IO error: %s", error->message); + + if (error || (!nghttp2_session_want_read (io->session) && !nghttp2_session_want_write (io->session))) +- soup_server_connection_disconnect (conn); ++ soup_server_connection_disconnect (io->conn); + } + + g_clear_error (&error); +- g_object_unref (conn); ++ soup_server_message_io_http2_unprotect (io); + + return G_SOURCE_REMOVE; + } +@@ -931,5 +983,10 @@ soup_server_message_io_http2_new (SoupServerConnection *conn, + nghttp2_submit_settings (io->session, NGHTTP2_FLAG_NONE, settings, G_N_ELEMENTS (settings)); + io_try_write (io); + ++#ifdef __clang_analyzer__ ++ // Suppress false positive about io being destroyed here, since at this point we have only ++ // send the initial settings and not callback is called. ++ [[clang::suppress]] ++#endif + return (SoupServerMessageIO *)io; + } +diff --git a/tests/http2-test.c b/tests/http2-test.c +index df86d9bb..7973f481 100644 +--- a/tests/http2-test.c ++++ b/tests/http2-test.c +@@ -1265,6 +1265,40 @@ do_broken_pseudo_header_test (Test *test, gconstpointer data) + g_uri_unref (uri); + } + ++static void ++disconnect_on_got_headers (SoupServerMessage *msg, gpointer user_data) ++{ ++ GUri *uri; ++ SoupServerConnection *conn; ++ ++ uri = soup_server_message_get_uri (msg); ++ if (!g_str_equal (g_uri_get_path (uri), "/close-on-got-headers")) ++ return; ++ ++ conn = soup_server_message_get_connection (msg); ++ soup_server_connection_disconnect (conn); ++} ++ ++static void ++do_server_disconnect_on_got_headers_test (Test *test, gconstpointer data) ++{ ++ SoupMessage *msg; ++ GUri *uri; ++ GBytes *response; ++ GError *error = NULL; ++ ++ uri = g_uri_parse_relative (base_uri, "/close-on-got-headers", SOUP_HTTP_URI_FLAGS, NULL); ++ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); ++ ++ response = soup_test_session_async_send (test->session, msg, NULL, &error); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT); ++ ++ g_clear_error (&error); ++ g_bytes_unref (response); ++ g_object_unref (msg); ++ g_uri_unref (uri); ++} ++ + static gboolean + unpause_message (SoupServerMessage *msg) + { +@@ -1389,12 +1423,26 @@ server_handler (SoupServer *server, + shutdown (fd, SHUT_WR); + #endif + ++ soup_server_message_set_response (msg, "text/plain", ++ SOUP_MEMORY_STATIC, ++ "Success!", 8); ++ } else if (strcmp (path, "/close-on-got-headers") == 0) { + soup_server_message_set_response (msg, "text/plain", + SOUP_MEMORY_STATIC, + "Success!", 8); + } + } + ++static void ++server_request_started (SoupServer *server, ++ SoupServerMessage *msg, ++ SoupServerConnection *conn, ++ gpointer user_data) ++{ ++ g_signal_connect (msg, "got-headers", ++ G_CALLBACK (disconnect_on_got_headers), NULL); ++} ++ + static gboolean + server_basic_auth_callback (SoupAuthDomain *auth_domain, + SoupServerMessage *msg, +@@ -1421,6 +1469,8 @@ main (int argc, char **argv) + return 0; + + server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD | SOUP_TEST_SERVER_HTTP2); ++ g_signal_connect (server, "request-started", ++ G_CALLBACK (server_request_started), NULL); + auth = soup_auth_domain_basic_new ("realm", "http2-test", + "auth-callback", server_basic_auth_callback, + NULL); +@@ -1577,6 +1627,10 @@ main (int argc, char **argv) + setup_session, + do_broken_pseudo_header_test, + teardown_session); ++ g_test_add ("/http2/server-disconnect-on-got-headers", Test, NULL, ++ setup_session, ++ do_server_disconnect_on_got_headers_test, ++ teardown_session); + + ret = g_test_run (); + +-- +2.54.0 + diff --git a/CVE-2026-5119.patch b/CVE-2026-5119.patch new file mode 100644 index 0000000..a94b6f6 --- /dev/null +++ b/CVE-2026-5119.patch @@ -0,0 +1,120 @@ +From 9ef37ee3ec29479a2ee107b7649159cef9d23e42 Mon Sep 17 00:00:00 2001 +From: Carlos Garcia Campos +Date: Fri, 27 Feb 2026 12:03:25 +0100 +Subject: [PATCH] cookies: do not send cookies to a HTTP proxy for a HTTPS + request + +Closes #502 +--- + libsoup/cookies/soup-cookie-jar.c | 24 +++++++++++----- + tests/proxy-test.c | 47 +++++++++++++++++++++++++++++++ + 2 files changed, 64 insertions(+), 7 deletions(-) + +diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c +index 7f92ace1..aac70f43 100644 +--- a/libsoup/cookies/soup-cookie-jar.c ++++ b/libsoup/cookies/soup-cookie-jar.c +@@ -890,18 +890,28 @@ process_set_cookie_header (SoupMessage *msg, gpointer user_data) + g_slist_free (new_cookies); + } + ++static gboolean ++allow_cookies_for_request (SoupMessage *msg) ++{ ++ /* Do not send cookies to a HTTP proxy for a HTTPS request */ ++ return soup_message_get_method (msg) != SOUP_METHOD_CONNECT || !soup_connection_is_tunnelled (soup_message_get_connection (msg)); ++} ++ + static void + msg_starting_cb (SoupMessage *msg, gpointer feature) + { + SoupCookieJar *jar = SOUP_COOKIE_JAR (feature); +- GSList *cookies; ++ GSList *cookies = NULL; ++ ++ if (allow_cookies_for_request (msg)) { ++ cookies = soup_cookie_jar_get_cookie_list_with_same_site_info (jar, soup_message_get_uri (msg), ++ soup_message_get_first_party (msg), ++ soup_message_get_site_for_cookies (msg), ++ TRUE, ++ SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)), ++ soup_message_get_is_top_level_navigation (msg)); ++ } + +- cookies = soup_cookie_jar_get_cookie_list_with_same_site_info (jar, soup_message_get_uri (msg), +- soup_message_get_first_party (msg), +- soup_message_get_site_for_cookies (msg), +- TRUE, +- SOUP_METHOD_IS_SAFE (soup_message_get_method (msg)), +- soup_message_get_is_top_level_navigation (msg)); + if (cookies != NULL) { + char *cookie_header = soup_cookies_to_cookie_header (cookies); + soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_COOKIE, cookie_header); +diff --git a/tests/proxy-test.c b/tests/proxy-test.c +index d730c8a7..7d90c053 100644 +--- a/tests/proxy-test.c ++++ b/tests/proxy-test.c +@@ -373,6 +373,52 @@ do_proxy_connect_error_test (gconstpointer data) + soup_test_session_abort_unref (session); + } + ++static void ++connect_message_wrote_headers_cb (SoupMessage *msg, guint *counter) ++{ ++ SoupMessageHeaders *hdrs; ++ ++ *counter += 1; ++ ++ hdrs = soup_message_get_request_headers (msg); ++ if (soup_message_get_method (msg) == SOUP_METHOD_CONNECT) ++ g_assert_null (soup_message_headers_get_one (hdrs, "Cookie")); ++ else ++ g_assert_nonnull (soup_message_headers_get_one (hdrs, "Cookie")); ++} ++ ++static void ++request_queued_cb (SoupSession *session, SoupMessage *msg, guint *counter) ++{ ++ g_signal_connect (msg, "wrote-headers", G_CALLBACK (connect_message_wrote_headers_cb), counter); ++} ++ ++static void ++do_proxy_secure_cookies_test (void) ++{ ++ SoupSession *session; ++ SoupMessage *msg; ++ SoupCookieJar *jar; ++ guint counter = 0; ++ ++ SOUP_TEST_SKIP_IF_NO_APACHE; ++ SOUP_TEST_SKIP_IF_NO_TLS; ++ ++ session = soup_test_session_new ("proxy-resolver", proxy_resolvers[SIMPLE_PROXY], NULL); ++ g_signal_connect (session, "request-queued", G_CALLBACK (request_queued_cb), &counter); ++ ++ soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR); ++ jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR)); ++ ++ msg = soup_message_new (SOUP_METHOD_GET, HTTPS_SERVER); ++ soup_cookie_jar_set_cookie (jar, soup_message_get_uri (msg), "user=password; secure"); ++ soup_test_session_send_message (session, msg); ++ soup_test_assert_message_status (msg, SOUP_STATUS_OK); ++ g_assert_cmpuint (counter, ==, 2); ++ ++ soup_test_session_abort_unref (session); ++} ++ + int + main (int argc, char **argv) + { +@@ -404,6 +450,7 @@ main (int argc, char **argv) + g_test_add_func ("/proxy/redirect", do_proxy_redirect_test); + g_test_add_func ("/proxy/auth-cache", do_proxy_auth_cache_test); + g_test_add_data_func ("/proxy/connect-error", base_https_uri, do_proxy_connect_error_test); ++ g_test_add_func ("/proxy/secure-cookies", do_proxy_secure_cookies_test); + + ret = g_test_run (); + +-- +2.54.0 + diff --git a/libsoup3.spec b/libsoup3.spec index 20bfc95..f024553 100644 --- a/libsoup3.spec +++ b/libsoup3.spec @@ -1,8 +1,8 @@ ## START: Set by rpmautospec -## (rpmautospec version 0.6.5) +## (rpmautospec version 0.8.3) ## RPMAUTOSPEC: autorelease, autochangelog %define autorelease(e:s:pb:n) %{?-p:0.}%{lua: - release_number = 10; + release_number = 11; base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); print(release_number + base_release_number - 1); }%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} @@ -51,6 +51,10 @@ Patch: CVE-2025-14523.patch Patch: CVE-2026-0719.patch # https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/496 Patch: CVE-2026-1761.patch +# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/516 +Patch: CVE-2026-5119.patch +# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/511 +Patch: CVE-2026-4271.patch BuildRequires: ca-certificates BuildRequires: gcc @@ -145,6 +149,9 @@ install -m 644 -D tests/libsoup.supp %{buildroot}%{_datadir}/libsoup-3.0/libsoup %changelog ## START: Generated by rpmautospec +* Mon May 04 2026 Michael Catanzaro - 3.6.5-11 +- Add patches for CVE-2026-4271 and CVE-2026-5119 + * Mon Feb 02 2026 Michael Catanzaro - 3.6.5-10 - Add patch for CVE-2026-1761