133 lines
5.0 KiB
Diff
133 lines
5.0 KiB
Diff
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;
|