guix_mirror_bot pushed a commit to branch gnome-team
in repository guix.

commit 111d7e518e982820d6f1948fc2cc799d3e586ba9
Author: Maxim Cournoyer <[email protected]>
AuthorDate: Thu Jul 31 08:02:12 2025 +0900

    gnu: libsoup: Apply patches fixing deadlocks and CVE-2025-4476.
    
    The patches are a subset taken from Debian (see:
    <https://sources.debian.org/patches/libsoup3/3.6.5-3/>).
    
    * gnu/packages/patches/libsoup-auth-digest-fix-crash.patch
    * gnu/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch
    * gnu/packages/patches/libsoup-fix-merge-of-ranges.patch
    * gnu/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch
    * gnu/packages/patches/libsoup-multipart-bounds-check.patch
    * gnu/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch: New 
files.
    * gnu/local.mk (dist_patch_DATA): Register them.
    * gnu/packages/gnome.scm (libsoup-minimal): Apply them.
    
    Change-Id: I7e4968c1d87e28860fc68616f6107d018e0d93dd
---
 gnu/local.mk                                       |   6 +
 gnu/packages/gnome.scm                             |  18 +-
 .../patches/libsoup-auth-digest-fix-crash.patch    |  31 ++++
 ...ibsoup-deadlock-in-add_listener_in_thread.patch |  42 +++++
 .../patches/libsoup-fix-merge-of-ranges.patch      | 192 +++++++++++++++++++++
 .../libsoup-memory-leak-in-soup_form_decode.patch  | 101 +++++++++++
 .../patches/libsoup-multipart-bounds-check.patch   | 106 ++++++++++++
 .../libsoup-use-libdl-instead-of-gmodule.patch     |  70 ++++++++
 8 files changed, 561 insertions(+), 5 deletions(-)

diff --git a/gnu/local.mk b/gnu/local.mk
index dd6f86a0e1..16054e7686 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1799,6 +1799,12 @@ dist_patch_DATA =                                        
        \
   %D%/packages/patches/libsecret-fix-test-paths.patch          \
   %D%/packages/patches/libsepol-versioned-docbook.patch                \
   %D%/packages/patches/libskk-fix-invalid-escape.patch         \
+  %D%/packages/patches/libsoup-auth-digest-fix-crash.patch      \
+  %D%/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch \
+  %D%/packages/patches/libsoup-fix-merge-of-ranges.patch        \
+  %D%/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch    \
+  %D%/packages/patches/libsoup-multipart-bounds-check.patch     \
+  %D%/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch       \
   %D%/packages/patches/libspatialite-libxml2-2.14.patch                \
   %D%/packages/patches/libtar-CVE-2013-4420.patch              \
   %D%/packages/patches/libtar-CVE-2021-33643-CVE-2021-33644.patch      \
diff --git a/gnu/packages/gnome.scm b/gnu/packages/gnome.scm
index 4175a29c07..aab387b0d4 100644
--- a/gnu/packages/gnome.scm
+++ b/gnu/packages/gnome.scm
@@ -5104,7 +5104,15 @@ as OpenStreetMap, OpenCycleMap, OpenAerialMap and Maps.")
                                   "libsoup-" version ".tar.xz"))
               (sha256
                (base32
-                "0d52mnvvsvwpc3scjva5fbvns8f8ijyswgjwjhbr151ymid7d4b8"))))
+                "0d52mnvvsvwpc3scjva5fbvns8f8ijyswgjwjhbr151ymid7d4b8"))
+              (patches
+               (search-patches
+                "libsoup-auth-digest-fix-crash.patch"
+                "libsoup-deadlock-in-add_listener_in_thread.patch"
+                "libsoup-fix-merge-of-ranges.patch"
+                "libsoup-memory-leak-in-soup_form_decode.patch"
+                "libsoup-multipart-bounds-check.patch"
+                "libsoup-use-libdl-instead-of-gmodule.patch"))))
     (build-system meson-build-system)
     (arguments
      (list
@@ -5128,21 +5136,21 @@ as OpenStreetMap, OpenCycleMap, OpenAerialMap and 
Maps.")
               (substitute* "tests/hsts-db-test.c"
                 ((".*/hsts-db/subdomains.*") "")))))))
     (native-inputs
-     (list `(,glib "bin") ;for glib-mkenums
+     (list `(,glib "bin")               ;for glib-mkenums
            gobject-introspection
            pkg-config
            python-wrapper
            vala
            curl
-           gnutls ;for 'certtool'
+           gnutls                       ;for 'certtool'
            httpd/pinned))
     (propagated-inputs
      ;; libsoup-3.0.pc refers to all of these (except where otherwise noted)
      (list brotli
            glib
-           glib-networking ; for GIO runtime modules
+           glib-networking              ; for GIO runtime modules
            libpsl
-           nghttp2 ;for pkg-config
+           nghttp2                      ;for pkg-config
            `(,nghttp2 "lib")
            libxml2
            mit-krb5
diff --git a/gnu/packages/patches/libsoup-auth-digest-fix-crash.patch 
b/gnu/packages/patches/libsoup-auth-digest-fix-crash.patch
new file mode 100644
index 0000000000..7b147338a2
--- /dev/null
+++ b/gnu/packages/patches/libsoup-auth-digest-fix-crash.patch
@@ -0,0 +1,31 @@
+From: Michael Catanzaro <[email protected]>
+Date: Thu, 8 May 2025 09:27:01 -0500
+Subject: auth-digest: fix crash in soup_auth_digest_get_protection_space()
+
+We need to validate the Domain parameter in the WWW-Authenticate header.
+
+Unfortunately this crash only occurs when listening on default ports 80
+and 443, so there's no good way to test for this. The test would require
+running as root.
+
+Origin: upstream, 3.7.0, commit:e64c221f9c7d09b48b610c5626b3b8c400f0907c
+Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/440
+Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2025-4476
+Bug-Debian: https://bugs.debian.org/1105887
+---
+ libsoup/auth/soup-auth-digest.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libsoup/auth/soup-auth-digest.c b/libsoup/auth/soup-auth-digest.c
+index d8bb291..292f204 100644
+--- a/libsoup/auth/soup-auth-digest.c
++++ b/libsoup/auth/soup-auth-digest.c
+@@ -220,7 +220,7 @@ soup_auth_digest_get_protection_space (SoupAuth *auth, 
GUri *source_uri)
+                       if (uri &&
+                             g_strcmp0 (g_uri_get_scheme (uri), 
g_uri_get_scheme (source_uri)) == 0 &&
+                           g_uri_get_port (uri) == g_uri_get_port (source_uri) 
&&
+-                          !strcmp (g_uri_get_host (uri), g_uri_get_host 
(source_uri)))
++                          !g_strcmp0 (g_uri_get_host (uri), g_uri_get_host 
(source_uri)))
+                               dir = g_strdup (g_uri_get_path (uri));
+                       else
+                               dir = NULL;
diff --git 
a/gnu/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch 
b/gnu/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch
new file mode 100644
index 0000000000..1e3fa161bc
--- /dev/null
+++ b/gnu/packages/patches/libsoup-deadlock-in-add_listener_in_thread.patch
@@ -0,0 +1,42 @@
+From: Michael Catanzaro <[email protected]>
+Date: Wed, 30 Apr 2025 14:13:41 -0500
+Subject: test-utils: fix deadlock in add_listener_in_thread()
+
+The mutex is locked in the wrong place here.
+
+Hopefully fixes #379
+
+Origin: upstream, 3.7.0, commit:3c0cee2cfddb9ba31b30421f2b3cdd3c5a255e99
+Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/379
+---
+ tests/test-utils.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/tests/test-utils.c b/tests/test-utils.c
+index 62f0b83..6fb09b6 100644
+--- a/tests/test-utils.c
++++ b/tests/test-utils.c
+@@ -627,9 +627,11 @@ static gboolean
+ add_listener_in_thread (gpointer user_data)
+ {
+       AddListenerData *data = user_data;
++      GUri *uri;
+ 
+-      data->uri = add_listener (data->server, data->scheme, data->host);
++      uri = add_listener (data->server, data->scheme, data->host);
+       g_mutex_lock (&data->mutex);
++      data->uri = uri;
+       g_cond_signal (&data->cond);
+       g_mutex_unlock (&data->mutex);
+ 
+@@ -661,9 +663,9 @@ soup_test_server_get_uri (SoupServer    *server,
+               data.host = host;
+               data.uri = NULL;
+ 
+-              g_mutex_lock (&data.mutex);
+               soup_add_completion (context, add_listener_in_thread, &data);
+ 
++              g_mutex_lock (&data.mutex);
+               while (!data.uri)
+                       g_cond_wait (&data.cond, &data.mutex);
+ 
diff --git a/gnu/packages/patches/libsoup-fix-merge-of-ranges.patch 
b/gnu/packages/patches/libsoup-fix-merge-of-ranges.patch
new file mode 100644
index 0000000000..5cc7325a5d
--- /dev/null
+++ b/gnu/packages/patches/libsoup-fix-merge-of-ranges.patch
@@ -0,0 +1,192 @@
+From: Milan Crha <[email protected]>
+Date: Tue, 15 Apr 2025 12:17:39 +0200
+Subject: soup-message-headers: Correct merge of ranges
+
+It had been skipping every second range, which generated an array
+of a lot of insane ranges, causing large memory usage by the server.
+
+Origin: upstream, 3.7.0, commit:9bb92f7a685e31e10e9e8221d0342280432ce836
+Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/428
+Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2025-32907
+Bug-Debian: https://bugs.debian.org/1103264
+---
+ libsoup/soup-message-headers.c |   1 +
+ tests/meson.build              |   1 +
+ tests/server-mem-limit-test.c  | 144 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 146 insertions(+)
+ create mode 100644 tests/server-mem-limit-test.c
+
+diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
+index ee7a3cb..f101d4b 100644
+--- a/libsoup/soup-message-headers.c
++++ b/libsoup/soup-message-headers.c
+@@ -1244,6 +1244,7 @@ soup_message_headers_get_ranges_internal 
(SoupMessageHeaders  *hdrs,
+                       if (cur->start <= prev->end) {
+                               prev->end = MAX (prev->end, cur->end);
+                               g_array_remove_index (array, i);
++                              i--;
+                       }
+               }
+       }
+diff --git a/tests/meson.build b/tests/meson.build
+index cf4ddbd..68e6d01 100644
+--- a/tests/meson.build
++++ b/tests/meson.build
+@@ -102,6 +102,7 @@ tests = [
+   {'name': 'samesite'},
+   {'name': 'session'},
+   {'name': 'server-auth'},
++  {'name': 'server-mem-limit'},
+   {'name': 'server'},
+   {'name': 'sniffing',
+     'depends': [test_resources],
+diff --git a/tests/server-mem-limit-test.c b/tests/server-mem-limit-test.c
+new file mode 100644
+index 0000000..98f1c40
+--- /dev/null
++++ b/tests/server-mem-limit-test.c
+@@ -0,0 +1,144 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
++/*
++ * Copyright (C) 2025 Red Hat <www.redhat.com>
++ */
++
++#include "test-utils.h"
++
++#include <sys/resource.h>
++
++/*
++ This test limits memory usage to trigger too large buffer allocation crash.
++ As restoring the limits back to what it was does not always work, it's split
++ out of the server-test.c test with copied minimal server code.
++ */
++
++typedef struct {
++      SoupServer *server;
++      GUri *base_uri, *ssl_base_uri;
++      GSList *handlers;
++} ServerData;
++
++static void
++server_setup_nohandler (ServerData *sd, gconstpointer test_data)
++{
++      sd->server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
++      sd->base_uri = soup_test_server_get_uri (sd->server, "http", NULL);
++      if (tls_available)
++              sd->ssl_base_uri = soup_test_server_get_uri (sd->server, 
"https", NULL);
++}
++
++static void
++server_add_handler (ServerData         *sd,
++                  const char         *path,
++                  SoupServerCallback  callback,
++                  gpointer            user_data,
++                  GDestroyNotify      destroy)
++{
++      soup_server_add_handler (sd->server, path, callback, user_data, 
destroy);
++      sd->handlers = g_slist_prepend (sd->handlers, g_strdup (path));
++}
++
++static void
++server_setup (ServerData *sd, gconstpointer test_data)
++{
++      server_setup_nohandler (sd, test_data);
++}
++
++static void
++server_teardown (ServerData *sd, gconstpointer test_data)
++{
++      GSList *iter;
++
++      for (iter = sd->handlers; iter; iter = iter->next)
++              soup_server_remove_handler (sd->server, iter->data);
++      g_slist_free_full (sd->handlers, g_free);
++
++      g_clear_pointer (&sd->server, soup_test_server_quit_unref);
++      g_clear_pointer (&sd->base_uri, g_uri_unref);
++      g_clear_pointer (&sd->ssl_base_uri, g_uri_unref);
++}
++
++static void
++server_file_callback (SoupServer        *server,
++                    SoupServerMessage *msg,
++                    const char        *path,
++                    GHashTable        *query,
++                    gpointer           data)
++{
++      void *mem;
++
++      g_assert_cmpstr (path, ==, "/file");
++      g_assert_cmpstr (soup_server_message_get_method (msg), ==, 
SOUP_METHOD_GET);
++
++      mem = g_malloc0 (sizeof (char) * 1024 * 1024);
++      /* fedora-scan CI claims a warning about possibly leaked `mem` 
variable, thus use
++         the copy and free it explicitly, to workaround the false positive; 
the g_steal_pointer()
++         did not help for the malloc-ed memory */
++      soup_server_message_set_response (msg, "application/octet-stream", 
SOUP_MEMORY_COPY, mem, sizeof (char) * 1024 *1024);
++      soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
++      g_free (mem);
++}
++
++static void
++do_ranges_overlaps_test (ServerData *sd, gconstpointer test_data)
++{
++      SoupSession *session;
++      SoupMessage *msg;
++      GString *range;
++      GUri *uri;
++      const char *chunk = ",0,0,0,0,0,0,0,0,0,0,0";
++
++      g_test_bug ("428");
++
++      #ifdef G_OS_WIN32
++      g_test_skip ("Cannot run under windows");
++      return;
++      #endif
++
++      range = g_string_sized_new (99 * 1024);
++      g_string_append (range, "bytes=1024");
++      while (range->len < 99 * 1024)
++              g_string_append (range, chunk);
++
++      session = soup_test_session_new (NULL);
++      server_add_handler (sd, "/file", server_file_callback, NULL, NULL);
++
++      uri = g_uri_parse_relative (sd->base_uri, "/file", SOUP_HTTP_URI_FLAGS, 
NULL);
++
++      msg = soup_message_new_from_uri ("GET", uri);
++      soup_message_headers_append (soup_message_get_request_headers (msg), 
"Range", range->str);
++
++      soup_test_session_send_message (session, msg);
++
++      soup_test_assert_message_status (msg, SOUP_STATUS_PARTIAL_CONTENT);
++
++      g_object_unref (msg);
++
++      g_string_free (range, TRUE);
++      g_uri_unref (uri);
++
++      soup_test_session_abort_unref (session);
++}
++
++int
++main (int argc, char **argv)
++{
++      int ret;
++
++      test_init (argc, argv, NULL);
++
++      #ifndef G_OS_WIN32
++      struct rlimit new_rlimit = { 1024 * 1024 * 64, 1024 * 1024 * 64 };
++      /* limit memory usage, to trigger too large memory allocation abort */
++      g_assert_cmpint (setrlimit (RLIMIT_DATA, &new_rlimit), ==, 0);
++      #endif
++
++      g_test_add ("/server-mem/range-overlaps", ServerData, NULL,
++                  server_setup, do_ranges_overlaps_test, server_teardown);
++
++      ret = g_test_run ();
++
++      test_cleanup ();
++      return ret;
++}
diff --git a/gnu/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch 
b/gnu/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch
new file mode 100644
index 0000000000..ccba980ab7
--- /dev/null
+++ b/gnu/packages/patches/libsoup-memory-leak-in-soup_form_decode.patch
@@ -0,0 +1,101 @@
+From: Milan Crha <[email protected]>
+Date: Tue, 13 May 2025 10:38:49 +0200
+Subject: soup-form: Fix a possible memory leak in
+ soup_form_decode_multipart()
+
+The output variables can be set multiple times, when there are multiparts
+with the same name, thus first clear any previously value and only then
+assign a new value.
+
+Origin: upstream, 3.7.0, commit:66b5c5be947062df9caf7025b56ee1de32aee3ac
+Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/446
+---
+ libsoup/soup-form.c | 12 +++++++++---
+ tests/forms-test.c  | 41 +++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 50 insertions(+), 3 deletions(-)
+
+diff --git a/libsoup/soup-form.c b/libsoup/soup-form.c
+index 2eb5d57..98130c8 100644
+--- a/libsoup/soup-form.c
++++ b/libsoup/soup-form.c
+@@ -168,12 +168,18 @@ soup_form_decode_multipart (SoupMultipart *multipart,
+               }
+ 
+               if (file_control_name && !strcmp (name, file_control_name)) {
+-                      if (filename)
++                      if (filename) {
++                              g_free (*filename);
+                               *filename = g_strdup (g_hash_table_lookup 
(params, "filename"));
+-                      if (content_type)
++                      }
++                      if (content_type) {
++                              g_free (*content_type);
+                               *content_type = g_strdup 
(soup_message_headers_get_content_type (part_headers, NULL));
+-                      if (file)
++                      }
++                      if (file) {
++                              g_clear_pointer (file, g_bytes_unref);
+                               *file = g_bytes_ref (part_body);
++                      }
+               } else {
+                       g_hash_table_insert (form_data_set,
+                                            g_strdup (name),
+diff --git a/tests/forms-test.c b/tests/forms-test.c
+index 1002374..183900f 100644
+--- a/tests/forms-test.c
++++ b/tests/forms-test.c
+@@ -485,6 +485,46 @@ md5_callback (SoupServer        *server,
+               soup_server_message_set_status (msg, 
SOUP_STATUS_METHOD_NOT_ALLOWED, NULL);
+ }
+ 
++static void
++do_form_decode_multipart_test (void)
++{
++      SoupMultipart *multipart = soup_multipart_new ("multipart/form-data");
++      const char *file_control_name = "uploaded_file";
++      char *content_type = NULL;
++      char *filename = NULL;
++      GBytes *file = NULL;
++      GHashTable *result;
++      int part;
++
++      for (part = 0; part < 2; part++) {
++              SoupMessageHeaders *headers = soup_message_headers_new 
(SOUP_MESSAGE_HEADERS_MULTIPART);
++              GHashTable *params = g_hash_table_new_full (g_str_hash, 
g_str_equal, g_free, g_free);
++              GBytes *body = g_bytes_new (NULL, 0);
++
++              g_hash_table_insert (params, g_strdup ("name"), g_strdup 
(file_control_name));
++              g_hash_table_insert (params, g_strdup ("filename"), g_strdup 
(file_control_name));
++              soup_message_headers_set_content_disposition (headers, 
"form-data", params);
++              soup_message_headers_set_content_type (headers, "text/x-form", 
NULL);
++              soup_multipart_append_part (multipart, headers, body);
++
++              soup_message_headers_unref (headers);
++              g_hash_table_destroy (params);
++              g_bytes_unref (body);
++      }
++
++      /* this would leak memory of the output variables, due to two parts 
having the same 'file_control_name' */
++      result = soup_form_decode_multipart (multipart, file_control_name, 
&filename, &content_type, &file);
++      g_assert_nonnull (result);
++      g_assert_cmpstr (content_type, ==, "text/x-form");
++      g_assert_cmpstr (filename, ==, file_control_name);
++      g_assert_nonnull (file);
++
++      g_hash_table_destroy (result);
++      g_free (content_type);
++      g_free (filename);
++      g_bytes_unref (file);
++}
++
+ static gboolean run_tests = TRUE;
+ 
+ static GOptionEntry no_test_entry[] = {
+@@ -525,6 +565,7 @@ main (int argc, char **argv)
+               g_uri_unref (uri);
+ 
+               g_test_add_func ("/forms/decode", do_form_decode_test);
++              g_test_add_func ("/forms/decodemultipart", 
do_form_decode_multipart_test);
+ 
+               ret = g_test_run ();
+       } else {
diff --git a/gnu/packages/patches/libsoup-multipart-bounds-check.patch 
b/gnu/packages/patches/libsoup-multipart-bounds-check.patch
new file mode 100644
index 0000000000..0bafe09206
--- /dev/null
+++ b/gnu/packages/patches/libsoup-multipart-bounds-check.patch
@@ -0,0 +1,106 @@
+From: Milan Crha <[email protected]>
+Date: Tue, 15 Apr 2025 09:03:00 +0200
+Subject: multipart: Fix read out of buffer bounds under
+ soup_multipart_new_from_message()
+
+This is CVE-2025-32914, special crafted input can cause read out of buffer 
bounds
+of the body argument.
+
+Origin: upstream, 3.7.0, commit:5bfcf8157597f2d327050114fb37ff600004dbcf
+Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/436
+Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2025-32914
+Bug-Debian: https://bugs.debian.org/1103267
+---
+ libsoup/soup-multipart.c |  2 +-
+ tests/multipart-test.c   | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 59 insertions(+), 1 deletion(-)
+
+diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
+index 2421c91..102ce37 100644
+--- a/libsoup/soup-multipart.c
++++ b/libsoup/soup-multipart.c
+@@ -173,7 +173,7 @@ soup_multipart_new_from_message (SoupMessageHeaders 
*headers,
+                       return NULL;
+               }
+ 
+-              split = strstr (start, "\r\n\r\n");
++              split = g_strstr_len (start, body_end - start, "\r\n\r\n");
+               if (!split || split > end) {
+                       soup_multipart_free (multipart);
+                       return NULL;
+diff --git a/tests/multipart-test.c b/tests/multipart-test.c
+index 2c0e7e9..f5b9868 100644
+--- a/tests/multipart-test.c
++++ b/tests/multipart-test.c
+@@ -471,6 +471,62 @@ test_multipart (gconstpointer data)
+       loop = NULL;
+ }
+ 
++static void
++test_multipart_bounds_good (void)
++{
++      #define TEXT "line1\r\nline2"
++      SoupMultipart *multipart;
++      SoupMessageHeaders *headers, *set_headers = NULL;
++      GBytes *bytes, *set_bytes = NULL;
++      const char *raw_data = "--123\r\nContent-Type: text/plain;\r\n\r\n" 
TEXT "\r\n--123--\r\n";
++      gboolean success;
++
++      headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
++      soup_message_headers_append (headers, "Content-Type", "multipart/mixed; 
boundary=\"123\"");
++
++      bytes = g_bytes_new (raw_data, strlen (raw_data));
++
++      multipart = soup_multipart_new_from_message (headers, bytes);
++
++      g_assert_nonnull (multipart);
++      g_assert_cmpint (soup_multipart_get_length (multipart), ==, 1);
++      success = soup_multipart_get_part (multipart, 0, &set_headers, 
&set_bytes);
++      g_assert_true (success);
++      g_assert_nonnull (set_headers);
++      g_assert_nonnull (set_bytes);
++      g_assert_cmpint (strlen (TEXT), ==, g_bytes_get_size (set_bytes));
++      g_assert_cmpstr ("text/plain", ==, 
soup_message_headers_get_content_type (set_headers, NULL));
++      g_assert_cmpmem (TEXT, strlen (TEXT), g_bytes_get_data (set_bytes, 
NULL), g_bytes_get_size (set_bytes));
++
++      soup_message_headers_unref (headers);
++      g_bytes_unref (bytes);
++
++      soup_multipart_free (multipart);
++
++      #undef TEXT
++}
++
++static void
++test_multipart_bounds_bad (void)
++{
++      SoupMultipart *multipart;
++      SoupMessageHeaders *headers;
++      GBytes *bytes;
++      const char *raw_data = "--123\r\nContent-Type: 
text/plain;\r\nline1\r\nline2\r\n--123--\r\n";
++
++      headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
++      soup_message_headers_append (headers, "Content-Type", "multipart/mixed; 
boundary=\"123\"");
++
++      bytes = g_bytes_new (raw_data, strlen (raw_data));
++
++      /* it did read out of raw_data/bytes bounds */
++      multipart = soup_multipart_new_from_message (headers, bytes);
++      g_assert_null (multipart);
++
++      soup_message_headers_unref (headers);
++      g_bytes_unref (bytes);
++}
++
+ int
+ main (int argc, char **argv)
+ {
+@@ -498,6 +554,8 @@ main (int argc, char **argv)
+       g_test_add_data_func ("/multipart/sync", GINT_TO_POINTER 
(SYNC_MULTIPART), test_multipart);
+       g_test_add_data_func ("/multipart/async", GINT_TO_POINTER 
(ASYNC_MULTIPART), test_multipart);
+       g_test_add_data_func ("/multipart/async-small-reads", GINT_TO_POINTER 
(ASYNC_MULTIPART_SMALL_READS), test_multipart);
++      g_test_add_func ("/multipart/bounds-good", test_multipart_bounds_good);
++      g_test_add_func ("/multipart/bounds-bad", test_multipart_bounds_bad);
+ 
+       ret = g_test_run ();
+ 
diff --git a/gnu/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch 
b/gnu/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch
new file mode 100644
index 0000000000..3b6608cb04
--- /dev/null
+++ b/gnu/packages/patches/libsoup-use-libdl-instead-of-gmodule.patch
@@ -0,0 +1,70 @@
+From: Fabio Manganiello <[email protected]>
+Date: Tue, 15 Jul 2025 15:41:47 +0200
+Subject: soup-init: Use libdl instead of gmodule in `soup2_is_loaded` check
+
+Calling `g_module_open` in the library constructor can cause deadlocks
+when libsoup is used with other libraries that also contend for GLib
+mutexes. `dlopen` should be used instead.
+
+Co-authored-by: Nirbheek Chauhan <[email protected]>
+Bug: https://gitlab.gnome.org/GNOME/libsoup/-/issues/463
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/1443
+Bug-Debian: https://bugs.debian.org/1109685
+Origin: https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/475
+Applied-upstream: 3.7.0, commit:1296cbf983f036f20262c453926dff77e1d6a852
+Applied-upstream: 3.6.6, commit:2316e56a5502ac4c41ef4ff56a3266e680aca129
+---
+ libsoup/soup-init.c | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/libsoup/soup-init.c b/libsoup/soup-init.c
+index 8a33c77..3392e8e 100644
+--- a/libsoup/soup-init.c
++++ b/libsoup/soup-init.c
+@@ -10,7 +10,6 @@
+ #endif
+ 
+ #include <glib/gi18n-lib.h>
+-#include <gmodule.h>
+ #include "gconstructor.h"
+ 
+ #ifdef G_OS_WIN32
+@@ -18,21 +17,28 @@
+ #include <windows.h>
+ 
+ HMODULE soup_dll;
++#else
++#include <dlfcn.h>
+ #endif
+ 
+ static gboolean
+ soup2_is_loaded (void)
+ {
+-    GModule *module = g_module_open (NULL, 0);
+-    gpointer func;
+-    gboolean result = FALSE;
+-
+-    if (g_module_symbol (module, "soup_uri_new", &func))
+-        result = TRUE;
+-
+-    g_module_close (module);
+-
+-    return result;
++      gboolean result = FALSE;
++
++      /* Skip on PE/COFF, as it doesn't have a flat symbol namespace */
++#ifndef G_OS_WIN32
++      gpointer handle;
++      gpointer func;
++
++      handle = dlopen (NULL, RTLD_LAZY | RTLD_GLOBAL);
++      if (handle != NULL) {
++              func = dlsym (handle, "soup_uri_new");
++              result = (func != NULL);
++              dlclose (handle);
++      }
++#endif
++      return result;
+ }
+ 
+ static void

Reply via email to