Package: release.debian.org Severity: normal Tags: X-Debbugs-Cc: glib...@packages.debian.org, debian-b...@lists.debian.org Control: affects -1 + src:glib2.0 User: release.debian....@packages.debian.org Usertags: unblock
[ Reason ] CVE-2025-4373 (#1104930). I also took the opportunity to catch up with the upstream glib-2-84 branch by adding one unrelated bugfix commit (a 1-line change). [ Impact ] Fixes an out-of-bounds write if an attacker can somehow arrange for GLib to be acting on overwhelmingly large strings (half the address space in a single GString object, so 2GB for 32-bit processes). Ensures that localtime_r() is not called without first calling tzset(), which has unspecified behaviour. [ Tests ] Not yet tested. I will run autopkgtests and boot a GNOME system with the proposed GLib before upload, and inform this bug if further changes are needed. GLib has a quite thorough test suite in general, but CVE-2025-4373 is not covered by it, because exploiting the bug requires a huge memory allocation that will, in practice, usually fail. [ Risks ] I can't think of any. If there is a problem, these changes would be easy to revert. [ 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 testing (preliminary diff, will need a `dch -r` before release) [ Other info ] Needs a d-i ack due to the GTK-based graphical installer. unblock glib2.0/2.84.1-3
diff --git a/debian/changelog b/debian/changelog index 7f9c9d65fc..67651dcdd7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,28 @@ +glib2.0 (2.84.1-3) UNRELEASED; urgency=medium + + [ Jeremy BĂcha ] + * d/p/gfileutils-Preserve-mode-during-atomic-updates.patch: + Add a note that this fix for LP#2072586 was reverted in the upstream + 2.84.x branch as a behaviour change. It was kept in 2.85.x, + and seems reasonable to keep for trixie. + + [ Simon McVittie ] + * d/p/gfileutils-Preserve-mode-during-atomic-updates.patch: + Add a cross-reference to LP#2072586 + * d/p/gstring-carefully-handle-gssize-parameters.patch, + d/p/gstring-Make-len_unsigned-unsigned.patch: + Add patches from upstream to fix a buffer underflow with very large + GString instances (Closes: #1104930, CVE-2025-4373) + * d/p/gdate-Call-tzset-before-localtime_r.patch: + Add patch from upstream to ensure that tzset() is called before + localtime_r(); otherwise the behaviour of localtime_r() is unspecified. + * These patches bring us up to date with upstream glib-2-84 branch commit + 2.84.1-15-gb3de15acf9, excluding changes that are not relevant to + Debian architectures (macOS CI and Windows) and the revert of the fix + for LP#2072586 (discussed above). + + -- Simon McVittie <s...@debian.org> Fri, 09 May 2025 10:46:25 +0100 + glib2.0 (2.84.1-2) unstable; urgency=medium * Cherry-pick 2 commits from glib-2-84 branch (LP: #2072586) diff --git a/debian/patches/gdate-Call-tzset-before-localtime_r.patch b/debian/patches/gdate-Call-tzset-before-localtime_r.patch new file mode 100644 index 0000000000..05e378bfa6 --- /dev/null +++ b/debian/patches/gdate-Call-tzset-before-localtime_r.patch @@ -0,0 +1,24 @@ +From: Alessandro Astone <alessandro.ast...@canonical.com> +Date: Wed, 30 Apr 2025 16:04:34 +0200 +Subject: gdate: Call tzset before localtime_r + +From `man 3 ctime`: + According to POSIX.1, localtime() is required to behave as though tzset(3) + was called, while localtime_r() does not have this requirement. + For portable code, tzset(3) should be called before localtime_r(). +--- + glib/gdate.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/glib/gdate.c b/glib/gdate.c +index ffc21f1..ed25ec3 100644 +--- a/glib/gdate.c ++++ b/glib/gdate.c +@@ -1392,6 +1392,7 @@ _g_localtime (time_t timet, struct tm *out_tm) + gboolean success = TRUE; + + #ifdef HAVE_LOCALTIME_R ++ tzset (); + if (!localtime_r (&timet, out_tm)) + success = FALSE; + #else diff --git a/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch b/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch index 79e1c9c014..5d0771924c 100644 --- a/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch +++ b/debian/patches/gfileutils-Preserve-mode-during-atomic-updates.patch @@ -13,6 +13,10 @@ Closes GNOME/dconf#76 (cherry picked from commit 3cc0c0de33bc4b461e89b05d142e1ecf5f474317) Origin: upstream glib-2-84 branch, after 2.84.1 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/glib2.0/+bug/2072586 +Comment: This was actually reverted from the glib-2-84 branch but + it seems reasonable to keep it for trixie anyway + https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4608 --- glib/gfileutils.c | 25 +++++++++++++++++++++++-- glib/tests/fileutils.c | 14 ++++++++++---- diff --git a/debian/patches/gstring-Make-len_unsigned-unsigned.patch b/debian/patches/gstring-Make-len_unsigned-unsigned.patch new file mode 100644 index 0000000000..33b48bf796 --- /dev/null +++ b/debian/patches/gstring-Make-len_unsigned-unsigned.patch @@ -0,0 +1,25 @@ +From: Peter Bloomfield <peterbloomfi...@bellsouth.net> +Date: Fri, 11 Apr 2025 05:52:33 +0000 +Subject: gstring: Make len_unsigned unsigned + +Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3677 +Bug-CVE: CVE-2025-4373 +Bug-Debian: https://bugs.debian.org/1104930 +Origin: upstream, 2.84.2, commit:f32f4aea514e39086a2627e9483d841c9eeb9bc3 +--- + glib/gstring.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/gstring.c b/glib/gstring.c +index d79a484..2a399ee 100644 +--- a/glib/gstring.c ++++ b/glib/gstring.c +@@ -928,7 +928,7 @@ g_string_overwrite_len (GString *string, + const gchar *val, + gssize len) + { +- gssize len_unsigned; ++ gsize len_unsigned; + gsize end; + + g_return_val_if_fail (string != NULL, NULL); diff --git a/debian/patches/gstring-carefully-handle-gssize-parameters.patch b/debian/patches/gstring-carefully-handle-gssize-parameters.patch new file mode 100644 index 0000000000..95c83f41f7 --- /dev/null +++ b/debian/patches/gstring-carefully-handle-gssize-parameters.patch @@ -0,0 +1,119 @@ +From: Michael Catanzaro <mcatanz...@redhat.com> +Date: Mon, 28 Apr 2025 16:03:08 +0000 +Subject: gstring: carefully handle gssize parameters + +Wherever we use gssize to allow passing -1, we need to ensure we don't +overflow the value by assigning a gsize to it without checking if the +size exceeds the maximum gssize. The safest way to do this is to just +use normal gsize everywhere instead and use gssize only for the +parameter. + +Our computers don't have enough RAM to write tests for this. I tried +forcing string->len to high values for test purposes, but this isn't +valid and will just cause out of bounds reads/writes due to +string->allocated_len being unexpectedly small, so I don't think we can +test this easily. + +(cherry picked from commit cc647f9e46d55509a93498af19659baf9c80f2e3) + +Co-authored-by: Michael Catanzaro <mcatanz...@redhat.com> +Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3677 +Bug-CVE: CVE-2025-4373 +Bug-Debian: https://bugs.debian.org/1104930 +Origin: upstream, 2.84.2, commit:a47dc889463d73dd47ad428ac217e3d84f28e242 +--- + glib/gstring.c | 36 +++++++++++++++++++++++------------- + 1 file changed, 23 insertions(+), 13 deletions(-) + +diff --git a/glib/gstring.c b/glib/gstring.c +index 5279ed3..d79a484 100644 +--- a/glib/gstring.c ++++ b/glib/gstring.c +@@ -480,8 +480,9 @@ g_string_insert_len (GString *string, + return string; + + if (len < 0) +- len = strlen (val); +- len_unsigned = len; ++ len_unsigned = strlen (val); ++ else ++ len_unsigned = len; + + if (pos < 0) + pos_unsigned = string->len; +@@ -778,10 +779,12 @@ g_string_insert_c (GString *string, + g_string_maybe_expand (string, 1); + + if (pos < 0) +- pos = string->len; ++ pos_unsigned = string->len; + else +- g_return_val_if_fail ((gsize) pos <= string->len, string); +- pos_unsigned = pos; ++ { ++ pos_unsigned = pos; ++ g_return_val_if_fail (pos_unsigned <= string->len, string); ++ } + + /* If not just an append, move the old stuff */ + if (pos_unsigned < string->len) +@@ -814,6 +817,7 @@ g_string_insert_unichar (GString *string, + gssize pos, + gunichar wc) + { ++ gsize pos_unsigned; + gint charlen, first, i; + gchar *dest; + +@@ -855,15 +859,18 @@ g_string_insert_unichar (GString *string, + g_string_maybe_expand (string, charlen); + + if (pos < 0) +- pos = string->len; ++ pos_unsigned = string->len; + else +- g_return_val_if_fail ((gsize) pos <= string->len, string); ++ { ++ pos_unsigned = pos; ++ g_return_val_if_fail (pos_unsigned <= string->len, string); ++ } + + /* If not just an append, move the old stuff */ +- if ((gsize) pos < string->len) +- memmove (string->str + pos + charlen, string->str + pos, string->len - pos); ++ if (pos_unsigned < string->len) ++ memmove (string->str + pos_unsigned + charlen, string->str + pos_unsigned, string->len - pos_unsigned); + +- dest = string->str + pos; ++ dest = string->str + pos_unsigned; + /* Code copied from g_unichar_to_utf() */ + for (i = charlen - 1; i > 0; --i) + { +@@ -921,6 +928,7 @@ g_string_overwrite_len (GString *string, + const gchar *val, + gssize len) + { ++ gssize len_unsigned; + gsize end; + + g_return_val_if_fail (string != NULL, NULL); +@@ -932,14 +940,16 @@ g_string_overwrite_len (GString *string, + g_return_val_if_fail (pos <= string->len, string); + + if (len < 0) +- len = strlen (val); ++ len_unsigned = strlen (val); ++ else ++ len_unsigned = len; + +- end = pos + len; ++ end = pos + len_unsigned; + + if (end > string->len) + g_string_maybe_expand (string, end - string->len); + +- memcpy (string->str + pos, val, len); ++ memcpy (string->str + pos, val, len_unsigned); + + if (end > string->len) + { diff --git a/debian/patches/series b/debian/patches/series index 797de6b376..fe3988c90c 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -16,3 +16,6 @@ workarounds/testfilemonitor-Skip-if-we-are-avoiding-flaky-tests.patch debian/girepository-Describe-the-Debian-specific-cross-prefixed-.patch gclosure-fix-ATOMIC_CHANGE_FIELD-to-read-vint-atomically.patch gfileutils-Preserve-mode-during-atomic-updates.patch +gstring-carefully-handle-gssize-parameters.patch +gstring-Make-len_unsigned-unsigned.patch +gdate-Call-tzset-before-localtime_r.patch diff --git a/glib/gdate.c b/glib/gdate.c index ffc21f1b9b..ed25ec308c 100644 --- a/glib/gdate.c +++ b/glib/gdate.c @@ -1392,6 +1392,7 @@ _g_localtime (time_t timet, struct tm *out_tm) gboolean success = TRUE; #ifdef HAVE_LOCALTIME_R + tzset (); if (!localtime_r (&timet, out_tm)) success = FALSE; #else diff --git a/glib/gstring.c b/glib/gstring.c index 5279ed3cca..2a399ee21f 100644 --- a/glib/gstring.c +++ b/glib/gstring.c @@ -480,8 +480,9 @@ g_string_insert_len (GString *string, return string; if (len < 0) - len = strlen (val); - len_unsigned = len; + len_unsigned = strlen (val); + else + len_unsigned = len; if (pos < 0) pos_unsigned = string->len; @@ -778,10 +779,12 @@ g_string_insert_c (GString *string, g_string_maybe_expand (string, 1); if (pos < 0) - pos = string->len; + pos_unsigned = string->len; else - g_return_val_if_fail ((gsize) pos <= string->len, string); - pos_unsigned = pos; + { + pos_unsigned = pos; + g_return_val_if_fail (pos_unsigned <= string->len, string); + } /* If not just an append, move the old stuff */ if (pos_unsigned < string->len) @@ -814,6 +817,7 @@ g_string_insert_unichar (GString *string, gssize pos, gunichar wc) { + gsize pos_unsigned; gint charlen, first, i; gchar *dest; @@ -855,15 +859,18 @@ g_string_insert_unichar (GString *string, g_string_maybe_expand (string, charlen); if (pos < 0) - pos = string->len; + pos_unsigned = string->len; else - g_return_val_if_fail ((gsize) pos <= string->len, string); + { + pos_unsigned = pos; + g_return_val_if_fail (pos_unsigned <= string->len, string); + } /* If not just an append, move the old stuff */ - if ((gsize) pos < string->len) - memmove (string->str + pos + charlen, string->str + pos, string->len - pos); + if (pos_unsigned < string->len) + memmove (string->str + pos_unsigned + charlen, string->str + pos_unsigned, string->len - pos_unsigned); - dest = string->str + pos; + dest = string->str + pos_unsigned; /* Code copied from g_unichar_to_utf() */ for (i = charlen - 1; i > 0; --i) { @@ -921,6 +928,7 @@ g_string_overwrite_len (GString *string, const gchar *val, gssize len) { + gsize len_unsigned; gsize end; g_return_val_if_fail (string != NULL, NULL); @@ -932,14 +940,16 @@ g_string_overwrite_len (GString *string, g_return_val_if_fail (pos <= string->len, string); if (len < 0) - len = strlen (val); + len_unsigned = strlen (val); + else + len_unsigned = len; - end = pos + len; + end = pos + len_unsigned; if (end > string->len) g_string_maybe_expand (string, end - string->len); - memcpy (string->str + pos, val, len); + memcpy (string->str + pos, val, len_unsigned); if (end > string->len) {