import UBI glib2-2.80.4-12.el10_2.21
This commit is contained in:
parent
33edc76541
commit
0d48bae10d
263
CVE-2026-15588.patch
Normal file
263
CVE-2026-15588.patch
Normal file
@ -0,0 +1,263 @@
|
||||
From 327681e682af8c413fc26a9bd3cba4e77be3a069 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sat, 4 Jul 2026 18:13:08 +0100
|
||||
Subject: [PATCH] gdbusauth: Limit length of lines read from client
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The client isn’t trusted at this point, and there was previously nothing
|
||||
limiting how long a line `GDBusAuth` would read. So an untrusted client
|
||||
could exhaust the server’s memory by sending anything except `\r\n`.
|
||||
|
||||
Fix that by applying a reasonably length limit when reading a line, and
|
||||
add a unit test.
|
||||
|
||||
Spotted by Gitee Codepecker Lab.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
Fixes: #3985
|
||||
---
|
||||
gio/gdbusauth.c | 44 +++++++++++++++
|
||||
gio/tests/gdbus-auth.c | 119 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 163 insertions(+)
|
||||
|
||||
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
|
||||
index 9e31c8318..a5938c969 100644
|
||||
--- a/gio/gdbusauth.c
|
||||
+++ b/gio/gdbusauth.c
|
||||
@@ -260,6 +260,21 @@ find_mech_by_name (GDBusAuth *auth,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static size_t
|
||||
+get_longest_mechanism_name_length (GDBusAuth *auth)
|
||||
+{
|
||||
+ size_t len = 0;
|
||||
+
|
||||
+ for (GList *l = auth->priv->available_mechanisms; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ Mechanism *m = l->data;
|
||||
+
|
||||
+ len = MAX (len, strlen (m->name));
|
||||
+ }
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
GDBusAuth *
|
||||
_g_dbus_auth_new (GIOStream *stream)
|
||||
{
|
||||
@@ -268,6 +283,20 @@ _g_dbus_auth_new (GIOStream *stream)
|
||||
NULL);
|
||||
}
|
||||
|
||||
+/* Arbitrarily chosen limit on the length of a DATA command payload, to prevent
|
||||
+ * unbounded reads from malicious clients.
|
||||
+ *
|
||||
+ * - The ANONYMOUS mechanism doesn’t use DATA.
|
||||
+ * - The EXTERNAL mechanism just uses it to transfer a decimal-encoded UID.
|
||||
+ * - The DBUS_COOKIE_SHA1 mechanism transfers a challenge and a SHA1 hash. The
|
||||
+ * hash is bounded in length, but the challenge is not, so could potentially
|
||||
+ * hit this limit. It doesn’t seem unreasonable to bound the challenge to
|
||||
+ * ~4KB though. GDBus itself generates a 16 byte challenge.
|
||||
+ *
|
||||
+ * See https://dbus.freedesktop.org/doc/dbus-specification.html#auth-command-data
|
||||
+ */
|
||||
+#define MAX_DATA_PAYLOAD_LENGTH_BYTES 4096
|
||||
+
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
/* like g_data_input_stream_read_line() but sets error if there's no content to read */
|
||||
static gchar *
|
||||
@@ -305,6 +334,7 @@ _my_g_data_input_stream_read_line (GDataInputStream *dis,
|
||||
*/
|
||||
static gchar *
|
||||
_my_g_input_stream_read_line_safe (GInputStream *i,
|
||||
+ size_t max_line_length,
|
||||
gsize *out_line_length,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@@ -314,11 +344,22 @@ _my_g_input_stream_read_line_safe (GInputStream *i,
|
||||
gssize num_read;
|
||||
gboolean last_was_cr;
|
||||
|
||||
+ g_assert (max_line_length <= SIZE_MAX - 2);
|
||||
+
|
||||
str = g_string_new (NULL);
|
||||
|
||||
last_was_cr = FALSE;
|
||||
while (TRUE)
|
||||
{
|
||||
+ if (str->len >= max_line_length + 2 /* allow for \r\n */)
|
||||
+ {
|
||||
+ g_set_error_literal (error,
|
||||
+ G_IO_ERROR,
|
||||
+ G_IO_ERROR_FAILED,
|
||||
+ _("Malformed D-Bus authentication line"));
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
num_read = g_input_stream_read (i,
|
||||
&c,
|
||||
1,
|
||||
@@ -1071,6 +1112,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
case SERVER_STATE_WAITING_FOR_AUTH:
|
||||
debug_print ("SERVER: WaitingForAuth");
|
||||
line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
|
||||
+ strlen ("AUTH ") + get_longest_mechanism_name_length (auth) + strlen (" ") + MAX_DATA_PAYLOAD_LENGTH_BYTES,
|
||||
&line_length,
|
||||
cancellable,
|
||||
error);
|
||||
@@ -1292,6 +1334,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
case SERVER_STATE_WAITING_FOR_DATA:
|
||||
debug_print ("SERVER: WaitingForData");
|
||||
line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
|
||||
+ strlen ("DATA ") + MAX_DATA_PAYLOAD_LENGTH_BYTES,
|
||||
&line_length,
|
||||
cancellable,
|
||||
error);
|
||||
@@ -1334,6 +1377,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
case SERVER_STATE_WAITING_FOR_BEGIN:
|
||||
debug_print ("SERVER: WaitingForBegin");
|
||||
line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
|
||||
+ MAX (strlen ("BEGIN"), strlen ("NEGOTIATE_UNIX_FD")),
|
||||
&line_length,
|
||||
cancellable,
|
||||
error);
|
||||
diff --git a/gio/tests/gdbus-auth.c b/gio/tests/gdbus-auth.c
|
||||
index 657571be3..3323d6eeb 100644
|
||||
--- a/gio/tests/gdbus-auth.c
|
||||
+++ b/gio/tests/gdbus-auth.c
|
||||
@@ -263,6 +263,124 @@ temp_dbus_keyrings_teardown (void)
|
||||
g_unsetenv ("G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION");
|
||||
}
|
||||
|
||||
+static void
|
||||
+async_result_cb (GObject *obj,
|
||||
+ GAsyncResult *result,
|
||||
+ void *user_data)
|
||||
+{
|
||||
+ GAsyncResult **result_out = user_data;
|
||||
+
|
||||
+ g_assert (result_out != NULL);
|
||||
+ g_assert (*result_out == NULL);
|
||||
+
|
||||
+ *result_out = g_object_ref (result);
|
||||
+ g_main_context_wakeup (g_main_context_get_thread_default ());
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+server_new_connection_unexpected_cb (GDBusServer *server,
|
||||
+ GDBusConnection *connection,
|
||||
+ void *user_data)
|
||||
+{
|
||||
+ g_assert_not_reached ();
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_auth_server_read_limit (void)
|
||||
+{
|
||||
+ GDBusServer *server = NULL;
|
||||
+ unsigned long new_connection_id = 0;
|
||||
+ const char *server_address;
|
||||
+ GIOStream *client_stream = NULL;
|
||||
+ GOutputStream *client_output_stream;
|
||||
+ GInputStream *client_input_stream;
|
||||
+ GAsyncResult *result = NULL;
|
||||
+ char *write_buffer = NULL;
|
||||
+ char read_buffer[100];
|
||||
+ ssize_t read_len;
|
||||
+ size_t bytes_written;
|
||||
+ GError *local_error = NULL;
|
||||
+
|
||||
+ g_test_summary ("Test that GDBusServer limits the lengths of reads it does during auth from a client");
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3985");
|
||||
+
|
||||
+ server = server_new_for_mechanism (NULL);
|
||||
+
|
||||
+ new_connection_id = g_signal_connect (server,
|
||||
+ "new-connection",
|
||||
+ G_CALLBACK (server_new_connection_unexpected_cb),
|
||||
+ NULL);
|
||||
+ server_address = g_dbus_server_get_client_address (server);
|
||||
+ g_dbus_server_start (server);
|
||||
+
|
||||
+ /* Start connecting as a client */
|
||||
+ g_dbus_address_get_stream (server_address, NULL, async_result_cb, &result);
|
||||
+
|
||||
+ while (result == NULL)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ client_stream = g_dbus_address_get_stream_finish (result, NULL, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+ g_clear_object (&result);
|
||||
+
|
||||
+ /* Send an over-long AUTH line, maliciously */
|
||||
+ client_output_stream = g_io_stream_get_output_stream (client_stream);
|
||||
+ client_input_stream = g_io_stream_get_input_stream (client_stream);
|
||||
+
|
||||
+ write_buffer = g_strdup_printf ("AUTH DBUS_COOKIE_SHA1 context%0*d 123 456\r\n", 5000, 0);
|
||||
+
|
||||
+ g_output_stream_write_all_async (client_output_stream,
|
||||
+ write_buffer,
|
||||
+ strlen (write_buffer),
|
||||
+ G_PRIORITY_DEFAULT,
|
||||
+ NULL,
|
||||
+ async_result_cb,
|
||||
+ &result);
|
||||
+
|
||||
+ while (result == NULL)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_output_stream_write_all_finish (client_output_stream, result, &bytes_written, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+ g_assert_cmpuint (bytes_written, ==, strlen (write_buffer));
|
||||
+ g_clear_object (&result);
|
||||
+
|
||||
+ g_clear_pointer (&write_buffer, g_free);
|
||||
+
|
||||
+ /* Authentication should have been rejected, so reading or writing the stream
|
||||
+ * should now fail. */
|
||||
+ read_len = g_input_stream_read (client_input_stream,
|
||||
+ read_buffer,
|
||||
+ sizeof (read_buffer),
|
||||
+ NULL,
|
||||
+ &local_error);
|
||||
+ g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED);
|
||||
+ g_assert_cmpint (read_len, <, 0);
|
||||
+ g_clear_error (&local_error);
|
||||
+
|
||||
+ write_buffer = g_strdup_printf ("AUTH\r\n");
|
||||
+
|
||||
+ g_output_stream_write_all (client_output_stream,
|
||||
+ write_buffer,
|
||||
+ strlen (write_buffer),
|
||||
+ &bytes_written,
|
||||
+ NULL,
|
||||
+ &local_error);
|
||||
+ g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED);
|
||||
+ g_assert_cmpuint (bytes_written, ==, 0);
|
||||
+ g_clear_error (&local_error);
|
||||
+
|
||||
+ g_clear_pointer (&write_buffer, g_free);
|
||||
+
|
||||
+ /* Cleanup */
|
||||
+ g_clear_object (&client_stream);
|
||||
+ g_dbus_server_stop (server);
|
||||
+
|
||||
+ g_clear_signal_handler (&new_connection_id, server);
|
||||
+ g_clear_object (&server);
|
||||
+}
|
||||
+
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
@@ -282,6 +400,7 @@ main (int argc,
|
||||
g_test_add_func ("/gdbus/auth/server/ANONYMOUS", auth_server_anonymous);
|
||||
g_test_add_func ("/gdbus/auth/server/EXTERNAL", auth_server_external);
|
||||
g_test_add_func ("/gdbus/auth/server/DBUS_COOKIE_SHA1", auth_server_dbus_cookie_sha1);
|
||||
+ g_test_add_func ("/gdbus/auth/server/read-limit", test_auth_server_read_limit);
|
||||
|
||||
/* TODO: we currently don't have tests for
|
||||
*
|
||||
132
CVE-2026-58010.patch
Normal file
132
CVE-2026-58010.patch
Normal file
@ -0,0 +1,132 @@
|
||||
From a75acc5b29cd4940a1a25a65bcee7432ed8ba2c1 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sun, 29 Mar 2026 19:10:41 +0100
|
||||
Subject: [PATCH 1/2] gvariant: Fix an off-by-one error in an offset comparison
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This allows a single byte out-of-bounds read off the end of the
|
||||
(potentially untrusted) byte array backing a `GVariant` when it’s
|
||||
being checked for normal form.
|
||||
|
||||
I can’t see how this could practically be exploited, but it’s certainly
|
||||
a security bug as the `GVariant` normal form checking code is supposed
|
||||
to be robust to malicious inputs.
|
||||
|
||||
Spotted by linhlhq as #YWH-PGM9867-190, and fix and reproducer provided
|
||||
by them too, thanks. Confirmed and turned into a unit test by me.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
|
||||
Fixes: #3915
|
||||
---
|
||||
glib/gvariant-serialiser.c | 2 +-
|
||||
glib/tests/gvariant.c | 48 ++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 49 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
|
||||
index 9a2975b33..85f28cdce 100644
|
||||
--- a/glib/gvariant-serialiser.c
|
||||
+++ b/glib/gvariant-serialiser.c
|
||||
@@ -1248,7 +1248,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
|
||||
|
||||
while (offset & alignment)
|
||||
{
|
||||
- if (offset > value.size || value.data[offset] != '\0')
|
||||
+ if (offset >= value.size || value.data[offset] != '\0')
|
||||
return FALSE;
|
||||
offset++;
|
||||
}
|
||||
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
|
||||
index c24cd2f3e..0d59779ed 100644
|
||||
--- a/glib/tests/gvariant.c
|
||||
+++ b/glib/tests/gvariant.c
|
||||
@@ -5646,6 +5646,52 @@ test_normal_checking_tuple_offsets5 (void)
|
||||
g_variant_unref (variant);
|
||||
}
|
||||
|
||||
+/* This is a regression test that looping over the padding bytes in a short
|
||||
+ * (non-normal) tuple doesn’t overflow the input data.
|
||||
+ *
|
||||
+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/3915 */
|
||||
+static void
|
||||
+test_normal_checking_tuple_offsets6 (void)
|
||||
+{
|
||||
+ /*
|
||||
+ * Type: (ynqiuxthdsog) — 12 members, first member 'y' (byte) has
|
||||
+ * alignment 0, second 'n' (int16) has alignment 1.
|
||||
+ * With 1 byte of data (0x28), after reading the first byte member,
|
||||
+ * offset=1, alignment check for 'n' requires offset to be even,
|
||||
+ * so the while loop checks value.data[1] — but size is only 1.
|
||||
+ *
|
||||
+ * Use heap allocation via GBytes so ASan reports heap-buffer-overflow.
|
||||
+ */
|
||||
+ uint8_t *heap_data = NULL;
|
||||
+ GBytes *bytes = NULL;
|
||||
+ const GVariantType *data_type = G_VARIANT_TYPE ("(ynqiuxthdsog)");
|
||||
+ GVariant *variant = NULL;
|
||||
+ GVariant *normal_variant = NULL;
|
||||
+ GVariant *expected = NULL;
|
||||
+
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3915");
|
||||
+
|
||||
+ heap_data = g_malloc (1);
|
||||
+ heap_data[0] = 0x28;
|
||||
+ bytes = g_bytes_new_take (heap_data, 1);
|
||||
+
|
||||
+ variant = g_variant_new_from_bytes (data_type, bytes, FALSE);
|
||||
+ g_assert_nonnull (variant);
|
||||
+
|
||||
+ g_assert_false (g_variant_is_normal_form (variant));
|
||||
+
|
||||
+ normal_variant = g_variant_get_normal_form (variant);
|
||||
+ g_assert_nonnull (normal_variant);
|
||||
+
|
||||
+ expected = g_variant_new_parsed ("(byte 0x28, int16 0, uint16 0, 0, uint32 0, int64 0, uint64 0, handle 0, 0.0, '', objectpath '/', signature '')");
|
||||
+ g_assert_cmpvariant (expected, variant);
|
||||
+ g_assert_cmpvariant (expected, normal_variant);
|
||||
+
|
||||
+ g_variant_unref (expected);
|
||||
+ g_variant_unref (normal_variant);
|
||||
+ g_variant_unref (variant);
|
||||
+}
|
||||
+
|
||||
/* Test that an otherwise-valid serialised GVariant is considered non-normal if
|
||||
* its offset table entries are too wide.
|
||||
*
|
||||
@@ -5899,6 +5945,8 @@ main (int argc, char **argv)
|
||||
test_normal_checking_tuple_offsets4);
|
||||
g_test_add_func ("/gvariant/normal-checking/tuple-offsets5",
|
||||
test_normal_checking_tuple_offsets5);
|
||||
+ g_test_add_func ("/gvariant/normal-checking/tuple-offsets6",
|
||||
+ test_normal_checking_tuple_offsets6);
|
||||
g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized",
|
||||
test_normal_checking_tuple_offsets_minimal_sized);
|
||||
g_test_add_func ("/gvariant/normal-checking/empty-object-path",
|
||||
|
||||
From bccf3bf4cad47dd7de29f41bde7a7cfdd5f77cbc Mon Sep 17 00:00:00 2001
|
||||
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
|
||||
Date: Mon, 20 Jul 2026 07:02:55 +0000
|
||||
Subject: [PATCH 2/2] Fix uint8_t -> guint8 for compatibility with GLib 2.80.x
|
||||
|
||||
The upstream commit used uint8_t which requires <stdint.h>, but
|
||||
glib/tests/gvariant.c does not include it. Use guint8 (GLib's
|
||||
equivalent type) instead, consistent with the rest of the file.
|
||||
---
|
||||
glib/tests/gvariant.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
|
||||
index 0d59779ed..637bd07bc 100644
|
||||
--- a/glib/tests/gvariant.c
|
||||
+++ b/glib/tests/gvariant.c
|
||||
@@ -5662,7 +5662,7 @@ test_normal_checking_tuple_offsets6 (void)
|
||||
*
|
||||
* Use heap allocation via GBytes so ASan reports heap-buffer-overflow.
|
||||
*/
|
||||
- uint8_t *heap_data = NULL;
|
||||
+ guint8 *heap_data = NULL;
|
||||
GBytes *bytes = NULL;
|
||||
const GVariantType *data_type = G_VARIANT_TYPE ("(ynqiuxthdsog)");
|
||||
GVariant *variant = NULL;
|
||||
122
CVE-2026-58011.patch
Normal file
122
CVE-2026-58011.patch
Normal file
@ -0,0 +1,122 @@
|
||||
From b1410fefcb0f478eef003de6f62c5308a0c37847 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sun, 29 Mar 2026 23:19:47 +0100
|
||||
Subject: [PATCH 1/2] gdatetime: Factor out a couple of magic constants
|
||||
|
||||
This introduces no functional changes, it just makes the code a little
|
||||
clearer.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
---
|
||||
glib/gdatetime.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
|
||||
index b5372d834..d2a46eb80 100644
|
||||
--- a/glib/gdatetime.c
|
||||
+++ b/glib/gdatetime.c
|
||||
@@ -103,7 +103,7 @@ struct _GDateTime
|
||||
gint interval;
|
||||
|
||||
/* 1 is 0001-01-01 in Proleptic Gregorian */
|
||||
- gint32 days;
|
||||
+ gint32 days; /* in range [MIN_DAYS, MAX_DAYS] */
|
||||
|
||||
gint ref_count; /* (atomic) */
|
||||
};
|
||||
@@ -145,6 +145,9 @@ struct _GDateTime
|
||||
#define JULIAN_YEAR(d) ((d)->julian / 365.25)
|
||||
#define DAYS_PER_PERIOD (G_GINT64_CONSTANT (2914695))
|
||||
|
||||
+#define MIN_DAYS 1 /* the days count for 0001-01-01 in Proleptic Gregorian */
|
||||
+#define MAX_DAYS 3652059 /* the days count for 9999-12-31 in Proleptic Gregorian */
|
||||
+
|
||||
static const guint16 days_in_months[2][13] =
|
||||
{
|
||||
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
@@ -779,7 +782,7 @@ g_date_time_from_instant (GTimeZone *tz,
|
||||
datetime->days = instant / USEC_PER_DAY;
|
||||
datetime->usec = instant % USEC_PER_DAY;
|
||||
|
||||
- if (datetime->days < 1 || 3652059 < datetime->days)
|
||||
+ if (datetime->days < MIN_DAYS || datetime->days > MAX_DAYS)
|
||||
{
|
||||
g_date_time_unref (datetime);
|
||||
datetime = NULL;
|
||||
@@ -815,7 +818,7 @@ g_date_time_deal_with_date_change (GDateTime *datetime)
|
||||
gint64 full_time;
|
||||
gint64 usec;
|
||||
|
||||
- if (datetime->days < 1 || datetime->days > 3652059)
|
||||
+ if (datetime->days < MIN_DAYS || datetime->days > MAX_DAYS)
|
||||
return FALSE;
|
||||
|
||||
was_dst = g_time_zone_is_dst (datetime->tz, datetime->interval);
|
||||
|
||||
From 1fa222226d7e1737acd463b38ebd45759953de39 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sun, 29 Mar 2026 23:46:17 +0100
|
||||
Subject: [PATCH 2/2] gdatetime: Add missing range validation to
|
||||
g_date_time_add_full()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Otherwise it’s possible to create a non-`NULL` but invalid `GDateTime`,
|
||||
which breaks all kinds of internal assumptions.
|
||||
|
||||
Spotted by linhlhq as #YWH-PGM9867-191. Thanks to them for providing a
|
||||
suggested fix and a test case, which I have adapted and validated.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
|
||||
Fixes: #3917
|
||||
---
|
||||
glib/gdatetime.c | 4 +++-
|
||||
glib/tests/gdatetime.c | 18 ++++++++++++++++++
|
||||
2 files changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
|
||||
index d2a46eb80..e1bfd9e1c 100644
|
||||
--- a/glib/gdatetime.c
|
||||
+++ b/glib/gdatetime.c
|
||||
@@ -2074,7 +2074,9 @@ g_date_time_add_full (GDateTime *datetime,
|
||||
new->days = full_time / USEC_PER_DAY;
|
||||
new->usec = full_time % USEC_PER_DAY;
|
||||
|
||||
- /* XXX validate */
|
||||
+ /* Validate it’s still in the range 0001-01-01 to 9999-12-31 */
|
||||
+ if (new->days < MIN_DAYS || new->days > MAX_DAYS)
|
||||
+ g_clear_pointer (&new, g_date_time_unref);
|
||||
|
||||
return new;
|
||||
}
|
||||
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
|
||||
index 9e1acd097..bca5c93a4 100644
|
||||
--- a/glib/tests/gdatetime.c
|
||||
+++ b/glib/tests/gdatetime.c
|
||||
@@ -1124,6 +1124,24 @@ test_GDateTime_add_full (void)
|
||||
TEST_ADD_FULL (2010, 8, 25, 22, 45, 0,
|
||||
0, 1, 6, 1, 25, 0,
|
||||
2010, 10, 2, 0, 10, 0);
|
||||
+
|
||||
+#define TEST_ADD_FULL_ERROR(y,m,d,h,mi,s,ay,am,ad,ah,ami,as) G_STMT_START { \
|
||||
+ GDateTime *dt; \
|
||||
+ dt = g_date_time_new_utc (y, m, d, h, mi, s); \
|
||||
+ g_assert_null (g_date_time_add_full (dt, ay, am, ad, ah, ami, as)); \
|
||||
+ g_date_time_unref (dt); \
|
||||
+} G_STMT_END
|
||||
+
|
||||
+ TEST_ADD_FULL_ERROR ( 1, 12, 1, 0, 0, 0,
|
||||
+ -1, 0, 0, 0, 0, 0);
|
||||
+ TEST_ADD_FULL_ERROR ( 1, 12, 1, 0, 0, 0,
|
||||
+ 10000, 0, 0, 0, 0, 0);
|
||||
+ TEST_ADD_FULL_ERROR ( 9999, 12, 1, 0, 0, 0,
|
||||
+ -10000, 0, 0, 0, 0, 0);
|
||||
+ TEST_ADD_FULL_ERROR ( 1, 12, 1, 0, 0, 0,
|
||||
+ 0, 0, 3660001, 0, 0, 0);
|
||||
+ TEST_ADD_FULL_ERROR ( 9999, 12, 1, 0, 0, 0,
|
||||
+ 0, 0, -3660001, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
221
CVE-2026-58012.patch
Normal file
221
CVE-2026-58012.patch
Normal file
@ -0,0 +1,221 @@
|
||||
From b06ab979cbf61a7eee2caa2201da4c015249407a Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Tue, 31 Mar 2026 16:13:57 +0100
|
||||
Subject: [PATCH] gregex: Fix case changing substitutions with G_REGEX_RAW
|
||||
|
||||
In `G_REGEX_RAW` mode, the input string is treated as a byte array
|
||||
(basically ASCII) rather than a unichar array. Accordingly, the case
|
||||
changing code for substitutions needs to operate on bytes with
|
||||
`G_REGEX_RAW`, rather than operating on unichars.
|
||||
|
||||
This fixes a potential buffer overflow when trying to do a case change
|
||||
on a match of a set of bytes which are a truncated multi-byte UTF-8
|
||||
encoding at the end of the input buffer.
|
||||
|
||||
Spotted by linhlhq as #YWH-PGM9867-193. I adapted their reproducer as
|
||||
the unit test, but implemented the fix in `gregex.c` independently.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
|
||||
Fixes: #3918
|
||||
---
|
||||
glib/gregex.c | 59 ++++++++++++++++++++++++++++++++++------------
|
||||
glib/tests/regex.c | 53 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 97 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/glib/gregex.c b/glib/gregex.c
|
||||
index d1633a8b2..128bf672c 100644
|
||||
--- a/glib/gregex.c
|
||||
+++ b/glib/gregex.c
|
||||
@@ -3146,19 +3146,25 @@ split_replacement (const gchar *replacement,
|
||||
return g_list_reverse (list);
|
||||
}
|
||||
|
||||
-/* Change the case of c based on change_case. */
|
||||
-#define CHANGE_CASE(c, change_case) \
|
||||
+/* Change the case of c based on change_case.
|
||||
+ * g_ascii_to*() will happily pass through non-ASCII bytes unchanged. */
|
||||
+#define UTF8_CHANGE_CASE(c, change_case) \
|
||||
(((change_case) & CHANGE_CASE_LOWER_MASK) ? \
|
||||
g_unichar_tolower (c) : \
|
||||
g_unichar_toupper (c))
|
||||
+#define RAW_CHANGE_CASE(c, change_case) \
|
||||
+ (((change_case) & CHANGE_CASE_LOWER_MASK) ? \
|
||||
+ g_ascii_tolower (c) : \
|
||||
+ g_ascii_toupper (c))
|
||||
|
||||
+/* If @text_is_raw is set, @text might not be valid UTF-8 (but will be
|
||||
+ * nul-terminated). */
|
||||
static void
|
||||
string_append (GString *string,
|
||||
const gchar *text,
|
||||
+ gboolean text_is_raw,
|
||||
ChangeCase *change_case)
|
||||
{
|
||||
- gunichar c;
|
||||
-
|
||||
if (text[0] == '\0')
|
||||
return;
|
||||
|
||||
@@ -3168,22 +3174,44 @@ string_append (GString *string,
|
||||
}
|
||||
else if (*change_case & CHANGE_CASE_SINGLE_MASK)
|
||||
{
|
||||
- c = g_utf8_get_char (text);
|
||||
- g_string_append_unichar (string, CHANGE_CASE (c, *change_case));
|
||||
- g_string_append (string, g_utf8_next_char (text));
|
||||
+ if (!text_is_raw)
|
||||
+ {
|
||||
+ gunichar c = g_utf8_get_char (text);
|
||||
+ g_string_append_unichar (string, UTF8_CHANGE_CASE (c, *change_case));
|
||||
+ g_string_append (string, g_utf8_next_char (text));
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ g_string_append_c (string, RAW_CHANGE_CASE (text[0], *change_case));
|
||||
+ g_string_append (string, text + 1);
|
||||
+ }
|
||||
+
|
||||
*change_case = CHANGE_CASE_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
- while (*text != '\0')
|
||||
+ if (!text_is_raw)
|
||||
{
|
||||
- c = g_utf8_get_char (text);
|
||||
- g_string_append_unichar (string, CHANGE_CASE (c, *change_case));
|
||||
- text = g_utf8_next_char (text);
|
||||
+ while (*text != '\0')
|
||||
+ {
|
||||
+ gunichar c = g_utf8_get_char (text);
|
||||
+ g_string_append_unichar (string, UTF8_CHANGE_CASE (c, *change_case));
|
||||
+ text = g_utf8_next_char (text);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ while (*text != '\0')
|
||||
+ {
|
||||
+ char c = *text;
|
||||
+ g_string_append_c (string, RAW_CHANGE_CASE (c, *change_case));
|
||||
+ text++;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+/* @match_info is (nullable) */
|
||||
static gboolean
|
||||
interpolate_replacement (const GMatchInfo *match_info,
|
||||
GString *result,
|
||||
@@ -3193,6 +3221,7 @@ interpolate_replacement (const GMatchInfo *match_info,
|
||||
InterpolationData *idata;
|
||||
gchar *match;
|
||||
ChangeCase change_case = CHANGE_CASE_NONE;
|
||||
+ gboolean is_raw = (match_info != NULL && (match_info->regex->orig_compile_opts & G_REGEX_RAW));
|
||||
|
||||
for (list = data; list; list = list->next)
|
||||
{
|
||||
@@ -3200,10 +3229,10 @@ interpolate_replacement (const GMatchInfo *match_info,
|
||||
switch (idata->type)
|
||||
{
|
||||
case REPL_TYPE_STRING:
|
||||
- string_append (result, idata->text, &change_case);
|
||||
+ string_append (result, idata->text, is_raw, &change_case);
|
||||
break;
|
||||
case REPL_TYPE_CHARACTER:
|
||||
- g_string_append_c (result, CHANGE_CASE (idata->c, change_case));
|
||||
+ g_string_append_c (result, UTF8_CHANGE_CASE (idata->c, change_case));
|
||||
if (change_case & CHANGE_CASE_SINGLE_MASK)
|
||||
change_case = CHANGE_CASE_NONE;
|
||||
break;
|
||||
@@ -3211,7 +3240,7 @@ interpolate_replacement (const GMatchInfo *match_info,
|
||||
match = g_match_info_fetch (match_info, idata->num);
|
||||
if (match)
|
||||
{
|
||||
- string_append (result, match, &change_case);
|
||||
+ string_append (result, match, is_raw, &change_case);
|
||||
g_free (match);
|
||||
}
|
||||
break;
|
||||
@@ -3219,7 +3248,7 @@ interpolate_replacement (const GMatchInfo *match_info,
|
||||
match = g_match_info_fetch_named (match_info, idata->text);
|
||||
if (match)
|
||||
{
|
||||
- string_append (result, match, &change_case);
|
||||
+ string_append (result, match, is_raw, &change_case);
|
||||
g_free (match);
|
||||
}
|
||||
break;
|
||||
diff --git a/glib/tests/regex.c b/glib/tests/regex.c
|
||||
index d7a698ec6..bffb52a87 100644
|
||||
--- a/glib/tests/regex.c
|
||||
+++ b/glib/tests/regex.c
|
||||
@@ -2529,6 +2529,58 @@ test_compiled_regex_after_jit_failure (void)
|
||||
g_regex_unref (regex);
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_replace_raw_change_case (void)
|
||||
+{
|
||||
+ GError *local_error = NULL;
|
||||
+ GRegex *regex = NULL;
|
||||
+
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3918");
|
||||
+ g_test_summary ("Test that case changes as part of a replacement are handled correctly in G_REGEX_RAW mode");
|
||||
+
|
||||
+ /*
|
||||
+ * Match a multi-byte sequence in RAW mode. The pattern matches
|
||||
+ * exactly 2 bytes. The subject contains a 4-byte UTF-8 lead (0xF4)
|
||||
+ * followed by only one continuation byte, then NUL.
|
||||
+ *
|
||||
+ * The matched substring will be "\xf4\x80" (2 bytes, heap-allocated
|
||||
+ * as 3-byte buffer with NUL). If the code regresses and tries to handle
|
||||
+ * the replacement as UTF-8 then g_utf8_get_char() would see 0xF4 and try
|
||||
+ * to read 4 bytes, going 1 byte past the NUL into OOB territory.
|
||||
+ */
|
||||
+ regex = g_regex_new ("..", G_REGEX_RAW, 0, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ /*
|
||||
+ * Build a subject string with truncated UTF-8.
|
||||
+ * \xF4 = 4-byte UTF-8 lead byte
|
||||
+ * \x80 = continuation byte
|
||||
+ * No 3rd/4th continuation bytes — the match is only 2 bytes.
|
||||
+ *
|
||||
+ * \U\0 = uppercase the entire match → triggers string_append()
|
||||
+ * with case change on the 2-byte non-UTF-8 match.
|
||||
+ */
|
||||
+ char subject[] = "\xf4\x80";
|
||||
+ char *result = g_regex_replace (regex, subject, -1, 0, "\\U\\0", 0, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ g_clear_pointer (&result, g_free);
|
||||
+ g_clear_pointer (®ex, g_regex_unref);
|
||||
+
|
||||
+ /*
|
||||
+ * Second variant: single-char case change \u with \0 backreference.
|
||||
+ */
|
||||
+ regex = g_regex_new (".", G_REGEX_RAW, 0, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ char subject2[] = "\xe6\xb0"; /* 3-byte UTF-8 lead, only 2 bytes */
|
||||
+ result = g_regex_replace (regex, subject2, -1, 0, "\\u\\0", 0, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ g_clear_pointer (&result, g_free);
|
||||
+ g_clear_pointer (®ex, g_regex_unref);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -2550,6 +2602,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/regex/jit-unsupported-matching", test_jit_unsupported_matching_options);
|
||||
g_test_add_func ("/regex/unmatched-named-subpattern", test_unmatched_named_subpattern);
|
||||
g_test_add_func ("/regex/compiled-regex-after-jit-failure", test_compiled_regex_after_jit_failure);
|
||||
+ g_test_add_func ("/regex/replace-raw-change-case", test_replace_raw_change_case);
|
||||
|
||||
/* TEST_NEW(pattern, compile_opts, match_opts) */
|
||||
TEST_NEW("[A-Z]+", G_REGEX_CASELESS | G_REGEX_EXTENDED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTBOL | G_REGEX_MATCH_PARTIAL);
|
||||
142
CVE-2026-58013.patch
Normal file
142
CVE-2026-58013.patch
Normal file
@ -0,0 +1,142 @@
|
||||
From 632da30304f724b806e224531775d9054b1d829a Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Tue, 28 Apr 2026 16:45:14 +0100
|
||||
Subject: [PATCH 1/2] giochannel: Fix memcmp() off the end of the buffer with
|
||||
long terminators
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
If the line terminator is longer than a single byte, and the current
|
||||
line extends to the end of the buffer, and the buffer (which is a
|
||||
`GString`) is near a power of two in length (as that’s how `GString`s
|
||||
are allocated) it’s possible for the `memcmp()` which checks the
|
||||
terminator to read off the end of the string buffer.
|
||||
|
||||
Fix that by checking the terminator length against the last character
|
||||
before calling `memcmp()`. Add a unit test.
|
||||
|
||||
Spotted by linhlhq as #YWH-PGM9867-199. The fix is theirs (validated by
|
||||
me), and the unit test is adapted from their proof of concept.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
Fixes: #3925
|
||||
---
|
||||
glib/giochannel.c | 3 ++-
|
||||
glib/tests/io-channel.c | 60 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 62 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/glib/giochannel.c b/glib/giochannel.c
|
||||
index b44fff35b..4e682e2a9 100644
|
||||
--- a/glib/giochannel.c
|
||||
+++ b/glib/giochannel.c
|
||||
@@ -1822,7 +1822,8 @@ read_again:
|
||||
{
|
||||
if (channel->line_term)
|
||||
{
|
||||
- if (memcmp (channel->line_term, nextchar, line_term_len) == 0)
|
||||
+ if ((size_t) (lastchar - nextchar) >= line_term_len &&
|
||||
+ memcmp (channel->line_term, nextchar, line_term_len) == 0)
|
||||
{
|
||||
line_length = nextchar - use_buf->str;
|
||||
got_term_len = line_term_len;
|
||||
diff --git a/glib/tests/io-channel.c b/glib/tests/io-channel.c
|
||||
index c5dd01d04..cf81a9f6b 100644
|
||||
--- a/glib/tests/io-channel.c
|
||||
+++ b/glib/tests/io-channel.c
|
||||
@@ -216,6 +216,65 @@ test_read_line_embedded_nuls (void)
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_read_line_long_terminator (void)
|
||||
+{
|
||||
+ uint8_t *test_data = NULL;
|
||||
+ size_t test_data_len = 0;
|
||||
+ int fd;
|
||||
+ char *filename = NULL;
|
||||
+ GIOChannel *channel = NULL;
|
||||
+ GError *local_error = NULL;
|
||||
+ char *line = NULL;
|
||||
+ size_t line_length, terminator_pos;
|
||||
+ const char *line_term;
|
||||
+ int line_term_length;
|
||||
+ GIOStatus status;
|
||||
+
|
||||
+ g_test_summary ("Test that reading a line when using a long terminator doesn’t over-read the buffer.");
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/work_items/3925");
|
||||
+
|
||||
+ /* Write out a temporary file containing 2047 bytes. This is enough to make it
|
||||
+ * near the length of the GString buffer when read back in. */
|
||||
+ fd = g_file_open_tmp ("glib-test-io-channel-XXXXXX", &filename, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+ g_close (g_steal_fd (&fd), NULL);
|
||||
+
|
||||
+ test_data_len = 2047;
|
||||
+ test_data = g_malloc (test_data_len);
|
||||
+ memset (test_data, 'M', test_data_len);
|
||||
+ g_file_set_contents (filename, (const gchar *) test_data, test_data_len, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ /* Create the channel. */
|
||||
+ channel = g_io_channel_new_file (filename, "r", &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ /* Use a long line terminator so it could potentially over-read the end of the buffer. */
|
||||
+ g_io_channel_set_line_term (channel, "DEADBEEF", 8);
|
||||
+
|
||||
+ line_term = g_io_channel_get_line_term (channel, &line_term_length);
|
||||
+ g_assert_cmpstr (line_term, ==, "DEADBEEF");
|
||||
+ g_assert_cmpint (line_term_length, ==, 8);
|
||||
+
|
||||
+ g_io_channel_set_encoding (channel, "UTF-8", &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ status = g_io_channel_read_line (channel, &line, &line_length,
|
||||
+ &terminator_pos, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+ g_assert_cmpint (status, ==, G_IO_STATUS_NORMAL);
|
||||
+ g_assert_cmpuint (line_length, ==, 2047);
|
||||
+ g_assert_cmpuint (terminator_pos, ==, 2047);
|
||||
+ g_assert_cmpmem (line, line_length, test_data, test_data_len);
|
||||
+
|
||||
+ g_free (line);
|
||||
+ g_io_channel_unref (channel);
|
||||
+ g_free (test_data);
|
||||
+ g_unlink (filename);
|
||||
+ g_free (filename);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@@ -224,6 +283,7 @@ main (int argc,
|
||||
|
||||
g_test_add_func ("/io-channel/read-write", test_read_write);
|
||||
g_test_add_func ("/io-channel/read-line/embedded-nuls", test_read_line_embedded_nuls);
|
||||
+ g_test_add_func ("/io-channel/read-line/long-terminator", test_read_line_long_terminator);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
From 71eb9479c3521ce6b0bf007f51271aeb9354f797 Mon Sep 17 00:00:00 2001
|
||||
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
|
||||
Date: Mon, 20 Jul 2026 06:25:23 +0000
|
||||
Subject: [PATCH 2/2] tests: Include stdint.h for uint8_t in io-channel test
|
||||
|
||||
---
|
||||
glib/tests/io-channel.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/glib/tests/io-channel.c b/glib/tests/io-channel.c
|
||||
index cf81a9f6b..4b4189b68 100644
|
||||
--- a/glib/tests/io-channel.c
|
||||
+++ b/glib/tests/io-channel.c
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
+#include <stdint.h>
|
||||
|
||||
static void
|
||||
test_small_writes (void)
|
||||
101
CVE-2026-58014.patch
Normal file
101
CVE-2026-58014.patch
Normal file
@ -0,0 +1,101 @@
|
||||
From 8eede181b24ffd492c3e8892880b5d8172984c4c Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sat, 11 Apr 2026 14:42:57 +0100
|
||||
Subject: [PATCH] gkeyfile: Fix a one-byte heap under-read with
|
||||
g_key_file_get_locale_string_list()
|
||||
|
||||
If this method was called on a key file key which has an empty value,
|
||||
`len == 0` and this leads to a one-byte under-read off the start of the
|
||||
key file buffer.
|
||||
|
||||
Spotted by linhlhq as #YWH-PGM9867-200. The suggested fix is theirs, and
|
||||
the unit test is adapted from their report. I added the fuzzing test.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
|
||||
Fixes: #3930
|
||||
---
|
||||
fuzzing/fuzz_key.c | 9 +++++++++
|
||||
glib/gkeyfile.c | 2 +-
|
||||
glib/tests/keyfile.c | 23 +++++++++++++++++++++++
|
||||
3 files changed, 33 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/fuzzing/fuzz_key.c b/fuzzing/fuzz_key.c
|
||||
index 77cb684ae..7d0044331 100644
|
||||
--- a/fuzzing/fuzz_key.c
|
||||
+++ b/fuzzing/fuzz_key.c
|
||||
@@ -26,11 +26,20 @@ test_parse (const gchar *data,
|
||||
GKeyFileFlags flags)
|
||||
{
|
||||
GKeyFile *key = NULL;
|
||||
+ char *comment = NULL;
|
||||
+ char **list = NULL;
|
||||
|
||||
key = g_key_file_new ();
|
||||
g_key_file_load_from_data (key, (const gchar*) data, size, G_KEY_FILE_NONE,
|
||||
NULL);
|
||||
|
||||
+ /* Also try some additional parsing and see if it crashes */
|
||||
+ comment = g_key_file_get_comment (key, "group", "key", NULL);
|
||||
+ g_free (comment);
|
||||
+
|
||||
+ list = g_key_file_get_locale_string_list (key, "group", "key", "de", NULL, NULL);
|
||||
+ g_strfreev (list);
|
||||
+
|
||||
g_key_file_free (key);
|
||||
}
|
||||
|
||||
diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c
|
||||
index 637ac9c15..bae4053c7 100644
|
||||
--- a/glib/gkeyfile.c
|
||||
+++ b/glib/gkeyfile.c
|
||||
@@ -2410,7 +2410,7 @@ g_key_file_get_locale_string_list (GKeyFile *key_file,
|
||||
}
|
||||
|
||||
len = strlen (value);
|
||||
- if (value[len - 1] == key_file->list_separator)
|
||||
+ if (len > 0 && value[len - 1] == key_file->list_separator)
|
||||
value[len - 1] = '\0';
|
||||
|
||||
list_separator[0] = key_file->list_separator;
|
||||
diff --git a/glib/tests/keyfile.c b/glib/tests/keyfile.c
|
||||
index 92f80100b..1ac88a152 100644
|
||||
--- a/glib/tests/keyfile.c
|
||||
+++ b/glib/tests/keyfile.c
|
||||
@@ -855,6 +855,28 @@ test_locale_string_multiple_loads (void)
|
||||
g_free (old_locale);
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_locale_string_empty (void)
|
||||
+{
|
||||
+ GKeyFile *keyfile = NULL;
|
||||
+ GError *local_error = NULL;
|
||||
+ const char *data =
|
||||
+ "[valid]\n"
|
||||
+ "key1=\n";
|
||||
+
|
||||
+ g_test_summary ("Check that loading an empty translatable string works");
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3930");
|
||||
+
|
||||
+ keyfile = g_key_file_new ();
|
||||
+
|
||||
+ g_key_file_load_from_data (keyfile, data, -1, G_KEY_FILE_NONE, &local_error);
|
||||
+ g_assert_no_error (local_error);
|
||||
+
|
||||
+ check_locale_string_list_value (keyfile, "valid", "key1", NULL, NULL);
|
||||
+
|
||||
+ g_key_file_free (keyfile);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
test_lists (void)
|
||||
{
|
||||
@@ -1944,6 +1966,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/keyfile/number", test_number);
|
||||
g_test_add_func ("/keyfile/locale-string", test_locale_string);
|
||||
g_test_add_func ("/keyfile/locale-string/multiple-loads", test_locale_string_multiple_loads);
|
||||
+ g_test_add_func ("/keyfile/locale-string/empty", test_locale_string_empty);
|
||||
g_test_add_func ("/keyfile/lists", test_lists);
|
||||
g_test_add_func ("/keyfile/lists-set-get", test_lists_set_get);
|
||||
g_test_add_func ("/keyfile/group-remove", test_group_remove);
|
||||
104
CVE-2026-58015.patch
Normal file
104
CVE-2026-58015.patch
Normal file
@ -0,0 +1,104 @@
|
||||
From 88277f4e2054966f093c29a167cc9d2ad767dd37 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Tue, 28 Apr 2026 15:47:30 +0100
|
||||
Subject: [PATCH 1/2] gdbusauthmechanismsha1: Validate cookie context
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Without validation, the server could send a malicious context which
|
||||
contains path traversal characters, allowing it to exfiltrate a SHA-1
|
||||
hashed copy of arbitrary data from the client’s file system.
|
||||
|
||||
To exploit this successfully would require the client to choose to
|
||||
connect peer-to-peer to a malicious D-Bus server and to choose the SHA-1
|
||||
authentication mechanism in preference to all the other mechanisms. This
|
||||
is vanishingly unlikely.
|
||||
|
||||
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
|
||||
|
||||
Fixes: #3931
|
||||
---
|
||||
gio/gdbusauthmechanismsha1.c | 36 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
|
||||
diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c
|
||||
index c8aa08977..7f348d862 100644
|
||||
--- a/gio/gdbusauthmechanismsha1.c
|
||||
+++ b/gio/gdbusauthmechanismsha1.c
|
||||
@@ -1198,6 +1198,34 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism,
|
||||
return initial_response;
|
||||
}
|
||||
|
||||
+/* Context names must be valid ASCII, nonzero length, and may not contain the
|
||||
+ * characters slash ("/"), backslash ("\"), space (" "), newline ("\n"),
|
||||
+ * carriage return ("\r"), tab ("\t"), or period (".").
|
||||
+ *
|
||||
+ * See https://dbus.freedesktop.org/doc/dbus-specification.html#auth-mechanisms-sha */
|
||||
+static gboolean
|
||||
+validate_cookie_context (const char *cookie_context)
|
||||
+{
|
||||
+ size_t i = 0;
|
||||
+
|
||||
+ g_return_val_if_fail (cookie_context != NULL, FALSE);
|
||||
+
|
||||
+ for (i = 0; cookie_context[i] != '\0'; i++)
|
||||
+ {
|
||||
+ if ((uint8_t) cookie_context[i] >= 128 ||
|
||||
+ cookie_context[i] == '/' ||
|
||||
+ cookie_context[i] == '\\' ||
|
||||
+ cookie_context[i] == ' ' ||
|
||||
+ cookie_context[i] == '\n' ||
|
||||
+ cookie_context[i] == '\r' ||
|
||||
+ cookie_context[i] == '\t' ||
|
||||
+ cookie_context[i] == '.')
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ return (i > 0);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
const gchar *data,
|
||||
@@ -1232,6 +1260,14 @@ mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
}
|
||||
|
||||
cookie_context = tokens[0];
|
||||
+ if (!validate_cookie_context (tokens[0]))
|
||||
+ {
|
||||
+ g_free (m->priv->reject_reason);
|
||||
+ m->priv->reject_reason = g_strdup_printf ("Malformed cookie_context '%s'", tokens[0]);
|
||||
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
cookie_id = g_ascii_strtoll (tokens[1], &endp, 10);
|
||||
if (*endp != '\0')
|
||||
{
|
||||
|
||||
From dd797f572cda38571aeda60334b365178f81b157 Mon Sep 17 00:00:00 2001
|
||||
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
|
||||
Date: Mon, 20 Jul 2026 06:43:46 +0000
|
||||
Subject: [PATCH 2/2] Fix: use guint8 instead of uint8_t for portability
|
||||
|
||||
The upstream commit used uint8_t which requires <stdint.h>, but the
|
||||
older GLib 2.80 codebase does not include that header in this file.
|
||||
Use GLib's own guint8 type instead, which is always available.
|
||||
---
|
||||
gio/gdbusauthmechanismsha1.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c
|
||||
index 7f348d862..6e6b2b876 100644
|
||||
--- a/gio/gdbusauthmechanismsha1.c
|
||||
+++ b/gio/gdbusauthmechanismsha1.c
|
||||
@@ -1212,7 +1212,7 @@ validate_cookie_context (const char *cookie_context)
|
||||
|
||||
for (i = 0; cookie_context[i] != '\0'; i++)
|
||||
{
|
||||
- if ((uint8_t) cookie_context[i] >= 128 ||
|
||||
+ if ((guint8) cookie_context[i] >= 128 ||
|
||||
cookie_context[i] == '/' ||
|
||||
cookie_context[i] == '\\' ||
|
||||
cookie_context[i] == ' ' ||
|
||||
44
glib2.spec
44
glib2.spec
@ -2,7 +2,7 @@
|
||||
## (rpmautospec version 0.8.4)
|
||||
## RPMAUTOSPEC: autorelease, autochangelog
|
||||
%define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
|
||||
release_number = 14;
|
||||
release_number = 21;
|
||||
base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
|
||||
print(release_number + base_release_number - 1);
|
||||
}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
|
||||
@ -63,6 +63,27 @@ Patch: CVE-2025-14512.patch
|
||||
# https://github.com/GNOME/glib/commit/c9da977c178fbfc0e4caf99f9fdf5dc433d6fcc2
|
||||
Patch: CVE-2026-58016.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5170
|
||||
Patch: CVE-2026-58013.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/5f6d86b50bebf5458ab1becf4de2c5e5f066122b
|
||||
Patch: CVE-2026-58014.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/8b72ad09c874ddff122b3e67b3470c5e2eab7690
|
||||
Patch: CVE-2026-58015.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/8338414f6560216efe67d3cbf549e32f8630252a
|
||||
Patch: CVE-2026-58010.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5132
|
||||
Patch: CVE-2026-58012.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5131
|
||||
Patch: CVE-2026-58011.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5240
|
||||
Patch: CVE-2026-15588.patch
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: gettext
|
||||
@ -326,6 +347,27 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
|
||||
|
||||
%changelog
|
||||
## START: Generated by rpmautospec
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-21
|
||||
- Fix CVE-2026-15588: limit D-Bus auth line read length
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-20
|
||||
- Fix CVE-2026-58011: range validation in g_date_time_add_full()
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-19
|
||||
- Fix CVE-2026-58012: buffer overflow in gregex.c with G_REGEX_RAW
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-18
|
||||
- Fix CVE-2026-58010: off-by-one in GVariant tuple offset checking
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-17
|
||||
- Fix CVE-2026-58015: validate D-Bus DBUS_COOKIE_SHA1 cookie context
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-16
|
||||
- Fix CVE-2026-58014: heap under-read in g_key_file_get_locale_string_list
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-15
|
||||
- Fix CVE-2026-58013: GIOChannel memcmp buffer over-read
|
||||
|
||||
* Thu Jul 09 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.80.4-14
|
||||
- Fix CVE-2026-58016: D-Bus introspection XML node nesting validation
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user