summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch291
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch97
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch282
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb3
4 files changed, 673 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch
new file mode 100644
index 0000000000..65174efa6d
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch
@@ -0,0 +1,291 @@
1From 5f4485c4ff57fdefb1661531788def7ca5a47328 Mon Sep 17 00:00:00 2001
2From: Philip Withnall <pwithnall@endlessos.org>
3Date: Thu, 17 Aug 2023 04:19:44 +0000
4Subject: [PATCH] gvariant-serialiser: Check offset table entry size is minimal
5
6The entries in an offset table (which is used for variable sized arrays
7and tuples containing variable sized members) are sized so that they can
8address every byte in the overall variant.
9
10The specification requires that for a variant to be in normal form, its
11offset table entries must be the minimum width such that they can
12address every byte in the variant.
13
14That minimality requirement was not checked in
15`g_variant_is_normal_form()`, leading to two different byte arrays being
16interpreted as the normal form of a given variant tree. That kind of
17confusion could potentially be exploited, and is certainly a bug.
18
19Fix it by adding the necessary checks on offset table entry width, and
20unit tests.
21
22Spotted by William Manley.
23
24Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
25
26Fixes: #2794
27
28CVE: CVE-2023-29499
29
30Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/5f4485c4ff57fdefb1661531788def7ca5a47328]
31
32Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
33---
34 glib/gvariant-serialiser.c | 19 +++-
35 glib/tests/gvariant.c | 176 +++++++++++++++++++++++++++++++++++++
36 2 files changed, 194 insertions(+), 1 deletion(-)
37
38diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
39index 9c7f12a..3d6e7b8 100644
40--- a/glib/gvariant-serialiser.c
41+++ b/glib/gvariant-serialiser.c
42@@ -694,6 +694,10 @@ gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
43 out.data_size = last_end;
44 out.array = value.data + last_end;
45 out.length = offsets_array_size / out.offset_size;
46+
47+ if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
48+ return out; /* offset size not minimal */
49+
50 out.is_normal = TRUE;
51
52 return out;
53@@ -1201,6 +1205,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
54 gsize length;
55 gsize offset;
56 gsize i;
57+ gsize offset_table_size;
58
59 /* as per the comment in gvs_tuple_get_child() */
60 if G_UNLIKELY (value.data == NULL && value.size != 0)
61@@ -1305,7 +1310,19 @@ gvs_tuple_is_normal (GVariantSerialised value)
62 }
63 }
64
65- return offset_ptr == offset;
66+ /* @offset_ptr has been counting backwards from the end of the variant, to
67+ * find the beginning of the offset table. @offset has been counting forwards
68+ * from the beginning of the variant to find the end of the data. They should
69+ * have met in the middle. */
70+ if (offset_ptr != offset)
71+ return FALSE;
72+
73+ offset_table_size = value.size - offset_ptr;
74+ if (value.size > 0 &&
75+ gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
76+ return FALSE; /* offset size not minimal */
77+
78+ return TRUE;
79 }
80
81 /* Variants {{{2
82diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
83index 44e4451..ad45043 100644
84--- a/glib/tests/gvariant.c
85+++ b/glib/tests/gvariant.c
86@@ -5076,6 +5076,86 @@ test_normal_checking_array_offsets2 (void)
87 g_variant_unref (variant);
88 }
89
90+/* Test that an otherwise-valid serialised GVariant is considered non-normal if
91+ * its offset table entries are too wide.
92+ *
93+ * See §2.3.6 (Framing Offsets) of the GVariant specification. */
94+static void
95+test_normal_checking_array_offsets_minimal_sized (void)
96+{
97+ GVariantBuilder builder;
98+ gsize i;
99+ GVariant *aay_constructed = NULL;
100+ const guint8 *data = NULL;
101+ guint8 *data_owned = NULL;
102+ GVariant *aay_deserialised = NULL;
103+ GVariant *aay_normalised = NULL;
104+
105+ /* Construct an array of type aay, consisting of 128 elements which are each
106+ * an empty array, i.e. `[[] * 128]`. This is chosen because the inner
107+ * elements are variable sized (making the outer array variable sized, so it
108+ * must have an offset table), but they are also zero-sized when serialised.
109+ * So the serialised representation of @aay_constructed consists entirely of
110+ * its offset table, which is entirely zeroes.
111+ *
112+ * The array is chosen to be 128 elements long because that means offset
113+ * table entries which are 1 byte long. If the elements in the array were
114+ * non-zero-sized (to the extent that the overall array is ≥256 bytes long),
115+ * the offset table entries would end up being 2 bytes long. */
116+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
117+
118+ for (i = 0; i < 128; i++)
119+ g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
120+
121+ aay_constructed = g_variant_builder_end (&builder);
122+
123+ /* Verify that the constructed array is in normal form, and its serialised
124+ * form is `b'\0' * 128`. */
125+ g_assert_true (g_variant_is_normal_form (aay_constructed));
126+ g_assert_cmpuint (g_variant_n_children (aay_constructed), ==, 128);
127+ g_assert_cmpuint (g_variant_get_size (aay_constructed), ==, 128);
128+
129+ data = g_variant_get_data (aay_constructed);
130+ for (i = 0; i < g_variant_get_size (aay_constructed); i++)
131+ g_assert_cmpuint (data[i], ==, 0);
132+
133+ /* Construct a serialised `aay` GVariant which is `b'\0' * 256`. This has to
134+ * be a non-normal form of `[[] * 128]`, with 2-byte-long offset table
135+ * entries, because each offset table entry has to be able to reference all of
136+ * the byte boundaries in the container. All the entries in the offset table
137+ * are zero, so all the elements of the array are zero-sized. */
138+ data = data_owned = g_malloc0 (256);
139+ aay_deserialised = g_variant_new_from_data (G_VARIANT_TYPE ("aay"),
140+ data,
141+ 256,
142+ FALSE,
143+ g_free,
144+ g_steal_pointer (&data_owned));
145+
146+ g_assert_false (g_variant_is_normal_form (aay_deserialised));
147+ g_assert_cmpuint (g_variant_n_children (aay_deserialised), ==, 128);
148+ g_assert_cmpuint (g_variant_get_size (aay_deserialised), ==, 256);
149+
150+ data = g_variant_get_data (aay_deserialised);
151+ for (i = 0; i < g_variant_get_size (aay_deserialised); i++)
152+ g_assert_cmpuint (data[i], ==, 0);
153+
154+ /* Get its normal form. That should change the serialised size. */
155+ aay_normalised = g_variant_get_normal_form (aay_deserialised);
156+
157+ g_assert_true (g_variant_is_normal_form (aay_normalised));
158+ g_assert_cmpuint (g_variant_n_children (aay_normalised), ==, 128);
159+ g_assert_cmpuint (g_variant_get_size (aay_normalised), ==, 128);
160+
161+ data = g_variant_get_data (aay_normalised);
162+ for (i = 0; i < g_variant_get_size (aay_normalised); i++)
163+ g_assert_cmpuint (data[i], ==, 0);
164+
165+ g_variant_unref (aay_normalised);
166+ g_variant_unref (aay_deserialised);
167+ g_variant_unref (aay_constructed);
168+}
169+
170 /* Test that a tuple with invalidly large values in its offset table is
171 * normalised successfully without looping infinitely. */
172 static void
173@@ -5270,6 +5350,98 @@ test_normal_checking_tuple_offsets4 (void)
174 g_variant_unref (variant);
175 }
176
177+/* Test that an otherwise-valid serialised GVariant is considered non-normal if
178+ * its offset table entries are too wide.
179+ *
180+ * See §2.3.6 (Framing Offsets) of the GVariant specification. */
181+static void
182+test_normal_checking_tuple_offsets_minimal_sized (void)
183+{
184+ GString *type_string = NULL;
185+ GVariantBuilder builder;
186+ gsize i;
187+ GVariant *ray_constructed = NULL;
188+ const guint8 *data = NULL;
189+ guint8 *data_owned = NULL;
190+ GVariant *ray_deserialised = NULL;
191+ GVariant *ray_normalised = NULL;
192+
193+ /* Construct a tuple of type (ay…ay), consisting of 129 members which are each
194+ * an empty array, i.e. `([] * 129)`. This is chosen because the inner
195+ * members are variable sized, so the outer tuple must have an offset table,
196+ * but they are also zero-sized when serialised. So the serialised
197+ * representation of @ray_constructed consists entirely of its offset table,
198+ * which is entirely zeroes.
199+ *
200+ * The tuple is chosen to be 129 members long because that means it has 128
201+ * offset table entries which are 1 byte long each. If the members in the
202+ * tuple were non-zero-sized (to the extent that the overall tuple is ≥256
203+ * bytes long), the offset table entries would end up being 2 bytes long.
204+ *
205+ * 129 members are used unlike 128 array elements in
206+ * test_normal_checking_array_offsets_minimal_sized(), because the last member
207+ * in a tuple never needs an offset table entry. */
208+ type_string = g_string_new ("");
209+ g_string_append_c (type_string, '(');
210+ for (i = 0; i < 129; i++)
211+ g_string_append (type_string, "ay");
212+ g_string_append_c (type_string, ')');
213+
214+ g_variant_builder_init (&builder, G_VARIANT_TYPE (type_string->str));
215+
216+ for (i = 0; i < 129; i++)
217+ g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
218+
219+ ray_constructed = g_variant_builder_end (&builder);
220+
221+ /* Verify that the constructed tuple is in normal form, and its serialised
222+ * form is `b'\0' * 128`. */
223+ g_assert_true (g_variant_is_normal_form (ray_constructed));
224+ g_assert_cmpuint (g_variant_n_children (ray_constructed), ==, 129);
225+ g_assert_cmpuint (g_variant_get_size (ray_constructed), ==, 128);
226+
227+ data = g_variant_get_data (ray_constructed);
228+ for (i = 0; i < g_variant_get_size (ray_constructed); i++)
229+ g_assert_cmpuint (data[i], ==, 0);
230+
231+ /* Construct a serialised `(ay…ay)` GVariant which is `b'\0' * 256`. This has
232+ * to be a non-normal form of `([] * 129)`, with 2-byte-long offset table
233+ * entries, because each offset table entry has to be able to reference all of
234+ * the byte boundaries in the container. All the entries in the offset table
235+ * are zero, so all the members of the tuple are zero-sized. */
236+ data = data_owned = g_malloc0 (256);
237+ ray_deserialised = g_variant_new_from_data (G_VARIANT_TYPE (type_string->str),
238+ data,
239+ 256,
240+ FALSE,
241+ g_free,
242+ g_steal_pointer (&data_owned));
243+
244+ g_assert_false (g_variant_is_normal_form (ray_deserialised));
245+ g_assert_cmpuint (g_variant_n_children (ray_deserialised), ==, 129);
246+ g_assert_cmpuint (g_variant_get_size (ray_deserialised), ==, 256);
247+
248+ data = g_variant_get_data (ray_deserialised);
249+ for (i = 0; i < g_variant_get_size (ray_deserialised); i++)
250+ g_assert_cmpuint (data[i], ==, 0);
251+
252+ /* Get its normal form. That should change the serialised size. */
253+ ray_normalised = g_variant_get_normal_form (ray_deserialised);
254+
255+ g_assert_true (g_variant_is_normal_form (ray_normalised));
256+ g_assert_cmpuint (g_variant_n_children (ray_normalised), ==, 129);
257+ g_assert_cmpuint (g_variant_get_size (ray_normalised), ==, 128);
258+
259+ data = g_variant_get_data (ray_normalised);
260+ for (i = 0; i < g_variant_get_size (ray_normalised); i++)
261+ g_assert_cmpuint (data[i], ==, 0);
262+
263+ g_variant_unref (ray_normalised);
264+ g_variant_unref (ray_deserialised);
265+ g_variant_unref (ray_constructed);
266+ g_string_free (type_string, TRUE);
267+}
268+
269 /* Test that an empty object path is normalised successfully to the base object
270 * path, ‘/’. */
271 static void
272@@ -5414,6 +5586,8 @@ main (int argc, char **argv)
273 test_normal_checking_array_offsets);
274 g_test_add_func ("/gvariant/normal-checking/array-offsets2",
275 test_normal_checking_array_offsets2);
276+ g_test_add_func ("/gvariant/normal-checking/array-offsets/minimal-sized",
277+ test_normal_checking_array_offsets_minimal_sized);
278 g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
279 test_normal_checking_tuple_offsets);
280 g_test_add_func ("/gvariant/normal-checking/tuple-offsets2",
281@@ -5422,6 +5596,8 @@ main (int argc, char **argv)
282 test_normal_checking_tuple_offsets3);
283 g_test_add_func ("/gvariant/normal-checking/tuple-offsets4",
284 test_normal_checking_tuple_offsets4);
285+ g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized",
286+ test_normal_checking_tuple_offsets_minimal_sized);
287 g_test_add_func ("/gvariant/normal-checking/empty-object-path",
288 test_normal_checking_empty_object_path);
289
290--
2912.40.0
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch
new file mode 100644
index 0000000000..cc4b4055b2
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch
@@ -0,0 +1,97 @@
1From 4c4cf568f0f710baf0bd04d52df715636bc6b971 Mon Sep 17 00:00:00 2001
2From: Philip Withnall <pwithnall@endlessos.org>
3Date: Thu, 17 Aug 2023 04:23:41 +0000
4Subject: [PATCH] gvariant: Fix g_variant_byteswap() returning non-normal data
5
6If `g_variant_byteswap()` was called on a non-normal variant of a type
7which doesn’t need byteswapping, it would return a non-normal output.
8
9That contradicts the documentation, which says that the return value is
10always in normal form.
11
12Fix the code so it matches the documentation.
13
14Includes a unit test.
15
16Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
17
18Helps: #2797
19
20CVE: CVE-2023-32611
21
22Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/4c4cf568f0f710baf0bd04d52df715636bc6b971]
23
24Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
25---
26 glib/gvariant.c | 8 +++++---
27 glib/tests/gvariant.c | 24 ++++++++++++++++++++++++
28 2 files changed, 29 insertions(+), 3 deletions(-)
29
30diff --git a/glib/gvariant.c b/glib/gvariant.c
31index 30a3280..7e568d1 100644
32--- a/glib/gvariant.c
33+++ b/glib/gvariant.c
34@@ -6004,14 +6004,16 @@ g_variant_byteswap (GVariant *value)
35 g_variant_serialised_byteswap (serialised);
36
37 bytes = g_bytes_new_take (serialised.data, serialised.size);
38- new = g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE);
39+ new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE));
40 g_bytes_unref (bytes);
41 }
42 else
43 /* contains no multi-byte data */
44- new = value;
45+ new = g_variant_get_normal_form (value);
46
47- return g_variant_ref_sink (new);
48+ g_assert (g_variant_is_trusted (new));
49+
50+ return g_steal_pointer (&new);
51 }
52
53 /**
54diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
55index ad45043..36c86c2 100644
56--- a/glib/tests/gvariant.c
57+++ b/glib/tests/gvariant.c
58@@ -3818,6 +3818,29 @@ test_gv_byteswap (void)
59 g_free (string);
60 }
61
62+static void
63+test_gv_byteswap_non_normal_non_aligned (void)
64+{
65+ const guint8 data[] = { 0x02 };
66+ GVariant *v = NULL;
67+ GVariant *v_byteswapped = NULL;
68+
69+ g_test_summary ("Test that calling g_variant_byteswap() on a variant which "
70+ "is in non-normal form and doesn’t need byteswapping returns "
71+ "the same variant in normal form.");
72+
73+ v = g_variant_new_from_data (G_VARIANT_TYPE_BOOLEAN, data, sizeof (data), FALSE, NULL, NULL);
74+ g_assert_false (g_variant_is_normal_form (v));
75+
76+ v_byteswapped = g_variant_byteswap (v);
77+ g_assert_true (g_variant_is_normal_form (v_byteswapped));
78+
79+ g_assert_cmpvariant (v, v_byteswapped);
80+
81+ g_variant_unref (v);
82+ g_variant_unref (v_byteswapped);
83+}
84+
85 static void
86 test_parser (void)
87 {
88@@ -5553,6 +5576,7 @@ main (int argc, char **argv)
89 g_test_add_func ("/gvariant/builder-memory", test_builder_memory);
90 g_test_add_func ("/gvariant/hashing", test_hashing);
91 g_test_add_func ("/gvariant/byteswap", test_gv_byteswap);
92+ g_test_add_func ("/gvariant/byteswap/non-normal-non-aligned", test_gv_byteswap_non_normal_non_aligned);
93 g_test_add_func ("/gvariant/parser", test_parses);
94 g_test_add_func ("/gvariant/parser/integer-bounds", test_parser_integer_bounds);
95 g_test_add_func ("/gvariant/parser/recursion", test_parser_recursion);
96--
972.40.0
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch
new file mode 100644
index 0000000000..304c15bceb
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch
@@ -0,0 +1,282 @@
1From 7d7efce1d9c379fdd7d2ff58caea88f8806fdd2e Mon Sep 17 00:00:00 2001
2From: Philip Withnall <pwithnall@endlessos.org>
3Date: Thu, 17 Aug 2023 05:05:39 +0000
4Subject: [PATCH] gvariant: Allow g_variant_byteswap() to operate on tree-form
5 variants
6
7This avoids needing to always serialise a variant before byteswapping it.
8With variants in non-normal forms, serialisation can result in a large
9increase in size of the variant, and a lot of allocations for leaf
10`GVariant`s. This can lead to a denial of service attack.
11
12Avoid that by changing byteswapping so that it happens on the tree form
13of the variant if the input is in non-normal form. If the input is in
14normal form (either serialised or in tree form), continue using the
15existing code as byteswapping an already-serialised normal variant is
16about 3× faster than byteswapping on the equivalent tree form.
17
18The existing unit tests cover byteswapping well, but need some
19adaptation so that they operate on tree form variants too.
20
21I considered dropping the serialised byteswapping code and doing all
22byteswapping on tree-form variants, as that would make maintenance
23simpler (avoiding having two parallel implementations of byteswapping).
24However, most inputs to `g_variant_byteswap()` are likely to be
25serialised variants (coming from a byte array of input from some foreign
26source) and most of them are going to be in normal form (as corruption
27and malicious action are rare). So getting rid of the serialised
28byteswapping code would impose quite a performance penalty on the common
29case.
30
31Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
32
33Fixes: #2797
34
35CVE: CVE-2023-32611
36
37Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/7d7efce1d9c379fdd7d2ff58caea88f8806fdd2e]
38
39Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
40---
41 glib/gvariant.c | 83 ++++++++++++++++++++++++++++++++-----------
42 glib/tests/gvariant.c | 57 +++++++++++++++++++++++++----
43 2 files changed, 113 insertions(+), 27 deletions(-)
44
45diff --git a/glib/gvariant.c b/glib/gvariant.c
46index 7e568d1..65b8443 100644
47--- a/glib/gvariant.c
48+++ b/glib/gvariant.c
49@@ -5839,7 +5839,8 @@ g_variant_iter_loop (GVariantIter *iter,
50
51 /* Serialized data {{{1 */
52 static GVariant *
53-g_variant_deep_copy (GVariant *value)
54+g_variant_deep_copy (GVariant *value,
55+ gboolean byteswap)
56 {
57 switch (g_variant_classify (value))
58 {
59@@ -5857,7 +5858,7 @@ g_variant_deep_copy (GVariant *value)
60 for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++)
61 {
62 GVariant *child = g_variant_get_child_value (value, i);
63- g_variant_builder_add_value (&builder, g_variant_deep_copy (child));
64+ g_variant_builder_add_value (&builder, g_variant_deep_copy (child, byteswap));
65 g_variant_unref (child);
66 }
67
68@@ -5871,28 +5872,63 @@ g_variant_deep_copy (GVariant *value)
69 return g_variant_new_byte (g_variant_get_byte (value));
70
71 case G_VARIANT_CLASS_INT16:
72- return g_variant_new_int16 (g_variant_get_int16 (value));
73+ if (byteswap)
74+ return g_variant_new_int16 (GUINT16_SWAP_LE_BE (g_variant_get_int16 (value)));
75+ else
76+ return g_variant_new_int16 (g_variant_get_int16 (value));
77
78 case G_VARIANT_CLASS_UINT16:
79- return g_variant_new_uint16 (g_variant_get_uint16 (value));
80+ if (byteswap)
81+ return g_variant_new_uint16 (GUINT16_SWAP_LE_BE (g_variant_get_uint16 (value)));
82+ else
83+ return g_variant_new_uint16 (g_variant_get_uint16 (value));
84
85 case G_VARIANT_CLASS_INT32:
86- return g_variant_new_int32 (g_variant_get_int32 (value));
87+ if (byteswap)
88+ return g_variant_new_int32 (GUINT32_SWAP_LE_BE (g_variant_get_int32 (value)));
89+ else
90+ return g_variant_new_int32 (g_variant_get_int32 (value));
91
92 case G_VARIANT_CLASS_UINT32:
93- return g_variant_new_uint32 (g_variant_get_uint32 (value));
94+ if (byteswap)
95+ return g_variant_new_uint32 (GUINT32_SWAP_LE_BE (g_variant_get_uint32 (value)));
96+ else
97+ return g_variant_new_uint32 (g_variant_get_uint32 (value));
98
99 case G_VARIANT_CLASS_INT64:
100- return g_variant_new_int64 (g_variant_get_int64 (value));
101+ if (byteswap)
102+ return g_variant_new_int64 (GUINT64_SWAP_LE_BE (g_variant_get_int64 (value)));
103+ else
104+ return g_variant_new_int64 (g_variant_get_int64 (value));
105
106 case G_VARIANT_CLASS_UINT64:
107- return g_variant_new_uint64 (g_variant_get_uint64 (value));
108+ if (byteswap)
109+ return g_variant_new_uint64 (GUINT64_SWAP_LE_BE (g_variant_get_uint64 (value)));
110+ else
111+ return g_variant_new_uint64 (g_variant_get_uint64 (value));
112
113 case G_VARIANT_CLASS_HANDLE:
114- return g_variant_new_handle (g_variant_get_handle (value));
115+ if (byteswap)
116+ return g_variant_new_handle (GUINT32_SWAP_LE_BE (g_variant_get_handle (value)));
117+ else
118+ return g_variant_new_handle (g_variant_get_handle (value));
119
120 case G_VARIANT_CLASS_DOUBLE:
121- return g_variant_new_double (g_variant_get_double (value));
122+ if (byteswap)
123+ {
124+ /* We have to convert the double to a uint64 here using a union,
125+ * because a cast will round it numerically. */
126+ union
127+ {
128+ guint64 u64;
129+ gdouble dbl;
130+ } u1, u2;
131+ u1.dbl = g_variant_get_double (value);
132+ u2.u64 = GUINT64_SWAP_LE_BE (u1.u64);
133+ return g_variant_new_double (u2.dbl);
134+ }
135+ else
136+ return g_variant_new_double (g_variant_get_double (value));
137
138 case G_VARIANT_CLASS_STRING:
139 return g_variant_new_string (g_variant_get_string (value, NULL));
140@@ -5947,7 +5983,7 @@ g_variant_get_normal_form (GVariant *value)
141 if (g_variant_is_normal_form (value))
142 return g_variant_ref (value);
143
144- trusted = g_variant_deep_copy (value);
145+ trusted = g_variant_deep_copy (value, FALSE);
146 g_assert (g_variant_is_trusted (trusted));
147
148 return g_variant_ref_sink (trusted);
149@@ -5967,6 +6003,11 @@ g_variant_get_normal_form (GVariant *value)
150 * contain multi-byte numeric data. That include strings, booleans,
151 * bytes and containers containing only these things (recursively).
152 *
153+ * While this function can safely handle untrusted, non-normal data, it is
154+ * recommended to check whether the input is in normal form beforehand, using
155+ * g_variant_is_normal_form(), and to reject non-normal inputs if your
156+ * application can be strict about what inputs it rejects.
157+ *
158 * The returned value is always in normal form and is marked as trusted.
159 *
160 * Returns: (transfer full): the byteswapped form of @value
161@@ -5984,22 +6025,21 @@ g_variant_byteswap (GVariant *value)
162
163 g_variant_type_info_query (type_info, &alignment, NULL);
164
165- if (alignment)
166- /* (potentially) contains multi-byte numeric data */
167+ if (alignment && g_variant_is_normal_form (value))
168 {
169+ /* (potentially) contains multi-byte numeric data, but is also already in
170+ * normal form so we can use a faster byteswapping codepath on the
171+ * serialised data */
172 GVariantSerialised serialised = { 0, };
173- GVariant *trusted;
174 GBytes *bytes;
175
176- trusted = g_variant_get_normal_form (value);
177- serialised.type_info = g_variant_get_type_info (trusted);
178- serialised.size = g_variant_get_size (trusted);
179+ serialised.type_info = g_variant_get_type_info (value);
180+ serialised.size = g_variant_get_size (value);
181 serialised.data = g_malloc (serialised.size);
182- serialised.depth = g_variant_get_depth (trusted);
183+ serialised.depth = g_variant_get_depth (value);
184 serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */
185 serialised.checked_offsets_up_to = G_MAXSIZE;
186- g_variant_store (trusted, serialised.data);
187- g_variant_unref (trusted);
188+ g_variant_store (value, serialised.data);
189
190 g_variant_serialised_byteswap (serialised);
191
192@@ -6007,6 +6047,9 @@ g_variant_byteswap (GVariant *value)
193 new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE));
194 g_bytes_unref (bytes);
195 }
196+ else if (alignment)
197+ /* (potentially) contains multi-byte numeric data */
198+ new = g_variant_ref_sink (g_variant_deep_copy (value, TRUE));
199 else
200 /* contains no multi-byte data */
201 new = g_variant_get_normal_form (value);
202diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
203index 36c86c2..43091f2 100644
204--- a/glib/tests/gvariant.c
205+++ b/glib/tests/gvariant.c
206@@ -2280,24 +2280,67 @@ serialise_tree (TreeInstance *tree,
207 static void
208 test_byteswap (void)
209 {
210- GVariantSerialised one = { 0, }, two = { 0, };
211+ GVariantSerialised one = { 0, }, two = { 0, }, three = { 0, };
212 TreeInstance *tree;
213-
214+ GVariant *one_variant = NULL;
215+ GVariant *two_variant = NULL;
216+ GVariant *two_byteswapped = NULL;
217+ GVariant *three_variant = NULL;
218+ GVariant *three_byteswapped = NULL;
219+ guint8 *three_data_copy = NULL;
220+ gsize three_size_copy = 0;
221+
222+ /* Write a tree out twice, once normally and once byteswapped. */
223 tree = tree_instance_new (NULL, 3);
224 serialise_tree (tree, &one);
225
226+ one_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (one.type_info)),
227+ one.data, one.size, FALSE, NULL, NULL);
228+
229 i_am_writing_byteswapped = TRUE;
230 serialise_tree (tree, &two);
231+ serialise_tree (tree, &three);
232 i_am_writing_byteswapped = FALSE;
233
234- g_variant_serialised_byteswap (two);
235-
236- g_assert_cmpmem (one.data, one.size, two.data, two.size);
237- g_assert_cmpuint (one.depth, ==, two.depth);
238-
239+ /* Swap the first byteswapped one back using the function we want to test. */
240+ two_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (two.type_info)),
241+ two.data, two.size, FALSE, NULL, NULL);
242+ two_byteswapped = g_variant_byteswap (two_variant);
243+
244+ /* Make the second byteswapped one non-normal (hopefully), and then byteswap
245+ * it back using the function we want to test in its non-normal mode.
246+ * This might not work because it’s not necessarily possible to make an
247+ * arbitrary random variant non-normal. Adding a single zero byte to the end
248+ * often makes something non-normal but still readable. */
249+ three_size_copy = three.size + 1;
250+ three_data_copy = g_malloc (three_size_copy);
251+ memcpy (three_data_copy, three.data, three.size);
252+ three_data_copy[three.size] = '\0';
253+
254+ three_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (three.type_info)),
255+ three_data_copy, three_size_copy, FALSE, NULL, NULL);
256+ three_byteswapped = g_variant_byteswap (three_variant);
257+
258+ /* Check they’re the same. We can always compare @one_variant and
259+ * @two_byteswapped. We can only compare @two_byteswapped and
260+ * @three_byteswapped if @two_variant and @three_variant are equal: in that
261+ * case, the corruption to @three_variant was enough to make it non-normal but
262+ * not enough to change its value. */
263+ g_assert_cmpvariant (one_variant, two_byteswapped);
264+
265+ if (g_variant_equal (two_variant, three_variant))
266+ g_assert_cmpvariant (two_byteswapped, three_byteswapped);
267+
268+ g_variant_unref (three_byteswapped);
269+ g_variant_unref (three_variant);
270+ g_variant_unref (two_byteswapped);
271+ g_variant_unref (two_variant);
272+ g_variant_unref (one_variant);
273 tree_instance_free (tree);
274 g_free (one.data);
275 g_free (two.data);
276+ g_free (three.data);
277+ g_free (three_data_copy);
278 }
279
280 static void
281--
2822.40.0
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb
index b04b5f0a44..3545e6675a 100644
--- a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb
+++ b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb
@@ -26,6 +26,9 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \
26 file://CVE-2023-32665-0007.patch \ 26 file://CVE-2023-32665-0007.patch \
27 file://CVE-2023-32665-0008.patch \ 27 file://CVE-2023-32665-0008.patch \
28 file://CVE-2023-32665-0009.patch \ 28 file://CVE-2023-32665-0009.patch \
29 file://CVE-2023-29499.patch \
30 file://CVE-2023-32611-0001.patch \
31 file://CVE-2023-32611-0002.patch \
29 " 32 "
30SRC_URI:append:class-native = " file://relocate-modules.patch" 33SRC_URI:append:class-native = " file://relocate-modules.patch"
31 34