summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch')
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch290
1 files changed, 290 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..ce90586290
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch
@@ -0,0 +1,290 @@
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
29Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/5f4485c4ff57fdefb1661531788def7ca5a47328]
30Signed-off-by: Siddharth Doshi <sdoshi@mvista.com>
31---
32 glib/gvariant-serialiser.c | 19 +++-
33 glib/tests/gvariant.c | 176 +++++++++++++++++++++++++++++++++++++
34 2 files changed, 194 insertions(+), 1 deletion(-)
35
36diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
37index 0bf7243..5aa2cbc 100644
38--- a/glib/gvariant-serialiser.c
39+++ b/glib/gvariant-serialiser.c
40@@ -694,6 +694,10 @@ gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
41 out.data_size = last_end;
42 out.array = value.data + last_end;
43 out.length = offsets_array_size / out.offset_size;
44+
45+ if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
46+ return out; /* offset size not minimal */
47+
48 out.is_normal = TRUE;
49
50 return out;
51@@ -1201,6 +1205,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
52 gsize length;
53 gsize offset;
54 gsize i;
55+ gsize offset_table_size;
56
57 /* as per the comment in gvs_tuple_get_child() */
58 if G_UNLIKELY (value.data == NULL && value.size != 0)
59@@ -1305,7 +1310,19 @@ gvs_tuple_is_normal (GVariantSerialised value)
60 }
61 }
62
63- return offset_ptr == offset;
64+ /* @offset_ptr has been counting backwards from the end of the variant, to
65+ * find the beginning of the offset table. @offset has been counting forwards
66+ * from the beginning of the variant to find the end of the data. They should
67+ * have met in the middle. */
68+ if (offset_ptr != offset)
69+ return FALSE;
70+
71+ offset_table_size = value.size - offset_ptr;
72+ if (value.size > 0 &&
73+ gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
74+ return FALSE; /* offset size not minimal */
75+
76+ return TRUE;
77 }
78
79 /* Variants {{{2
80diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
81index d640c81..4ce0e4f 100644
82--- a/glib/tests/gvariant.c
83+++ b/glib/tests/gvariant.c
84@@ -5092,6 +5092,86 @@ test_normal_checking_array_offsets2 (void)
85 g_variant_unref (variant);
86 }
87
88+/* Test that an otherwise-valid serialised GVariant is considered non-normal if
89+ * its offset table entries are too wide.
90+ *
91+ * See §2.3.6 (Framing Offsets) of the GVariant specification. */
92+static void
93+test_normal_checking_array_offsets_minimal_sized (void)
94+{
95+ GVariantBuilder builder;
96+ gsize i;
97+ GVariant *aay_constructed = NULL;
98+ const guint8 *data = NULL;
99+ guint8 *data_owned = NULL;
100+ GVariant *aay_deserialised = NULL;
101+ GVariant *aay_normalised = NULL;
102+
103+ /* Construct an array of type aay, consisting of 128 elements which are each
104+ * an empty array, i.e. `[[] * 128]`. This is chosen because the inner
105+ * elements are variable sized (making the outer array variable sized, so it
106+ * must have an offset table), but they are also zero-sized when serialised.
107+ * So the serialised representation of @aay_constructed consists entirely of
108+ * its offset table, which is entirely zeroes.
109+ *
110+ * The array is chosen to be 128 elements long because that means offset
111+ * table entries which are 1 byte long. If the elements in the array were
112+ * non-zero-sized (to the extent that the overall array is ≥256 bytes long),
113+ * the offset table entries would end up being 2 bytes long. */
114+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
115+
116+ for (i = 0; i < 128; i++)
117+ g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
118+
119+ aay_constructed = g_variant_builder_end (&builder);
120+
121+ /* Verify that the constructed array is in normal form, and its serialised
122+ * form is `b'\0' * 128`. */
123+ g_assert_true (g_variant_is_normal_form (aay_constructed));
124+ g_assert_cmpuint (g_variant_n_children (aay_constructed), ==, 128);
125+ g_assert_cmpuint (g_variant_get_size (aay_constructed), ==, 128);
126+
127+ data = g_variant_get_data (aay_constructed);
128+ for (i = 0; i < g_variant_get_size (aay_constructed); i++)
129+ g_assert_cmpuint (data[i], ==, 0);
130+
131+ /* Construct a serialised `aay` GVariant which is `b'\0' * 256`. This has to
132+ * be a non-normal form of `[[] * 128]`, with 2-byte-long offset table
133+ * entries, because each offset table entry has to be able to reference all of
134+ * the byte boundaries in the container. All the entries in the offset table
135+ * are zero, so all the elements of the array are zero-sized. */
136+ data = data_owned = g_malloc0 (256);
137+ aay_deserialised = g_variant_new_from_data (G_VARIANT_TYPE ("aay"),
138+ data,
139+ 256,
140+ FALSE,
141+ g_free,
142+ g_steal_pointer (&data_owned));
143+
144+ g_assert_false (g_variant_is_normal_form (aay_deserialised));
145+ g_assert_cmpuint (g_variant_n_children (aay_deserialised), ==, 128);
146+ g_assert_cmpuint (g_variant_get_size (aay_deserialised), ==, 256);
147+
148+ data = g_variant_get_data (aay_deserialised);
149+ for (i = 0; i < g_variant_get_size (aay_deserialised); i++)
150+ g_assert_cmpuint (data[i], ==, 0);
151+
152+ /* Get its normal form. That should change the serialised size. */
153+ aay_normalised = g_variant_get_normal_form (aay_deserialised);
154+
155+ g_assert_true (g_variant_is_normal_form (aay_normalised));
156+ g_assert_cmpuint (g_variant_n_children (aay_normalised), ==, 128);
157+ g_assert_cmpuint (g_variant_get_size (aay_normalised), ==, 128);
158+
159+ data = g_variant_get_data (aay_normalised);
160+ for (i = 0; i < g_variant_get_size (aay_normalised); i++)
161+ g_assert_cmpuint (data[i], ==, 0);
162+
163+ g_variant_unref (aay_normalised);
164+ g_variant_unref (aay_deserialised);
165+ g_variant_unref (aay_constructed);
166+}
167+
168 /* Test that a tuple with invalidly large values in its offset table is
169 * normalised successfully without looping infinitely. */
170 static void
171@@ -5286,6 +5366,98 @@ test_normal_checking_tuple_offsets4 (void)
172 g_variant_unref (variant);
173 }
174
175+/* Test that an otherwise-valid serialised GVariant is considered non-normal if
176+ * its offset table entries are too wide.
177+ *
178+ * See §2.3.6 (Framing Offsets) of the GVariant specification. */
179+static void
180+test_normal_checking_tuple_offsets_minimal_sized (void)
181+{
182+ GString *type_string = NULL;
183+ GVariantBuilder builder;
184+ gsize i;
185+ GVariant *ray_constructed = NULL;
186+ const guint8 *data = NULL;
187+ guint8 *data_owned = NULL;
188+ GVariant *ray_deserialised = NULL;
189+ GVariant *ray_normalised = NULL;
190+
191+ /* Construct a tuple of type (ay…ay), consisting of 129 members which are each
192+ * an empty array, i.e. `([] * 129)`. This is chosen because the inner
193+ * members are variable sized, so the outer tuple must have an offset table,
194+ * but they are also zero-sized when serialised. So the serialised
195+ * representation of @ray_constructed consists entirely of its offset table,
196+ * which is entirely zeroes.
197+ *
198+ * The tuple is chosen to be 129 members long because that means it has 128
199+ * offset table entries which are 1 byte long each. If the members in the
200+ * tuple were non-zero-sized (to the extent that the overall tuple is ≥256
201+ * bytes long), the offset table entries would end up being 2 bytes long.
202+ *
203+ * 129 members are used unlike 128 array elements in
204+ * test_normal_checking_array_offsets_minimal_sized(), because the last member
205+ * in a tuple never needs an offset table entry. */
206+ type_string = g_string_new ("");
207+ g_string_append_c (type_string, '(');
208+ for (i = 0; i < 129; i++)
209+ g_string_append (type_string, "ay");
210+ g_string_append_c (type_string, ')');
211+
212+ g_variant_builder_init (&builder, G_VARIANT_TYPE (type_string->str));
213+
214+ for (i = 0; i < 129; i++)
215+ g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
216+
217+ ray_constructed = g_variant_builder_end (&builder);
218+
219+ /* Verify that the constructed tuple is in normal form, and its serialised
220+ * form is `b'\0' * 128`. */
221+ g_assert_true (g_variant_is_normal_form (ray_constructed));
222+ g_assert_cmpuint (g_variant_n_children (ray_constructed), ==, 129);
223+ g_assert_cmpuint (g_variant_get_size (ray_constructed), ==, 128);
224+
225+ data = g_variant_get_data (ray_constructed);
226+ for (i = 0; i < g_variant_get_size (ray_constructed); i++)
227+ g_assert_cmpuint (data[i], ==, 0);
228+
229+ /* Construct a serialised `(ay…ay)` GVariant which is `b'\0' * 256`. This has
230+ * to be a non-normal form of `([] * 129)`, with 2-byte-long offset table
231+ * entries, because each offset table entry has to be able to reference all of
232+ * the byte boundaries in the container. All the entries in the offset table
233+ * are zero, so all the members of the tuple are zero-sized. */
234+ data = data_owned = g_malloc0 (256);
235+ ray_deserialised = g_variant_new_from_data (G_VARIANT_TYPE (type_string->str),
236+ data,
237+ 256,
238+ FALSE,
239+ g_free,
240+ g_steal_pointer (&data_owned));
241+
242+ g_assert_false (g_variant_is_normal_form (ray_deserialised));
243+ g_assert_cmpuint (g_variant_n_children (ray_deserialised), ==, 129);
244+ g_assert_cmpuint (g_variant_get_size (ray_deserialised), ==, 256);
245+
246+ data = g_variant_get_data (ray_deserialised);
247+ for (i = 0; i < g_variant_get_size (ray_deserialised); i++)
248+ g_assert_cmpuint (data[i], ==, 0);
249+
250+ /* Get its normal form. That should change the serialised size. */
251+ ray_normalised = g_variant_get_normal_form (ray_deserialised);
252+
253+ g_assert_true (g_variant_is_normal_form (ray_normalised));
254+ g_assert_cmpuint (g_variant_n_children (ray_normalised), ==, 129);
255+ g_assert_cmpuint (g_variant_get_size (ray_normalised), ==, 128);
256+
257+ data = g_variant_get_data (ray_normalised);
258+ for (i = 0; i < g_variant_get_size (ray_normalised); i++)
259+ g_assert_cmpuint (data[i], ==, 0);
260+
261+ g_variant_unref (ray_normalised);
262+ g_variant_unref (ray_deserialised);
263+ g_variant_unref (ray_constructed);
264+ g_string_free (type_string, TRUE);
265+}
266+
267 /* Test that an empty object path is normalised successfully to the base object
268 * path, ‘/’. */
269 static void
270@@ -5431,6 +5603,8 @@ main (int argc, char **argv)
271 test_normal_checking_array_offsets);
272 g_test_add_func ("/gvariant/normal-checking/array-offsets2",
273 test_normal_checking_array_offsets2);
274+ g_test_add_func ("/gvariant/normal-checking/array-offsets/minimal-sized",
275+ test_normal_checking_array_offsets_minimal_sized);
276 g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
277 test_normal_checking_tuple_offsets);
278 g_test_add_func ("/gvariant/normal-checking/tuple-offsets2",
279@@ -5439,6 +5613,8 @@ main (int argc, char **argv)
280 test_normal_checking_tuple_offsets3);
281 g_test_add_func ("/gvariant/normal-checking/tuple-offsets4",
282 test_normal_checking_tuple_offsets4);
283+ g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized",
284+ test_normal_checking_tuple_offsets_minimal_sized);
285 g_test_add_func ("/gvariant/normal-checking/empty-object-path",
286 test_normal_checking_empty_object_path);
287
288--
2892.24.4
290