diff options
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.patch | 394 |
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 @@ | |||
1 | From d1a293c4e29880b8d17bb826c9a426a440ca4a91 Mon Sep 17 00:00:00 2001 | ||
2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
3 | Date: Thu, 17 Aug 2023 01:30:38 +0000 | ||
4 | Subject: [PATCH] gvariant: Track checked and ordered offsets independently | ||
5 | |||
6 | The past few commits introduced the concept of known-good offsets in the | ||
7 | offset table (which is used for variable-width arrays and tuples). | ||
8 | Good offsets are ones which are non-overlapping with all the previous | ||
9 | offsets in the table. | ||
10 | |||
11 | If a bad offset is encountered when indexing into the array or tuple, | ||
12 | the cached known-good offset index will not be increased. In this way, | ||
13 | all child variants at and beyond the first bad offset can be returned as | ||
14 | default values rather than dereferencing potentially invalid data. | ||
15 | |||
16 | In this case, there was no information about the fact that the indexes | ||
17 | between the highest known-good index and the requested one had been | ||
18 | checked already. That could lead to a pathological case where an offset | ||
19 | table with an invalid first offset is repeatedly checked in full when | ||
20 | trying to access higher-indexed children. | ||
21 | |||
22 | Avoid that by storing the index of the highest checked offset in the | ||
23 | table, as well as the index of the highest good/ordered offset. | ||
24 | |||
25 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
26 | |||
27 | Helps: #2121 | ||
28 | |||
29 | CVE: CVE-2023-32665 | ||
30 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/d1a293c4e29880b8d17bb826c9a426a440ca4a91] | ||
31 | Signed-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 | |||
40 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
41 | index 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 | } | ||
146 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
147 | index 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; | ||
316 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
317 | index 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 */ | ||
336 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
337 | index 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 | |||
348 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
349 | index 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 | -- | ||
393 | 2.24.4 | ||
394 | |||