[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1122373: marked as done (trixie-pu: package glib2.0/2.84.4-3~deb13u2)



Your message dated Sat, 10 Jan 2026 11:52:34 +0000
with message-id <E1veXWE-00000004ReV-1O5f@coccia.debian.org>
and subject line Released with 13.3
has caused the Debian Bug report #1122373,
regarding trixie-pu: package glib2.0/2.84.4-3~deb13u2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1122373: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1122373
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: glib2.0@packages.debian.org
Control: affects -1 + src:glib2.0
User: release.debian.org@packages.debian.org
Usertags: pu

[ Reason ]
Fix low-severity CVEs

[ Impact ]
If software parses inadvisably large amounts of attacker-controlled 
GVariant text format (≥ 1 GiB), or escapes inadvisably large 
attacker-controlled strings for inclusion in URIs (≥ 0.5 GiB), or loads 
inadvisably large attacker-controlled GIO file attributes (≥ 1 GiB), 
then an attacker could cause denial of service or possibly arbitrary 
code execution.

The security team agrees that these are "no-DSA" issues.

[ Tests ]
The test suite still passes. The fixes are not really feasible to 
unit-test since they require allocating (at least) hundreds of MiB of 
junk.

A GNOME desktop boots successfully in a virtual machine with the 
proposed GLib. I'll test on real hardware before uploading.

[ Risks ]
The patches were reviewed by upstream and are narrowly targeted, so I 
think this is fine.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
All changes fix potential integer overflows by making sure to do 
address calculations in unsigned size_t space, except for one patch that 
adds a fuzzing driver for one of the affected areas.

The attached diff is not finalized and will need a `dch -r`.
diff --git a/debian/changelog b/debian/changelog
index 982cbafac0..cb0d81fc96 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,24 @@
+glib2.0 (2.84.4-3~deb13u2) UNRELEASED; urgency=medium
+
+  * d/patches: Add patches from 2.86.3 upstream to avoid integer overflows
+    - d/p/gconvert-Error-out-if-g_escape_uri_string-would-overflow.patch,
+      d/p/fuzzing-Add-fuzz-tests-for-g_filename_-to-from-_uri.patch:
+      Fix an integer overflow when interpolating hundreds of megabytes of
+      unescaped text into a URI, and add test coverage
+      (CVE-2025-13601, glib#3827 upstream, Closes: #1121488)
+    - d/p/gvariant-parser-Fix-potential-integer-overflow-parsing-by.patch:
+      Fix an integer overflow when parsing very large strings in GVariant
+      text format (CVE-2025-14087, glib#3834 upstream, Closes: #1122347)
+    - d/p/gvariant-parser-Use-size_t-to-count-numbers-of-child-elem.patch,
+      d/p/gvariant-parser-Convert-error-handling-code-to-use-size_t.patch:
+      Fix other potential integer overflows parsing very large container
+      types in GVariant text format, related to CVE-2025-14087
+    - d/p/gfileattribute-Fix-integer-overflow-calculating-escaping-.patch:
+      Fix an integer overflow when escaping invalid characters in very
+      large file attributes (glib#3845 upstream, Closes: #1122346)
+
+ -- Simon McVittie <smcv@debian.org>  Wed, 10 Dec 2025 12:13:08 +0000
+
 glib2.0 (2.84.4-3~deb13u1) trixie; urgency=medium
 
   * Go back to debian/trixie branch for a stable update
diff --git a/debian/patches/fuzzing-Add-fuzz-tests-for-g_filename_-to-from-_uri.patch b/debian/patches/fuzzing-Add-fuzz-tests-for-g_filename_-to-from-_uri.patch
new file mode 100644
index 0000000000..7cb6e04ac9
--- /dev/null
+++ b/debian/patches/fuzzing-Add-fuzz-tests-for-g_filename_-to-from-_uri.patch
@@ -0,0 +1,122 @@
+From: Philip Withnall <pwithnall@gnome.org>
+Date: Thu, 13 Nov 2025 18:31:43 +0000
+Subject: fuzzing: Add fuzz tests for g_filename_{to,from}_uri()
+
+These functions could be called on untrusted input data, and since they
+do URI escaping/unescaping, they have non-trivial string handling code.
+
+Signed-off-by: Philip Withnall <pwithnall@gnome.org>
+Origin: upstream, 2.86.3, commit:7e5489cb921d0531ee4ebc9938da30a02084b2fa
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3827
+Bug-Debian: https://bugs.debian.org/1121488
+---
+ ...get_locale_variants.c => fuzz_filename_from_uri.c} | 19 +++++++------------
+ ...z_get_locale_variants.c => fuzz_filename_to_uri.c} | 19 +++++++------------
+ fuzzing/meson.build                                   |  2 ++
+ 3 files changed, 16 insertions(+), 24 deletions(-)
+ copy fuzzing/{fuzz_get_locale_variants.c => fuzz_filename_from_uri.c} (70%)
+ copy fuzzing/{fuzz_get_locale_variants.c => fuzz_filename_to_uri.c} (70%)
+
+diff --git a/fuzzing/fuzz_get_locale_variants.c b/fuzzing/fuzz_filename_from_uri.c
+similarity index 70%
+copy from fuzzing/fuzz_get_locale_variants.c
+copy to fuzzing/fuzz_filename_from_uri.c
+index 248dbbf..9b7a715 100644
+--- a/fuzzing/fuzz_get_locale_variants.c
++++ b/fuzzing/fuzz_filename_from_uri.c
+@@ -15,9 +15,6 @@
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+- *
+- * Authors:
+- *  - Philip Withnall <pwithnall@gnome.org>
+  */
+ 
+ #include "fuzz.h"
+@@ -26,20 +23,18 @@ int
+ LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+ {
+   unsigned char *nul_terminated_data = NULL;
+-  char **v;
++  char *filename = NULL;
++  GError *local_error = NULL;
+ 
+   fuzz_set_logging_func ();
+ 
+-  /* ignore @size (g_get_locale_variants() doesn’t support it); ensure @data is nul-terminated */
++  /* ignore @size (g_filename_from_uri() doesn’t support it); ensure @data is nul-terminated */
+   nul_terminated_data = (unsigned char *) g_strndup ((const char *) data, size);
+-
+-  v = g_get_locale_variants ((char *) nul_terminated_data);
+-  g_assert_nonnull (v);
+-  /* g_get_locale_variants() guarantees that the input is always in the output: */
+-  g_assert_true (g_strv_contains ((const char * const *) v, (char *) nul_terminated_data));
+-  g_strfreev (v);
+-
++  filename = g_filename_from_uri ((const char *) nul_terminated_data, NULL, &local_error);
+   g_free (nul_terminated_data);
+ 
++  g_free (filename);
++  g_clear_error (&local_error);
++
+   return 0;
+ }
+diff --git a/fuzzing/fuzz_get_locale_variants.c b/fuzzing/fuzz_filename_to_uri.c
+similarity index 70%
+copy from fuzzing/fuzz_get_locale_variants.c
+copy to fuzzing/fuzz_filename_to_uri.c
+index 248dbbf..acb3192 100644
+--- a/fuzzing/fuzz_get_locale_variants.c
++++ b/fuzzing/fuzz_filename_to_uri.c
+@@ -15,9 +15,6 @@
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+- *
+- * Authors:
+- *  - Philip Withnall <pwithnall@gnome.org>
+  */
+ 
+ #include "fuzz.h"
+@@ -26,20 +23,18 @@ int
+ LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+ {
+   unsigned char *nul_terminated_data = NULL;
+-  char **v;
++  char *uri = NULL;
++  GError *local_error = NULL;
+ 
+   fuzz_set_logging_func ();
+ 
+-  /* ignore @size (g_get_locale_variants() doesn’t support it); ensure @data is nul-terminated */
++  /* ignore @size (g_filename_to_uri() doesn’t support it); ensure @data is nul-terminated */
+   nul_terminated_data = (unsigned char *) g_strndup ((const char *) data, size);
+-
+-  v = g_get_locale_variants ((char *) nul_terminated_data);
+-  g_assert_nonnull (v);
+-  /* g_get_locale_variants() guarantees that the input is always in the output: */
+-  g_assert_true (g_strv_contains ((const char * const *) v, (char *) nul_terminated_data));
+-  g_strfreev (v);
+-
++  uri = g_filename_to_uri ((const char *) nul_terminated_data, NULL, &local_error);
+   g_free (nul_terminated_data);
+ 
++  g_free (uri);
++  g_clear_error (&local_error);
++
+   return 0;
+ }
+diff --git a/fuzzing/meson.build b/fuzzing/meson.build
+index d3107a1..accff0a 100644
+--- a/fuzzing/meson.build
++++ b/fuzzing/meson.build
+@@ -25,6 +25,8 @@ fuzz_targets = [
+   'fuzz_date_parse',
+   'fuzz_date_time_new_from_iso8601',
+   'fuzz_dbus_message',
++  'fuzz_filename_from_uri',
++  'fuzz_filename_to_uri',
+   'fuzz_get_locale_variants',
+   'fuzz_inet_address_mask_new_from_string',
+   'fuzz_inet_address_new_from_string',
diff --git a/debian/patches/gconvert-Error-out-if-g_escape_uri_string-would-overflow.patch b/debian/patches/gconvert-Error-out-if-g_escape_uri_string-would-overflow.patch
new file mode 100644
index 0000000000..73cdcdfd72
--- /dev/null
+++ b/debian/patches/gconvert-Error-out-if-g_escape_uri_string-would-overflow.patch
@@ -0,0 +1,131 @@
+From: Philip Withnall <pwithnall@gnome.org>
+Date: Thu, 13 Nov 2025 18:27:22 +0000
+Subject: gconvert: Error out if g_escape_uri_string() would overflow
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+If the string to escape contains a very large number of unacceptable
+characters (which would need escaping), the calculation of the length of
+the escaped string could overflow, leading to a potential write off the
+end of the newly allocated string.
+
+In addition to that, the number of unacceptable characters was counted
+in a signed integer, which would overflow to become negative, making it
+easier for an attacker to craft an input string which would cause an
+out-of-bounds write.
+
+Fix that by validating the allocation length, and using an unsigned
+integer to count the number of unacceptable characters.
+
+Spotted by treeplus. Thanks to the Sovereign Tech Resilience programme
+from the Sovereign Tech Agency. ID: #YWH-PGM9867-134
+
+Signed-off-by: Philip Withnall <pwithnall@gnome.org>
+
+Backport 2.86: Changed the translatable error message to re-use an
+existing translatable string, to avoid adding new translatable strings
+to a stable branch. The re-used string doesn’t perfectly match the
+error, but it’s good enough given that no users will ever see it.
+
+Origin: upstream, 2.86.3, commit:9bcd65ba5fa1b92ff0fb8380faea335ccef56253
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3827
+Bug-CVE: CVE-2025-13601
+Bug-Debian: https://bugs.debian.org/1121488
+---
+ glib/gconvert.c | 36 +++++++++++++++++++++++++-----------
+ 1 file changed, 25 insertions(+), 11 deletions(-)
+
+diff --git a/glib/gconvert.c b/glib/gconvert.c
+index c6a2441..7a23d7d 100644
+--- a/glib/gconvert.c
++++ b/glib/gconvert.c
+@@ -1336,8 +1336,9 @@ static const gchar hex[] = "0123456789ABCDEF";
+ /* Note: This escape function works on file: URIs, but if you want to
+  * escape something else, please read RFC-2396 */
+ static gchar *
+-g_escape_uri_string (const gchar *string, 
+-		     UnsafeCharacterSet mask)
++g_escape_uri_string (const gchar         *string,
++                     UnsafeCharacterSet   mask,
++                     GError             **error)
+ {
+ #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
+ 
+@@ -1345,7 +1346,7 @@ g_escape_uri_string (const gchar *string,
+   gchar *q;
+   gchar *result;
+   int c;
+-  gint unacceptable;
++  size_t unacceptable;
+   UnsafeCharacterSet use_mask;
+   
+   g_return_val_if_fail (mask == UNSAFE_ALL
+@@ -1362,7 +1363,14 @@ g_escape_uri_string (const gchar *string,
+       if (!ACCEPTABLE (c)) 
+ 	unacceptable++;
+     }
+-  
++
++  if (unacceptable >= (G_MAXSIZE - (p - string)) / 2)
++    {
++      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
++                           _("Invalid hostname"));
++      return NULL;
++    }
++
+   result = g_malloc (p - string + unacceptable * 2 + 1);
+   
+   use_mask = mask;
+@@ -1387,12 +1395,13 @@ g_escape_uri_string (const gchar *string,
+ 
+ 
+ static gchar *
+-g_escape_file_uri (const gchar *hostname,
+-		   const gchar *pathname)
++g_escape_file_uri (const gchar  *hostname,
++                   const gchar  *pathname,
++                   GError      **error)
+ {
+   char *escaped_hostname = NULL;
+-  char *escaped_path;
+-  char *res;
++  char *escaped_path = NULL;
++  char *res = NULL;
+ 
+ #ifdef G_OS_WIN32
+   char *p, *backslash;
+@@ -1413,10 +1422,14 @@ g_escape_file_uri (const gchar *hostname,
+ 
+   if (hostname && *hostname != '\0')
+     {
+-      escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST);
++      escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST, error);
++      if (escaped_hostname == NULL)
++        goto out;
+     }
+ 
+-  escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH);
++  escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH, error);
++  if (escaped_path == NULL)
++    goto out;
+ 
+   res = g_strconcat ("file://",
+ 		     (escaped_hostname) ? escaped_hostname : "",
+@@ -1424,6 +1437,7 @@ g_escape_file_uri (const gchar *hostname,
+ 		     escaped_path,
+ 		     NULL);
+ 
++out:
+ #ifdef G_OS_WIN32
+   g_free ((char *) pathname);
+ #endif
+@@ -1757,7 +1771,7 @@ g_filename_to_uri (const gchar *filename,
+     hostname = NULL;
+ #endif
+ 
+-  escaped_uri = g_escape_file_uri (hostname, filename);
++  escaped_uri = g_escape_file_uri (hostname, filename, error);
+ 
+   return escaped_uri;
+ }
diff --git a/debian/patches/gfileattribute-Fix-integer-overflow-calculating-escaping-.patch b/debian/patches/gfileattribute-Fix-integer-overflow-calculating-escaping-.patch
new file mode 100644
index 0000000000..d90bf1c6df
--- /dev/null
+++ b/debian/patches/gfileattribute-Fix-integer-overflow-calculating-escaping-.patch
@@ -0,0 +1,67 @@
+From: Philip Withnall <pwithnall@gnome.org>
+Date: Thu, 4 Dec 2025 16:37:19 +0000
+Subject: gfileattribute: Fix integer overflow calculating escaping for byte
+ strings
+
+The number of invalid characters in the byte string (characters which
+would have to be percent-encoded) was only stored in an `int`, which
+gave the possibility of a long string largely full of invalid
+characters overflowing this and allowing an attacker-controlled buffer
+size to be allocated.
+
+This could be triggered by an attacker controlled file attribute (of
+type `G_FILE_ATTRIBUTE_TYPE_BYTE_STRING`), such as
+`G_FILE_ATTRIBUTE_THUMBNAIL_PATH` or `G_FILE_ATTRIBUTE_STANDARD_NAME`,
+being read by user code.
+
+Spotted by Codean Labs.
+
+Signed-off-by: Philip Withnall <pwithnall@gnome.org>
+
+Origin: upstream, 2.86.3, commit:4f0399c0aaf3ffc86b5625424580294bc7460404
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3845
+Bug-Debian: https://bugs.debian.org/1122346
+---
+ gio/gfileattribute.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/gio/gfileattribute.c b/gio/gfileattribute.c
+index c6fde60..d3083e5 100644
+--- a/gio/gfileattribute.c
++++ b/gio/gfileattribute.c
+@@ -22,6 +22,7 @@
+ 
+ #include "config.h"
+ 
++#include <stdint.h>
+ #include <string.h>
+ 
+ #include "gfileattribute.h"
+@@ -166,11 +167,12 @@ valid_char (char c)
+   return c >= 32 && c <= 126 && c != '\\';
+ }
+ 
++/* Returns NULL on error */
+ static char *
+ escape_byte_string (const char *str)
+ {
+   size_t i, len;
+-  int num_invalid;
++  size_t num_invalid;
+   char *escaped_val, *p;
+   unsigned char c;
+   const char hex_digits[] = "0123456789abcdef";
+@@ -188,7 +190,12 @@ escape_byte_string (const char *str)
+     return g_strdup (str);
+   else
+     {
+-      escaped_val = g_malloc (len + num_invalid*3 + 1);
++      /* Check for overflow. We want to check the inequality:
++       * !(len + num_invalid * 3 + 1 > SIZE_MAX) */
++      if (num_invalid >= (SIZE_MAX - len) / 3)
++        return NULL;
++
++      escaped_val = g_malloc (len + num_invalid * 3 + 1);
+ 
+       p = escaped_val;
+       for (i = 0; i < len; i++)
diff --git a/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch b/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch
index 5d0771924c..ba158cfd97 100644
--- a/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch
+++ b/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch
@@ -23,7 +23,7 @@ Comment: This was actually reverted from the glib-2-84 branch but
  2 files changed, 33 insertions(+), 6 deletions(-)
 
 diff --git a/glib/gfileutils.c b/glib/gfileutils.c
-index bc4bcf1..1768358 100644
+index 9930030..62928fd 100644
 --- a/glib/gfileutils.c
 +++ b/glib/gfileutils.c
 @@ -1318,8 +1318,8 @@ g_file_set_contents (const gchar  *filename,
diff --git a/debian/patches/gvariant-parser-Convert-error-handling-code-to-use-size_t.patch b/debian/patches/gvariant-parser-Convert-error-handling-code-to-use-size_t.patch
new file mode 100644
index 0000000000..2701039ffb
--- /dev/null
+++ b/debian/patches/gvariant-parser-Convert-error-handling-code-to-use-size_t.patch
@@ -0,0 +1,148 @@
+From: Philip Withnall <pwithnall@gnome.org>
+Date: Tue, 25 Nov 2025 19:25:58 +0000
+Subject: gvariant-parser: Convert error handling code to use size_t
+
+The error handling code allows for printing out the range of input bytes
+related to a parsing error. This was previously done using `gint`, but
+the input could be longer than `INT_MAX`, so it should really be done
+using `size_t`.
+
+Spotted while working on #3834.
+
+Signed-off-by: Philip Withnall <pwithnall@gnome.org>
+Origin: upstream, 2.86.3, commit:dd333a40aa95819720a01caf6de564cd8a4a6310
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3834
+Bug-Debian: https://bugs.debian.org/1122347
+---
+ glib/gvariant-parser.c | 36 +++++++++++++++++++++++-------------
+ 1 file changed, 23 insertions(+), 13 deletions(-)
+
+diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c
+index 519baa3..1b1ddd6 100644
+--- a/glib/gvariant-parser.c
++++ b/glib/gvariant-parser.c
+@@ -91,7 +91,9 @@ g_variant_parser_get_error_quark (void)
+ 
+ typedef struct
+ {
+-  gint start, end;
++  /* Offsets from the start of the input, in bytes. Can be equal when referring
++   * to a point rather than a range. The invariant `end >= start` always holds. */
++  size_t start, end;
+ } SourceRef;
+ 
+ G_GNUC_PRINTF(5, 0)
+@@ -106,14 +108,16 @@ parser_set_error_va (GError      **error,
+   GString *msg = g_string_new (NULL);
+ 
+   if (location->start == location->end)
+-    g_string_append_printf (msg, "%d", location->start);
++    g_string_append_printf (msg, "%" G_GSIZE_FORMAT, location->start);
+   else
+-    g_string_append_printf (msg, "%d-%d", location->start, location->end);
++    g_string_append_printf (msg, "%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
++                            location->start, location->end);
+ 
+   if (other != NULL)
+     {
+       g_assert (other->start != other->end);
+-      g_string_append_printf (msg, ",%d-%d", other->start, other->end);
++      g_string_append_printf (msg, ",%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
++                              other->start, other->end);
+     }
+   g_string_append_c (msg, ':');
+ 
+@@ -140,11 +144,15 @@ parser_set_error (GError      **error,
+ 
+ typedef struct
+ {
++  /* We should always have the following ordering constraint:
++   *   start <= this <= stream <= end
++   * Additionally, unless in an error or EOF state, `this < stream`.
++   */
+   const gchar *start;
+   const gchar *stream;
+   const gchar *end;
+ 
+-  const gchar *this;
++  const gchar *this;  /* (nullable) */
+ } TokenStream;
+ 
+ 
+@@ -175,7 +183,7 @@ token_stream_set_error (TokenStream  *stream,
+ static gboolean
+ token_stream_prepare (TokenStream *stream)
+ {
+-  gint brackets = 0;
++  gssize brackets = 0;
+   const gchar *end;
+ 
+   if (stream->this != NULL)
+@@ -407,7 +415,7 @@ static void
+ pattern_copy (gchar       **out,
+               const gchar **in)
+ {
+-  gint brackets = 0;
++  gssize brackets = 0;
+ 
+   while (**in == 'a' || **in == 'm' || **in == 'M')
+     *(*out)++ = *(*in)++;
+@@ -2765,7 +2773,7 @@ g_variant_builder_add_parsed (GVariantBuilder *builder,
+ static gboolean
+ parse_num (const gchar *num,
+            const gchar *limit,
+-           guint       *result)
++           size_t      *result)
+ {
+   gchar *endptr;
+   gint64 bignum;
+@@ -2775,10 +2783,12 @@ parse_num (const gchar *num,
+   if (endptr != limit)
+     return FALSE;
+ 
++  /* The upper bound here is more restrictive than it technically needs to be,
++   * but should be enough for any practical situation: */
+   if (bignum < 0 || bignum > G_MAXINT)
+     return FALSE;
+ 
+-  *result = (guint) bignum;
++  *result = (size_t) bignum;
+ 
+   return TRUE;
+ }
+@@ -2789,7 +2799,7 @@ add_last_line (GString     *err,
+ {
+   const gchar *last_nl;
+   gchar *chomped;
+-  gint i;
++  size_t i;
+ 
+   /* This is an error at the end of input.  If we have a file
+    * with newlines, that's probably the empty string after the
+@@ -2934,7 +2944,7 @@ g_variant_parse_error_print_context (GError      *error,
+ 
+   if (dash == NULL || colon < dash)
+     {
+-      guint point;
++      size_t point;
+ 
+       /* we have a single point */
+       if (!parse_num (error->message, colon, &point))
+@@ -2952,7 +2962,7 @@ g_variant_parse_error_print_context (GError      *error,
+       /* We have one or two ranges... */
+       if (comma && comma < colon)
+         {
+-          guint start1, end1, start2, end2;
++          size_t start1, end1, start2, end2;
+           const gchar *dash2;
+ 
+           /* Two ranges */
+@@ -2968,7 +2978,7 @@ g_variant_parse_error_print_context (GError      *error,
+         }
+       else
+         {
+-          guint start, end;
++          size_t start, end;
+ 
+           /* One range */
+           if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
diff --git a/debian/patches/gvariant-parser-Fix-potential-integer-overflow-parsing-by.patch b/debian/patches/gvariant-parser-Fix-potential-integer-overflow-parsing-by.patch
new file mode 100644
index 0000000000..c34b4ed5a3
--- /dev/null
+++ b/debian/patches/gvariant-parser-Fix-potential-integer-overflow-parsing-by.patch
@@ -0,0 +1,67 @@
+From: Philip Withnall <pwithnall@gnome.org>
+Date: Tue, 25 Nov 2025 19:02:56 +0000
+Subject: gvariant-parser: Fix potential integer overflow parsing
+ (byte)strings
+
+The termination condition for parsing string and bytestring literals in
+GVariant text format input was subject to an integer overflow for input
+string (or bytestring) literals longer than `INT_MAX`.
+
+Fix that by counting as a `size_t` rather than as an `int`. The counter
+can never correctly be negative.
+
+Spotted by treeplus. Thanks to the Sovereign Tech Resilience programme
+from the Sovereign Tech Agency. ID: #YWH-PGM9867-145
+
+Signed-off-by: Philip Withnall <pwithnall@gnome.org>
+Origin: upstream, 2.86.3, commit:3e72fe0fbb32c18a66486c4da8bc851f656af287
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3834
+Bug-CVE: CVE-2025-14087
+Bug-Debian: https://bugs.debian.org/1122347
+---
+ glib/gvariant-parser.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c
+index 2f1d3db..2d6e985 100644
+--- a/glib/gvariant-parser.c
++++ b/glib/gvariant-parser.c
+@@ -609,7 +609,7 @@ ast_resolve (AST     *ast,
+ {
+   GVariant *value;
+   gchar *pattern;
+-  gint i, j = 0;
++  size_t i, j = 0;
+ 
+   pattern = ast_get_pattern (ast, error);
+ 
+@@ -1637,9 +1637,9 @@ string_free (AST *ast)
+  */
+ static gboolean
+ unicode_unescape (const gchar  *src,
+-                  gint         *src_ofs,
++                  size_t       *src_ofs,
+                   gchar        *dest,
+-                  gint         *dest_ofs,
++                  size_t       *dest_ofs,
+                   gsize         length,
+                   SourceRef    *ref,
+                   GError      **error)
+@@ -1700,7 +1700,7 @@ string_parse (TokenStream  *stream,
+   gsize length;
+   gchar quote;
+   gchar *str;
+-  gint i, j;
++  size_t i, j;
+ 
+   token_stream_start_ref (stream, &ref);
+   token = token_stream_get (stream);
+@@ -1833,7 +1833,7 @@ bytestring_parse (TokenStream  *stream,
+   gsize length;
+   gchar quote;
+   gchar *str;
+-  gint i, j;
++  size_t i, j;
+ 
+   token_stream_start_ref (stream, &ref);
+   token = token_stream_get (stream);
diff --git a/debian/patches/gvariant-parser-Use-size_t-to-count-numbers-of-child-elem.patch b/debian/patches/gvariant-parser-Use-size_t-to-count-numbers-of-child-elem.patch
new file mode 100644
index 0000000000..cab75cc353
--- /dev/null
+++ b/debian/patches/gvariant-parser-Use-size_t-to-count-numbers-of-child-elem.patch
@@ -0,0 +1,237 @@
+From: Philip Withnall <pwithnall@gnome.org>
+Date: Tue, 25 Nov 2025 19:19:16 +0000
+Subject: gvariant-parser: Use size_t to count numbers of child elements
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+Rather than using `gint`, which could overflow for arrays (or dicts, or
+tuples) longer than `INT_MAX`. There may be other limits which prevent
+parsed containers becoming that long, but we might as well make the type
+system reflect the programmer’s intention as best it can anyway.
+
+For arrays and tuples this is straightforward. For dictionaries, it’s
+slightly complicated by the fact that the code used
+`dict->n_children == -1` to indicate that the `Dictionary` struct in
+question actually represented a single freestanding dict entry. In
+GVariant text format, that would be `{1, "one"}`.
+
+The implementation previously didn’t define the semantics of
+`dict->n_children < -1`.
+
+Now, instead, change `Dictionary.n_children` to `size_t`, and define a
+magic value `DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY` to indicate that
+the `Dictionary` represents a single freestanding dict entry.
+
+This magic value is `SIZE_MAX`, and given that a dictionary entry takes
+more than one byte to represent in GVariant text format, that means it’s
+not possible to have that many entries in a parsed dictionary, so this
+magic value won’t be hit by a normal dictionary. An assertion checks
+this anyway.
+
+Spotted while working on #3834.
+
+Signed-off-by: Philip Withnall <pwithnall@gnome.org>
+Origin: upstream, 2.86.3, commit:6fe481cec709ec65b5846113848723bc25a8782a
+Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3834
+Bug-Debian: https://bugs.debian.org/1122347
+---
+ glib/gvariant-parser.c | 58 ++++++++++++++++++++++++++++----------------------
+ 1 file changed, 33 insertions(+), 25 deletions(-)
+
+diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c
+index 2d6e985..519baa3 100644
+--- a/glib/gvariant-parser.c
++++ b/glib/gvariant-parser.c
+@@ -662,9 +662,9 @@ static AST *parse (TokenStream  *stream,
+                    GError      **error);
+ 
+ static void
+-ast_array_append (AST  ***array,
+-                  gint   *n_items,
+-                  AST    *ast)
++ast_array_append (AST    ***array,
++                  size_t   *n_items,
++                  AST      *ast)
+ {
+   if ((*n_items & (*n_items - 1)) == 0)
+     *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
+@@ -673,10 +673,10 @@ ast_array_append (AST  ***array,
+ }
+ 
+ static void
+-ast_array_free (AST  **array,
+-                gint   n_items)
++ast_array_free (AST    **array,
++                size_t   n_items)
+ {
+-  gint i;
++  size_t i;
+ 
+   for (i = 0; i < n_items; i++)
+     ast_free (array[i]);
+@@ -685,11 +685,11 @@ ast_array_free (AST  **array,
+ 
+ static gchar *
+ ast_array_get_pattern (AST    **array,
+-                       gint     n_items,
++                       size_t   n_items,
+                        GError **error)
+ {
+   gchar *pattern;
+-  gint i;
++  size_t i;
+ 
+   /* Find the pattern which applies to all children in the array, by l-folding a
+    * coalesce operation.
+@@ -721,7 +721,7 @@ ast_array_get_pattern (AST    **array,
+          * pair of values.
+          */
+         {
+-          int j = 0;
++          size_t j = 0;
+ 
+           while (TRUE)
+             {
+@@ -969,7 +969,7 @@ typedef struct
+   AST ast;
+ 
+   AST **children;
+-  gint n_children;
++  size_t n_children;
+ } Array;
+ 
+ static gchar *
+@@ -1002,7 +1002,7 @@ array_get_value (AST                 *ast,
+   Array *array = (Array *) ast;
+   const GVariantType *childtype;
+   GVariantBuilder builder;
+-  gint i;
++  size_t i;
+ 
+   if (!g_variant_type_is_array (type))
+     return ast_type_error (ast, type, error);
+@@ -1088,7 +1088,7 @@ typedef struct
+   AST ast;
+ 
+   AST **children;
+-  gint n_children;
++  size_t n_children;
+ } Tuple;
+ 
+ static gchar *
+@@ -1098,7 +1098,7 @@ tuple_get_pattern (AST     *ast,
+   Tuple *tuple = (Tuple *) ast;
+   gchar *result = NULL;
+   gchar **parts;
+-  gint i;
++  size_t i;
+ 
+   parts = g_new (gchar *, tuple->n_children + 4);
+   parts[tuple->n_children + 1] = (gchar *) ")";
+@@ -1128,7 +1128,7 @@ tuple_get_value (AST                 *ast,
+   Tuple *tuple = (Tuple *) ast;
+   const GVariantType *childtype;
+   GVariantBuilder builder;
+-  gint i;
++  size_t i;
+ 
+   if (!g_variant_type_is_tuple (type))
+     return ast_type_error (ast, type, error);
+@@ -1320,9 +1320,16 @@ typedef struct
+ 
+   AST **keys;
+   AST **values;
+-  gint n_children;
++
++  /* Iff this is DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY then this struct
++   * represents a single freestanding dict entry (`{1, "one"}`) rather than a
++   * full dict. In the freestanding case, @keys and @values have exactly one
++   * member each. */
++  size_t n_children;
+ } Dictionary;
+ 
++#define DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY ((size_t) -1)
++
+ static gchar *
+ dictionary_get_pattern (AST     *ast,
+                         GError **error)
+@@ -1337,7 +1344,7 @@ dictionary_get_pattern (AST     *ast,
+     return g_strdup ("Ma{**}");
+ 
+   key_pattern = ast_array_get_pattern (dict->keys,
+-                                       abs (dict->n_children),
++                                       (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? 1 : dict->n_children,
+                                        error);
+ 
+   if (key_pattern == NULL)
+@@ -1368,7 +1375,7 @@ dictionary_get_pattern (AST     *ast,
+     return NULL;
+ 
+   result = g_strdup_printf ("M%s{%c%s}",
+-                            dict->n_children > 0 ? "a" : "",
++                            (dict->n_children > 0 && dict->n_children != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? "a" : "",
+                             key_char, value_pattern);
+   g_free (value_pattern);
+ 
+@@ -1382,7 +1389,7 @@ dictionary_get_value (AST                 *ast,
+ {
+   Dictionary *dict = (Dictionary *) ast;
+ 
+-  if (dict->n_children == -1)
++  if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY)
+     {
+       const GVariantType *subtype;
+       GVariantBuilder builder;
+@@ -1415,7 +1422,7 @@ dictionary_get_value (AST                 *ast,
+     {
+       const GVariantType *entry, *key, *val;
+       GVariantBuilder builder;
+-      gint i;
++      size_t i;
+ 
+       if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
+         return ast_type_error (ast, type, error);
+@@ -1456,12 +1463,12 @@ static void
+ dictionary_free (AST *ast)
+ {
+   Dictionary *dict = (Dictionary *) ast;
+-  gint n_children;
++  size_t n_children;
+ 
+-  if (dict->n_children > -1)
+-    n_children = dict->n_children;
+-  else
++  if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY)
+     n_children = 1;
++  else
++    n_children = dict->n_children;
+ 
+   ast_array_free (dict->keys, n_children);
+   ast_array_free (dict->values, n_children);
+@@ -1479,7 +1486,7 @@ dictionary_parse (TokenStream  *stream,
+     maybe_wrapper, dictionary_get_value,
+     dictionary_free
+   };
+-  gint n_keys, n_values;
++  size_t n_keys, n_values;
+   gboolean only_one;
+   Dictionary *dict;
+   AST *first;
+@@ -1522,7 +1529,7 @@ dictionary_parse (TokenStream  *stream,
+         goto error;
+ 
+       g_assert (n_keys == 1 && n_values == 1);
+-      dict->n_children = -1;
++      dict->n_children = DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY;
+ 
+       return (AST *) dict;
+     }
+@@ -1555,6 +1562,7 @@ dictionary_parse (TokenStream  *stream,
+     }
+ 
+   g_assert (n_keys == n_values);
++  g_assert (n_keys != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY);
+   dict->n_children = n_keys;
+ 
+   return (AST *) dict;
diff --git a/debian/patches/series b/debian/patches/series
index b289a11790..1efc465162 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -15,3 +15,9 @@ workarounds/tests-Skip-debugcontroller-test.patch
 workarounds/testfilemonitor-Skip-if-we-are-avoiding-flaky-tests.patch
 debian/girepository-Describe-the-Debian-specific-cross-prefixed-.patch
 gfileutils-Preserve-mode-during-atomic-updates.patch
+gconvert-Error-out-if-g_escape_uri_string-would-overflow.patch
+fuzzing-Add-fuzz-tests-for-g_filename_-to-from-_uri.patch
+gvariant-parser-Fix-potential-integer-overflow-parsing-by.patch
+gvariant-parser-Use-size_t-to-count-numbers-of-child-elem.patch
+gvariant-parser-Convert-error-handling-code-to-use-size_t.patch
+gfileattribute-Fix-integer-overflow-calculating-escaping-.patch

--- End Message ---
--- Begin Message ---
Package: release.debian.org\nVersion: 13.3\n\nThis update has been released as part of Debian 13.3.

--- End Message ---

Reply to: