summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch')
-rw-r--r--meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch394
1 files changed, 394 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch
new file mode 100644
index 0000000000..f098548618
--- /dev/null
+++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch
@@ -0,0 +1,394 @@
1From d1a293c4e29880b8d17bb826c9a426a440ca4a91 Mon Sep 17 00:00:00 2001
2From: Philip Withnall <pwithnall@endlessos.org>
3Date: Thu, 17 Aug 2023 01:30:38 +0000
4Subject: [PATCH] gvariant: Track checked and ordered offsets independently
5
6The past few commits introduced the concept of known-good offsets in the
7offset table (which is used for variable-width arrays and tuples).
8Good offsets are ones which are non-overlapping with all the previous
9offsets in the table.
10
11If a bad offset is encountered when indexing into the array or tuple,
12the cached known-good offset index will not be increased. In this way,
13all child variants at and beyond the first bad offset can be returned as
14default values rather than dereferencing potentially invalid data.
15
16In this case, there was no information about the fact that the indexes
17between the highest known-good index and the requested one had been
18checked already. That could lead to a pathological case where an offset
19table with an invalid first offset is repeatedly checked in full when
20trying to access higher-indexed children.
21
22Avoid that by storing the index of the highest checked offset in the
23table, as well as the index of the highest good/ordered offset.
24
25Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
26
27Helps: #2121
28
29CVE: CVE-2023-32665
30Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/d1a293c4e29880b8d17bb826c9a426a440ca4a91]
31Signed-off-by: Siddharth Doshi <sdoshi@mvista.com>
32---
33 glib/gvariant-core.c | 28 ++++++++++++++++++++++++
34 glib/gvariant-serialiser.c | 44 +++++++++++++++++++++++++++-----------
35 glib/gvariant-serialiser.h | 9 ++++++++
36 glib/gvariant.c | 1 +
37 glib/tests/gvariant.c | 5 +++++
38 5 files changed, 75 insertions(+), 12 deletions(-)
39
40diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
41index b951cd9..1b9d5cc 100644
42--- a/glib/gvariant-core.c
43+++ b/glib/gvariant-core.c
44@@ -67,6 +67,7 @@ struct _GVariant
45 GBytes *bytes;
46 gconstpointer data;
47 gsize ordered_offsets_up_to;
48+ gsize checked_offsets_up_to;
49 } serialised;
50
51 struct
52@@ -182,6 +183,24 @@ struct _GVariant
53 * This field is only relevant for arrays of non
54 * fixed width types and for tuples.
55 *
56+ * .checked_offsets_up_to: Similarly to .ordered_offsets_up_to, this stores
57+ * the index of the highest element, n, whose frame
58+ * offsets (and all the preceding frame offsets)
59+ * have been checked for validity.
60+ *
61+ * It is always the case that
62+ * .checked_offsets_up_to ≥ .ordered_offsets_up_to.
63+ *
64+ * If .checked_offsets_up_to == .ordered_offsets_up_to,
65+ * then a bad offset has not been found so far.
66+ *
67+ * If .checked_offsets_up_to > .ordered_offsets_up_to,
68+ * then a bad offset has been found at
69+ * (.ordered_offsets_up_to + 1).
70+ *
71+ * This field is only relevant for arrays of non
72+ * fixed width types and for tuples.
73+ *
74 * .tree: Only valid when the instance is in tree form.
75 *
76 * Note that accesses from other threads could result in
77@@ -386,6 +405,7 @@ g_variant_to_serialised (GVariant *value)
78 value->size,
79 value->depth,
80 value->contents.serialised.ordered_offsets_up_to,
81+ value->contents.serialised.checked_offsets_up_to,
82 };
83 return serialised;
84 }
85@@ -418,6 +438,7 @@ g_variant_serialise (GVariant *value,
86 serialised.data = data;
87 serialised.depth = value->depth;
88 serialised.ordered_offsets_up_to = 0;
89+ serialised.checked_offsets_up_to = 0;
90
91 children = (gpointer *) value->contents.tree.children;
92 n_children = value->contents.tree.n_children;
93@@ -464,10 +485,12 @@ g_variant_fill_gvs (GVariantSerialised *serialised,
94 if (value->state & STATE_SERIALISED)
95 {
96 serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to;
97+ serialised->checked_offsets_up_to = value->contents.serialised.checked_offsets_up_to;
98 }
99 else
100 {
101 serialised->ordered_offsets_up_to = 0;
102+ serialised->checked_offsets_up_to = 0;
103 }
104
105 if (serialised->data)
106@@ -513,6 +536,7 @@ g_variant_ensure_serialised (GVariant *value)
107 value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
108 value->contents.serialised.bytes = bytes;
109 value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE;
110+ value->contents.serialised.checked_offsets_up_to = G_MAXSIZE;
111 value->state |= STATE_SERIALISED;
112 }
113 }
114@@ -594,6 +618,7 @@ g_variant_new_from_bytes (const GVariantType *type,
115 serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size);
116 serialised.depth = 0;
117 serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0;
118+ serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0;
119
120 if (!g_variant_serialised_check (serialised))
121 {
122@@ -644,6 +669,7 @@ g_variant_new_from_bytes (const GVariantType *type,
123 }
124
125 value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0;
126+ value->contents.serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0;
127
128 g_clear_pointer (&owned_bytes, g_bytes_unref);
129
130@@ -1120,6 +1146,7 @@ g_variant_get_child_value (GVariant *value,
131
132 /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */
133 value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to);
134+ value->contents.serialised.checked_offsets_up_to = MAX (value->contents.serialised.checked_offsets_up_to, serialised.checked_offsets_up_to);
135
136 /* Check whether this would cause nesting too deep. If so, return a fake
137 * child. The only situation we expect this to happen in is with a variant,
138@@ -1147,6 +1174,7 @@ g_variant_get_child_value (GVariant *value,
139 g_bytes_ref (value->contents.serialised.bytes);
140 child->contents.serialised.data = s_child.data;
141 child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to;
142+ child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to;
143
144 return child;
145 }
146diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
147index cd4a3e6..0bf7243 100644
148--- a/glib/gvariant-serialiser.c
149+++ b/glib/gvariant-serialiser.c
150@@ -120,6 +120,8 @@
151 *
152 * @depth has no restrictions; the depth of a top-level serialised #GVariant is
153 * zero, and it increases for each level of nested child.
154+ *
155+ * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to
156 */
157
158 /* < private >
159@@ -147,6 +149,9 @@ g_variant_serialised_check (GVariantSerialised serialised)
160 !(serialised.size == 0 || serialised.data != NULL))
161 return FALSE;
162
163+ if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to)
164+ return FALSE;
165+
166 /* Depending on the native alignment requirements of the machine, the
167 * compiler will insert either 3 or 7 padding bytes after the char.
168 * This will result in the sizeof() the struct being 12 or 16.
169@@ -266,6 +271,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
170 g_variant_type_info_ref (value.type_info);
171 value.depth++;
172 value.ordered_offsets_up_to = 0;
173+ value.checked_offsets_up_to = 0;
174
175 return value;
176 }
177@@ -297,7 +303,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value,
178 {
179 if (n_children)
180 {
181- GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 };
182+ GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 };
183
184 gvs_filler (&child, children[0]);
185 }
186@@ -320,6 +326,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
187 value.type_info = g_variant_type_info_element (value.type_info);
188 value.depth++;
189 value.ordered_offsets_up_to = 0;
190+ value.checked_offsets_up_to = 0;
191
192 return g_variant_serialised_is_normal (value);
193 }
194@@ -362,6 +369,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value,
195
196 value.depth++;
197 value.ordered_offsets_up_to = 0;
198+ value.checked_offsets_up_to = 0;
199
200 return value;
201 }
202@@ -392,7 +400,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value,
203 {
204 if (n_children)
205 {
206- GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 };
207+ GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 };
208
209 /* write the data for the child. */
210 gvs_filler (&child, children[0]);
211@@ -413,6 +421,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
212 value.size--;
213 value.depth++;
214 value.ordered_offsets_up_to = 0;
215+ value.checked_offsets_up_to = 0;
216
217 return g_variant_serialised_is_normal (value);
218 }
219@@ -739,39 +748,46 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
220
221 /* If the requested @index_ is beyond the set of indices whose framing offsets
222 * have been checked, check the remaining offsets to see whether they’re
223- * normal (in order, no overlapping array elements). */
224- if (index_ > value.ordered_offsets_up_to)
225+ * normal (in order, no overlapping array elements).
226+ *
227+ * Don’t bother checking if the highest known-good offset is lower than the
228+ * highest checked offset, as that means there’s an invalid element at that
229+ * index, so there’s no need to check further. */
230+ if (index_ > value.checked_offsets_up_to &&
231+ value.ordered_offsets_up_to == value.checked_offsets_up_to)
232 {
233 switch (offsets.offset_size)
234 {
235 case 1:
236 {
237 value.ordered_offsets_up_to = find_unordered_guint8 (
238- offsets.array, value.ordered_offsets_up_to, index_ + 1);
239+ offsets.array, value.checked_offsets_up_to, index_ + 1);
240 break;
241 }
242 case 2:
243 {
244 value.ordered_offsets_up_to = find_unordered_guint16 (
245- offsets.array, value.ordered_offsets_up_to, index_ + 1);
246+ offsets.array, value.checked_offsets_up_to, index_ + 1);
247 break;
248 }
249 case 4:
250 {
251 value.ordered_offsets_up_to = find_unordered_guint32 (
252- offsets.array, value.ordered_offsets_up_to, index_ + 1);
253+ offsets.array, value.checked_offsets_up_to, index_ + 1);
254 break;
255 }
256 case 8:
257 {
258 value.ordered_offsets_up_to = find_unordered_guint64 (
259- offsets.array, value.ordered_offsets_up_to, index_ + 1);
260+ offsets.array, value.checked_offsets_up_to, index_ + 1);
261 break;
262 }
263 default:
264 /* gvs_get_offset_size() only returns maximum 8 */
265 g_assert_not_reached ();
266 }
267+
268+ value.checked_offsets_up_to = index_;
269 }
270
271 if (index_ > value.ordered_offsets_up_to)
272@@ -916,6 +932,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
273
274 /* All offsets have now been checked. */
275 value.ordered_offsets_up_to = G_MAXSIZE;
276+ value.checked_offsets_up_to = G_MAXSIZE;
277
278 return TRUE;
279 }
280@@ -1040,14 +1057,15 @@ gvs_tuple_get_child (GVariantSerialised value,
281 * all the tuple *elements* here, not just all the framing offsets, since
282 * tuples contain a mix of elements which use framing offsets and ones which
283 * don’t. None of them are allowed to overlap. */
284- if (index_ > value.ordered_offsets_up_to)
285+ if (index_ > value.checked_offsets_up_to &&
286+ value.ordered_offsets_up_to == value.checked_offsets_up_to)
287 {
288 gsize i, prev_i_end = 0;
289
290- if (value.ordered_offsets_up_to > 0)
291- gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
292+ if (value.checked_offsets_up_to > 0)
293+ gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
294
295- for (i = value.ordered_offsets_up_to; i <= index_; i++)
296+ for (i = value.checked_offsets_up_to; i <= index_; i++)
297 {
298 gsize i_start, i_end;
299
300@@ -1060,6 +1078,7 @@ gvs_tuple_get_child (GVariantSerialised value,
301 }
302
303 value.ordered_offsets_up_to = i - 1;
304+ value.checked_offsets_up_to = index_;
305 }
306
307 if (index_ > value.ordered_offsets_up_to)
308@@ -1257,6 +1276,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
309
310 /* All element bounds have been checked above. */
311 value.ordered_offsets_up_to = G_MAXSIZE;
312+ value.checked_offsets_up_to = G_MAXSIZE;
313
314 {
315 gsize fixed_size;
316diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h
317index 144aec8..e132451 100644
318--- a/glib/gvariant-serialiser.h
319+++ b/glib/gvariant-serialiser.h
320@@ -40,6 +40,15 @@ typedef struct
321 * Even when dealing with tuples, @ordered_offsets_up_to is an element index,
322 * rather than an index into the frame offsets. */
323 gsize ordered_offsets_up_to;
324+
325+ /* Similar to @ordered_offsets_up_to. This gives the index of the child element
326+ * whose frame offset is the highest in the offset table which has been
327+ * checked so far.
328+ *
329+ * This is always ≥ @ordered_offsets_up_to. It is always an element index.
330+ *
331+ * See documentation in gvariant-core.c for `struct GVariant` for details. */
332+ gsize checked_offsets_up_to;
333 } GVariantSerialised;
334
335 /* deserialisation */
336diff --git a/glib/gvariant.c b/glib/gvariant.c
337index fdd36be..f910bd4 100644
338--- a/glib/gvariant.c
339+++ b/glib/gvariant.c
340@@ -5945,6 +5945,7 @@ g_variant_byteswap (GVariant *value)
341 serialised.size = g_variant_get_size (trusted);
342 serialised.data = g_malloc (serialised.size);
343 serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */
344+ serialised.checked_offsets_up_to = G_MAXSIZE;
345 g_variant_store (trusted, serialised.data);
346 g_variant_unref (trusted);
347
348diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
349index a84b02e..640f3c0 100644
350--- a/glib/tests/gvariant.c
351+++ b/glib/tests/gvariant.c
352@@ -1286,6 +1286,7 @@ random_instance_filler (GVariantSerialised *serialised,
353
354 serialised->depth = 0;
355 serialised->ordered_offsets_up_to = 0;
356+ serialised->checked_offsets_up_to = 0;
357
358 g_assert_true (serialised->type_info == instance->type_info);
359 g_assert_cmpuint (serialised->size, ==, instance->size);
360@@ -1453,6 +1454,7 @@ test_maybe (void)
361 serialised.size = needed_size;
362 serialised.depth = 0;
363 serialised.ordered_offsets_up_to = 0;
364+ serialised.checked_offsets_up_to = 0;
365
366 g_variant_serialiser_serialise (serialised,
367 random_instance_filler,
368@@ -1577,6 +1579,7 @@ test_array (void)
369 serialised.size = needed_size;
370 serialised.depth = 0;
371 serialised.ordered_offsets_up_to = 0;
372+ serialised.checked_offsets_up_to = 0;
373
374 g_variant_serialiser_serialise (serialised, random_instance_filler,
375 (gpointer *) instances, n_children);
376@@ -1742,6 +1745,7 @@ test_tuple (void)
377 serialised.size = needed_size;
378 serialised.depth = 0;
379 serialised.ordered_offsets_up_to = 0;
380+ serialised.checked_offsets_up_to = 0;
381
382 g_variant_serialiser_serialise (serialised, random_instance_filler,
383 (gpointer *) instances, n_children);
384@@ -1839,6 +1843,7 @@ test_variant (void)
385 serialised.size = needed_size;
386 serialised.depth = 0;
387 serialised.ordered_offsets_up_to = 0;
388+ serialised.checked_offsets_up_to = 0;
389
390 g_variant_serialiser_serialise (serialised, random_instance_filler,
391 (gpointer *) &instance, 1);
392--
3932.24.4
394