import CS git glib2-2.56.4-177.el8_10
This commit is contained in:
parent
5331870f3f
commit
654de02701
312
SOURCES/CVE-2026-15588.patch
Normal file
312
SOURCES/CVE-2026-15588.patch
Normal file
@ -0,0 +1,312 @@
|
||||
From fd2ce100affce9e822c81f51d66b2b4b93a76889 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sat, 4 Jul 2026 18:13:08 +0100
|
||||
Subject: [PATCH 1/2] 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 | 55 ++++++++++++++++++-
|
||||
gio/tests/gdbus-auth.c | 122 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 175 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
|
||||
index e9a953a2c..a94a3e359 100644
|
||||
--- a/gio/gdbusauth.c
|
||||
+++ b/gio/gdbusauth.c
|
||||
@@ -262,6 +262,22 @@ find_mech_by_name (GDBusAuth *auth,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static size_t
|
||||
+get_longest_mechanism_name_length (GDBusAuth *auth)
|
||||
+{
|
||||
+ size_t len = 0;
|
||||
+ GList *l;
|
||||
+
|
||||
+ for (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)
|
||||
{
|
||||
@@ -270,6 +286,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 *
|
||||
@@ -307,6 +337,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)
|
||||
@@ -316,11 +347,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,
|
||||
@@ -1073,7 +1115,11 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
{
|
||||
case SERVER_STATE_WAITING_FOR_AUTH:
|
||||
debug_print ("SERVER: WaitingForAuth");
|
||||
- line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
|
||||
+ 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);
|
||||
debug_print ("SERVER: WaitingForAuth, read '%s'", line);
|
||||
if (line == NULL)
|
||||
goto out;
|
||||
@@ -1272,7 +1318,11 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
|
||||
case SERVER_STATE_WAITING_FOR_DATA:
|
||||
debug_print ("SERVER: WaitingForData");
|
||||
- line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
|
||||
+ 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);
|
||||
debug_print ("SERVER: WaitingForData, read '%s'", line);
|
||||
if (line == NULL)
|
||||
goto out;
|
||||
@@ -1319,6 +1369,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
|
||||
* appears after "BEGIN\r\n"....)
|
||||
*/
|
||||
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 f44e932e2..0fb780c1e 100644
|
||||
--- a/gio/tests/gdbus-auth.c
|
||||
+++ b/gio/tests/gdbus-auth.c
|
||||
@@ -278,6 +278,127 @@ 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_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);
|
||||
+
|
||||
+ if (new_connection_id != 0)
|
||||
+ {
|
||||
+ g_signal_handler_disconnect (server, new_connection_id);
|
||||
+ new_connection_id = 0;
|
||||
+ }
|
||||
+ g_clear_object (&server);
|
||||
+}
|
||||
+
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
int
|
||||
@@ -297,6 +418,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
|
||||
*
|
||||
|
||||
From c50053362f01e6927f9347532a93e32074495bde Mon Sep 17 00:00:00 2001
|
||||
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
|
||||
Date: Thu, 30 Jul 2026 12:09:40 +0000
|
||||
Subject: [PATCH 2/2] Fix g_test_bug usage for GLib 2.56.x compatibility
|
||||
|
||||
In GLib 2.56.x, g_test_bug() requires g_test_bug_base() to be called first
|
||||
to set the base URI. The upstream test used a full URL in g_test_bug() which
|
||||
is only supported in newer GLib versions. Fix by adding g_test_bug_base()
|
||||
in main() and using just the issue number in g_test_bug().
|
||||
---
|
||||
gio/tests/gdbus-auth.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/gio/tests/gdbus-auth.c b/gio/tests/gdbus-auth.c
|
||||
index 0fb780c1e..53898dbeb 100644
|
||||
--- a/gio/tests/gdbus-auth.c
|
||||
+++ b/gio/tests/gdbus-auth.c
|
||||
@@ -317,7 +317,7 @@ test_auth_server_read_limit (void)
|
||||
size_t bytes_written;
|
||||
GError *local_error = NULL;
|
||||
|
||||
- g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3985");
|
||||
+ g_test_bug ("3985");
|
||||
|
||||
server = server_new_for_mechanism (NULL);
|
||||
|
||||
@@ -412,6 +412,7 @@ main (int argc,
|
||||
temp_dbus_keyrings_setup ();
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
+ g_test_bug_base ("https://gitlab.gnome.org/GNOME/glib/-/issues/");
|
||||
|
||||
g_test_add_func ("/gdbus/auth/client/EXTERNAL", auth_client_external);
|
||||
g_test_add_func ("/gdbus/auth/client/DBUS_COOKIE_SHA1", auth_client_dbus_cookie_sha1);
|
||||
99
SOURCES/CVE-2026-58010.patch
Normal file
99
SOURCES/CVE-2026-58010.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From 1e659071a5138209dfefc647eebccbca43250434 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Sun, 29 Mar 2026 19:10:41 +0100
|
||||
Subject: [PATCH] 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 | 41 ++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
|
||||
index c6e400b53..9e862e50b 100644
|
||||
--- a/glib/gvariant-serialiser.c
|
||||
+++ b/glib/gvariant-serialiser.c
|
||||
@@ -1078,7 +1078,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 c4a996c1f..4d3186e46 100644
|
||||
--- a/glib/tests/gvariant.c
|
||||
+++ b/glib/tests/gvariant.c
|
||||
@@ -4842,6 +4842,45 @@ test_normal_checking_tuple_offsets (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.
|
||||
+ */
|
||||
+ guint8 *heap_data = NULL;
|
||||
+ GBytes *bytes = NULL;
|
||||
+ const GVariantType *data_type = G_VARIANT_TYPE ("(ynqiuxthdsog)");
|
||||
+ GVariant *variant = NULL;
|
||||
+ GVariant *normal_variant = NULL;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ g_bytes_unref (bytes);
|
||||
+ g_variant_unref (normal_variant);
|
||||
+ g_variant_unref (variant);
|
||||
+}
|
||||
+
|
||||
/* Test that an empty object path is normalised successfully to the base object
|
||||
* path, ‘/’. */
|
||||
static void
|
||||
@@ -4941,6 +4980,8 @@ main (int argc, char **argv)
|
||||
test_normal_checking_array_offsets);
|
||||
g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
|
||||
test_normal_checking_tuple_offsets);
|
||||
+ g_test_add_func ("/gvariant/normal-checking/tuple-offsets6",
|
||||
+ test_normal_checking_tuple_offsets6);
|
||||
g_test_add_func ("/gvariant/normal-checking/empty-object-path",
|
||||
test_normal_checking_empty_object_path);
|
||||
|
||||
122
SOURCES/CVE-2026-58011.patch
Normal file
122
SOURCES/CVE-2026-58011.patch
Normal file
@ -0,0 +1,122 @@
|
||||
From 0a26e16a79b589f0fb534612a3febaf089cef981 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 ba8503813..6f9cff5c0 100644
|
||||
--- a/glib/gdatetime.c
|
||||
+++ b/glib/gdatetime.c
|
||||
@@ -123,7 +123,7 @@ struct _GDateTime
|
||||
gint interval;
|
||||
|
||||
/* 1 is 0001-01-01 in Proleptic Gregorian */
|
||||
- gint32 days;
|
||||
+ gint32 days; /* in range [MIN_DAYS, MAX_DAYS] */
|
||||
|
||||
volatile gint ref_count;
|
||||
};
|
||||
@@ -159,6 +159,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 },
|
||||
@@ -768,7 +771,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;
|
||||
@@ -804,7 +807,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 727ab7692db7e15889c4ffd455cfac498c7c3ada 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 6f9cff5c0..057746b17 100644
|
||||
--- a/glib/gdatetime.c
|
||||
+++ b/glib/gdatetime.c
|
||||
@@ -1960,7 +1960,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 d0755e722..b0bda25a3 100644
|
||||
--- a/glib/tests/gdatetime.c
|
||||
+++ b/glib/tests/gdatetime.c
|
||||
@@ -925,6 +925,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
SOURCES/CVE-2026-58012.patch
Normal file
221
SOURCES/CVE-2026-58012.patch
Normal file
@ -0,0 +1,221 @@
|
||||
From 502cc4445106a6adc3bf21d47f5adf4c02165299 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 225b8967c..2597abe96 100644
|
||||
--- a/glib/gregex.c
|
||||
+++ b/glib/gregex.c
|
||||
@@ -2640,19 +2640,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;
|
||||
|
||||
@@ -2662,22 +2668,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,
|
||||
@@ -2687,6 +2715,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->compile_opts & G_REGEX_RAW));
|
||||
|
||||
for (list = data; list; list = list->next)
|
||||
{
|
||||
@@ -2694,10 +2723,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;
|
||||
@@ -2705,7 +2734,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;
|
||||
@@ -2713,7 +2742,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 56bd2d5eb..25c3ff783 100644
|
||||
--- a/glib/tests/regex.c
|
||||
+++ b/glib/tests/regex.c
|
||||
@@ -2183,6 +2183,58 @@ pcre_ge (guint64 major, guint64 minor)
|
||||
return (pcre_major > major) || (pcre_major == major && pcre_minor >= minor);
|
||||
}
|
||||
|
||||
+static void
|
||||
+test_replace_raw_change_case (void)
|
||||
+{
|
||||
+ GError *local_error = NULL;
|
||||
+ GRegex *regex = NULL;
|
||||
+ char *result = NULL;
|
||||
+ char subject[] = "\xf4\x80";
|
||||
+ char subject2[] = "\xe6\xb0"; /* 3-byte UTF-8 lead, only 2 bytes */
|
||||
+
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3918");
|
||||
+
|
||||
+ /*
|
||||
+ * 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.
|
||||
+ */
|
||||
+ 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);
|
||||
+
|
||||
+ 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[])
|
||||
{
|
||||
@@ -2202,6 +2254,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/regex/multiline", test_multiline);
|
||||
g_test_add_func ("/regex/explicit-crlf", test_explicit_crlf);
|
||||
g_test_add_func ("/regex/max-lookbehind", test_max_lookbehind);
|
||||
+ 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);
|
||||
127
SOURCES/CVE-2026-58013.patch
Normal file
127
SOURCES/CVE-2026-58013.patch
Normal file
@ -0,0 +1,127 @@
|
||||
From bb5c37897584ca09c583161f908046edc2ec9d85 Mon Sep 17 00:00:00 2001
|
||||
From: Philip Withnall <pwithnall@gnome.org>
|
||||
Date: Tue, 28 Apr 2026 16:45:14 +0100
|
||||
Subject: [PATCH] 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 | 78 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 80 insertions(+), 1 deletion(-)
|
||||
create mode 100644 glib/tests/io-channel.c
|
||||
|
||||
diff --git a/glib/giochannel.c b/glib/giochannel.c
|
||||
index f01817a83..32a1550b7 100644
|
||||
--- a/glib/giochannel.c
|
||||
+++ b/glib/giochannel.c
|
||||
@@ -1807,7 +1807,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
|
||||
new file mode 100644
|
||||
index 000000000..447675ee8
|
||||
--- /dev/null
|
||||
+++ b/glib/tests/io-channel.c
|
||||
@@ -0,0 +1,78 @@
|
||||
+/* Test for CVE-2026-58013: memcmp() off the end of the buffer with long terminators
|
||||
+ *
|
||||
+ * Copyright © 2026 Philip Withnall
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+ */
|
||||
+
|
||||
+#include <glib.h>
|
||||
+#include <glib/gstdio.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+static void
|
||||
+test_read_line_long_terminator (void)
|
||||
+{
|
||||
+ guint8 *test_data = NULL;
|
||||
+ gsize test_data_len = 0;
|
||||
+ gint fd;
|
||||
+ gchar *filename = NULL;
|
||||
+ GIOChannel *channel = NULL;
|
||||
+ GError *local_error = NULL;
|
||||
+ gchar *line = NULL;
|
||||
+ gsize line_length, terminator_pos;
|
||||
+ const gchar *line_term;
|
||||
+ gint line_term_length;
|
||||
+ GIOStatus status;
|
||||
+
|
||||
+ /* 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 (fd, NULL);
|
||||
+ fd = -1;
|
||||
+
|
||||
+ 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[])
|
||||
+{
|
||||
+ g_test_init (&argc, &argv, NULL);
|
||||
+
|
||||
+ g_test_add_func ("/io-channel/read-line/long-terminator", test_read_line_long_terminator);
|
||||
+
|
||||
+ return g_test_run ();
|
||||
+}
|
||||
74
SOURCES/CVE-2026-58014.patch
Normal file
74
SOURCES/CVE-2026-58014.patch
Normal file
@ -0,0 +1,74 @@
|
||||
From d3e1d6f9ea497bd1b6bb258c6d078f06b8cd4338 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
|
||||
---
|
||||
glib/gkeyfile.c | 2 +-
|
||||
glib/tests/keyfile.c | 22 ++++++++++++++++++++++
|
||||
2 files changed, 23 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c
|
||||
index ae3bbbc1d..0ddde22db 100644
|
||||
--- a/glib/gkeyfile.c
|
||||
+++ b/glib/gkeyfile.c
|
||||
@@ -2391,7 +2391,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 16f3b788b..d7c648260 100644
|
||||
--- a/glib/tests/keyfile.c
|
||||
+++ b/glib/tests/keyfile.c
|
||||
@@ -751,6 +751,27 @@ test_locale_string (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_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)
|
||||
{
|
||||
@@ -1745,6 +1766,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/keyfile/boolean", test_boolean);
|
||||
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/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);
|
||||
74
SOURCES/CVE-2026-58015.patch
Normal file
74
SOURCES/CVE-2026-58015.patch
Normal file
@ -0,0 +1,74 @@
|
||||
From 2f486f021aa46d172c7c7e8eef60dc7e22ad49f2 Mon Sep 17 00:00:00 2001
|
||||
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
|
||||
Date: Mon, 20 Jul 2026 07:02:12 +0000
|
||||
Subject: [PATCH] gdbusauthmechanismsha1: Validate cookie context
|
||||
|
||||
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 | 35 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 35 insertions(+)
|
||||
|
||||
diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c
|
||||
index 0cbaf946d..85fb5edc8 100644
|
||||
--- a/gio/gdbusauthmechanismsha1.c
|
||||
+++ b/gio/gdbusauthmechanismsha1.c
|
||||
@@ -1130,6 +1130,34 @@ initial_response = _g_dbus_win32_get_user_sid ();
|
||||
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 ((guint8) 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,
|
||||
@@ -1163,6 +1191,13 @@ mechanism_client_data_receive (GDBusAuthMechanism *mechanism,
|
||||
}
|
||||
|
||||
cookie_context = tokens[0];
|
||||
+ if (!validate_cookie_context (tokens[0]))
|
||||
+ {
|
||||
+ g_warning ("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')
|
||||
{
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
Name: glib2
|
||||
Version: 2.56.4
|
||||
Release: 170%{?dist}
|
||||
Release: 177%{?dist}
|
||||
Summary: A library of handy utility functions
|
||||
|
||||
License: LGPLv2+
|
||||
@ -172,6 +172,27 @@ Patch35: CVE-2025-14512.patch
|
||||
# https://github.com/GNOME/glib/commit/c9da977c178fbfc0e4caf99f9fdf5dc433d6fcc2
|
||||
Patch36: CVE-2026-58016.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5171
|
||||
Patch37: CVE-2026-58014.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/8b72ad09c874ddff122b3e67b3470c5e2eab7690
|
||||
Patch38: CVE-2026-58015.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/9f557746c52ae2a62fd5929f532b77024a18abe2
|
||||
Patch39: CVE-2026-58013.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/49e067570dfa208c45d76f0b602664fd11a629ef
|
||||
Patch40: CVE-2026-58012.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5131
|
||||
Patch41: CVE-2026-58011.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/commit/8338414f6560216efe67d3cbf549e32f8630252a
|
||||
Patch42: CVE-2026-58010.patch
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5240
|
||||
Patch43: CVE-2026-15588.patch
|
||||
|
||||
%description
|
||||
GLib is the low-level core library that forms the basis for projects
|
||||
such as GTK+ and GNOME. It provides data structure handling for C,
|
||||
@ -287,7 +308,8 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
|
||||
glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
|
||||
|
||||
%check
|
||||
make %{?_smp_mflags} check
|
||||
# One job at a time. The tests are not safe to run in parallel until 2.60. See: glib!505
|
||||
make check
|
||||
|
||||
%files -f glib20.lang
|
||||
%license COPYING
|
||||
@ -372,6 +394,32 @@ make %{?_smp_mflags} check
|
||||
%{_datadir}/installed-tests
|
||||
|
||||
%changelog
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-177
|
||||
- Fix CVE-2026-15588: limit D-Bus auth line read length
|
||||
|
||||
* Thu Jul 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-176
|
||||
- Fix CVE-2026-58010: off-by-one in GVariant tuple offset checking
|
||||
|
||||
* Mon Jul 20 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-175
|
||||
- Fix CVE-2026-58011: range validation in g_date_time_add_full()
|
||||
- Resolves: RHEL-212187
|
||||
|
||||
* Mon Jul 20 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-174
|
||||
- Fix CVE-2026-58012: buffer overflow in gregex case changing substitutions
|
||||
- Resolves: RHEL-212204
|
||||
|
||||
* Mon Jul 20 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-173
|
||||
- Fix CVE-2026-58013: buffer over-read in GIOChannel with long terminators
|
||||
- Resolves: RHEL-212229
|
||||
|
||||
* Mon Jul 20 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-172
|
||||
- Fix CVE-2026-58015: validate D-Bus DBUS_COOKIE_SHA1 cookie context
|
||||
- Resolves: RHEL-212254
|
||||
|
||||
* Sun Jul 12 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-171
|
||||
- Fix one-byte heap under-read in g_key_file_get_locale_string_list()
|
||||
- Resolves: RHEL-190587
|
||||
|
||||
* Thu Jul 09 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.56.4-170
|
||||
- Add patch for CVE-2026-58016
|
||||
- Resolves: RHEL-190622
|
||||
|
||||
Loading…
Reference in New Issue
Block a user