1b5975d6bSopenharmony_ciFrom 1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1 Mon Sep 17 00:00:00 2001
2b5975d6bSopenharmony_ciFrom: William Manley <will@stb-tester.com>
3b5975d6bSopenharmony_ciDate: Tue, 23 Jun 2020 22:59:58 +0100
4b5975d6bSopenharmony_ciSubject: [PATCH 01/18] gvariant-core: Consolidate construction of
5b5975d6bSopenharmony_ci `GVariantSerialised`
6b5975d6bSopenharmony_ci
7b5975d6bSopenharmony_ciSo I only need to change it in one place.
8b5975d6bSopenharmony_ci
9b5975d6bSopenharmony_ciThis introduces no functional changes.
10b5975d6bSopenharmony_ci
11b5975d6bSopenharmony_ciHelps: #2121
12b5975d6bSopenharmony_ci---
13b5975d6bSopenharmony_ci glib/gvariant-core.c | 49 ++++++++++++++++++++++----------------------
14b5975d6bSopenharmony_ci 1 file changed, 25 insertions(+), 24 deletions(-)
15b5975d6bSopenharmony_ci
16b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
17b5975d6bSopenharmony_ciindex 89ea54c013..d5d78da88b 100644
18b5975d6bSopenharmony_ci--- a/glib/gvariant-core.c
19b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.c
20b5975d6bSopenharmony_ci@@ -351,6 +351,27 @@ g_variant_ensure_size (GVariant *value)
21b5975d6bSopenharmony_ci     }
22b5975d6bSopenharmony_ci }
23b5975d6bSopenharmony_ci 
24b5975d6bSopenharmony_ci+/* < private >
25b5975d6bSopenharmony_ci+ * g_variant_to_serialised:
26b5975d6bSopenharmony_ci+ * @value: a #GVariant
27b5975d6bSopenharmony_ci+ *
28b5975d6bSopenharmony_ci+ * Gets a GVariantSerialised for a GVariant in state STATE_SERIALISED.
29b5975d6bSopenharmony_ci+ */
30b5975d6bSopenharmony_ci+inline static GVariantSerialised
31b5975d6bSopenharmony_ci+g_variant_to_serialised (GVariant *value)
32b5975d6bSopenharmony_ci+{
33b5975d6bSopenharmony_ci+  g_assert (value->state & STATE_SERIALISED);
34b5975d6bSopenharmony_ci+  {
35b5975d6bSopenharmony_ci+    GVariantSerialised serialised = {
36b5975d6bSopenharmony_ci+      value->type_info,
37b5975d6bSopenharmony_ci+      (gpointer) value->contents.serialised.data,
38b5975d6bSopenharmony_ci+      value->size,
39b5975d6bSopenharmony_ci+      value->depth,
40b5975d6bSopenharmony_ci+    };
41b5975d6bSopenharmony_ci+    return serialised;
42b5975d6bSopenharmony_ci+  }
43b5975d6bSopenharmony_ci+}
44b5975d6bSopenharmony_ci+
45b5975d6bSopenharmony_ci /* < private >
46b5975d6bSopenharmony_ci  * g_variant_serialise:
47b5975d6bSopenharmony_ci  * @value: a #GVariant
48b5975d6bSopenharmony_ci@@ -1009,16 +1030,8 @@ g_variant_n_children (GVariant *value)
49b5975d6bSopenharmony_ci   g_variant_lock (value);
50b5975d6bSopenharmony_ci 
51b5975d6bSopenharmony_ci   if (value->state & STATE_SERIALISED)
52b5975d6bSopenharmony_ci-    {
53b5975d6bSopenharmony_ci-      GVariantSerialised serialised = {
54b5975d6bSopenharmony_ci-        value->type_info,
55b5975d6bSopenharmony_ci-        (gpointer) value->contents.serialised.data,
56b5975d6bSopenharmony_ci-        value->size,
57b5975d6bSopenharmony_ci-        value->depth,
58b5975d6bSopenharmony_ci-      };
59b5975d6bSopenharmony_ci-
60b5975d6bSopenharmony_ci-      n_children = g_variant_serialised_n_children (serialised);
61b5975d6bSopenharmony_ci-    }
62b5975d6bSopenharmony_ci+    n_children = g_variant_serialised_n_children (
63b5975d6bSopenharmony_ci+        g_variant_to_serialised (value));
64b5975d6bSopenharmony_ci   else
65b5975d6bSopenharmony_ci     n_children = value->contents.tree.n_children;
66b5975d6bSopenharmony_ci 
67b5975d6bSopenharmony_ci@@ -1085,12 +1098,7 @@ g_variant_get_child_value (GVariant *value,
68b5975d6bSopenharmony_ci     }
69b5975d6bSopenharmony_ci 
70b5975d6bSopenharmony_ci   {
71b5975d6bSopenharmony_ci-    GVariantSerialised serialised = {
72b5975d6bSopenharmony_ci-      value->type_info,
73b5975d6bSopenharmony_ci-      (gpointer) value->contents.serialised.data,
74b5975d6bSopenharmony_ci-      value->size,
75b5975d6bSopenharmony_ci-      value->depth,
76b5975d6bSopenharmony_ci-    };
77b5975d6bSopenharmony_ci+    GVariantSerialised serialised = g_variant_to_serialised (value);
78b5975d6bSopenharmony_ci     GVariantSerialised s_child;
79b5975d6bSopenharmony_ci     GVariant *child;
80b5975d6bSopenharmony_ci 
81b5975d6bSopenharmony_ci@@ -1203,14 +1211,7 @@ g_variant_is_normal_form (GVariant *value)
82b5975d6bSopenharmony_ci 
83b5975d6bSopenharmony_ci   if (value->state & STATE_SERIALISED)
84b5975d6bSopenharmony_ci     {
85b5975d6bSopenharmony_ci-      GVariantSerialised serialised = {
86b5975d6bSopenharmony_ci-        value->type_info,
87b5975d6bSopenharmony_ci-        (gpointer) value->contents.serialised.data,
88b5975d6bSopenharmony_ci-        value->size,
89b5975d6bSopenharmony_ci-        value->depth
90b5975d6bSopenharmony_ci-      };
91b5975d6bSopenharmony_ci-
92b5975d6bSopenharmony_ci-      if (g_variant_serialised_is_normal (serialised))
93b5975d6bSopenharmony_ci+      if (g_variant_serialised_is_normal (g_variant_to_serialised (value)))
94b5975d6bSopenharmony_ci         value->state |= STATE_TRUSTED;
95b5975d6bSopenharmony_ci     }
96b5975d6bSopenharmony_ci   else
97b5975d6bSopenharmony_ci-- 
98b5975d6bSopenharmony_ciGitLab
99b5975d6bSopenharmony_ci
100b5975d6bSopenharmony_ci
101b5975d6bSopenharmony_ciFrom 446e69f5edd72deb2196dee36bbaf8056caf6948 Mon Sep 17 00:00:00 2001
102b5975d6bSopenharmony_ciFrom: William Manley <will@stb-tester.com>
103b5975d6bSopenharmony_ciDate: Thu, 25 Jun 2020 17:08:21 +0100
104b5975d6bSopenharmony_ciSubject: [PATCH 02/18] gvariant-serialiser: Factor out functions for dealing
105b5975d6bSopenharmony_ci with framing offsets
106b5975d6bSopenharmony_ci
107b5975d6bSopenharmony_ciThis introduces no functional changes.
108b5975d6bSopenharmony_ci
109b5975d6bSopenharmony_ciHelps: #2121
110b5975d6bSopenharmony_ci---
111b5975d6bSopenharmony_ci glib/gvariant-serialiser.c | 108 +++++++++++++++++++------------------
112b5975d6bSopenharmony_ci 1 file changed, 57 insertions(+), 51 deletions(-)
113b5975d6bSopenharmony_ci
114b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
115b5975d6bSopenharmony_ciindex 6ebaec7d40..1eaa80b29f 100644
116b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
117b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
118b5975d6bSopenharmony_ci@@ -635,30 +635,62 @@ gvs_calculate_total_size (gsize body_size,
119b5975d6bSopenharmony_ci   return body_size + 8 * offsets;
120b5975d6bSopenharmony_ci }
121b5975d6bSopenharmony_ci 
122b5975d6bSopenharmony_ci+struct Offsets
123b5975d6bSopenharmony_ci+{
124b5975d6bSopenharmony_ci+  gsize     data_size;
125b5975d6bSopenharmony_ci+
126b5975d6bSopenharmony_ci+  guchar   *array;
127b5975d6bSopenharmony_ci+  gsize     length;
128b5975d6bSopenharmony_ci+  guint     offset_size;
129b5975d6bSopenharmony_ci+
130b5975d6bSopenharmony_ci+  gboolean  is_normal;
131b5975d6bSopenharmony_ci+};
132b5975d6bSopenharmony_ci+
133b5975d6bSopenharmony_ci static gsize
134b5975d6bSopenharmony_ci-gvs_variable_sized_array_n_children (GVariantSerialised value)
135b5975d6bSopenharmony_ci+gvs_offsets_get_offset_n (struct Offsets *offsets,
136b5975d6bSopenharmony_ci+                          gsize           n)
137b5975d6bSopenharmony_ci+{
138b5975d6bSopenharmony_ci+  return gvs_read_unaligned_le (
139b5975d6bSopenharmony_ci+      offsets->array + (offsets->offset_size * n), offsets->offset_size);
140b5975d6bSopenharmony_ci+}
141b5975d6bSopenharmony_ci+
142b5975d6bSopenharmony_ci+static struct Offsets
143b5975d6bSopenharmony_ci+gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
144b5975d6bSopenharmony_ci {
145b5975d6bSopenharmony_ci+  struct Offsets out = { 0, };
146b5975d6bSopenharmony_ci   gsize offsets_array_size;
147b5975d6bSopenharmony_ci-  gsize offset_size;
148b5975d6bSopenharmony_ci   gsize last_end;
149b5975d6bSopenharmony_ci 
150b5975d6bSopenharmony_ci   if (value.size == 0)
151b5975d6bSopenharmony_ci-    return 0;
152b5975d6bSopenharmony_ci-
153b5975d6bSopenharmony_ci-  offset_size = gvs_get_offset_size (value.size);
154b5975d6bSopenharmony_ci+    {
155b5975d6bSopenharmony_ci+      out.is_normal = TRUE;
156b5975d6bSopenharmony_ci+      return out;
157b5975d6bSopenharmony_ci+    }
158b5975d6bSopenharmony_ci 
159b5975d6bSopenharmony_ci-  last_end = gvs_read_unaligned_le (value.data + value.size -
160b5975d6bSopenharmony_ci-                                    offset_size, offset_size);
161b5975d6bSopenharmony_ci+  out.offset_size = gvs_get_offset_size (value.size);
162b5975d6bSopenharmony_ci+  last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size,
163b5975d6bSopenharmony_ci+                                    out.offset_size);
164b5975d6bSopenharmony_ci 
165b5975d6bSopenharmony_ci   if (last_end > value.size)
166b5975d6bSopenharmony_ci-    return 0;
167b5975d6bSopenharmony_ci+    return out;  /* offsets not normal */
168b5975d6bSopenharmony_ci 
169b5975d6bSopenharmony_ci   offsets_array_size = value.size - last_end;
170b5975d6bSopenharmony_ci 
171b5975d6bSopenharmony_ci-  if (offsets_array_size % offset_size)
172b5975d6bSopenharmony_ci-    return 0;
173b5975d6bSopenharmony_ci+  if (offsets_array_size % out.offset_size)
174b5975d6bSopenharmony_ci+    return out;  /* offsets not normal */
175b5975d6bSopenharmony_ci+
176b5975d6bSopenharmony_ci+  out.data_size = last_end;
177b5975d6bSopenharmony_ci+  out.array = value.data + last_end;
178b5975d6bSopenharmony_ci+  out.length = offsets_array_size / out.offset_size;
179b5975d6bSopenharmony_ci+  out.is_normal = TRUE;
180b5975d6bSopenharmony_ci 
181b5975d6bSopenharmony_ci-  return offsets_array_size / offset_size;
182b5975d6bSopenharmony_ci+  return out;
183b5975d6bSopenharmony_ci+}
184b5975d6bSopenharmony_ci+
185b5975d6bSopenharmony_ci+static gsize
186b5975d6bSopenharmony_ci+gvs_variable_sized_array_n_children (GVariantSerialised value)
187b5975d6bSopenharmony_ci+{
188b5975d6bSopenharmony_ci+  return gvs_variable_sized_array_get_frame_offsets (value).length;
189b5975d6bSopenharmony_ci }
190b5975d6bSopenharmony_ci 
191b5975d6bSopenharmony_ci static GVariantSerialised
192b5975d6bSopenharmony_ci@@ -666,8 +698,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
193b5975d6bSopenharmony_ci                                     gsize              index_)
194b5975d6bSopenharmony_ci {
195b5975d6bSopenharmony_ci   GVariantSerialised child = { 0, };
196b5975d6bSopenharmony_ci-  gsize offset_size;
197b5975d6bSopenharmony_ci-  gsize last_end;
198b5975d6bSopenharmony_ci+
199b5975d6bSopenharmony_ci+  struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
200b5975d6bSopenharmony_ci+
201b5975d6bSopenharmony_ci   gsize start;
202b5975d6bSopenharmony_ci   gsize end;
203b5975d6bSopenharmony_ci 
204b5975d6bSopenharmony_ci@@ -675,18 +708,11 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
205b5975d6bSopenharmony_ci   g_variant_type_info_ref (child.type_info);
206b5975d6bSopenharmony_ci   child.depth = value.depth + 1;
207b5975d6bSopenharmony_ci 
208b5975d6bSopenharmony_ci-  offset_size = gvs_get_offset_size (value.size);
209b5975d6bSopenharmony_ci-
210b5975d6bSopenharmony_ci-  last_end = gvs_read_unaligned_le (value.data + value.size -
211b5975d6bSopenharmony_ci-                                    offset_size, offset_size);
212b5975d6bSopenharmony_ci-
213b5975d6bSopenharmony_ci   if (index_ > 0)
214b5975d6bSopenharmony_ci     {
215b5975d6bSopenharmony_ci       guint alignment;
216b5975d6bSopenharmony_ci 
217b5975d6bSopenharmony_ci-      start = gvs_read_unaligned_le (value.data + last_end +
218b5975d6bSopenharmony_ci-                                     (offset_size * (index_ - 1)),
219b5975d6bSopenharmony_ci-                                     offset_size);
220b5975d6bSopenharmony_ci+      start = gvs_offsets_get_offset_n (&offsets, index_ - 1);
221b5975d6bSopenharmony_ci 
222b5975d6bSopenharmony_ci       g_variant_type_info_query (child.type_info, &alignment, NULL);
223b5975d6bSopenharmony_ci       start += (-start) & alignment;
224b5975d6bSopenharmony_ci@@ -694,11 +720,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
225b5975d6bSopenharmony_ci   else
226b5975d6bSopenharmony_ci     start = 0;
227b5975d6bSopenharmony_ci 
228b5975d6bSopenharmony_ci-  end = gvs_read_unaligned_le (value.data + last_end +
229b5975d6bSopenharmony_ci-                               (offset_size * index_),
230b5975d6bSopenharmony_ci-                               offset_size);
231b5975d6bSopenharmony_ci+  end = gvs_offsets_get_offset_n (&offsets, index_);
232b5975d6bSopenharmony_ci 
233b5975d6bSopenharmony_ci-  if (start < end && end <= value.size && end <= last_end)
234b5975d6bSopenharmony_ci+  if (start < end && end <= value.size && end <= offsets.data_size)
235b5975d6bSopenharmony_ci     {
236b5975d6bSopenharmony_ci       child.data = value.data + start;
237b5975d6bSopenharmony_ci       child.size = end - start;
238b5975d6bSopenharmony_ci@@ -770,34 +794,16 @@ static gboolean
239b5975d6bSopenharmony_ci gvs_variable_sized_array_is_normal (GVariantSerialised value)
240b5975d6bSopenharmony_ci {
241b5975d6bSopenharmony_ci   GVariantSerialised child = { 0, };
242b5975d6bSopenharmony_ci-  gsize offsets_array_size;
243b5975d6bSopenharmony_ci-  guchar *offsets_array;
244b5975d6bSopenharmony_ci-  guint offset_size;
245b5975d6bSopenharmony_ci   guint alignment;
246b5975d6bSopenharmony_ci-  gsize last_end;
247b5975d6bSopenharmony_ci-  gsize length;
248b5975d6bSopenharmony_ci   gsize offset;
249b5975d6bSopenharmony_ci   gsize i;
250b5975d6bSopenharmony_ci 
251b5975d6bSopenharmony_ci-  if (value.size == 0)
252b5975d6bSopenharmony_ci-    return TRUE;
253b5975d6bSopenharmony_ci-
254b5975d6bSopenharmony_ci-  offset_size = gvs_get_offset_size (value.size);
255b5975d6bSopenharmony_ci-  last_end = gvs_read_unaligned_le (value.data + value.size -
256b5975d6bSopenharmony_ci-                                    offset_size, offset_size);
257b5975d6bSopenharmony_ci+  struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
258b5975d6bSopenharmony_ci 
259b5975d6bSopenharmony_ci-  if (last_end > value.size)
260b5975d6bSopenharmony_ci+  if (!offsets.is_normal)
261b5975d6bSopenharmony_ci     return FALSE;
262b5975d6bSopenharmony_ci 
263b5975d6bSopenharmony_ci-  offsets_array_size = value.size - last_end;
264b5975d6bSopenharmony_ci-
265b5975d6bSopenharmony_ci-  if (offsets_array_size % offset_size)
266b5975d6bSopenharmony_ci-    return FALSE;
267b5975d6bSopenharmony_ci-
268b5975d6bSopenharmony_ci-  offsets_array = value.data + value.size - offsets_array_size;
269b5975d6bSopenharmony_ci-  length = offsets_array_size / offset_size;
270b5975d6bSopenharmony_ci-
271b5975d6bSopenharmony_ci-  if (length == 0)
272b5975d6bSopenharmony_ci+  if (value.size != 0 && offsets.length == 0)
273b5975d6bSopenharmony_ci     return FALSE;
274b5975d6bSopenharmony_ci 
275b5975d6bSopenharmony_ci   child.type_info = g_variant_type_info_element (value.type_info);
276b5975d6bSopenharmony_ci@@ -805,14 +811,14 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
277b5975d6bSopenharmony_ci   child.depth = value.depth + 1;
278b5975d6bSopenharmony_ci   offset = 0;
279b5975d6bSopenharmony_ci 
280b5975d6bSopenharmony_ci-  for (i = 0; i < length; i++)
281b5975d6bSopenharmony_ci+  for (i = 0; i < offsets.length; i++)
282b5975d6bSopenharmony_ci     {
283b5975d6bSopenharmony_ci       gsize this_end;
284b5975d6bSopenharmony_ci 
285b5975d6bSopenharmony_ci-      this_end = gvs_read_unaligned_le (offsets_array + offset_size * i,
286b5975d6bSopenharmony_ci-                                        offset_size);
287b5975d6bSopenharmony_ci+      this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i,
288b5975d6bSopenharmony_ci+                                        offsets.offset_size);
289b5975d6bSopenharmony_ci 
290b5975d6bSopenharmony_ci-      if (this_end < offset || this_end > last_end)
291b5975d6bSopenharmony_ci+      if (this_end < offset || this_end > offsets.data_size)
292b5975d6bSopenharmony_ci         return FALSE;
293b5975d6bSopenharmony_ci 
294b5975d6bSopenharmony_ci       while (offset & alignment)
295b5975d6bSopenharmony_ci@@ -834,7 +840,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
296b5975d6bSopenharmony_ci       offset = this_end;
297b5975d6bSopenharmony_ci     }
298b5975d6bSopenharmony_ci 
299b5975d6bSopenharmony_ci-  g_assert (offset == last_end);
300b5975d6bSopenharmony_ci+  g_assert (offset == offsets.data_size);
301b5975d6bSopenharmony_ci 
302b5975d6bSopenharmony_ci   return TRUE;
303b5975d6bSopenharmony_ci }
304b5975d6bSopenharmony_ci-- 
305b5975d6bSopenharmony_ciGitLab
306b5975d6bSopenharmony_ci
307b5975d6bSopenharmony_ci
308b5975d6bSopenharmony_ciFrom 298a537d5f6783e55d87e40011ee3fd3b22b72f9 Mon Sep 17 00:00:00 2001
309b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
310b5975d6bSopenharmony_ciDate: Tue, 25 Oct 2022 18:05:52 +0100
311b5975d6bSopenharmony_ciSubject: [PATCH 03/18] gvariant: Zero-initialise various GVariantSerialised
312b5975d6bSopenharmony_ci objects
313b5975d6bSopenharmony_ci
314b5975d6bSopenharmony_ciThe following few commits will add a couple of new fields to
315b5975d6bSopenharmony_ci`GVariantSerialised`, and they should be zero-filled by default.
316b5975d6bSopenharmony_ci
317b5975d6bSopenharmony_ciTry and pre-empt that a bit by zero-filling `GVariantSerialised` by
318b5975d6bSopenharmony_cidefault in a few places.
319b5975d6bSopenharmony_ci
320b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
321b5975d6bSopenharmony_ci
322b5975d6bSopenharmony_ciHelps: #2121
323b5975d6bSopenharmony_ci---
324b5975d6bSopenharmony_ci glib/gvariant.c       |  2 +-
325b5975d6bSopenharmony_ci glib/tests/gvariant.c | 12 ++++++------
326b5975d6bSopenharmony_ci 2 files changed, 7 insertions(+), 7 deletions(-)
327b5975d6bSopenharmony_ci
328b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
329b5975d6bSopenharmony_ciindex 6863f341d6..e4c85ca636 100644
330b5975d6bSopenharmony_ci--- a/glib/gvariant.c
331b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
332b5975d6bSopenharmony_ci@@ -6002,7 +6002,7 @@ g_variant_byteswap (GVariant *value)
333b5975d6bSopenharmony_ci   if (alignment)
334b5975d6bSopenharmony_ci     /* (potentially) contains multi-byte numeric data */
335b5975d6bSopenharmony_ci     {
336b5975d6bSopenharmony_ci-      GVariantSerialised serialised;
337b5975d6bSopenharmony_ci+      GVariantSerialised serialised = { 0, };
338b5975d6bSopenharmony_ci       GVariant *trusted;
339b5975d6bSopenharmony_ci       GBytes *bytes;
340b5975d6bSopenharmony_ci 
341b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
342b5975d6bSopenharmony_ciindex 058d02ad22..18fa855aeb 100644
343b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
344b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
345b5975d6bSopenharmony_ci@@ -1440,7 +1440,7 @@ test_maybe (void)
346b5975d6bSopenharmony_ci 
347b5975d6bSopenharmony_ci     for (flavour = 0; flavour < 8; flavour += alignment)
348b5975d6bSopenharmony_ci       {
349b5975d6bSopenharmony_ci-        GVariantSerialised serialised;
350b5975d6bSopenharmony_ci+        GVariantSerialised serialised = { 0, };
351b5975d6bSopenharmony_ci         GVariantSerialised child;
352b5975d6bSopenharmony_ci 
353b5975d6bSopenharmony_ci         serialised.type_info = type_info;
354b5975d6bSopenharmony_ci@@ -1564,7 +1564,7 @@ test_array (void)
355b5975d6bSopenharmony_ci 
356b5975d6bSopenharmony_ci     for (flavour = 0; flavour < 8; flavour += alignment)
357b5975d6bSopenharmony_ci       {
358b5975d6bSopenharmony_ci-        GVariantSerialised serialised;
359b5975d6bSopenharmony_ci+        GVariantSerialised serialised = { 0, };
360b5975d6bSopenharmony_ci 
361b5975d6bSopenharmony_ci         serialised.type_info = array_info;
362b5975d6bSopenharmony_ci         serialised.data = flavoured_malloc (needed_size, flavour);
363b5975d6bSopenharmony_ci@@ -1728,7 +1728,7 @@ test_tuple (void)
364b5975d6bSopenharmony_ci 
365b5975d6bSopenharmony_ci     for (flavour = 0; flavour < 8; flavour += alignment)
366b5975d6bSopenharmony_ci       {
367b5975d6bSopenharmony_ci-        GVariantSerialised serialised;
368b5975d6bSopenharmony_ci+        GVariantSerialised serialised = { 0, };
369b5975d6bSopenharmony_ci 
370b5975d6bSopenharmony_ci         serialised.type_info = type_info;
371b5975d6bSopenharmony_ci         serialised.data = flavoured_malloc (needed_size, flavour);
372b5975d6bSopenharmony_ci@@ -1823,7 +1823,7 @@ test_variant (void)
373b5975d6bSopenharmony_ci 
374b5975d6bSopenharmony_ci     for (flavour = 0; flavour < 8; flavour += alignment)
375b5975d6bSopenharmony_ci       {
376b5975d6bSopenharmony_ci-        GVariantSerialised serialised;
377b5975d6bSopenharmony_ci+        GVariantSerialised serialised = { 0, };
378b5975d6bSopenharmony_ci         GVariantSerialised child;
379b5975d6bSopenharmony_ci 
380b5975d6bSopenharmony_ci         serialised.type_info = type_info;
381b5975d6bSopenharmony_ci@@ -2270,7 +2270,7 @@ serialise_tree (TreeInstance       *tree,
382b5975d6bSopenharmony_ci static void
383b5975d6bSopenharmony_ci test_byteswap (void)
384b5975d6bSopenharmony_ci {
385b5975d6bSopenharmony_ci-  GVariantSerialised one, two;
386b5975d6bSopenharmony_ci+  GVariantSerialised one = { 0, }, two = { 0, };
387b5975d6bSopenharmony_ci   TreeInstance *tree;
388b5975d6bSopenharmony_ci 
389b5975d6bSopenharmony_ci   tree = tree_instance_new (NULL, 3);
390b5975d6bSopenharmony_ci@@ -2344,7 +2344,7 @@ test_serialiser_children (void)
391b5975d6bSopenharmony_ci static void
392b5975d6bSopenharmony_ci test_fuzz (gdouble *fuzziness)
393b5975d6bSopenharmony_ci {
394b5975d6bSopenharmony_ci-  GVariantSerialised serialised;
395b5975d6bSopenharmony_ci+  GVariantSerialised serialised = { 0, };
396b5975d6bSopenharmony_ci   TreeInstance *tree;
397b5975d6bSopenharmony_ci 
398b5975d6bSopenharmony_ci   /* make an instance */
399b5975d6bSopenharmony_ci-- 
400b5975d6bSopenharmony_ciGitLab
401b5975d6bSopenharmony_ci
402b5975d6bSopenharmony_ci
403b5975d6bSopenharmony_ciFrom ade71fb544391b2e33e1859645726bfee0d5eaaf Mon Sep 17 00:00:00 2001
404b5975d6bSopenharmony_ciFrom: William Manley <will@stb-tester.com>
405b5975d6bSopenharmony_ciDate: Mon, 29 Jun 2020 16:59:44 +0100
406b5975d6bSopenharmony_ciSubject: [PATCH 04/18] =?UTF-8?q?gvariant:=20Don=E2=80=99t=20allow=20child?=
407b5975d6bSopenharmony_ci =?UTF-8?q?=20elements=20to=20overlap=20with=20each=20other?=
408b5975d6bSopenharmony_ciMIME-Version: 1.0
409b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
410b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
411b5975d6bSopenharmony_ci
412b5975d6bSopenharmony_ciIf different elements of a variable sized array can overlap with each
413b5975d6bSopenharmony_ciother then we can cause a `GVariant` to normalise to a much larger type.
414b5975d6bSopenharmony_ci
415b5975d6bSopenharmony_ciThis commit changes the behaviour of `GVariant` with non-normal form data. If
416b5975d6bSopenharmony_cian invalid frame offset is found all subsequent elements are given their
417b5975d6bSopenharmony_cidefault value.
418b5975d6bSopenharmony_ci
419b5975d6bSopenharmony_ciWhen retrieving an element at index `n` we scan the frame offsets up to index
420b5975d6bSopenharmony_ci`n` and if they are not in order we return an element with the default value
421b5975d6bSopenharmony_cifor that type.  This guarantees that elements don't overlap with each
422b5975d6bSopenharmony_ciother.  We remember the offset we've scanned up to so we don't need to
423b5975d6bSopenharmony_cirepeat this work on subsequent accesses.  We skip these checks for trusted
424b5975d6bSopenharmony_cidata.
425b5975d6bSopenharmony_ci
426b5975d6bSopenharmony_ciUnfortunately this makes random access of untrusted data O(n) — at least
427b5975d6bSopenharmony_cion first access.  It doesn't affect the algorithmic complexity of accessing
428b5975d6bSopenharmony_cielements in order, such as when using the `GVariantIter` interface.  Also:
429b5975d6bSopenharmony_cithe cost of validation will be amortised as the `GVariant` instance is
430b5975d6bSopenharmony_cicontinued to be used.
431b5975d6bSopenharmony_ci
432b5975d6bSopenharmony_ciI've implemented this with 4 different functions, 1 for each element size,
433b5975d6bSopenharmony_cirather than looping calling `gvs_read_unaligned_le` in the hope that the
434b5975d6bSopenharmony_cicompiler will find it easy to optimise and should produce fairly tight
435b5975d6bSopenharmony_cicode.
436b5975d6bSopenharmony_ci
437b5975d6bSopenharmony_ciFixes: #2121
438b5975d6bSopenharmony_ci---
439b5975d6bSopenharmony_ci glib/gvariant-core.c       | 35 ++++++++++++++++
440b5975d6bSopenharmony_ci glib/gvariant-serialiser.c | 86 ++++++++++++++++++++++++++++++++++++--
441b5975d6bSopenharmony_ci glib/gvariant-serialiser.h |  9 ++++
442b5975d6bSopenharmony_ci glib/tests/gvariant.c      | 45 ++++++++++++++++++++
443b5975d6bSopenharmony_ci 4 files changed, 172 insertions(+), 3 deletions(-)
444b5975d6bSopenharmony_ci
445b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
446b5975d6bSopenharmony_ciindex d5d78da88b..f25d472794 100644
447b5975d6bSopenharmony_ci--- a/glib/gvariant-core.c
448b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.c
449b5975d6bSopenharmony_ci@@ -67,6 +67,7 @@ struct _GVariant
450b5975d6bSopenharmony_ci     {
451b5975d6bSopenharmony_ci       GBytes *bytes;
452b5975d6bSopenharmony_ci       gconstpointer data;
453b5975d6bSopenharmony_ci+      gsize ordered_offsets_up_to;
454b5975d6bSopenharmony_ci     } serialised;
455b5975d6bSopenharmony_ci 
456b5975d6bSopenharmony_ci     struct
457b5975d6bSopenharmony_ci@@ -164,6 +165,24 @@ struct _GVariant
458b5975d6bSopenharmony_ci  *                if .data pointed to the appropriate number of nul
459b5975d6bSopenharmony_ci  *                bytes.
460b5975d6bSopenharmony_ci  *
461b5975d6bSopenharmony_ci+ *     .ordered_offsets_up_to: If ordered_offsets_up_to == n this means that all
462b5975d6bSopenharmony_ci+ *                             the frame offsets up to and including the frame
463b5975d6bSopenharmony_ci+ *                             offset determining the end of element n are in
464b5975d6bSopenharmony_ci+ *                             order. This guarantees that the bytes of element
465b5975d6bSopenharmony_ci+ *                             n don't overlap with any previous element.
466b5975d6bSopenharmony_ci+ *
467b5975d6bSopenharmony_ci+ *                             For trusted data this is set to G_MAXSIZE and we
468b5975d6bSopenharmony_ci+ *                             don't check that the frame offsets are in order.
469b5975d6bSopenharmony_ci+ *
470b5975d6bSopenharmony_ci+ *                             Note: This doesn't imply the offsets are good in
471b5975d6bSopenharmony_ci+ *                             any way apart from their ordering.  In particular
472b5975d6bSopenharmony_ci+ *                             offsets may be out of bounds for this value or
473b5975d6bSopenharmony_ci+ *                             may imply that the data overlaps the frame
474b5975d6bSopenharmony_ci+ *                             offsets themselves.
475b5975d6bSopenharmony_ci+ *
476b5975d6bSopenharmony_ci+ *                             This field is only relevant for arrays of non
477b5975d6bSopenharmony_ci+ *                             fixed width types.
478b5975d6bSopenharmony_ci+ *
479b5975d6bSopenharmony_ci  *   .tree: Only valid when the instance is in tree form.
480b5975d6bSopenharmony_ci  *
481b5975d6bSopenharmony_ci  *          Note that accesses from other threads could result in
482b5975d6bSopenharmony_ci@@ -367,6 +386,7 @@ g_variant_to_serialised (GVariant *value)
483b5975d6bSopenharmony_ci       (gpointer) value->contents.serialised.data,
484b5975d6bSopenharmony_ci       value->size,
485b5975d6bSopenharmony_ci       value->depth,
486b5975d6bSopenharmony_ci+      value->contents.serialised.ordered_offsets_up_to,
487b5975d6bSopenharmony_ci     };
488b5975d6bSopenharmony_ci     return serialised;
489b5975d6bSopenharmony_ci   }
490b5975d6bSopenharmony_ci@@ -398,6 +418,7 @@ g_variant_serialise (GVariant *value,
491b5975d6bSopenharmony_ci   serialised.size = value->size;
492b5975d6bSopenharmony_ci   serialised.data = data;
493b5975d6bSopenharmony_ci   serialised.depth = value->depth;
494b5975d6bSopenharmony_ci+  serialised.ordered_offsets_up_to = 0;
495b5975d6bSopenharmony_ci 
496b5975d6bSopenharmony_ci   children = (gpointer *) value->contents.tree.children;
497b5975d6bSopenharmony_ci   n_children = value->contents.tree.n_children;
498b5975d6bSopenharmony_ci@@ -441,6 +462,15 @@ g_variant_fill_gvs (GVariantSerialised *serialised,
499b5975d6bSopenharmony_ci   g_assert (serialised->size == value->size);
500b5975d6bSopenharmony_ci   serialised->depth = value->depth;
501b5975d6bSopenharmony_ci 
502b5975d6bSopenharmony_ci+  if (value->state & STATE_SERIALISED)
503b5975d6bSopenharmony_ci+    {
504b5975d6bSopenharmony_ci+      serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to;
505b5975d6bSopenharmony_ci+    }
506b5975d6bSopenharmony_ci+  else
507b5975d6bSopenharmony_ci+    {
508b5975d6bSopenharmony_ci+      serialised->ordered_offsets_up_to = 0;
509b5975d6bSopenharmony_ci+    }
510b5975d6bSopenharmony_ci+
511b5975d6bSopenharmony_ci   if (serialised->data)
512b5975d6bSopenharmony_ci     /* g_variant_store() is a public API, so it
513b5975d6bSopenharmony_ci      * it will reacquire the lock if it needs to.
514b5975d6bSopenharmony_ci@@ -483,6 +513,7 @@ g_variant_ensure_serialised (GVariant *value)
515b5975d6bSopenharmony_ci       bytes = g_bytes_new_take (data, value->size);
516b5975d6bSopenharmony_ci       value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
517b5975d6bSopenharmony_ci       value->contents.serialised.bytes = bytes;
518b5975d6bSopenharmony_ci+      value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE;
519b5975d6bSopenharmony_ci       value->state |= STATE_SERIALISED;
520b5975d6bSopenharmony_ci     }
521b5975d6bSopenharmony_ci }
522b5975d6bSopenharmony_ci@@ -563,6 +594,7 @@ g_variant_new_from_bytes (const GVariantType *type,
523b5975d6bSopenharmony_ci   serialised.type_info = value->type_info;
524b5975d6bSopenharmony_ci   serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size);
525b5975d6bSopenharmony_ci   serialised.depth = 0;
526b5975d6bSopenharmony_ci+  serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0;
527b5975d6bSopenharmony_ci 
528b5975d6bSopenharmony_ci   if (!g_variant_serialised_check (serialised))
529b5975d6bSopenharmony_ci     {
530b5975d6bSopenharmony_ci@@ -613,6 +645,8 @@ g_variant_new_from_bytes (const GVariantType *type,
531b5975d6bSopenharmony_ci       value->contents.serialised.data = g_bytes_get_data (bytes, &value->size);
532b5975d6bSopenharmony_ci     }
533b5975d6bSopenharmony_ci 
534b5975d6bSopenharmony_ci+  value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0;
535b5975d6bSopenharmony_ci+
536b5975d6bSopenharmony_ci   g_clear_pointer (&owned_bytes, g_bytes_unref);
537b5975d6bSopenharmony_ci 
538b5975d6bSopenharmony_ci   return value;
539b5975d6bSopenharmony_ci@@ -1132,6 +1166,7 @@ g_variant_get_child_value (GVariant *value,
540b5975d6bSopenharmony_ci     child->contents.serialised.bytes =
541b5975d6bSopenharmony_ci       g_bytes_ref (value->contents.serialised.bytes);
542b5975d6bSopenharmony_ci     child->contents.serialised.data = s_child.data;
543b5975d6bSopenharmony_ci+    child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to;
544b5975d6bSopenharmony_ci 
545b5975d6bSopenharmony_ci     return child;
546b5975d6bSopenharmony_ci   }
547b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
548b5975d6bSopenharmony_ciindex 1eaa80b29f..c33a903bff 100644
549b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
550b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
551b5975d6bSopenharmony_ci@@ -1,6 +1,7 @@
552b5975d6bSopenharmony_ci /*
553b5975d6bSopenharmony_ci  * Copyright © 2007, 2008 Ryan Lortie
554b5975d6bSopenharmony_ci  * Copyright © 2010 Codethink Limited
555b5975d6bSopenharmony_ci+ * Copyright © 2020 William Manley
556b5975d6bSopenharmony_ci  *
557b5975d6bSopenharmony_ci  * This library is free software; you can redistribute it and/or
558b5975d6bSopenharmony_ci  * modify it under the terms of the GNU Lesser General Public
559b5975d6bSopenharmony_ci@@ -266,6 +267,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
560b5975d6bSopenharmony_ci   value.type_info = g_variant_type_info_element (value.type_info);
561b5975d6bSopenharmony_ci   g_variant_type_info_ref (value.type_info);
562b5975d6bSopenharmony_ci   value.depth++;
563b5975d6bSopenharmony_ci+  value.ordered_offsets_up_to = 0;
564b5975d6bSopenharmony_ci 
565b5975d6bSopenharmony_ci   return value;
566b5975d6bSopenharmony_ci }
567b5975d6bSopenharmony_ci@@ -297,7 +299,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
568b5975d6bSopenharmony_ci {
569b5975d6bSopenharmony_ci   if (n_children)
570b5975d6bSopenharmony_ci     {
571b5975d6bSopenharmony_ci-      GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1 };
572b5975d6bSopenharmony_ci+      GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 };
573b5975d6bSopenharmony_ci 
574b5975d6bSopenharmony_ci       gvs_filler (&child, children[0]);
575b5975d6bSopenharmony_ci     }
576b5975d6bSopenharmony_ci@@ -319,6 +321,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
577b5975d6bSopenharmony_ci       /* proper element size: "Just".  recurse to the child. */
578b5975d6bSopenharmony_ci       value.type_info = g_variant_type_info_element (value.type_info);
579b5975d6bSopenharmony_ci       value.depth++;
580b5975d6bSopenharmony_ci+      value.ordered_offsets_up_to = 0;
581b5975d6bSopenharmony_ci 
582b5975d6bSopenharmony_ci       return g_variant_serialised_is_normal (value);
583b5975d6bSopenharmony_ci     }
584b5975d6bSopenharmony_ci@@ -360,6 +363,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value,
585b5975d6bSopenharmony_ci     value.data = NULL;
586b5975d6bSopenharmony_ci 
587b5975d6bSopenharmony_ci   value.depth++;
588b5975d6bSopenharmony_ci+  value.ordered_offsets_up_to = 0;
589b5975d6bSopenharmony_ci 
590b5975d6bSopenharmony_ci   return value;
591b5975d6bSopenharmony_ci }
592b5975d6bSopenharmony_ci@@ -390,7 +394,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
593b5975d6bSopenharmony_ci {
594b5975d6bSopenharmony_ci   if (n_children)
595b5975d6bSopenharmony_ci     {
596b5975d6bSopenharmony_ci-      GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1 };
597b5975d6bSopenharmony_ci+      GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 };
598b5975d6bSopenharmony_ci 
599b5975d6bSopenharmony_ci       /* write the data for the child.  */
600b5975d6bSopenharmony_ci       gvs_filler (&child, children[0]);
601b5975d6bSopenharmony_ci@@ -410,6 +414,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
602b5975d6bSopenharmony_ci   value.type_info = g_variant_type_info_element (value.type_info);
603b5975d6bSopenharmony_ci   value.size--;
604b5975d6bSopenharmony_ci   value.depth++;
605b5975d6bSopenharmony_ci+  value.ordered_offsets_up_to = 0;
606b5975d6bSopenharmony_ci 
607b5975d6bSopenharmony_ci   return g_variant_serialised_is_normal (value);
608b5975d6bSopenharmony_ci }
609b5975d6bSopenharmony_ci@@ -693,6 +698,32 @@ gvs_variable_sized_array_n_children (GVariantSerialised value)
610b5975d6bSopenharmony_ci   return gvs_variable_sized_array_get_frame_offsets (value).length;
611b5975d6bSopenharmony_ci }
612b5975d6bSopenharmony_ci 
613b5975d6bSopenharmony_ci+/* Find the index of the first out-of-order element in @data, assuming that
614b5975d6bSopenharmony_ci+ * @data is an array of elements of given @type, starting at index @start and
615b5975d6bSopenharmony_ci+ * containing a further @len-@start elements. */
616b5975d6bSopenharmony_ci+#define DEFINE_FIND_UNORDERED(type) \
617b5975d6bSopenharmony_ci+  static gsize \
618b5975d6bSopenharmony_ci+  find_unordered_##type (const guint8 *data, gsize start, gsize len) \
619b5975d6bSopenharmony_ci+  { \
620b5975d6bSopenharmony_ci+    gsize off; \
621b5975d6bSopenharmony_ci+    type current, previous; \
622b5975d6bSopenharmony_ci+    \
623b5975d6bSopenharmony_ci+    memcpy (&previous, data + start * sizeof (current), sizeof (current)); \
624b5975d6bSopenharmony_ci+    for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \
625b5975d6bSopenharmony_ci+      { \
626b5975d6bSopenharmony_ci+        memcpy (&current, data + off, sizeof (current)); \
627b5975d6bSopenharmony_ci+        if (current < previous) \
628b5975d6bSopenharmony_ci+          break; \
629b5975d6bSopenharmony_ci+        previous = current; \
630b5975d6bSopenharmony_ci+      } \
631b5975d6bSopenharmony_ci+    return off / sizeof (current) - 1; \
632b5975d6bSopenharmony_ci+  }
633b5975d6bSopenharmony_ci+
634b5975d6bSopenharmony_ci+DEFINE_FIND_UNORDERED (guint8);
635b5975d6bSopenharmony_ci+DEFINE_FIND_UNORDERED (guint16);
636b5975d6bSopenharmony_ci+DEFINE_FIND_UNORDERED (guint32);
637b5975d6bSopenharmony_ci+DEFINE_FIND_UNORDERED (guint64);
638b5975d6bSopenharmony_ci+
639b5975d6bSopenharmony_ci static GVariantSerialised
640b5975d6bSopenharmony_ci gvs_variable_sized_array_get_child (GVariantSerialised value,
641b5975d6bSopenharmony_ci                                     gsize              index_)
642b5975d6bSopenharmony_ci@@ -708,6 +739,49 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
643b5975d6bSopenharmony_ci   g_variant_type_info_ref (child.type_info);
644b5975d6bSopenharmony_ci   child.depth = value.depth + 1;
645b5975d6bSopenharmony_ci 
646b5975d6bSopenharmony_ci+  /* If the requested @index_ is beyond the set of indices whose framing offsets
647b5975d6bSopenharmony_ci+   * have been checked, check the remaining offsets to see whether they’re
648b5975d6bSopenharmony_ci+   * normal (in order, no overlapping array elements). */
649b5975d6bSopenharmony_ci+  if (index_ > value.ordered_offsets_up_to)
650b5975d6bSopenharmony_ci+    {
651b5975d6bSopenharmony_ci+      switch (offsets.offset_size)
652b5975d6bSopenharmony_ci+        {
653b5975d6bSopenharmony_ci+        case 1:
654b5975d6bSopenharmony_ci+          {
655b5975d6bSopenharmony_ci+            value.ordered_offsets_up_to = find_unordered_guint8 (
656b5975d6bSopenharmony_ci+                offsets.array, value.ordered_offsets_up_to, index_ + 1);
657b5975d6bSopenharmony_ci+            break;
658b5975d6bSopenharmony_ci+          }
659b5975d6bSopenharmony_ci+        case 2:
660b5975d6bSopenharmony_ci+          {
661b5975d6bSopenharmony_ci+            value.ordered_offsets_up_to = find_unordered_guint16 (
662b5975d6bSopenharmony_ci+                offsets.array, value.ordered_offsets_up_to, index_ + 1);
663b5975d6bSopenharmony_ci+            break;
664b5975d6bSopenharmony_ci+          }
665b5975d6bSopenharmony_ci+        case 4:
666b5975d6bSopenharmony_ci+          {
667b5975d6bSopenharmony_ci+            value.ordered_offsets_up_to = find_unordered_guint32 (
668b5975d6bSopenharmony_ci+                offsets.array, value.ordered_offsets_up_to, index_ + 1);
669b5975d6bSopenharmony_ci+            break;
670b5975d6bSopenharmony_ci+          }
671b5975d6bSopenharmony_ci+        case 8:
672b5975d6bSopenharmony_ci+          {
673b5975d6bSopenharmony_ci+            value.ordered_offsets_up_to = find_unordered_guint64 (
674b5975d6bSopenharmony_ci+                offsets.array, value.ordered_offsets_up_to, index_ + 1);
675b5975d6bSopenharmony_ci+            break;
676b5975d6bSopenharmony_ci+          }
677b5975d6bSopenharmony_ci+        default:
678b5975d6bSopenharmony_ci+          /* gvs_get_offset_size() only returns maximum 8 */
679b5975d6bSopenharmony_ci+          g_assert_not_reached ();
680b5975d6bSopenharmony_ci+        }
681b5975d6bSopenharmony_ci+    }
682b5975d6bSopenharmony_ci+
683b5975d6bSopenharmony_ci+  if (index_ > value.ordered_offsets_up_to)
684b5975d6bSopenharmony_ci+    {
685b5975d6bSopenharmony_ci+      /* Offsets are invalid somewhere, so return an empty child. */
686b5975d6bSopenharmony_ci+      return child;
687b5975d6bSopenharmony_ci+    }
688b5975d6bSopenharmony_ci+
689b5975d6bSopenharmony_ci   if (index_ > 0)
690b5975d6bSopenharmony_ci     {
691b5975d6bSopenharmony_ci       guint alignment;
692b5975d6bSopenharmony_ci@@ -842,6 +916,9 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
693b5975d6bSopenharmony_ci 
694b5975d6bSopenharmony_ci   g_assert (offset == offsets.data_size);
695b5975d6bSopenharmony_ci 
696b5975d6bSopenharmony_ci+  /* All offsets have now been checked. */
697b5975d6bSopenharmony_ci+  value.ordered_offsets_up_to = G_MAXSIZE;
698b5975d6bSopenharmony_ci+
699b5975d6bSopenharmony_ci   return TRUE;
700b5975d6bSopenharmony_ci }
701b5975d6bSopenharmony_ci 
702b5975d6bSopenharmony_ci@@ -1078,7 +1155,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
703b5975d6bSopenharmony_ci   for (i = 0; i < length; i++)
704b5975d6bSopenharmony_ci     {
705b5975d6bSopenharmony_ci       const GVariantMemberInfo *member_info;
706b5975d6bSopenharmony_ci-      GVariantSerialised child;
707b5975d6bSopenharmony_ci+      GVariantSerialised child = { 0, };
708b5975d6bSopenharmony_ci       gsize fixed_size;
709b5975d6bSopenharmony_ci       guint alignment;
710b5975d6bSopenharmony_ci       gsize end;
711b5975d6bSopenharmony_ci@@ -1138,6 +1215,9 @@ gvs_tuple_is_normal (GVariantSerialised value)
712b5975d6bSopenharmony_ci       offset = end;
713b5975d6bSopenharmony_ci     }
714b5975d6bSopenharmony_ci 
715b5975d6bSopenharmony_ci+  /* All element bounds have been checked above. */
716b5975d6bSopenharmony_ci+  value.ordered_offsets_up_to = G_MAXSIZE;
717b5975d6bSopenharmony_ci+
718b5975d6bSopenharmony_ci   {
719b5975d6bSopenharmony_ci     gsize fixed_size;
720b5975d6bSopenharmony_ci     guint alignment;
721b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h
722b5975d6bSopenharmony_ciindex 6ced7e3d6c..a1bccb834b 100644
723b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.h
724b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.h
725b5975d6bSopenharmony_ci@@ -31,6 +31,15 @@ typedef struct
726b5975d6bSopenharmony_ci   guchar           *data;
727b5975d6bSopenharmony_ci   gsize             size;
728b5975d6bSopenharmony_ci   gsize             depth;  /* same semantics as GVariant.depth */
729b5975d6bSopenharmony_ci+
730b5975d6bSopenharmony_ci+  /* If ordered_offsets_up_to == n this means that all the frame offsets up to and
731b5975d6bSopenharmony_ci+   * including the frame offset determining the end of element n are in order.
732b5975d6bSopenharmony_ci+   * This guarantees that the bytes of element n don't overlap with any previous
733b5975d6bSopenharmony_ci+   * element.
734b5975d6bSopenharmony_ci+   *
735b5975d6bSopenharmony_ci+   * This is both read and set by g_variant_serialised_get_child for arrays of
736b5975d6bSopenharmony_ci+   * non-fixed-width types */
737b5975d6bSopenharmony_ci+  gsize             ordered_offsets_up_to;
738b5975d6bSopenharmony_ci } GVariantSerialised;
739b5975d6bSopenharmony_ci 
740b5975d6bSopenharmony_ci /* deserialization */
741b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
742b5975d6bSopenharmony_ciindex 18fa855aeb..45e302c926 100644
743b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
744b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
745b5975d6bSopenharmony_ci@@ -1,5 +1,6 @@
746b5975d6bSopenharmony_ci /*
747b5975d6bSopenharmony_ci  * Copyright © 2010 Codethink Limited
748b5975d6bSopenharmony_ci+ * Copyright © 2020 William Manley
749b5975d6bSopenharmony_ci  *
750b5975d6bSopenharmony_ci  * This library is free software; you can redistribute it and/or
751b5975d6bSopenharmony_ci  * modify it under the terms of the GNU Lesser General Public
752b5975d6bSopenharmony_ci@@ -1281,6 +1282,7 @@ random_instance_filler (GVariantSerialised *serialised,
753b5975d6bSopenharmony_ci     serialised->size = instance->size;
754b5975d6bSopenharmony_ci 
755b5975d6bSopenharmony_ci   serialised->depth = 0;
756b5975d6bSopenharmony_ci+  serialised->ordered_offsets_up_to = 0;
757b5975d6bSopenharmony_ci 
758b5975d6bSopenharmony_ci   g_assert_true (serialised->type_info == instance->type_info);
759b5975d6bSopenharmony_ci   g_assert_cmpuint (serialised->size, ==, instance->size);
760b5975d6bSopenharmony_ci@@ -5143,6 +5145,47 @@ test_normal_checking_array_offsets (void)
761b5975d6bSopenharmony_ci   g_variant_unref (variant);
762b5975d6bSopenharmony_ci }
763b5975d6bSopenharmony_ci 
764b5975d6bSopenharmony_ci+/* This is a regression test that we can't have non-normal values that take up
765b5975d6bSopenharmony_ci+ * significantly more space than the normal equivalent, by specifying the
766b5975d6bSopenharmony_ci+ * offset table entries so that array elements overlap.
767b5975d6bSopenharmony_ci+ *
768b5975d6bSopenharmony_ci+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_832242 */
769b5975d6bSopenharmony_ci+static void
770b5975d6bSopenharmony_ci+test_normal_checking_array_offsets2 (void)
771b5975d6bSopenharmony_ci+{
772b5975d6bSopenharmony_ci+  const guint8 data[] = {
773b5975d6bSopenharmony_ci+    'h', 'i', '\0',
774b5975d6bSopenharmony_ci+    0x03, 0x00, 0x03,
775b5975d6bSopenharmony_ci+    0x06, 0x00, 0x06,
776b5975d6bSopenharmony_ci+    0x09, 0x00, 0x09,
777b5975d6bSopenharmony_ci+    0x0c, 0x00, 0x0c,
778b5975d6bSopenharmony_ci+    0x0f, 0x00, 0x0f,
779b5975d6bSopenharmony_ci+    0x12, 0x00, 0x12,
780b5975d6bSopenharmony_ci+    0x15, 0x00, 0x15,
781b5975d6bSopenharmony_ci+  };
782b5975d6bSopenharmony_ci+  gsize size = sizeof (data);
783b5975d6bSopenharmony_ci+  const GVariantType *aaaaaaas = G_VARIANT_TYPE ("aaaaaaas");
784b5975d6bSopenharmony_ci+  GVariant *variant = NULL;
785b5975d6bSopenharmony_ci+  GVariant *normal_variant = NULL;
786b5975d6bSopenharmony_ci+  GVariant *expected = NULL;
787b5975d6bSopenharmony_ci+
788b5975d6bSopenharmony_ci+  variant = g_variant_new_from_data (aaaaaaas, data, size, FALSE, NULL, NULL);
789b5975d6bSopenharmony_ci+  g_assert_nonnull (variant);
790b5975d6bSopenharmony_ci+
791b5975d6bSopenharmony_ci+  normal_variant = g_variant_get_normal_form (variant);
792b5975d6bSopenharmony_ci+  g_assert_nonnull (normal_variant);
793b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 2);
794b5975d6bSopenharmony_ci+
795b5975d6bSopenharmony_ci+  expected = g_variant_new_parsed (
796b5975d6bSopenharmony_ci+      "[[[[[[['hi', '', ''], [], []], [], []], [], []], [], []], [], []], [], []]");
797b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, variant);
798b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, normal_variant);
799b5975d6bSopenharmony_ci+
800b5975d6bSopenharmony_ci+  g_variant_unref (expected);
801b5975d6bSopenharmony_ci+  g_variant_unref (normal_variant);
802b5975d6bSopenharmony_ci+  g_variant_unref (variant);
803b5975d6bSopenharmony_ci+}
804b5975d6bSopenharmony_ci+
805b5975d6bSopenharmony_ci /* Test that a tuple with invalidly large values in its offset table is
806b5975d6bSopenharmony_ci  * normalised successfully without looping infinitely. */
807b5975d6bSopenharmony_ci static void
808b5975d6bSopenharmony_ci@@ -5311,6 +5354,8 @@ main (int argc, char **argv)
809b5975d6bSopenharmony_ci                    test_normal_checking_tuples);
810b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/array-offsets",
811b5975d6bSopenharmony_ci                    test_normal_checking_array_offsets);
812b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/array-offsets2",
813b5975d6bSopenharmony_ci+                   test_normal_checking_array_offsets2);
814b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
815b5975d6bSopenharmony_ci                    test_normal_checking_tuple_offsets);
816b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/empty-object-path",
817b5975d6bSopenharmony_ci-- 
818b5975d6bSopenharmony_ciGitLab
819b5975d6bSopenharmony_ci
820b5975d6bSopenharmony_ci
821b5975d6bSopenharmony_ciFrom 345cae9c1aa7bf6752039225ef4c8d8d69fa8d76 Mon Sep 17 00:00:00 2001
822b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
823b5975d6bSopenharmony_ciDate: Fri, 7 Jan 2022 15:03:52 +0000
824b5975d6bSopenharmony_ciSubject: [PATCH 05/18] gvariant-serialiser: Factor out code to get bounds of a
825b5975d6bSopenharmony_ci tuple member
826b5975d6bSopenharmony_ci
827b5975d6bSopenharmony_ciThis introduces no functional changes.
828b5975d6bSopenharmony_ci
829b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
830b5975d6bSopenharmony_ci
831b5975d6bSopenharmony_ciHelps: #2121
832b5975d6bSopenharmony_ci---
833b5975d6bSopenharmony_ci glib/gvariant-serialiser.c | 73 ++++++++++++++++++++++++--------------
834b5975d6bSopenharmony_ci 1 file changed, 46 insertions(+), 27 deletions(-)
835b5975d6bSopenharmony_ci
836b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
837b5975d6bSopenharmony_ciindex c33a903bff..5b67b3820f 100644
838b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
839b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
840b5975d6bSopenharmony_ci@@ -944,6 +944,51 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
841b5975d6bSopenharmony_ci  * for the tuple.  See the notes in gvarianttypeinfo.h.
842b5975d6bSopenharmony_ci  */
843b5975d6bSopenharmony_ci 
844b5975d6bSopenharmony_ci+static void
845b5975d6bSopenharmony_ci+gvs_tuple_get_member_bounds (GVariantSerialised  value,
846b5975d6bSopenharmony_ci+                             gsize               index_,
847b5975d6bSopenharmony_ci+                             gsize               offset_size,
848b5975d6bSopenharmony_ci+                             gsize              *out_member_start,
849b5975d6bSopenharmony_ci+                             gsize              *out_member_end)
850b5975d6bSopenharmony_ci+{
851b5975d6bSopenharmony_ci+  const GVariantMemberInfo *member_info;
852b5975d6bSopenharmony_ci+  gsize member_start, member_end;
853b5975d6bSopenharmony_ci+
854b5975d6bSopenharmony_ci+  member_info = g_variant_type_info_member_info (value.type_info, index_);
855b5975d6bSopenharmony_ci+
856b5975d6bSopenharmony_ci+  if (member_info->i + 1)
857b5975d6bSopenharmony_ci+    member_start = gvs_read_unaligned_le (value.data + value.size -
858b5975d6bSopenharmony_ci+                                          offset_size * (member_info->i + 1),
859b5975d6bSopenharmony_ci+                                          offset_size);
860b5975d6bSopenharmony_ci+  else
861b5975d6bSopenharmony_ci+    member_start = 0;
862b5975d6bSopenharmony_ci+
863b5975d6bSopenharmony_ci+  member_start += member_info->a;
864b5975d6bSopenharmony_ci+  member_start &= member_info->b;
865b5975d6bSopenharmony_ci+  member_start |= member_info->c;
866b5975d6bSopenharmony_ci+
867b5975d6bSopenharmony_ci+  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
868b5975d6bSopenharmony_ci+    member_end = value.size - offset_size * (member_info->i + 1);
869b5975d6bSopenharmony_ci+
870b5975d6bSopenharmony_ci+  else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
871b5975d6bSopenharmony_ci+    {
872b5975d6bSopenharmony_ci+      gsize fixed_size;
873b5975d6bSopenharmony_ci+
874b5975d6bSopenharmony_ci+      g_variant_type_info_query (member_info->type_info, NULL, &fixed_size);
875b5975d6bSopenharmony_ci+      member_end = member_start + fixed_size;
876b5975d6bSopenharmony_ci+    }
877b5975d6bSopenharmony_ci+
878b5975d6bSopenharmony_ci+  else /* G_VARIANT_MEMBER_ENDING_OFFSET */
879b5975d6bSopenharmony_ci+    member_end = gvs_read_unaligned_le (value.data + value.size -
880b5975d6bSopenharmony_ci+                                        offset_size * (member_info->i + 2),
881b5975d6bSopenharmony_ci+                                        offset_size);
882b5975d6bSopenharmony_ci+
883b5975d6bSopenharmony_ci+  if (out_member_start != NULL)
884b5975d6bSopenharmony_ci+    *out_member_start = member_start;
885b5975d6bSopenharmony_ci+  if (out_member_end != NULL)
886b5975d6bSopenharmony_ci+    *out_member_end = member_end;
887b5975d6bSopenharmony_ci+}
888b5975d6bSopenharmony_ci+
889b5975d6bSopenharmony_ci static gsize
890b5975d6bSopenharmony_ci gvs_tuple_n_children (GVariantSerialised value)
891b5975d6bSopenharmony_ci {
892b5975d6bSopenharmony_ci@@ -999,33 +1044,7 @@ gvs_tuple_get_child (GVariantSerialised value,
893b5975d6bSopenharmony_ci         }
894b5975d6bSopenharmony_ci     }
895b5975d6bSopenharmony_ci 
896b5975d6bSopenharmony_ci-  if (member_info->i + 1)
897b5975d6bSopenharmony_ci-    start = gvs_read_unaligned_le (value.data + value.size -
898b5975d6bSopenharmony_ci-                                   offset_size * (member_info->i + 1),
899b5975d6bSopenharmony_ci-                                   offset_size);
900b5975d6bSopenharmony_ci-  else
901b5975d6bSopenharmony_ci-    start = 0;
902b5975d6bSopenharmony_ci-
903b5975d6bSopenharmony_ci-  start += member_info->a;
904b5975d6bSopenharmony_ci-  start &= member_info->b;
905b5975d6bSopenharmony_ci-  start |= member_info->c;
906b5975d6bSopenharmony_ci-
907b5975d6bSopenharmony_ci-  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
908b5975d6bSopenharmony_ci-    end = value.size - offset_size * (member_info->i + 1);
909b5975d6bSopenharmony_ci-
910b5975d6bSopenharmony_ci-  else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
911b5975d6bSopenharmony_ci-    {
912b5975d6bSopenharmony_ci-      gsize fixed_size;
913b5975d6bSopenharmony_ci-
914b5975d6bSopenharmony_ci-      g_variant_type_info_query (child.type_info, NULL, &fixed_size);
915b5975d6bSopenharmony_ci-      end = start + fixed_size;
916b5975d6bSopenharmony_ci-      child.size = fixed_size;
917b5975d6bSopenharmony_ci-    }
918b5975d6bSopenharmony_ci-
919b5975d6bSopenharmony_ci-  else /* G_VARIANT_MEMBER_ENDING_OFFSET */
920b5975d6bSopenharmony_ci-    end = gvs_read_unaligned_le (value.data + value.size -
921b5975d6bSopenharmony_ci-                                 offset_size * (member_info->i + 2),
922b5975d6bSopenharmony_ci-                                 offset_size);
923b5975d6bSopenharmony_ci+  gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
924b5975d6bSopenharmony_ci 
925b5975d6bSopenharmony_ci   /* The child should not extend into the offset table. */
926b5975d6bSopenharmony_ci   if (index_ != g_variant_type_info_n_members (value.type_info) - 1)
927b5975d6bSopenharmony_ci-- 
928b5975d6bSopenharmony_ciGitLab
929b5975d6bSopenharmony_ci
930b5975d6bSopenharmony_ci
931b5975d6bSopenharmony_ciFrom 73d0aa81c2575a5c9ae77dcb94da919579014fc0 Mon Sep 17 00:00:00 2001
932b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
933b5975d6bSopenharmony_ciDate: Fri, 7 Jan 2022 16:37:29 +0000
934b5975d6bSopenharmony_ciSubject: [PATCH 06/18] gvariant-serialiser: Rework child size calculation
935b5975d6bSopenharmony_ciMIME-Version: 1.0
936b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
937b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
938b5975d6bSopenharmony_ci
939b5975d6bSopenharmony_ciThis reduces a few duplicate calls to `g_variant_type_info_query()` and
940b5975d6bSopenharmony_ciexplains why they’re needed.
941b5975d6bSopenharmony_ci
942b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
943b5975d6bSopenharmony_ci
944b5975d6bSopenharmony_ciHelps: #2121
945b5975d6bSopenharmony_ci---
946b5975d6bSopenharmony_ci glib/gvariant-serialiser.c | 31 +++++++++----------------------
947b5975d6bSopenharmony_ci 1 file changed, 9 insertions(+), 22 deletions(-)
948b5975d6bSopenharmony_ci
949b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
950b5975d6bSopenharmony_ciindex 5b67b3820f..bc131b7514 100644
951b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
952b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
953b5975d6bSopenharmony_ci@@ -1009,14 +1009,18 @@ gvs_tuple_get_child (GVariantSerialised value,
954b5975d6bSopenharmony_ci   child.depth = value.depth + 1;
955b5975d6bSopenharmony_ci   offset_size = gvs_get_offset_size (value.size);
956b5975d6bSopenharmony_ci 
957b5975d6bSopenharmony_ci+  /* Ensure the size is set for fixed-sized children, or
958b5975d6bSopenharmony_ci+   * g_variant_serialised_check() will fail, even if we return
959b5975d6bSopenharmony_ci+   * (child.data == NULL) to indicate an error. */
960b5975d6bSopenharmony_ci+  if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
961b5975d6bSopenharmony_ci+    g_variant_type_info_query (child.type_info, NULL, &child.size);
962b5975d6bSopenharmony_ci+
963b5975d6bSopenharmony_ci   /* tuples are the only (potentially) fixed-sized containers, so the
964b5975d6bSopenharmony_ci    * only ones that have to deal with the possibility of having %NULL
965b5975d6bSopenharmony_ci    * data with a non-zero %size if errors occurred elsewhere.
966b5975d6bSopenharmony_ci    */
967b5975d6bSopenharmony_ci   if G_UNLIKELY (value.data == NULL && value.size != 0)
968b5975d6bSopenharmony_ci     {
969b5975d6bSopenharmony_ci-      g_variant_type_info_query (child.type_info, NULL, &child.size);
970b5975d6bSopenharmony_ci-
971b5975d6bSopenharmony_ci       /* this can only happen in fixed-sized tuples,
972b5975d6bSopenharmony_ci        * so the child must also be fixed sized.
973b5975d6bSopenharmony_ci        */
974b5975d6bSopenharmony_ci@@ -1034,29 +1038,12 @@ gvs_tuple_get_child (GVariantSerialised value,
975b5975d6bSopenharmony_ci   else
976b5975d6bSopenharmony_ci     {
977b5975d6bSopenharmony_ci       if (offset_size * (member_info->i + 1) > value.size)
978b5975d6bSopenharmony_ci-        {
979b5975d6bSopenharmony_ci-          /* if the child is fixed size, return its size.
980b5975d6bSopenharmony_ci-           * if child is not fixed-sized, return size = 0.
981b5975d6bSopenharmony_ci-           */
982b5975d6bSopenharmony_ci-          g_variant_type_info_query (child.type_info, NULL, &child.size);
983b5975d6bSopenharmony_ci-
984b5975d6bSopenharmony_ci-          return child;
985b5975d6bSopenharmony_ci-        }
986b5975d6bSopenharmony_ci+        return child;
987b5975d6bSopenharmony_ci     }
988b5975d6bSopenharmony_ci 
989b5975d6bSopenharmony_ci-  gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
990b5975d6bSopenharmony_ci-
991b5975d6bSopenharmony_ci   /* The child should not extend into the offset table. */
992b5975d6bSopenharmony_ci-  if (index_ != g_variant_type_info_n_members (value.type_info) - 1)
993b5975d6bSopenharmony_ci-    {
994b5975d6bSopenharmony_ci-      GVariantSerialised last_child;
995b5975d6bSopenharmony_ci-      last_child = gvs_tuple_get_child (value,
996b5975d6bSopenharmony_ci-                                        g_variant_type_info_n_members (value.type_info) - 1);
997b5975d6bSopenharmony_ci-      last_end = last_child.data + last_child.size - value.data;
998b5975d6bSopenharmony_ci-      g_variant_type_info_unref (last_child.type_info);
999b5975d6bSopenharmony_ci-    }
1000b5975d6bSopenharmony_ci-  else
1001b5975d6bSopenharmony_ci-    last_end = end;
1002b5975d6bSopenharmony_ci+  gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
1003b5975d6bSopenharmony_ci+  gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end);
1004b5975d6bSopenharmony_ci 
1005b5975d6bSopenharmony_ci   if (start < end && end <= value.size && end <= last_end)
1006b5975d6bSopenharmony_ci     {
1007b5975d6bSopenharmony_ci-- 
1008b5975d6bSopenharmony_ciGitLab
1009b5975d6bSopenharmony_ci
1010b5975d6bSopenharmony_ci
1011b5975d6bSopenharmony_ciFrom 7cf6f5b69146d20948d42f0c476688fe17fef787 Mon Sep 17 00:00:00 2001
1012b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
1013b5975d6bSopenharmony_ciDate: Fri, 7 Jan 2022 16:42:14 +0000
1014b5975d6bSopenharmony_ciSubject: [PATCH 07/18] =?UTF-8?q?gvariant:=20Don=E2=80=99t=20allow=20child?=
1015b5975d6bSopenharmony_ci =?UTF-8?q?=20elements=20of=20a=20tuple=20to=20overlap=20each=20other?=
1016b5975d6bSopenharmony_ciMIME-Version: 1.0
1017b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
1018b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
1019b5975d6bSopenharmony_ci
1020b5975d6bSopenharmony_ciThis is similar to the earlier commit which prevents child elements of a
1021b5975d6bSopenharmony_civariable-sized array from overlapping each other, but this time for
1022b5975d6bSopenharmony_cituples. It is based heavily on ideas by William Manley.
1023b5975d6bSopenharmony_ci
1024b5975d6bSopenharmony_ciTuples are slightly different from variable-sized arrays in that they
1025b5975d6bSopenharmony_cicontain a mixture of fixed and variable sized elements. All but one of
1026b5975d6bSopenharmony_cithe variable sized elements have an entry in the frame offsets table.
1027b5975d6bSopenharmony_ciThis means that if we were to just check the ordering of the frame
1028b5975d6bSopenharmony_cioffsets table, the variable sized elements could still overlap
1029b5975d6bSopenharmony_ciinterleaving fixed sized elements, which would be bad.
1030b5975d6bSopenharmony_ci
1031b5975d6bSopenharmony_ciTherefore we have to check the elements rather than the frame offsets.
1032b5975d6bSopenharmony_ci
1033b5975d6bSopenharmony_ciThe logic of checking the elements up to the index currently being
1034b5975d6bSopenharmony_cirequested, and caching the result in `ordered_offsets_up_to`, means that
1035b5975d6bSopenharmony_cithe algorithmic cost implications are the same for this commit as for
1036b5975d6bSopenharmony_civariable-sized arrays: an O(N) cost for these checks is amortised out
1037b5975d6bSopenharmony_ciover N accesses to O(1) per access.
1038b5975d6bSopenharmony_ci
1039b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
1040b5975d6bSopenharmony_ci
1041b5975d6bSopenharmony_ciFixes: #2121
1042b5975d6bSopenharmony_ci---
1043b5975d6bSopenharmony_ci glib/gvariant-core.c       |   6 +-
1044b5975d6bSopenharmony_ci glib/gvariant-serialiser.c |  40 ++++++++
1045b5975d6bSopenharmony_ci glib/gvariant-serialiser.h |   7 +-
1046b5975d6bSopenharmony_ci glib/gvariant.c            |   1 +
1047b5975d6bSopenharmony_ci glib/tests/gvariant.c      | 181 +++++++++++++++++++++++++++++++++++++
1048b5975d6bSopenharmony_ci 5 files changed, 232 insertions(+), 3 deletions(-)
1049b5975d6bSopenharmony_ci
1050b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
1051b5975d6bSopenharmony_ciindex f25d472794..4419371136 100644
1052b5975d6bSopenharmony_ci--- a/glib/gvariant-core.c
1053b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.c
1054b5975d6bSopenharmony_ci@@ -1,6 +1,7 @@
1055b5975d6bSopenharmony_ci /*
1056b5975d6bSopenharmony_ci  * Copyright © 2007, 2008 Ryan Lortie
1057b5975d6bSopenharmony_ci  * Copyright © 2010 Codethink Limited
1058b5975d6bSopenharmony_ci+ * Copyright © 2022 Endless OS Foundation, LLC
1059b5975d6bSopenharmony_ci  *
1060b5975d6bSopenharmony_ci  * This library is free software; you can redistribute it and/or
1061b5975d6bSopenharmony_ci  * modify it under the terms of the GNU Lesser General Public
1062b5975d6bSopenharmony_ci@@ -181,7 +182,7 @@ struct _GVariant
1063b5975d6bSopenharmony_ci  *                             offsets themselves.
1064b5975d6bSopenharmony_ci  *
1065b5975d6bSopenharmony_ci  *                             This field is only relevant for arrays of non
1066b5975d6bSopenharmony_ci- *                             fixed width types.
1067b5975d6bSopenharmony_ci+ *                             fixed width types and for tuples.
1068b5975d6bSopenharmony_ci  *
1069b5975d6bSopenharmony_ci  *   .tree: Only valid when the instance is in tree form.
1070b5975d6bSopenharmony_ci  *
1071b5975d6bSopenharmony_ci@@ -1141,6 +1142,9 @@ g_variant_get_child_value (GVariant *value,
1072b5975d6bSopenharmony_ci      */
1073b5975d6bSopenharmony_ci     s_child = g_variant_serialised_get_child (serialised, index_);
1074b5975d6bSopenharmony_ci 
1075b5975d6bSopenharmony_ci+    /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */
1076b5975d6bSopenharmony_ci+    value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to);
1077b5975d6bSopenharmony_ci+
1078b5975d6bSopenharmony_ci     /* Check whether this would cause nesting too deep. If so, return a fake
1079b5975d6bSopenharmony_ci      * child. The only situation we expect this to happen in is with a variant,
1080b5975d6bSopenharmony_ci      * as all other deeply-nested types have a static type, and hence should
1081b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
1082b5975d6bSopenharmony_ciindex bc131b7514..263b74048c 100644
1083b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
1084b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
1085b5975d6bSopenharmony_ci@@ -944,6 +944,10 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
1086b5975d6bSopenharmony_ci  * for the tuple.  See the notes in gvarianttypeinfo.h.
1087b5975d6bSopenharmony_ci  */
1088b5975d6bSopenharmony_ci 
1089b5975d6bSopenharmony_ci+/* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that
1090b5975d6bSopenharmony_ci+ * condition may not hold true for invalid serialised variants. The caller is
1091b5975d6bSopenharmony_ci+ * responsible for checking the returned values and handling invalid ones
1092b5975d6bSopenharmony_ci+ * appropriately. */
1093b5975d6bSopenharmony_ci static void
1094b5975d6bSopenharmony_ci gvs_tuple_get_member_bounds (GVariantSerialised  value,
1095b5975d6bSopenharmony_ci                              gsize               index_,
1096b5975d6bSopenharmony_ci@@ -1030,6 +1034,42 @@ gvs_tuple_get_child (GVariantSerialised value,
1097b5975d6bSopenharmony_ci       return child;
1098b5975d6bSopenharmony_ci     }
1099b5975d6bSopenharmony_ci 
1100b5975d6bSopenharmony_ci+  /* If the requested @index_ is beyond the set of indices whose framing offsets
1101b5975d6bSopenharmony_ci+   * have been checked, check the remaining offsets to see whether they’re
1102b5975d6bSopenharmony_ci+   * normal (in order, no overlapping tuple elements).
1103b5975d6bSopenharmony_ci+   *
1104b5975d6bSopenharmony_ci+   * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check
1105b5975d6bSopenharmony_ci+   * all the tuple *elements* here, not just all the framing offsets, since
1106b5975d6bSopenharmony_ci+   * tuples contain a mix of elements which use framing offsets and ones which
1107b5975d6bSopenharmony_ci+   * don’t. None of them are allowed to overlap. */
1108b5975d6bSopenharmony_ci+  if (index_ > value.ordered_offsets_up_to)
1109b5975d6bSopenharmony_ci+    {
1110b5975d6bSopenharmony_ci+      gsize i, prev_i_end = 0;
1111b5975d6bSopenharmony_ci+
1112b5975d6bSopenharmony_ci+      if (value.ordered_offsets_up_to > 0)
1113b5975d6bSopenharmony_ci+        gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
1114b5975d6bSopenharmony_ci+
1115b5975d6bSopenharmony_ci+      for (i = value.ordered_offsets_up_to; i <= index_; i++)
1116b5975d6bSopenharmony_ci+        {
1117b5975d6bSopenharmony_ci+          gsize i_start, i_end;
1118b5975d6bSopenharmony_ci+
1119b5975d6bSopenharmony_ci+          gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end);
1120b5975d6bSopenharmony_ci+
1121b5975d6bSopenharmony_ci+          if (i_start > i_end || i_start < prev_i_end || i_end > value.size)
1122b5975d6bSopenharmony_ci+            break;
1123b5975d6bSopenharmony_ci+
1124b5975d6bSopenharmony_ci+          prev_i_end = i_end;
1125b5975d6bSopenharmony_ci+        }
1126b5975d6bSopenharmony_ci+
1127b5975d6bSopenharmony_ci+      value.ordered_offsets_up_to = i - 1;
1128b5975d6bSopenharmony_ci+    }
1129b5975d6bSopenharmony_ci+
1130b5975d6bSopenharmony_ci+  if (index_ > value.ordered_offsets_up_to)
1131b5975d6bSopenharmony_ci+    {
1132b5975d6bSopenharmony_ci+      /* Offsets are invalid somewhere, so return an empty child. */
1133b5975d6bSopenharmony_ci+      return child;
1134b5975d6bSopenharmony_ci+    }
1135b5975d6bSopenharmony_ci+
1136b5975d6bSopenharmony_ci   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1137b5975d6bSopenharmony_ci     {
1138b5975d6bSopenharmony_ci       if (offset_size * (member_info->i + 2) > value.size)
1139b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h
1140b5975d6bSopenharmony_ciindex a1bccb834b..661bd8fd1b 100644
1141b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.h
1142b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.h
1143b5975d6bSopenharmony_ci@@ -37,8 +37,11 @@ typedef struct
1144b5975d6bSopenharmony_ci    * This guarantees that the bytes of element n don't overlap with any previous
1145b5975d6bSopenharmony_ci    * element.
1146b5975d6bSopenharmony_ci    *
1147b5975d6bSopenharmony_ci-   * This is both read and set by g_variant_serialised_get_child for arrays of
1148b5975d6bSopenharmony_ci-   * non-fixed-width types */
1149b5975d6bSopenharmony_ci+   * This is both read and set by g_variant_serialised_get_child() for arrays of
1150b5975d6bSopenharmony_ci+   * non-fixed-width types, and for tuples.
1151b5975d6bSopenharmony_ci+   *
1152b5975d6bSopenharmony_ci+   * Even when dealing with tuples, @ordered_offsets_up_to is an element index,
1153b5975d6bSopenharmony_ci+   * rather than an index into the frame offsets. */
1154b5975d6bSopenharmony_ci   gsize             ordered_offsets_up_to;
1155b5975d6bSopenharmony_ci } GVariantSerialised;
1156b5975d6bSopenharmony_ci 
1157b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
1158b5975d6bSopenharmony_ciindex e4c85ca636..4f0d6b83c6 100644
1159b5975d6bSopenharmony_ci--- a/glib/gvariant.c
1160b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
1161b5975d6bSopenharmony_ci@@ -6011,6 +6011,7 @@ g_variant_byteswap (GVariant *value)
1162b5975d6bSopenharmony_ci       serialised.size = g_variant_get_size (trusted);
1163b5975d6bSopenharmony_ci       serialised.data = g_malloc (serialised.size);
1164b5975d6bSopenharmony_ci       serialised.depth = g_variant_get_depth (trusted);
1165b5975d6bSopenharmony_ci+      serialised.ordered_offsets_up_to = G_MAXSIZE;  /* operating on the normal form */
1166b5975d6bSopenharmony_ci       g_variant_store (trusted, serialised.data);
1167b5975d6bSopenharmony_ci       g_variant_unref (trusted);
1168b5975d6bSopenharmony_ci 
1169b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
1170b5975d6bSopenharmony_ciindex 45e302c926..4ae52e2bb9 100644
1171b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
1172b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
1173b5975d6bSopenharmony_ci@@ -1,6 +1,7 @@
1174b5975d6bSopenharmony_ci /*
1175b5975d6bSopenharmony_ci  * Copyright © 2010 Codethink Limited
1176b5975d6bSopenharmony_ci  * Copyright © 2020 William Manley
1177b5975d6bSopenharmony_ci+ * Copyright © 2022 Endless OS Foundation, LLC
1178b5975d6bSopenharmony_ci  *
1179b5975d6bSopenharmony_ci  * This library is free software; you can redistribute it and/or
1180b5975d6bSopenharmony_ci  * modify it under the terms of the GNU Lesser General Public
1181b5975d6bSopenharmony_ci@@ -1449,6 +1450,7 @@ test_maybe (void)
1182b5975d6bSopenharmony_ci         serialised.data = flavoured_malloc (needed_size, flavour);
1183b5975d6bSopenharmony_ci         serialised.size = needed_size;
1184b5975d6bSopenharmony_ci         serialised.depth = 0;
1185b5975d6bSopenharmony_ci+        serialised.ordered_offsets_up_to = 0;
1186b5975d6bSopenharmony_ci 
1187b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised,
1188b5975d6bSopenharmony_ci                                         random_instance_filler,
1189b5975d6bSopenharmony_ci@@ -1572,6 +1574,7 @@ test_array (void)
1190b5975d6bSopenharmony_ci         serialised.data = flavoured_malloc (needed_size, flavour);
1191b5975d6bSopenharmony_ci         serialised.size = needed_size;
1192b5975d6bSopenharmony_ci         serialised.depth = 0;
1193b5975d6bSopenharmony_ci+        serialised.ordered_offsets_up_to = 0;
1194b5975d6bSopenharmony_ci 
1195b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised, random_instance_filler,
1196b5975d6bSopenharmony_ci                                         (gpointer *) instances, n_children);
1197b5975d6bSopenharmony_ci@@ -1736,6 +1739,7 @@ test_tuple (void)
1198b5975d6bSopenharmony_ci         serialised.data = flavoured_malloc (needed_size, flavour);
1199b5975d6bSopenharmony_ci         serialised.size = needed_size;
1200b5975d6bSopenharmony_ci         serialised.depth = 0;
1201b5975d6bSopenharmony_ci+        serialised.ordered_offsets_up_to = 0;
1202b5975d6bSopenharmony_ci 
1203b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised, random_instance_filler,
1204b5975d6bSopenharmony_ci                                         (gpointer *) instances, n_children);
1205b5975d6bSopenharmony_ci@@ -1832,6 +1836,7 @@ test_variant (void)
1206b5975d6bSopenharmony_ci         serialised.data = flavoured_malloc (needed_size, flavour);
1207b5975d6bSopenharmony_ci         serialised.size = needed_size;
1208b5975d6bSopenharmony_ci         serialised.depth = 0;
1209b5975d6bSopenharmony_ci+        serialised.ordered_offsets_up_to = 0;
1210b5975d6bSopenharmony_ci 
1211b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised, random_instance_filler,
1212b5975d6bSopenharmony_ci                                         (gpointer *) &instance, 1);
1213b5975d6bSopenharmony_ci@@ -5210,6 +5215,176 @@ test_normal_checking_tuple_offsets (void)
1214b5975d6bSopenharmony_ci   g_variant_unref (variant);
1215b5975d6bSopenharmony_ci }
1216b5975d6bSopenharmony_ci 
1217b5975d6bSopenharmony_ci+/* This is a regression test that we can't have non-normal values that take up
1218b5975d6bSopenharmony_ci+ * significantly more space than the normal equivalent, by specifying the
1219b5975d6bSopenharmony_ci+ * offset table entries so that tuple elements overlap.
1220b5975d6bSopenharmony_ci+ *
1221b5975d6bSopenharmony_ci+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838503 and
1222b5975d6bSopenharmony_ci+ * https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838513 */
1223b5975d6bSopenharmony_ci+static void
1224b5975d6bSopenharmony_ci+test_normal_checking_tuple_offsets2 (void)
1225b5975d6bSopenharmony_ci+{
1226b5975d6bSopenharmony_ci+  const GVariantType *data_type = G_VARIANT_TYPE ("(yyaiyyaiyy)");
1227b5975d6bSopenharmony_ci+  const guint8 data[] = {
1228b5975d6bSopenharmony_ci+    0x12, 0x34, 0x56, 0x78, 0x01,
1229b5975d6bSopenharmony_ci+    /*
1230b5975d6bSopenharmony_ci+         ^───────────────────┘
1231b5975d6bSopenharmony_ci+
1232b5975d6bSopenharmony_ci+    ^^^^^^^^^^                   1st yy
1233b5975d6bSopenharmony_ci+          ^^^^^^^^^^             2nd yy
1234b5975d6bSopenharmony_ci+                ^^^^^^^^^^       3rd yy
1235b5975d6bSopenharmony_ci+                            ^^^^ Framing offsets
1236b5975d6bSopenharmony_ci+     */
1237b5975d6bSopenharmony_ci+
1238b5975d6bSopenharmony_ci+  /* If this variant was encoded normally, it would be something like this:
1239b5975d6bSopenharmony_ci+   * 0x12, 0x34,  pad,  pad, [array bytes], 0x56, 0x78,  pad,  pad, [array bytes], 0x9A, 0xBC, 0xXX
1240b5975d6bSopenharmony_ci+   *                                      ^─────────────────────────────────────────────────────┘
1241b5975d6bSopenharmony_ci+   *
1242b5975d6bSopenharmony_ci+   * ^^^^^^^^^^                                                                                     1st yy
1243b5975d6bSopenharmony_ci+   *                                        ^^^^^^^^^^                                              2nd yy
1244b5975d6bSopenharmony_ci+   *                                                                               ^^^^^^^^^^       3rd yy
1245b5975d6bSopenharmony_ci+   *                                                                                           ^^^^ Framing offsets
1246b5975d6bSopenharmony_ci+   */
1247b5975d6bSopenharmony_ci+  };
1248b5975d6bSopenharmony_ci+  gsize size = sizeof (data);
1249b5975d6bSopenharmony_ci+  GVariant *variant = NULL;
1250b5975d6bSopenharmony_ci+  GVariant *normal_variant = NULL;
1251b5975d6bSopenharmony_ci+  GVariant *expected = NULL;
1252b5975d6bSopenharmony_ci+
1253b5975d6bSopenharmony_ci+  variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
1254b5975d6bSopenharmony_ci+  g_assert_nonnull (variant);
1255b5975d6bSopenharmony_ci+
1256b5975d6bSopenharmony_ci+  normal_variant = g_variant_get_normal_form (variant);
1257b5975d6bSopenharmony_ci+  g_assert_nonnull (normal_variant);
1258b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3);
1259b5975d6bSopenharmony_ci+
1260b5975d6bSopenharmony_ci+  expected = g_variant_new_parsed (
1261b5975d6bSopenharmony_ci+      "@(yyaiyyaiyy) (0x12, 0x34, [], 0x00, 0x00, [], 0x00, 0x00)");
1262b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, variant);
1263b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, normal_variant);
1264b5975d6bSopenharmony_ci+
1265b5975d6bSopenharmony_ci+  g_variant_unref (expected);
1266b5975d6bSopenharmony_ci+  g_variant_unref (normal_variant);
1267b5975d6bSopenharmony_ci+  g_variant_unref (variant);
1268b5975d6bSopenharmony_ci+}
1269b5975d6bSopenharmony_ci+
1270b5975d6bSopenharmony_ci+/* This is a regression test that overlapping entries in the offset table are
1271b5975d6bSopenharmony_ci+ * decoded consistently, even though they’re non-normal.
1272b5975d6bSopenharmony_ci+ *
1273b5975d6bSopenharmony_ci+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */
1274b5975d6bSopenharmony_ci+static void
1275b5975d6bSopenharmony_ci+test_normal_checking_tuple_offsets3 (void)
1276b5975d6bSopenharmony_ci+{
1277b5975d6bSopenharmony_ci+  /* The expected decoding of this non-normal byte stream is complex. See
1278b5975d6bSopenharmony_ci+   * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant
1279b5975d6bSopenharmony_ci+   * specification.
1280b5975d6bSopenharmony_ci+   *
1281b5975d6bSopenharmony_ci+   * The rule “Child Values Overlapping Framing Offsets” from the specification
1282b5975d6bSopenharmony_ci+   * says that the first `ay` must be decoded as `[0x01]` even though it
1283b5975d6bSopenharmony_ci+   * overlaps the first byte of the offset table. However, since commit
1284b5975d6bSopenharmony_ci+   * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow
1285b5975d6bSopenharmony_ci+   * this as it’s exploitable. So the first `ay` must be given a default value.
1286b5975d6bSopenharmony_ci+   *
1287b5975d6bSopenharmony_ci+   * The second and third `ay`s must be given default values because of rule
1288b5975d6bSopenharmony_ci+   * “End Boundary Precedes Start Boundary”.
1289b5975d6bSopenharmony_ci+   *
1290b5975d6bSopenharmony_ci+   * The `i` must be given a default value because of rule “Start or End
1291b5975d6bSopenharmony_ci+   * Boundary of a Child Falls Outside the Container”.
1292b5975d6bSopenharmony_ci+   */
1293b5975d6bSopenharmony_ci+  const GVariantType *data_type = G_VARIANT_TYPE ("(ayayiay)");
1294b5975d6bSopenharmony_ci+  const guint8 data[] = {
1295b5975d6bSopenharmony_ci+    0x01, 0x00, 0x02,
1296b5975d6bSopenharmony_ci+    /*
1297b5975d6bSopenharmony_ci+               ^──┘
1298b5975d6bSopenharmony_ci+
1299b5975d6bSopenharmony_ci+    ^^^^^^^^^^                   1st ay, bytes 0-2 (but given a default value anyway, see above)
1300b5975d6bSopenharmony_ci+                                 2nd ay, bytes 2-0
1301b5975d6bSopenharmony_ci+                                     i,  bytes 0-4
1302b5975d6bSopenharmony_ci+                                 3rd ay, bytes 4-1
1303b5975d6bSopenharmony_ci+          ^^^^^^^^^^ Framing offsets
1304b5975d6bSopenharmony_ci+     */
1305b5975d6bSopenharmony_ci+  };
1306b5975d6bSopenharmony_ci+  gsize size = sizeof (data);
1307b5975d6bSopenharmony_ci+  GVariant *variant = NULL;
1308b5975d6bSopenharmony_ci+  GVariant *normal_variant = NULL;
1309b5975d6bSopenharmony_ci+  GVariant *expected = NULL;
1310b5975d6bSopenharmony_ci+
1311b5975d6bSopenharmony_ci+  variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
1312b5975d6bSopenharmony_ci+  g_assert_nonnull (variant);
1313b5975d6bSopenharmony_ci+
1314b5975d6bSopenharmony_ci+  g_assert_false (g_variant_is_normal_form (variant));
1315b5975d6bSopenharmony_ci+
1316b5975d6bSopenharmony_ci+  normal_variant = g_variant_get_normal_form (variant);
1317b5975d6bSopenharmony_ci+  g_assert_nonnull (normal_variant);
1318b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3);
1319b5975d6bSopenharmony_ci+
1320b5975d6bSopenharmony_ci+  expected = g_variant_new_parsed ("@(ayayiay) ([], [], 0, [])");
1321b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, variant);
1322b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, normal_variant);
1323b5975d6bSopenharmony_ci+
1324b5975d6bSopenharmony_ci+  g_variant_unref (expected);
1325b5975d6bSopenharmony_ci+  g_variant_unref (normal_variant);
1326b5975d6bSopenharmony_ci+  g_variant_unref (variant);
1327b5975d6bSopenharmony_ci+}
1328b5975d6bSopenharmony_ci+
1329b5975d6bSopenharmony_ci+/* This is a regression test that overlapping entries in the offset table are
1330b5975d6bSopenharmony_ci+ * decoded consistently, even though they’re non-normal.
1331b5975d6bSopenharmony_ci+ *
1332b5975d6bSopenharmony_ci+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */
1333b5975d6bSopenharmony_ci+static void
1334b5975d6bSopenharmony_ci+test_normal_checking_tuple_offsets4 (void)
1335b5975d6bSopenharmony_ci+{
1336b5975d6bSopenharmony_ci+  /* The expected decoding of this non-normal byte stream is complex. See
1337b5975d6bSopenharmony_ci+   * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant
1338b5975d6bSopenharmony_ci+   * specification.
1339b5975d6bSopenharmony_ci+   *
1340b5975d6bSopenharmony_ci+   * The rule “Child Values Overlapping Framing Offsets” from the specification
1341b5975d6bSopenharmony_ci+   * says that the first `ay` must be decoded as `[0x01]` even though it
1342b5975d6bSopenharmony_ci+   * overlaps the first byte of the offset table. However, since commit
1343b5975d6bSopenharmony_ci+   * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow
1344b5975d6bSopenharmony_ci+   * this as it’s exploitable. So the first `ay` must be given a default value.
1345b5975d6bSopenharmony_ci+   *
1346b5975d6bSopenharmony_ci+   * The second `ay` must be given a default value because of rule “End Boundary
1347b5975d6bSopenharmony_ci+   * Precedes Start Boundary”.
1348b5975d6bSopenharmony_ci+   *
1349b5975d6bSopenharmony_ci+   * The third `ay` must be given a default value because its framing offsets
1350b5975d6bSopenharmony_ci+   * overlap that of the first `ay`.
1351b5975d6bSopenharmony_ci+   */
1352b5975d6bSopenharmony_ci+  const GVariantType *data_type = G_VARIANT_TYPE ("(ayayay)");
1353b5975d6bSopenharmony_ci+  const guint8 data[] = {
1354b5975d6bSopenharmony_ci+    0x01, 0x00, 0x02,
1355b5975d6bSopenharmony_ci+    /*
1356b5975d6bSopenharmony_ci+               ^──┘
1357b5975d6bSopenharmony_ci+
1358b5975d6bSopenharmony_ci+    ^^^^^^^^^^                   1st ay, bytes 0-2 (but given a default value anyway, see above)
1359b5975d6bSopenharmony_ci+                                 2nd ay, bytes 2-0
1360b5975d6bSopenharmony_ci+                                 3rd ay, bytes 0-1
1361b5975d6bSopenharmony_ci+          ^^^^^^^^^^ Framing offsets
1362b5975d6bSopenharmony_ci+     */
1363b5975d6bSopenharmony_ci+  };
1364b5975d6bSopenharmony_ci+  gsize size = sizeof (data);
1365b5975d6bSopenharmony_ci+  GVariant *variant = NULL;
1366b5975d6bSopenharmony_ci+  GVariant *normal_variant = NULL;
1367b5975d6bSopenharmony_ci+  GVariant *expected = NULL;
1368b5975d6bSopenharmony_ci+
1369b5975d6bSopenharmony_ci+  variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
1370b5975d6bSopenharmony_ci+  g_assert_nonnull (variant);
1371b5975d6bSopenharmony_ci+
1372b5975d6bSopenharmony_ci+  g_assert_false (g_variant_is_normal_form (variant));
1373b5975d6bSopenharmony_ci+
1374b5975d6bSopenharmony_ci+  normal_variant = g_variant_get_normal_form (variant);
1375b5975d6bSopenharmony_ci+  g_assert_nonnull (normal_variant);
1376b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3);
1377b5975d6bSopenharmony_ci+
1378b5975d6bSopenharmony_ci+  expected = g_variant_new_parsed ("@(ayayay) ([], [], [])");
1379b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, variant);
1380b5975d6bSopenharmony_ci+  g_assert_cmpvariant (expected, normal_variant);
1381b5975d6bSopenharmony_ci+
1382b5975d6bSopenharmony_ci+  g_variant_unref (expected);
1383b5975d6bSopenharmony_ci+  g_variant_unref (normal_variant);
1384b5975d6bSopenharmony_ci+  g_variant_unref (variant);
1385b5975d6bSopenharmony_ci+}
1386b5975d6bSopenharmony_ci+
1387b5975d6bSopenharmony_ci /* Test that an empty object path is normalised successfully to the base object
1388b5975d6bSopenharmony_ci  * path, ‘/’. */
1389b5975d6bSopenharmony_ci static void
1390b5975d6bSopenharmony_ci@@ -5358,6 +5533,12 @@ main (int argc, char **argv)
1391b5975d6bSopenharmony_ci                    test_normal_checking_array_offsets2);
1392b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
1393b5975d6bSopenharmony_ci                    test_normal_checking_tuple_offsets);
1394b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/tuple-offsets2",
1395b5975d6bSopenharmony_ci+                   test_normal_checking_tuple_offsets2);
1396b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/tuple-offsets3",
1397b5975d6bSopenharmony_ci+                   test_normal_checking_tuple_offsets3);
1398b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/tuple-offsets4",
1399b5975d6bSopenharmony_ci+                   test_normal_checking_tuple_offsets4);
1400b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/empty-object-path",
1401b5975d6bSopenharmony_ci                    test_normal_checking_empty_object_path);
1402b5975d6bSopenharmony_ci 
1403b5975d6bSopenharmony_ci-- 
1404b5975d6bSopenharmony_ciGitLab
1405b5975d6bSopenharmony_ci
1406b5975d6bSopenharmony_ci
1407b5975d6bSopenharmony_ciFrom d1a293c4e29880b8d17bb826c9a426a440ca4a91 Mon Sep 17 00:00:00 2001
1408b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
1409b5975d6bSopenharmony_ciDate: Tue, 25 Oct 2022 15:14:14 +0100
1410b5975d6bSopenharmony_ciSubject: [PATCH 08/18] gvariant: Track checked and ordered offsets
1411b5975d6bSopenharmony_ci independently
1412b5975d6bSopenharmony_ci
1413b5975d6bSopenharmony_ciThe past few commits introduced the concept of known-good offsets in the
1414b5975d6bSopenharmony_cioffset table (which is used for variable-width arrays and tuples).
1415b5975d6bSopenharmony_ciGood offsets are ones which are non-overlapping with all the previous
1416b5975d6bSopenharmony_cioffsets in the table.
1417b5975d6bSopenharmony_ci
1418b5975d6bSopenharmony_ciIf a bad offset is encountered when indexing into the array or tuple,
1419b5975d6bSopenharmony_cithe cached known-good offset index will not be increased. In this way,
1420b5975d6bSopenharmony_ciall child variants at and beyond the first bad offset can be returned as
1421b5975d6bSopenharmony_cidefault values rather than dereferencing potentially invalid data.
1422b5975d6bSopenharmony_ci
1423b5975d6bSopenharmony_ciIn this case, there was no information about the fact that the indexes
1424b5975d6bSopenharmony_cibetween the highest known-good index and the requested one had been
1425b5975d6bSopenharmony_cichecked already. That could lead to a pathological case where an offset
1426b5975d6bSopenharmony_citable with an invalid first offset is repeatedly checked in full when
1427b5975d6bSopenharmony_citrying to access higher-indexed children.
1428b5975d6bSopenharmony_ci
1429b5975d6bSopenharmony_ciAvoid that by storing the index of the highest checked offset in the
1430b5975d6bSopenharmony_citable, as well as the index of the highest good/ordered offset.
1431b5975d6bSopenharmony_ci
1432b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
1433b5975d6bSopenharmony_ci
1434b5975d6bSopenharmony_ciHelps: #2121
1435b5975d6bSopenharmony_ci---
1436b5975d6bSopenharmony_ci glib/gvariant-core.c       | 28 ++++++++++++++++++++++++
1437b5975d6bSopenharmony_ci glib/gvariant-serialiser.c | 44 +++++++++++++++++++++++++++-----------
1438b5975d6bSopenharmony_ci glib/gvariant-serialiser.h |  9 ++++++++
1439b5975d6bSopenharmony_ci glib/gvariant.c            |  1 +
1440b5975d6bSopenharmony_ci glib/tests/gvariant.c      |  5 +++++
1441b5975d6bSopenharmony_ci 5 files changed, 75 insertions(+), 12 deletions(-)
1442b5975d6bSopenharmony_ci
1443b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
1444b5975d6bSopenharmony_ciindex 4419371136..f660e2d578 100644
1445b5975d6bSopenharmony_ci--- a/glib/gvariant-core.c
1446b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.c
1447b5975d6bSopenharmony_ci@@ -69,6 +69,7 @@ struct _GVariant
1448b5975d6bSopenharmony_ci       GBytes *bytes;
1449b5975d6bSopenharmony_ci       gconstpointer data;
1450b5975d6bSopenharmony_ci       gsize ordered_offsets_up_to;
1451b5975d6bSopenharmony_ci+      gsize checked_offsets_up_to;
1452b5975d6bSopenharmony_ci     } serialised;
1453b5975d6bSopenharmony_ci 
1454b5975d6bSopenharmony_ci     struct
1455b5975d6bSopenharmony_ci@@ -184,6 +185,24 @@ struct _GVariant
1456b5975d6bSopenharmony_ci  *                             This field is only relevant for arrays of non
1457b5975d6bSopenharmony_ci  *                             fixed width types and for tuples.
1458b5975d6bSopenharmony_ci  *
1459b5975d6bSopenharmony_ci+ *     .checked_offsets_up_to: Similarly to .ordered_offsets_up_to, this stores
1460b5975d6bSopenharmony_ci+ *                             the index of the highest element, n, whose frame
1461b5975d6bSopenharmony_ci+ *                             offsets (and all the preceding frame offsets)
1462b5975d6bSopenharmony_ci+ *                             have been checked for validity.
1463b5975d6bSopenharmony_ci+ *
1464b5975d6bSopenharmony_ci+ *                             It is always the case that
1465b5975d6bSopenharmony_ci+ *                             .checked_offsets_up_to ≥ .ordered_offsets_up_to.
1466b5975d6bSopenharmony_ci+ *
1467b5975d6bSopenharmony_ci+ *                             If .checked_offsets_up_to == .ordered_offsets_up_to,
1468b5975d6bSopenharmony_ci+ *                             then a bad offset has not been found so far.
1469b5975d6bSopenharmony_ci+ *
1470b5975d6bSopenharmony_ci+ *                             If .checked_offsets_up_to > .ordered_offsets_up_to,
1471b5975d6bSopenharmony_ci+ *                             then a bad offset has been found at
1472b5975d6bSopenharmony_ci+ *                             (.ordered_offsets_up_to + 1).
1473b5975d6bSopenharmony_ci+ *
1474b5975d6bSopenharmony_ci+ *                             This field is only relevant for arrays of non
1475b5975d6bSopenharmony_ci+ *                             fixed width types and for tuples.
1476b5975d6bSopenharmony_ci+ *
1477b5975d6bSopenharmony_ci  *   .tree: Only valid when the instance is in tree form.
1478b5975d6bSopenharmony_ci  *
1479b5975d6bSopenharmony_ci  *          Note that accesses from other threads could result in
1480b5975d6bSopenharmony_ci@@ -388,6 +407,7 @@ g_variant_to_serialised (GVariant *value)
1481b5975d6bSopenharmony_ci       value->size,
1482b5975d6bSopenharmony_ci       value->depth,
1483b5975d6bSopenharmony_ci       value->contents.serialised.ordered_offsets_up_to,
1484b5975d6bSopenharmony_ci+      value->contents.serialised.checked_offsets_up_to,
1485b5975d6bSopenharmony_ci     };
1486b5975d6bSopenharmony_ci     return serialised;
1487b5975d6bSopenharmony_ci   }
1488b5975d6bSopenharmony_ci@@ -420,6 +440,7 @@ g_variant_serialise (GVariant *value,
1489b5975d6bSopenharmony_ci   serialised.data = data;
1490b5975d6bSopenharmony_ci   serialised.depth = value->depth;
1491b5975d6bSopenharmony_ci   serialised.ordered_offsets_up_to = 0;
1492b5975d6bSopenharmony_ci+  serialised.checked_offsets_up_to = 0;
1493b5975d6bSopenharmony_ci 
1494b5975d6bSopenharmony_ci   children = (gpointer *) value->contents.tree.children;
1495b5975d6bSopenharmony_ci   n_children = value->contents.tree.n_children;
1496b5975d6bSopenharmony_ci@@ -466,10 +487,12 @@ g_variant_fill_gvs (GVariantSerialised *serialised,
1497b5975d6bSopenharmony_ci   if (value->state & STATE_SERIALISED)
1498b5975d6bSopenharmony_ci     {
1499b5975d6bSopenharmony_ci       serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to;
1500b5975d6bSopenharmony_ci+      serialised->checked_offsets_up_to = value->contents.serialised.checked_offsets_up_to;
1501b5975d6bSopenharmony_ci     }
1502b5975d6bSopenharmony_ci   else
1503b5975d6bSopenharmony_ci     {
1504b5975d6bSopenharmony_ci       serialised->ordered_offsets_up_to = 0;
1505b5975d6bSopenharmony_ci+      serialised->checked_offsets_up_to = 0;
1506b5975d6bSopenharmony_ci     }
1507b5975d6bSopenharmony_ci 
1508b5975d6bSopenharmony_ci   if (serialised->data)
1509b5975d6bSopenharmony_ci@@ -515,6 +538,7 @@ g_variant_ensure_serialised (GVariant *value)
1510b5975d6bSopenharmony_ci       value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
1511b5975d6bSopenharmony_ci       value->contents.serialised.bytes = bytes;
1512b5975d6bSopenharmony_ci       value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE;
1513b5975d6bSopenharmony_ci+      value->contents.serialised.checked_offsets_up_to = G_MAXSIZE;
1514b5975d6bSopenharmony_ci       value->state |= STATE_SERIALISED;
1515b5975d6bSopenharmony_ci     }
1516b5975d6bSopenharmony_ci }
1517b5975d6bSopenharmony_ci@@ -596,6 +620,7 @@ g_variant_new_from_bytes (const GVariantType *type,
1518b5975d6bSopenharmony_ci   serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size);
1519b5975d6bSopenharmony_ci   serialised.depth = 0;
1520b5975d6bSopenharmony_ci   serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0;
1521b5975d6bSopenharmony_ci+  serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0;
1522b5975d6bSopenharmony_ci 
1523b5975d6bSopenharmony_ci   if (!g_variant_serialised_check (serialised))
1524b5975d6bSopenharmony_ci     {
1525b5975d6bSopenharmony_ci@@ -647,6 +672,7 @@ g_variant_new_from_bytes (const GVariantType *type,
1526b5975d6bSopenharmony_ci     }
1527b5975d6bSopenharmony_ci 
1528b5975d6bSopenharmony_ci   value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0;
1529b5975d6bSopenharmony_ci+  value->contents.serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0;
1530b5975d6bSopenharmony_ci 
1531b5975d6bSopenharmony_ci   g_clear_pointer (&owned_bytes, g_bytes_unref);
1532b5975d6bSopenharmony_ci 
1533b5975d6bSopenharmony_ci@@ -1144,6 +1170,7 @@ g_variant_get_child_value (GVariant *value,
1534b5975d6bSopenharmony_ci 
1535b5975d6bSopenharmony_ci     /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */
1536b5975d6bSopenharmony_ci     value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to);
1537b5975d6bSopenharmony_ci+    value->contents.serialised.checked_offsets_up_to = MAX (value->contents.serialised.checked_offsets_up_to, serialised.checked_offsets_up_to);
1538b5975d6bSopenharmony_ci 
1539b5975d6bSopenharmony_ci     /* Check whether this would cause nesting too deep. If so, return a fake
1540b5975d6bSopenharmony_ci      * child. The only situation we expect this to happen in is with a variant,
1541b5975d6bSopenharmony_ci@@ -1171,6 +1198,7 @@ g_variant_get_child_value (GVariant *value,
1542b5975d6bSopenharmony_ci       g_bytes_ref (value->contents.serialised.bytes);
1543b5975d6bSopenharmony_ci     child->contents.serialised.data = s_child.data;
1544b5975d6bSopenharmony_ci     child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to;
1545b5975d6bSopenharmony_ci+    child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to;
1546b5975d6bSopenharmony_ci 
1547b5975d6bSopenharmony_ci     return child;
1548b5975d6bSopenharmony_ci   }
1549b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
1550b5975d6bSopenharmony_ciindex 263b74048c..69baeeb395 100644
1551b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
1552b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
1553b5975d6bSopenharmony_ci@@ -122,6 +122,8 @@
1554b5975d6bSopenharmony_ci  *
1555b5975d6bSopenharmony_ci  * @depth has no restrictions; the depth of a top-level serialized #GVariant is
1556b5975d6bSopenharmony_ci  * zero, and it increases for each level of nested child.
1557b5975d6bSopenharmony_ci+ *
1558b5975d6bSopenharmony_ci+ * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to
1559b5975d6bSopenharmony_ci  */
1560b5975d6bSopenharmony_ci 
1561b5975d6bSopenharmony_ci /* < private >
1562b5975d6bSopenharmony_ci@@ -149,6 +151,9 @@ g_variant_serialised_check (GVariantSerialised serialised)
1563b5975d6bSopenharmony_ci            !(serialised.size == 0 || serialised.data != NULL))
1564b5975d6bSopenharmony_ci     return FALSE;
1565b5975d6bSopenharmony_ci 
1566b5975d6bSopenharmony_ci+  if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to)
1567b5975d6bSopenharmony_ci+    return FALSE;
1568b5975d6bSopenharmony_ci+
1569b5975d6bSopenharmony_ci   /* Depending on the native alignment requirements of the machine, the
1570b5975d6bSopenharmony_ci    * compiler will insert either 3 or 7 padding bytes after the char.
1571b5975d6bSopenharmony_ci    * This will result in the sizeof() the struct being 12 or 16.
1572b5975d6bSopenharmony_ci@@ -268,6 +273,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
1573b5975d6bSopenharmony_ci   g_variant_type_info_ref (value.type_info);
1574b5975d6bSopenharmony_ci   value.depth++;
1575b5975d6bSopenharmony_ci   value.ordered_offsets_up_to = 0;
1576b5975d6bSopenharmony_ci+  value.checked_offsets_up_to = 0;
1577b5975d6bSopenharmony_ci 
1578b5975d6bSopenharmony_ci   return value;
1579b5975d6bSopenharmony_ci }
1580b5975d6bSopenharmony_ci@@ -299,7 +305,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
1581b5975d6bSopenharmony_ci {
1582b5975d6bSopenharmony_ci   if (n_children)
1583b5975d6bSopenharmony_ci     {
1584b5975d6bSopenharmony_ci-      GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 };
1585b5975d6bSopenharmony_ci+      GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 };
1586b5975d6bSopenharmony_ci 
1587b5975d6bSopenharmony_ci       gvs_filler (&child, children[0]);
1588b5975d6bSopenharmony_ci     }
1589b5975d6bSopenharmony_ci@@ -322,6 +328,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
1590b5975d6bSopenharmony_ci       value.type_info = g_variant_type_info_element (value.type_info);
1591b5975d6bSopenharmony_ci       value.depth++;
1592b5975d6bSopenharmony_ci       value.ordered_offsets_up_to = 0;
1593b5975d6bSopenharmony_ci+      value.checked_offsets_up_to = 0;
1594b5975d6bSopenharmony_ci 
1595b5975d6bSopenharmony_ci       return g_variant_serialised_is_normal (value);
1596b5975d6bSopenharmony_ci     }
1597b5975d6bSopenharmony_ci@@ -364,6 +371,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value,
1598b5975d6bSopenharmony_ci 
1599b5975d6bSopenharmony_ci   value.depth++;
1600b5975d6bSopenharmony_ci   value.ordered_offsets_up_to = 0;
1601b5975d6bSopenharmony_ci+  value.checked_offsets_up_to = 0;
1602b5975d6bSopenharmony_ci 
1603b5975d6bSopenharmony_ci   return value;
1604b5975d6bSopenharmony_ci }
1605b5975d6bSopenharmony_ci@@ -394,7 +402,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
1606b5975d6bSopenharmony_ci {
1607b5975d6bSopenharmony_ci   if (n_children)
1608b5975d6bSopenharmony_ci     {
1609b5975d6bSopenharmony_ci-      GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 };
1610b5975d6bSopenharmony_ci+      GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 };
1611b5975d6bSopenharmony_ci 
1612b5975d6bSopenharmony_ci       /* write the data for the child.  */
1613b5975d6bSopenharmony_ci       gvs_filler (&child, children[0]);
1614b5975d6bSopenharmony_ci@@ -415,6 +423,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
1615b5975d6bSopenharmony_ci   value.size--;
1616b5975d6bSopenharmony_ci   value.depth++;
1617b5975d6bSopenharmony_ci   value.ordered_offsets_up_to = 0;
1618b5975d6bSopenharmony_ci+  value.checked_offsets_up_to = 0;
1619b5975d6bSopenharmony_ci 
1620b5975d6bSopenharmony_ci   return g_variant_serialised_is_normal (value);
1621b5975d6bSopenharmony_ci }
1622b5975d6bSopenharmony_ci@@ -741,39 +750,46 @@ gvs_variable_sized_array_get_child (GVariantSerialised value,
1623b5975d6bSopenharmony_ci 
1624b5975d6bSopenharmony_ci   /* If the requested @index_ is beyond the set of indices whose framing offsets
1625b5975d6bSopenharmony_ci    * have been checked, check the remaining offsets to see whether they’re
1626b5975d6bSopenharmony_ci-   * normal (in order, no overlapping array elements). */
1627b5975d6bSopenharmony_ci-  if (index_ > value.ordered_offsets_up_to)
1628b5975d6bSopenharmony_ci+   * normal (in order, no overlapping array elements).
1629b5975d6bSopenharmony_ci+   *
1630b5975d6bSopenharmony_ci+   * Don’t bother checking if the highest known-good offset is lower than the
1631b5975d6bSopenharmony_ci+   * highest checked offset, as that means there’s an invalid element at that
1632b5975d6bSopenharmony_ci+   * index, so there’s no need to check further. */
1633b5975d6bSopenharmony_ci+  if (index_ > value.checked_offsets_up_to &&
1634b5975d6bSopenharmony_ci+      value.ordered_offsets_up_to == value.checked_offsets_up_to)
1635b5975d6bSopenharmony_ci     {
1636b5975d6bSopenharmony_ci       switch (offsets.offset_size)
1637b5975d6bSopenharmony_ci         {
1638b5975d6bSopenharmony_ci         case 1:
1639b5975d6bSopenharmony_ci           {
1640b5975d6bSopenharmony_ci             value.ordered_offsets_up_to = find_unordered_guint8 (
1641b5975d6bSopenharmony_ci-                offsets.array, value.ordered_offsets_up_to, index_ + 1);
1642b5975d6bSopenharmony_ci+                offsets.array, value.checked_offsets_up_to, index_ + 1);
1643b5975d6bSopenharmony_ci             break;
1644b5975d6bSopenharmony_ci           }
1645b5975d6bSopenharmony_ci         case 2:
1646b5975d6bSopenharmony_ci           {
1647b5975d6bSopenharmony_ci             value.ordered_offsets_up_to = find_unordered_guint16 (
1648b5975d6bSopenharmony_ci-                offsets.array, value.ordered_offsets_up_to, index_ + 1);
1649b5975d6bSopenharmony_ci+                offsets.array, value.checked_offsets_up_to, index_ + 1);
1650b5975d6bSopenharmony_ci             break;
1651b5975d6bSopenharmony_ci           }
1652b5975d6bSopenharmony_ci         case 4:
1653b5975d6bSopenharmony_ci           {
1654b5975d6bSopenharmony_ci             value.ordered_offsets_up_to = find_unordered_guint32 (
1655b5975d6bSopenharmony_ci-                offsets.array, value.ordered_offsets_up_to, index_ + 1);
1656b5975d6bSopenharmony_ci+                offsets.array, value.checked_offsets_up_to, index_ + 1);
1657b5975d6bSopenharmony_ci             break;
1658b5975d6bSopenharmony_ci           }
1659b5975d6bSopenharmony_ci         case 8:
1660b5975d6bSopenharmony_ci           {
1661b5975d6bSopenharmony_ci             value.ordered_offsets_up_to = find_unordered_guint64 (
1662b5975d6bSopenharmony_ci-                offsets.array, value.ordered_offsets_up_to, index_ + 1);
1663b5975d6bSopenharmony_ci+                offsets.array, value.checked_offsets_up_to, index_ + 1);
1664b5975d6bSopenharmony_ci             break;
1665b5975d6bSopenharmony_ci           }
1666b5975d6bSopenharmony_ci         default:
1667b5975d6bSopenharmony_ci           /* gvs_get_offset_size() only returns maximum 8 */
1668b5975d6bSopenharmony_ci           g_assert_not_reached ();
1669b5975d6bSopenharmony_ci         }
1670b5975d6bSopenharmony_ci+
1671b5975d6bSopenharmony_ci+      value.checked_offsets_up_to = index_;
1672b5975d6bSopenharmony_ci     }
1673b5975d6bSopenharmony_ci 
1674b5975d6bSopenharmony_ci   if (index_ > value.ordered_offsets_up_to)
1675b5975d6bSopenharmony_ci@@ -918,6 +934,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
1676b5975d6bSopenharmony_ci 
1677b5975d6bSopenharmony_ci   /* All offsets have now been checked. */
1678b5975d6bSopenharmony_ci   value.ordered_offsets_up_to = G_MAXSIZE;
1679b5975d6bSopenharmony_ci+  value.checked_offsets_up_to = G_MAXSIZE;
1680b5975d6bSopenharmony_ci 
1681b5975d6bSopenharmony_ci   return TRUE;
1682b5975d6bSopenharmony_ci }
1683b5975d6bSopenharmony_ci@@ -1042,14 +1059,15 @@ gvs_tuple_get_child (GVariantSerialised value,
1684b5975d6bSopenharmony_ci    * all the tuple *elements* here, not just all the framing offsets, since
1685b5975d6bSopenharmony_ci    * tuples contain a mix of elements which use framing offsets and ones which
1686b5975d6bSopenharmony_ci    * don’t. None of them are allowed to overlap. */
1687b5975d6bSopenharmony_ci-  if (index_ > value.ordered_offsets_up_to)
1688b5975d6bSopenharmony_ci+  if (index_ > value.checked_offsets_up_to &&
1689b5975d6bSopenharmony_ci+      value.ordered_offsets_up_to == value.checked_offsets_up_to)
1690b5975d6bSopenharmony_ci     {
1691b5975d6bSopenharmony_ci       gsize i, prev_i_end = 0;
1692b5975d6bSopenharmony_ci 
1693b5975d6bSopenharmony_ci-      if (value.ordered_offsets_up_to > 0)
1694b5975d6bSopenharmony_ci-        gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
1695b5975d6bSopenharmony_ci+      if (value.checked_offsets_up_to > 0)
1696b5975d6bSopenharmony_ci+        gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
1697b5975d6bSopenharmony_ci 
1698b5975d6bSopenharmony_ci-      for (i = value.ordered_offsets_up_to; i <= index_; i++)
1699b5975d6bSopenharmony_ci+      for (i = value.checked_offsets_up_to; i <= index_; i++)
1700b5975d6bSopenharmony_ci         {
1701b5975d6bSopenharmony_ci           gsize i_start, i_end;
1702b5975d6bSopenharmony_ci 
1703b5975d6bSopenharmony_ci@@ -1062,6 +1080,7 @@ gvs_tuple_get_child (GVariantSerialised value,
1704b5975d6bSopenharmony_ci         }
1705b5975d6bSopenharmony_ci 
1706b5975d6bSopenharmony_ci       value.ordered_offsets_up_to = i - 1;
1707b5975d6bSopenharmony_ci+      value.checked_offsets_up_to = index_;
1708b5975d6bSopenharmony_ci     }
1709b5975d6bSopenharmony_ci 
1710b5975d6bSopenharmony_ci   if (index_ > value.ordered_offsets_up_to)
1711b5975d6bSopenharmony_ci@@ -1263,6 +1282,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
1712b5975d6bSopenharmony_ci 
1713b5975d6bSopenharmony_ci   /* All element bounds have been checked above. */
1714b5975d6bSopenharmony_ci   value.ordered_offsets_up_to = G_MAXSIZE;
1715b5975d6bSopenharmony_ci+  value.checked_offsets_up_to = G_MAXSIZE;
1716b5975d6bSopenharmony_ci 
1717b5975d6bSopenharmony_ci   {
1718b5975d6bSopenharmony_ci     gsize fixed_size;
1719b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h
1720b5975d6bSopenharmony_ciindex 661bd8fd1b..eb74fe7804 100644
1721b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.h
1722b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.h
1723b5975d6bSopenharmony_ci@@ -43,6 +43,15 @@ typedef struct
1724b5975d6bSopenharmony_ci    * Even when dealing with tuples, @ordered_offsets_up_to is an element index,
1725b5975d6bSopenharmony_ci    * rather than an index into the frame offsets. */
1726b5975d6bSopenharmony_ci   gsize             ordered_offsets_up_to;
1727b5975d6bSopenharmony_ci+
1728b5975d6bSopenharmony_ci+  /* Similar to @ordered_offsets_up_to. This gives the index of the child element
1729b5975d6bSopenharmony_ci+   * whose frame offset is the highest in the offset table which has been
1730b5975d6bSopenharmony_ci+   * checked so far.
1731b5975d6bSopenharmony_ci+   *
1732b5975d6bSopenharmony_ci+   * This is always ≥ @ordered_offsets_up_to. It is always an element index.
1733b5975d6bSopenharmony_ci+   *
1734b5975d6bSopenharmony_ci+   * See documentation in gvariant-core.c for `struct GVariant` for details. */
1735b5975d6bSopenharmony_ci+  gsize             checked_offsets_up_to;
1736b5975d6bSopenharmony_ci } GVariantSerialised;
1737b5975d6bSopenharmony_ci 
1738b5975d6bSopenharmony_ci /* deserialization */
1739b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
1740b5975d6bSopenharmony_ciindex 4f0d6b83c6..fd066f1732 100644
1741b5975d6bSopenharmony_ci--- a/glib/gvariant.c
1742b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
1743b5975d6bSopenharmony_ci@@ -6012,6 +6012,7 @@ g_variant_byteswap (GVariant *value)
1744b5975d6bSopenharmony_ci       serialised.data = g_malloc (serialised.size);
1745b5975d6bSopenharmony_ci       serialised.depth = g_variant_get_depth (trusted);
1746b5975d6bSopenharmony_ci       serialised.ordered_offsets_up_to = G_MAXSIZE;  /* operating on the normal form */
1747b5975d6bSopenharmony_ci+      serialised.checked_offsets_up_to = G_MAXSIZE;
1748b5975d6bSopenharmony_ci       g_variant_store (trusted, serialised.data);
1749b5975d6bSopenharmony_ci       g_variant_unref (trusted);
1750b5975d6bSopenharmony_ci 
1751b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
1752b5975d6bSopenharmony_ciindex 4ae52e2bb9..d82aedd509 100644
1753b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
1754b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
1755b5975d6bSopenharmony_ci@@ -1284,6 +1284,7 @@ random_instance_filler (GVariantSerialised *serialised,
1756b5975d6bSopenharmony_ci 
1757b5975d6bSopenharmony_ci   serialised->depth = 0;
1758b5975d6bSopenharmony_ci   serialised->ordered_offsets_up_to = 0;
1759b5975d6bSopenharmony_ci+  serialised->checked_offsets_up_to = 0;
1760b5975d6bSopenharmony_ci 
1761b5975d6bSopenharmony_ci   g_assert_true (serialised->type_info == instance->type_info);
1762b5975d6bSopenharmony_ci   g_assert_cmpuint (serialised->size, ==, instance->size);
1763b5975d6bSopenharmony_ci@@ -1451,6 +1452,7 @@ test_maybe (void)
1764b5975d6bSopenharmony_ci         serialised.size = needed_size;
1765b5975d6bSopenharmony_ci         serialised.depth = 0;
1766b5975d6bSopenharmony_ci         serialised.ordered_offsets_up_to = 0;
1767b5975d6bSopenharmony_ci+        serialised.checked_offsets_up_to = 0;
1768b5975d6bSopenharmony_ci 
1769b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised,
1770b5975d6bSopenharmony_ci                                         random_instance_filler,
1771b5975d6bSopenharmony_ci@@ -1575,6 +1577,7 @@ test_array (void)
1772b5975d6bSopenharmony_ci         serialised.size = needed_size;
1773b5975d6bSopenharmony_ci         serialised.depth = 0;
1774b5975d6bSopenharmony_ci         serialised.ordered_offsets_up_to = 0;
1775b5975d6bSopenharmony_ci+        serialised.checked_offsets_up_to = 0;
1776b5975d6bSopenharmony_ci 
1777b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised, random_instance_filler,
1778b5975d6bSopenharmony_ci                                         (gpointer *) instances, n_children);
1779b5975d6bSopenharmony_ci@@ -1740,6 +1743,7 @@ test_tuple (void)
1780b5975d6bSopenharmony_ci         serialised.size = needed_size;
1781b5975d6bSopenharmony_ci         serialised.depth = 0;
1782b5975d6bSopenharmony_ci         serialised.ordered_offsets_up_to = 0;
1783b5975d6bSopenharmony_ci+        serialised.checked_offsets_up_to = 0;
1784b5975d6bSopenharmony_ci 
1785b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised, random_instance_filler,
1786b5975d6bSopenharmony_ci                                         (gpointer *) instances, n_children);
1787b5975d6bSopenharmony_ci@@ -1837,6 +1841,7 @@ test_variant (void)
1788b5975d6bSopenharmony_ci         serialised.size = needed_size;
1789b5975d6bSopenharmony_ci         serialised.depth = 0;
1790b5975d6bSopenharmony_ci         serialised.ordered_offsets_up_to = 0;
1791b5975d6bSopenharmony_ci+        serialised.checked_offsets_up_to = 0;
1792b5975d6bSopenharmony_ci 
1793b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised, random_instance_filler,
1794b5975d6bSopenharmony_ci                                         (gpointer *) &instance, 1);
1795b5975d6bSopenharmony_ci-- 
1796b5975d6bSopenharmony_ciGitLab
1797b5975d6bSopenharmony_ci
1798b5975d6bSopenharmony_ci
1799b5975d6bSopenharmony_ciFrom 6fa41d5bf61a249a395a83866c10fa4a79bbb7db Mon Sep 17 00:00:00 2001
1800b5975d6bSopenharmony_ciFrom: Philip Withnall <withnall@endlessm.com>
1801b5975d6bSopenharmony_ciDate: Fri, 12 Jun 2020 18:01:13 +0100
1802b5975d6bSopenharmony_ciSubject: [PATCH 09/18] tests: Add another test for overlapping offsets in
1803b5975d6bSopenharmony_ci GVariant
1804b5975d6bSopenharmony_ci
1805b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <withnall@endlessm.com>
1806b5975d6bSopenharmony_ci
1807b5975d6bSopenharmony_ciHelps: #2121
1808b5975d6bSopenharmony_ci---
1809b5975d6bSopenharmony_ci glib/tests/gvariant.c | 34 ++++++++++++++++++++++++++++++++++
1810b5975d6bSopenharmony_ci 1 file changed, 34 insertions(+)
1811b5975d6bSopenharmony_ci
1812b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
1813b5975d6bSopenharmony_ciindex d82aedd509..8ec94814e4 100644
1814b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
1815b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
1816b5975d6bSopenharmony_ci@@ -5131,6 +5131,38 @@ test_recursion_limits_array_in_variant (void)
1817b5975d6bSopenharmony_ci   g_variant_unref (wrapper_variant);
1818b5975d6bSopenharmony_ci }
1819b5975d6bSopenharmony_ci 
1820b5975d6bSopenharmony_ci+/* Test that a nested array with invalid values in its offset table (which point
1821b5975d6bSopenharmony_ci+ * from the inner to the outer array) is normalised successfully without
1822b5975d6bSopenharmony_ci+ * looping infinitely. */
1823b5975d6bSopenharmony_ci+static void
1824b5975d6bSopenharmony_ci+test_normal_checking_array_offsets_overlapped (void)
1825b5975d6bSopenharmony_ci+{
1826b5975d6bSopenharmony_ci+  const guint8 data[] = {
1827b5975d6bSopenharmony_ci+    0x01, 0x00,
1828b5975d6bSopenharmony_ci+  };
1829b5975d6bSopenharmony_ci+  gsize size = sizeof (data);
1830b5975d6bSopenharmony_ci+  GVariant *variant = NULL;
1831b5975d6bSopenharmony_ci+  GVariant *normal_variant = NULL;
1832b5975d6bSopenharmony_ci+  GVariant *expected_variant = NULL;
1833b5975d6bSopenharmony_ci+
1834b5975d6bSopenharmony_ci+  variant = g_variant_new_from_data (G_VARIANT_TYPE ("aay"), data, size,
1835b5975d6bSopenharmony_ci+                                     FALSE, NULL, NULL);
1836b5975d6bSopenharmony_ci+  g_assert_nonnull (variant);
1837b5975d6bSopenharmony_ci+
1838b5975d6bSopenharmony_ci+  normal_variant = g_variant_get_normal_form (variant);
1839b5975d6bSopenharmony_ci+  g_assert_nonnull (normal_variant);
1840b5975d6bSopenharmony_ci+
1841b5975d6bSopenharmony_ci+  expected_variant = g_variant_new_parsed ("[@ay [], []]");
1842b5975d6bSopenharmony_ci+  g_assert_cmpvariant (normal_variant, expected_variant);
1843b5975d6bSopenharmony_ci+
1844b5975d6bSopenharmony_ci+  g_assert_cmpmem (g_variant_get_data (normal_variant), g_variant_get_size (normal_variant),
1845b5975d6bSopenharmony_ci+                   g_variant_get_data (expected_variant), g_variant_get_size (expected_variant));
1846b5975d6bSopenharmony_ci+
1847b5975d6bSopenharmony_ci+  g_variant_unref (expected_variant);
1848b5975d6bSopenharmony_ci+  g_variant_unref (normal_variant);
1849b5975d6bSopenharmony_ci+  g_variant_unref (variant);
1850b5975d6bSopenharmony_ci+}
1851b5975d6bSopenharmony_ci+
1852b5975d6bSopenharmony_ci /* Test that an array with invalidly large values in its offset table is
1853b5975d6bSopenharmony_ci  * normalised successfully without looping infinitely. */
1854b5975d6bSopenharmony_ci static void
1855b5975d6bSopenharmony_ci@@ -5532,6 +5564,8 @@ main (int argc, char **argv)
1856b5975d6bSopenharmony_ci 
1857b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/tuples",
1858b5975d6bSopenharmony_ci                    test_normal_checking_tuples);
1859b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/array-offsets/overlapped",
1860b5975d6bSopenharmony_ci+                   test_normal_checking_array_offsets_overlapped);
1861b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/array-offsets",
1862b5975d6bSopenharmony_ci                    test_normal_checking_array_offsets);
1863b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/array-offsets2",
1864b5975d6bSopenharmony_ci-- 
1865b5975d6bSopenharmony_ciGitLab
1866b5975d6bSopenharmony_ci
1867b5975d6bSopenharmony_ci
1868b5975d6bSopenharmony_ciFrom 4c0ddb26bc3f27eddf802b35c4b5229c0cdf6085 Mon Sep 17 00:00:00 2001
1869b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
1870b5975d6bSopenharmony_ciDate: Mon, 24 Oct 2022 16:43:23 +0100
1871b5975d6bSopenharmony_ciSubject: [PATCH 10/18] tests: Disable some random instance tests of GVariants
1872b5975d6bSopenharmony_ciMIME-Version: 1.0
1873b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
1874b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
1875b5975d6bSopenharmony_ci
1876b5975d6bSopenharmony_ciBuilding a `GVariant` using entirely random data may result in a
1877b5975d6bSopenharmony_cinon-normally-formed `GVariant`. It’s always possible to read these
1878b5975d6bSopenharmony_ci`GVariant`s, but the API might return default values for some or all of
1879b5975d6bSopenharmony_citheir components.
1880b5975d6bSopenharmony_ci
1881b5975d6bSopenharmony_ciIn particular, this can easily happen when randomly generating the
1882b5975d6bSopenharmony_cioffset tables for non-fixed-width container types.
1883b5975d6bSopenharmony_ci
1884b5975d6bSopenharmony_ciIf it does happen, bytewise comparison of the parsed `GVariant` with the
1885b5975d6bSopenharmony_cioriginal bytes will not always match. So skip those checks.
1886b5975d6bSopenharmony_ci
1887b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
1888b5975d6bSopenharmony_ci
1889b5975d6bSopenharmony_ciHelps: #2121
1890b5975d6bSopenharmony_ci---
1891b5975d6bSopenharmony_ci glib/tests/gvariant.c | 12 +++++++++---
1892b5975d6bSopenharmony_ci 1 file changed, 9 insertions(+), 3 deletions(-)
1893b5975d6bSopenharmony_ci
1894b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
1895b5975d6bSopenharmony_ciindex 8ec94814e4..18aeb80f12 100644
1896b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
1897b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
1898b5975d6bSopenharmony_ci@@ -1231,6 +1231,7 @@ random_instance_assert (RandomInstance *instance,
1899b5975d6bSopenharmony_ci   GRand *rand;
1900b5975d6bSopenharmony_ci   gsize i;
1901b5975d6bSopenharmony_ci 
1902b5975d6bSopenharmony_ci+  g_assert_true (size == 0 || buffer != NULL);
1903b5975d6bSopenharmony_ci   g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
1904b5975d6bSopenharmony_ci   g_assert_cmpint (size, ==, instance->size);
1905b5975d6bSopenharmony_ci 
1906b5975d6bSopenharmony_ci@@ -1457,10 +1458,13 @@ test_maybe (void)
1907b5975d6bSopenharmony_ci         g_variant_serialiser_serialise (serialised,
1908b5975d6bSopenharmony_ci                                         random_instance_filler,
1909b5975d6bSopenharmony_ci                                         (gpointer *) &instance, 1);
1910b5975d6bSopenharmony_ci+
1911b5975d6bSopenharmony_ci         child = g_variant_serialised_get_child (serialised, 0);
1912b5975d6bSopenharmony_ci         g_assert_true (child.type_info == instance->type_info);
1913b5975d6bSopenharmony_ci-        random_instance_assert (instance, child.data, child.size);
1914b5975d6bSopenharmony_ci+        if (child.data != NULL)  /* could be NULL if element is non-normal */
1915b5975d6bSopenharmony_ci+          random_instance_assert (instance, child.data, child.size);
1916b5975d6bSopenharmony_ci         g_variant_type_info_unref (child.type_info);
1917b5975d6bSopenharmony_ci+
1918b5975d6bSopenharmony_ci         flavoured_free (serialised.data, flavour);
1919b5975d6bSopenharmony_ci       }
1920b5975d6bSopenharmony_ci   }
1921b5975d6bSopenharmony_ci@@ -1593,7 +1597,8 @@ test_array (void)
1922b5975d6bSopenharmony_ci 
1923b5975d6bSopenharmony_ci             child = g_variant_serialised_get_child (serialised, i);
1924b5975d6bSopenharmony_ci             g_assert_true (child.type_info == instances[i]->type_info);
1925b5975d6bSopenharmony_ci-            random_instance_assert (instances[i], child.data, child.size);
1926b5975d6bSopenharmony_ci+            if (child.data != NULL)  /* could be NULL if element is non-normal */
1927b5975d6bSopenharmony_ci+              random_instance_assert (instances[i], child.data, child.size);
1928b5975d6bSopenharmony_ci             g_variant_type_info_unref (child.type_info);
1929b5975d6bSopenharmony_ci           }
1930b5975d6bSopenharmony_ci 
1931b5975d6bSopenharmony_ci@@ -1759,7 +1764,8 @@ test_tuple (void)
1932b5975d6bSopenharmony_ci 
1933b5975d6bSopenharmony_ci             child = g_variant_serialised_get_child (serialised, i);
1934b5975d6bSopenharmony_ci             g_assert_true (child.type_info == instances[i]->type_info);
1935b5975d6bSopenharmony_ci-            random_instance_assert (instances[i], child.data, child.size);
1936b5975d6bSopenharmony_ci+            if (child.data != NULL)  /* could be NULL if element is non-normal */
1937b5975d6bSopenharmony_ci+              random_instance_assert (instances[i], child.data, child.size);
1938b5975d6bSopenharmony_ci             g_variant_type_info_unref (child.type_info);
1939b5975d6bSopenharmony_ci           }
1940b5975d6bSopenharmony_ci 
1941b5975d6bSopenharmony_ci-- 
1942b5975d6bSopenharmony_ciGitLab
1943b5975d6bSopenharmony_ci
1944b5975d6bSopenharmony_ci
1945b5975d6bSopenharmony_ciFrom 35dee77ed887a9b4d24b7a0e45f237f813e52591 Mon Sep 17 00:00:00 2001
1946b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
1947b5975d6bSopenharmony_ciDate: Mon, 24 Oct 2022 18:14:57 +0100
1948b5975d6bSopenharmony_ciSubject: [PATCH 11/18] gvariant: Clarify the docs for
1949b5975d6bSopenharmony_ci g_variant_get_normal_form()
1950b5975d6bSopenharmony_ci
1951b5975d6bSopenharmony_ciDocument how non-normal parts of the `GVariant` are handled.
1952b5975d6bSopenharmony_ci
1953b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
1954b5975d6bSopenharmony_ci---
1955b5975d6bSopenharmony_ci glib/gvariant.c | 4 +++-
1956b5975d6bSopenharmony_ci 1 file changed, 3 insertions(+), 1 deletion(-)
1957b5975d6bSopenharmony_ci
1958b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
1959b5975d6bSopenharmony_ciindex fd066f1732..a98f10b57a 100644
1960b5975d6bSopenharmony_ci--- a/glib/gvariant.c
1961b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
1962b5975d6bSopenharmony_ci@@ -5936,7 +5936,9 @@ g_variant_deep_copy (GVariant *value)
1963b5975d6bSopenharmony_ci  * marked as trusted and a new reference to it is returned.
1964b5975d6bSopenharmony_ci  *
1965b5975d6bSopenharmony_ci  * If @value is found not to be in normal form then a new trusted
1966b5975d6bSopenharmony_ci- * #GVariant is created with the same value as @value.
1967b5975d6bSopenharmony_ci+ * #GVariant is created with the same value as @value. The non-normal parts of
1968b5975d6bSopenharmony_ci+ * @value will be replaced with default values which are guaranteed to be in
1969b5975d6bSopenharmony_ci+ * normal form.
1970b5975d6bSopenharmony_ci  *
1971b5975d6bSopenharmony_ci  * It makes sense to call this function if you've received #GVariant
1972b5975d6bSopenharmony_ci  * data from untrusted sources and you want to ensure your serialized
1973b5975d6bSopenharmony_ci-- 
1974b5975d6bSopenharmony_ciGitLab
1975b5975d6bSopenharmony_ci
1976b5975d6bSopenharmony_ci
1977b5975d6bSopenharmony_ciFrom e6490c84e84ba9f182fbd83b51ff4f9f5a0a1793 Mon Sep 17 00:00:00 2001
1978b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
1979b5975d6bSopenharmony_ciDate: Mon, 24 Oct 2022 18:43:55 +0100
1980b5975d6bSopenharmony_ciSubject: [PATCH 12/18] gvariant: Port g_variant_deep_copy() to count its
1981b5975d6bSopenharmony_ci iterations directly
1982b5975d6bSopenharmony_ci
1983b5975d6bSopenharmony_ciThis is equivalent to what `GVariantIter` does, but it means that
1984b5975d6bSopenharmony_ci`g_variant_deep_copy()` is making its own `g_variant_get_child_value()`
1985b5975d6bSopenharmony_cicalls.
1986b5975d6bSopenharmony_ci
1987b5975d6bSopenharmony_ciThis will be useful in an upcoming commit, where those child values will
1988b5975d6bSopenharmony_cibe inspected a little more deeply.
1989b5975d6bSopenharmony_ci
1990b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
1991b5975d6bSopenharmony_ci
1992b5975d6bSopenharmony_ciHelps: #2121
1993b5975d6bSopenharmony_ci---
1994b5975d6bSopenharmony_ci glib/gvariant.c | 7 +++----
1995b5975d6bSopenharmony_ci 1 file changed, 3 insertions(+), 4 deletions(-)
1996b5975d6bSopenharmony_ci
1997b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
1998b5975d6bSopenharmony_ciindex a98f10b57a..9334ec393e 100644
1999b5975d6bSopenharmony_ci--- a/glib/gvariant.c
2000b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
2001b5975d6bSopenharmony_ci@@ -5863,14 +5863,13 @@ g_variant_deep_copy (GVariant *value)
2002b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_VARIANT:
2003b5975d6bSopenharmony_ci       {
2004b5975d6bSopenharmony_ci         GVariantBuilder builder;
2005b5975d6bSopenharmony_ci-        GVariantIter iter;
2006b5975d6bSopenharmony_ci-        GVariant *child;
2007b5975d6bSopenharmony_ci+        gsize i, n_children;
2008b5975d6bSopenharmony_ci 
2009b5975d6bSopenharmony_ci         g_variant_builder_init (&builder, g_variant_get_type (value));
2010b5975d6bSopenharmony_ci-        g_variant_iter_init (&iter, value);
2011b5975d6bSopenharmony_ci 
2012b5975d6bSopenharmony_ci-        while ((child = g_variant_iter_next_value (&iter)))
2013b5975d6bSopenharmony_ci+        for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++)
2014b5975d6bSopenharmony_ci           {
2015b5975d6bSopenharmony_ci+            GVariant *child = g_variant_get_child_value (value, i);
2016b5975d6bSopenharmony_ci             g_variant_builder_add_value (&builder, g_variant_deep_copy (child));
2017b5975d6bSopenharmony_ci             g_variant_unref (child);
2018b5975d6bSopenharmony_ci           }
2019b5975d6bSopenharmony_ci-- 
2020b5975d6bSopenharmony_ciGitLab
2021b5975d6bSopenharmony_ci
2022b5975d6bSopenharmony_ci
2023b5975d6bSopenharmony_ciFrom 168f9b42e55053611ad473898f7afb06ce20b08a Mon Sep 17 00:00:00 2001
2024b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
2025b5975d6bSopenharmony_ciDate: Tue, 25 Oct 2022 13:03:22 +0100
2026b5975d6bSopenharmony_ciSubject: [PATCH 13/18] gvariant: Add internal
2027b5975d6bSopenharmony_ci g_variant_maybe_get_child_value()
2028b5975d6bSopenharmony_ci
2029b5975d6bSopenharmony_ciThis will be used in a following commit.
2030b5975d6bSopenharmony_ci
2031b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
2032b5975d6bSopenharmony_ci
2033b5975d6bSopenharmony_ciHelps: #2540
2034b5975d6bSopenharmony_ci---
2035b5975d6bSopenharmony_ci glib/gvariant-core.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
2036b5975d6bSopenharmony_ci glib/gvariant-core.h |  3 ++
2037b5975d6bSopenharmony_ci 2 files changed, 71 insertions(+)
2038b5975d6bSopenharmony_ci
2039b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
2040b5975d6bSopenharmony_ciindex f660e2d578..3fa97f91eb 100644
2041b5975d6bSopenharmony_ci--- a/glib/gvariant-core.c
2042b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.c
2043b5975d6bSopenharmony_ci@@ -1204,6 +1204,74 @@ g_variant_get_child_value (GVariant *value,
2044b5975d6bSopenharmony_ci   }
2045b5975d6bSopenharmony_ci }
2046b5975d6bSopenharmony_ci 
2047b5975d6bSopenharmony_ci+/**
2048b5975d6bSopenharmony_ci+ * g_variant_maybe_get_child_value:
2049b5975d6bSopenharmony_ci+ * @value: a container #GVariant
2050b5975d6bSopenharmony_ci+ * @index_: the index of the child to fetch
2051b5975d6bSopenharmony_ci+ *
2052b5975d6bSopenharmony_ci+ * Reads a child item out of a container #GVariant instance, if it is in normal
2053b5975d6bSopenharmony_ci+ * form. If it is not in normal form, return %NULL.
2054b5975d6bSopenharmony_ci+ *
2055b5975d6bSopenharmony_ci+ * This function behaves the same as g_variant_get_child_value(), except that it
2056b5975d6bSopenharmony_ci+ * returns %NULL if the child is not in normal form. g_variant_get_child_value()
2057b5975d6bSopenharmony_ci+ * would instead return a new default value of the correct type.
2058b5975d6bSopenharmony_ci+ *
2059b5975d6bSopenharmony_ci+ * This is intended to be used internally to avoid unnecessary #GVariant
2060b5975d6bSopenharmony_ci+ * allocations.
2061b5975d6bSopenharmony_ci+ *
2062b5975d6bSopenharmony_ci+ * The returned value is never floating.  You should free it with
2063b5975d6bSopenharmony_ci+ * g_variant_unref() when you're done with it.
2064b5975d6bSopenharmony_ci+ *
2065b5975d6bSopenharmony_ci+ * This function is O(1).
2066b5975d6bSopenharmony_ci+ *
2067b5975d6bSopenharmony_ci+ * Returns: (transfer full): the child at the specified index
2068b5975d6bSopenharmony_ci+ *
2069b5975d6bSopenharmony_ci+ * Since: 2.74
2070b5975d6bSopenharmony_ci+ */
2071b5975d6bSopenharmony_ci+GVariant *
2072b5975d6bSopenharmony_ci+g_variant_maybe_get_child_value (GVariant *value,
2073b5975d6bSopenharmony_ci+                                 gsize     index_)
2074b5975d6bSopenharmony_ci+{
2075b5975d6bSopenharmony_ci+  g_return_val_if_fail (index_ < g_variant_n_children (value), NULL);
2076b5975d6bSopenharmony_ci+  g_return_val_if_fail (value->depth < G_MAXSIZE, NULL);
2077b5975d6bSopenharmony_ci+
2078b5975d6bSopenharmony_ci+  if (~g_atomic_int_get (&value->state) & STATE_SERIALISED)
2079b5975d6bSopenharmony_ci+    {
2080b5975d6bSopenharmony_ci+      g_variant_lock (value);
2081b5975d6bSopenharmony_ci+
2082b5975d6bSopenharmony_ci+      if (~value->state & STATE_SERIALISED)
2083b5975d6bSopenharmony_ci+        {
2084b5975d6bSopenharmony_ci+          GVariant *child;
2085b5975d6bSopenharmony_ci+
2086b5975d6bSopenharmony_ci+          child = g_variant_ref (value->contents.tree.children[index_]);
2087b5975d6bSopenharmony_ci+          g_variant_unlock (value);
2088b5975d6bSopenharmony_ci+
2089b5975d6bSopenharmony_ci+          return child;
2090b5975d6bSopenharmony_ci+        }
2091b5975d6bSopenharmony_ci+
2092b5975d6bSopenharmony_ci+      g_variant_unlock (value);
2093b5975d6bSopenharmony_ci+    }
2094b5975d6bSopenharmony_ci+
2095b5975d6bSopenharmony_ci+  {
2096b5975d6bSopenharmony_ci+    GVariantSerialised serialised = g_variant_to_serialised (value);
2097b5975d6bSopenharmony_ci+    GVariantSerialised s_child;
2098b5975d6bSopenharmony_ci+
2099b5975d6bSopenharmony_ci+    /* get the serializer to extract the serialized data for the child
2100b5975d6bSopenharmony_ci+     * from the serialized data for the container
2101b5975d6bSopenharmony_ci+     */
2102b5975d6bSopenharmony_ci+    s_child = g_variant_serialised_get_child (serialised, index_);
2103b5975d6bSopenharmony_ci+
2104b5975d6bSopenharmony_ci+    if (!(value->state & STATE_TRUSTED) && s_child.data == NULL)
2105b5975d6bSopenharmony_ci+      {
2106b5975d6bSopenharmony_ci+        g_variant_type_info_unref (s_child.type_info);
2107b5975d6bSopenharmony_ci+        return NULL;
2108b5975d6bSopenharmony_ci+      }
2109b5975d6bSopenharmony_ci+
2110b5975d6bSopenharmony_ci+    g_variant_type_info_unref (s_child.type_info);
2111b5975d6bSopenharmony_ci+    return g_variant_get_child_value (value, index_);
2112b5975d6bSopenharmony_ci+  }
2113b5975d6bSopenharmony_ci+}
2114b5975d6bSopenharmony_ci+
2115b5975d6bSopenharmony_ci /**
2116b5975d6bSopenharmony_ci  * g_variant_store:
2117b5975d6bSopenharmony_ci  * @value: the #GVariant to store
2118b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.h b/glib/gvariant-core.h
2119b5975d6bSopenharmony_ciindex a1c34739a3..fb5f4bff45 100644
2120b5975d6bSopenharmony_ci--- a/glib/gvariant-core.h
2121b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.h
2122b5975d6bSopenharmony_ci@@ -38,4 +38,7 @@ GVariantTypeInfo *      g_variant_get_type_info                         (GVarian
2123b5975d6bSopenharmony_ci 
2124b5975d6bSopenharmony_ci gsize                   g_variant_get_depth                             (GVariant            *value);
2125b5975d6bSopenharmony_ci 
2126b5975d6bSopenharmony_ci+GVariant *              g_variant_maybe_get_child_value                 (GVariant            *value,
2127b5975d6bSopenharmony_ci+                                                                         gsize                index_);
2128b5975d6bSopenharmony_ci+
2129b5975d6bSopenharmony_ci #endif /* __G_VARIANT_CORE_H__ */
2130b5975d6bSopenharmony_ci-- 
2131b5975d6bSopenharmony_ciGitLab
2132b5975d6bSopenharmony_ci
2133b5975d6bSopenharmony_ci
2134b5975d6bSopenharmony_ciFrom c2dc74e2ec9b846d88ac4dd4368a9e2ab377cf94 Mon Sep 17 00:00:00 2001
2135b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
2136b5975d6bSopenharmony_ciDate: Tue, 25 Oct 2022 13:03:45 +0100
2137b5975d6bSopenharmony_ciSubject: [PATCH 14/18] gvariant: Cut allocs of default values for children of
2138b5975d6bSopenharmony_ci non-normal arrays
2139b5975d6bSopenharmony_ciMIME-Version: 1.0
2140b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
2141b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
2142b5975d6bSopenharmony_ci
2143b5975d6bSopenharmony_ciThis improves a slow case in `g_variant_get_normal_form()` where
2144b5975d6bSopenharmony_ciallocating many identical default values for the children of a
2145b5975d6bSopenharmony_civariable-sized array which has a malformed offset table would take a lot
2146b5975d6bSopenharmony_ciof time.
2147b5975d6bSopenharmony_ci
2148b5975d6bSopenharmony_ciThe fix is to make all child values after the first invalid one be
2149b5975d6bSopenharmony_cireferences to the default value emitted for the first invalid one,
2150b5975d6bSopenharmony_cirather than identical new `GVariant`s.
2151b5975d6bSopenharmony_ci
2152b5975d6bSopenharmony_ciIn particular, this fixes a case where an attacker could create an array
2153b5975d6bSopenharmony_ciof length L of very large tuples of size T each, corrupt the offset table
2154b5975d6bSopenharmony_ciso they don’t have to specify the array content, and then induce
2155b5975d6bSopenharmony_ci`g_variant_get_normal_form()` into allocating L×T default values from an
2156b5975d6bSopenharmony_ciinput which is significantly smaller than L×T in length.
2157b5975d6bSopenharmony_ci
2158b5975d6bSopenharmony_ciA pre-existing workaround for this issue is for code to call
2159b5975d6bSopenharmony_ci`g_variant_is_normal_form()` before calling
2160b5975d6bSopenharmony_ci`g_variant_get_normal_form()`, and to skip the latter call if the former
2161b5975d6bSopenharmony_cireturns false. This commit improves the behaviour in the case that
2162b5975d6bSopenharmony_ci`g_variant_get_normal_form()` is called anyway.
2163b5975d6bSopenharmony_ci
2164b5975d6bSopenharmony_ciThis fix changes the time to run the `fuzz_variant_binary` test on the
2165b5975d6bSopenharmony_citestcase from oss-fuzz#19777 from >60s (before being terminated) with
2166b5975d6bSopenharmony_ci2.3GB of memory usage and 580k page faults; to 32s, 8.3MB of memory
2167b5975d6bSopenharmony_ciusage and 1500 page faults (as measured by `time -v`).
2168b5975d6bSopenharmony_ci
2169b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
2170b5975d6bSopenharmony_ci
2171b5975d6bSopenharmony_ciFixes: #2540
2172b5975d6bSopenharmony_cioss-fuzz#19777
2173b5975d6bSopenharmony_ci---
2174b5975d6bSopenharmony_ci glib/gvariant.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-
2175b5975d6bSopenharmony_ci 1 file changed, 65 insertions(+), 1 deletion(-)
2176b5975d6bSopenharmony_ci
2177b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
2178b5975d6bSopenharmony_ciindex 9334ec393e..356e199a0f 100644
2179b5975d6bSopenharmony_ci--- a/glib/gvariant.c
2180b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
2181b5975d6bSopenharmony_ci@@ -5857,7 +5857,6 @@ g_variant_deep_copy (GVariant *value)
2182b5975d6bSopenharmony_ci   switch (g_variant_classify (value))
2183b5975d6bSopenharmony_ci     {
2184b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_MAYBE:
2185b5975d6bSopenharmony_ci-    case G_VARIANT_CLASS_ARRAY:
2186b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_TUPLE:
2187b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_DICT_ENTRY:
2188b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_VARIANT:
2189b5975d6bSopenharmony_ci@@ -5877,6 +5876,71 @@ g_variant_deep_copy (GVariant *value)
2190b5975d6bSopenharmony_ci         return g_variant_builder_end (&builder);
2191b5975d6bSopenharmony_ci       }
2192b5975d6bSopenharmony_ci 
2193b5975d6bSopenharmony_ci+    case G_VARIANT_CLASS_ARRAY:
2194b5975d6bSopenharmony_ci+      {
2195b5975d6bSopenharmony_ci+        GVariantBuilder builder;
2196b5975d6bSopenharmony_ci+        gsize i, n_children;
2197b5975d6bSopenharmony_ci+        GVariant *first_invalid_child_deep_copy = NULL;
2198b5975d6bSopenharmony_ci+
2199b5975d6bSopenharmony_ci+        /* Arrays are in theory treated the same as maybes, tuples, dict entries
2200b5975d6bSopenharmony_ci+         * and variants, and could be another case in the above block of code.
2201b5975d6bSopenharmony_ci+         *
2202b5975d6bSopenharmony_ci+         * However, they have the property that when dealing with non-normal
2203b5975d6bSopenharmony_ci+         * data (which is the only time g_variant_deep_copy() is currently
2204b5975d6bSopenharmony_ci+         * called) in a variable-sized array, the code above can easily end up
2205b5975d6bSopenharmony_ci+         * creating many default child values in order to return an array which
2206b5975d6bSopenharmony_ci+         * is of the right length and type, but without containing non-normal
2207b5975d6bSopenharmony_ci+         * data. This can happen if the offset table for the array is malformed.
2208b5975d6bSopenharmony_ci+         *
2209b5975d6bSopenharmony_ci+         * In this case, the code above would end up allocating the same default
2210b5975d6bSopenharmony_ci+         * value for each one of the child indexes beyond the first malformed
2211b5975d6bSopenharmony_ci+         * entry in the offset table. This can end up being a lot of identical
2212b5975d6bSopenharmony_ci+         * allocations of default values, particularly if the non-normal array
2213b5975d6bSopenharmony_ci+         * is crafted maliciously.
2214b5975d6bSopenharmony_ci+         *
2215b5975d6bSopenharmony_ci+         * Avoid that problem by returning a new reference to the same default
2216b5975d6bSopenharmony_ci+         * value for every child after the first invalid one. This results in
2217b5975d6bSopenharmony_ci+         * returning an equivalent array, in normal form and trusted — but with
2218b5975d6bSopenharmony_ci+         * significantly fewer memory allocations.
2219b5975d6bSopenharmony_ci+         *
2220b5975d6bSopenharmony_ci+         * See https://gitlab.gnome.org/GNOME/glib/-/issues/2540 */
2221b5975d6bSopenharmony_ci+
2222b5975d6bSopenharmony_ci+        g_variant_builder_init (&builder, g_variant_get_type (value));
2223b5975d6bSopenharmony_ci+
2224b5975d6bSopenharmony_ci+        for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++)
2225b5975d6bSopenharmony_ci+          {
2226b5975d6bSopenharmony_ci+            /* Try maybe_get_child_value() first; if it returns NULL, this child
2227b5975d6bSopenharmony_ci+             * is non-normal. get_child_value() would have constructed and
2228b5975d6bSopenharmony_ci+             * returned a default value in that case. */
2229b5975d6bSopenharmony_ci+            GVariant *child = g_variant_maybe_get_child_value (value, i);
2230b5975d6bSopenharmony_ci+
2231b5975d6bSopenharmony_ci+            if (child != NULL)
2232b5975d6bSopenharmony_ci+              {
2233b5975d6bSopenharmony_ci+                /* Non-normal children may not always be contiguous, as they may
2234b5975d6bSopenharmony_ci+                 * be non-normal for reasons other than invalid offset table
2235b5975d6bSopenharmony_ci+                 * entries. As they are all the same type, they will all have
2236b5975d6bSopenharmony_ci+                 * the same default value though, so keep that around. */
2237b5975d6bSopenharmony_ci+                g_variant_builder_add_value (&builder, g_variant_deep_copy (child));
2238b5975d6bSopenharmony_ci+              }
2239b5975d6bSopenharmony_ci+            else if (child == NULL && first_invalid_child_deep_copy != NULL)
2240b5975d6bSopenharmony_ci+              {
2241b5975d6bSopenharmony_ci+                g_variant_builder_add_value (&builder, first_invalid_child_deep_copy);
2242b5975d6bSopenharmony_ci+              }
2243b5975d6bSopenharmony_ci+            else if (child == NULL)
2244b5975d6bSopenharmony_ci+              {
2245b5975d6bSopenharmony_ci+                child = g_variant_get_child_value (value, i);
2246b5975d6bSopenharmony_ci+                first_invalid_child_deep_copy = g_variant_ref_sink (g_variant_deep_copy (child));
2247b5975d6bSopenharmony_ci+                g_variant_builder_add_value (&builder, first_invalid_child_deep_copy);
2248b5975d6bSopenharmony_ci+              }
2249b5975d6bSopenharmony_ci+
2250b5975d6bSopenharmony_ci+            g_clear_pointer (&child, g_variant_unref);
2251b5975d6bSopenharmony_ci+          }
2252b5975d6bSopenharmony_ci+
2253b5975d6bSopenharmony_ci+        g_clear_pointer (&first_invalid_child_deep_copy, g_variant_unref);
2254b5975d6bSopenharmony_ci+
2255b5975d6bSopenharmony_ci+        return g_variant_builder_end (&builder);
2256b5975d6bSopenharmony_ci+      }
2257b5975d6bSopenharmony_ci+
2258b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_BOOLEAN:
2259b5975d6bSopenharmony_ci       return g_variant_new_boolean (g_variant_get_boolean (value));
2260b5975d6bSopenharmony_ci 
2261b5975d6bSopenharmony_ci-- 
2262b5975d6bSopenharmony_ciGitLab
2263b5975d6bSopenharmony_ci
2264b5975d6bSopenharmony_ci
2265b5975d6bSopenharmony_ciFrom f98c60e4eedf775fb896c89bc83c71c96224f6aa Mon Sep 17 00:00:00 2001
2266b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
2267b5975d6bSopenharmony_ciDate: Tue, 25 Oct 2022 18:03:56 +0100
2268b5975d6bSopenharmony_ciSubject: [PATCH 15/18] gvariant: Fix a leak of a GVariantTypeInfo on an error
2269b5975d6bSopenharmony_ci handling path
2270b5975d6bSopenharmony_ci
2271b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
2272b5975d6bSopenharmony_ci---
2273b5975d6bSopenharmony_ci glib/gvariant-core.c | 1 +
2274b5975d6bSopenharmony_ci 1 file changed, 1 insertion(+)
2275b5975d6bSopenharmony_ci
2276b5975d6bSopenharmony_cidiff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
2277b5975d6bSopenharmony_ciindex 3fa97f91eb..f441c4757e 100644
2278b5975d6bSopenharmony_ci--- a/glib/gvariant-core.c
2279b5975d6bSopenharmony_ci+++ b/glib/gvariant-core.c
2280b5975d6bSopenharmony_ci@@ -1183,6 +1183,7 @@ g_variant_get_child_value (GVariant *value,
2281b5975d6bSopenharmony_ci         G_VARIANT_MAX_RECURSION_DEPTH - value->depth)
2282b5975d6bSopenharmony_ci       {
2283b5975d6bSopenharmony_ci         g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_VARIANT));
2284b5975d6bSopenharmony_ci+        g_variant_type_info_unref (s_child.type_info);
2285b5975d6bSopenharmony_ci         return g_variant_new_tuple (NULL, 0);
2286b5975d6bSopenharmony_ci       }
2287b5975d6bSopenharmony_ci 
2288b5975d6bSopenharmony_ci-- 
2289b5975d6bSopenharmony_ciGitLab
2290b5975d6bSopenharmony_ci
2291b5975d6bSopenharmony_ci
2292b5975d6bSopenharmony_ciFrom 5f4485c4ff57fdefb1661531788def7ca5a47328 Mon Sep 17 00:00:00 2001
2293b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
2294b5975d6bSopenharmony_ciDate: Thu, 27 Oct 2022 12:00:04 +0100
2295b5975d6bSopenharmony_ciSubject: [PATCH 16/18] gvariant-serialiser: Check offset table entry size is
2296b5975d6bSopenharmony_ci minimal
2297b5975d6bSopenharmony_ci
2298b5975d6bSopenharmony_ciThe entries in an offset table (which is used for variable sized arrays
2299b5975d6bSopenharmony_ciand tuples containing variable sized members) are sized so that they can
2300b5975d6bSopenharmony_ciaddress every byte in the overall variant.
2301b5975d6bSopenharmony_ci
2302b5975d6bSopenharmony_ciThe specification requires that for a variant to be in normal form, its
2303b5975d6bSopenharmony_cioffset table entries must be the minimum width such that they can
2304b5975d6bSopenharmony_ciaddress every byte in the variant.
2305b5975d6bSopenharmony_ci
2306b5975d6bSopenharmony_ciThat minimality requirement was not checked in
2307b5975d6bSopenharmony_ci`g_variant_is_normal_form()`, leading to two different byte arrays being
2308b5975d6bSopenharmony_ciinterpreted as the normal form of a given variant tree. That kind of
2309b5975d6bSopenharmony_ciconfusion could potentially be exploited, and is certainly a bug.
2310b5975d6bSopenharmony_ci
2311b5975d6bSopenharmony_ciFix it by adding the necessary checks on offset table entry width, and
2312b5975d6bSopenharmony_ciunit tests.
2313b5975d6bSopenharmony_ci
2314b5975d6bSopenharmony_ciSpotted by William Manley.
2315b5975d6bSopenharmony_ci
2316b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
2317b5975d6bSopenharmony_ci
2318b5975d6bSopenharmony_ciFixes: #2794
2319b5975d6bSopenharmony_ci---
2320b5975d6bSopenharmony_ci glib/gvariant-serialiser.c |  19 +++-
2321b5975d6bSopenharmony_ci glib/tests/gvariant.c      | 176 +++++++++++++++++++++++++++++++++++++
2322b5975d6bSopenharmony_ci 2 files changed, 194 insertions(+), 1 deletion(-)
2323b5975d6bSopenharmony_ci
2324b5975d6bSopenharmony_cidiff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
2325b5975d6bSopenharmony_ciindex 69baeeb395..fadefab659 100644
2326b5975d6bSopenharmony_ci--- a/glib/gvariant-serialiser.c
2327b5975d6bSopenharmony_ci+++ b/glib/gvariant-serialiser.c
2328b5975d6bSopenharmony_ci@@ -696,6 +696,10 @@ gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
2329b5975d6bSopenharmony_ci   out.data_size = last_end;
2330b5975d6bSopenharmony_ci   out.array = value.data + last_end;
2331b5975d6bSopenharmony_ci   out.length = offsets_array_size / out.offset_size;
2332b5975d6bSopenharmony_ci+
2333b5975d6bSopenharmony_ci+  if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
2334b5975d6bSopenharmony_ci+    return out;  /* offset size not minimal */
2335b5975d6bSopenharmony_ci+
2336b5975d6bSopenharmony_ci   out.is_normal = TRUE;
2337b5975d6bSopenharmony_ci 
2338b5975d6bSopenharmony_ci   return out;
2339b5975d6bSopenharmony_ci@@ -1207,6 +1211,7 @@ gvs_tuple_is_normal (GVariantSerialised value)
2340b5975d6bSopenharmony_ci   gsize length;
2341b5975d6bSopenharmony_ci   gsize offset;
2342b5975d6bSopenharmony_ci   gsize i;
2343b5975d6bSopenharmony_ci+  gsize offset_table_size;
2344b5975d6bSopenharmony_ci 
2345b5975d6bSopenharmony_ci   /* as per the comment in gvs_tuple_get_child() */
2346b5975d6bSopenharmony_ci   if G_UNLIKELY (value.data == NULL && value.size != 0)
2347b5975d6bSopenharmony_ci@@ -1311,7 +1316,19 @@ gvs_tuple_is_normal (GVariantSerialised value)
2348b5975d6bSopenharmony_ci       }
2349b5975d6bSopenharmony_ci   }
2350b5975d6bSopenharmony_ci 
2351b5975d6bSopenharmony_ci-  return offset_ptr == offset;
2352b5975d6bSopenharmony_ci+  /* @offset_ptr has been counting backwards from the end of the variant, to
2353b5975d6bSopenharmony_ci+   * find the beginning of the offset table. @offset has been counting forwards
2354b5975d6bSopenharmony_ci+   * from the beginning of the variant to find the end of the data. They should
2355b5975d6bSopenharmony_ci+   * have met in the middle. */
2356b5975d6bSopenharmony_ci+  if (offset_ptr != offset)
2357b5975d6bSopenharmony_ci+    return FALSE;
2358b5975d6bSopenharmony_ci+
2359b5975d6bSopenharmony_ci+  offset_table_size = value.size - offset_ptr;
2360b5975d6bSopenharmony_ci+  if (value.size > 0 &&
2361b5975d6bSopenharmony_ci+      gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
2362b5975d6bSopenharmony_ci+    return FALSE;  /* offset size not minimal */
2363b5975d6bSopenharmony_ci+
2364b5975d6bSopenharmony_ci+  return TRUE;
2365b5975d6bSopenharmony_ci }
2366b5975d6bSopenharmony_ci 
2367b5975d6bSopenharmony_ci /* Variants {{{2
2368b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
2369b5975d6bSopenharmony_ciindex 18aeb80f12..d4893ed407 100644
2370b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
2371b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
2372b5975d6bSopenharmony_ci@@ -5234,6 +5234,86 @@ test_normal_checking_array_offsets2 (void)
2373b5975d6bSopenharmony_ci   g_variant_unref (variant);
2374b5975d6bSopenharmony_ci }
2375b5975d6bSopenharmony_ci 
2376b5975d6bSopenharmony_ci+/* Test that an otherwise-valid serialised GVariant is considered non-normal if
2377b5975d6bSopenharmony_ci+ * its offset table entries are too wide.
2378b5975d6bSopenharmony_ci+ *
2379b5975d6bSopenharmony_ci+ * See §2.3.6 (Framing Offsets) of the GVariant specification. */
2380b5975d6bSopenharmony_ci+static void
2381b5975d6bSopenharmony_ci+test_normal_checking_array_offsets_minimal_sized (void)
2382b5975d6bSopenharmony_ci+{
2383b5975d6bSopenharmony_ci+  GVariantBuilder builder;
2384b5975d6bSopenharmony_ci+  gsize i;
2385b5975d6bSopenharmony_ci+  GVariant *aay_constructed = NULL;
2386b5975d6bSopenharmony_ci+  const guint8 *data = NULL;
2387b5975d6bSopenharmony_ci+  guint8 *data_owned = NULL;
2388b5975d6bSopenharmony_ci+  GVariant *aay_deserialised = NULL;
2389b5975d6bSopenharmony_ci+  GVariant *aay_normalised = NULL;
2390b5975d6bSopenharmony_ci+
2391b5975d6bSopenharmony_ci+  /* Construct an array of type aay, consisting of 128 elements which are each
2392b5975d6bSopenharmony_ci+   * an empty array, i.e. `[[] * 128]`. This is chosen because the inner
2393b5975d6bSopenharmony_ci+   * elements are variable sized (making the outer array variable sized, so it
2394b5975d6bSopenharmony_ci+   * must have an offset table), but they are also zero-sized when serialised.
2395b5975d6bSopenharmony_ci+   * So the serialised representation of @aay_constructed consists entirely of
2396b5975d6bSopenharmony_ci+   * its offset table, which is entirely zeroes.
2397b5975d6bSopenharmony_ci+   *
2398b5975d6bSopenharmony_ci+   * The array is chosen to be 128 elements long because that means offset
2399b5975d6bSopenharmony_ci+   * table entries which are 1 byte long. If the elements in the array were
2400b5975d6bSopenharmony_ci+   * non-zero-sized (to the extent that the overall array is ≥256 bytes long),
2401b5975d6bSopenharmony_ci+   * the offset table entries would end up being 2 bytes long. */
2402b5975d6bSopenharmony_ci+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
2403b5975d6bSopenharmony_ci+
2404b5975d6bSopenharmony_ci+  for (i = 0; i < 128; i++)
2405b5975d6bSopenharmony_ci+    g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
2406b5975d6bSopenharmony_ci+
2407b5975d6bSopenharmony_ci+  aay_constructed = g_variant_builder_end (&builder);
2408b5975d6bSopenharmony_ci+
2409b5975d6bSopenharmony_ci+  /* Verify that the constructed array is in normal form, and its serialised
2410b5975d6bSopenharmony_ci+   * form is `b'\0' * 128`. */
2411b5975d6bSopenharmony_ci+  g_assert_true (g_variant_is_normal_form (aay_constructed));
2412b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_n_children (aay_constructed), ==, 128);
2413b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (aay_constructed), ==, 128);
2414b5975d6bSopenharmony_ci+
2415b5975d6bSopenharmony_ci+  data = g_variant_get_data (aay_constructed);
2416b5975d6bSopenharmony_ci+  for (i = 0; i < g_variant_get_size (aay_constructed); i++)
2417b5975d6bSopenharmony_ci+    g_assert_cmpuint (data[i], ==, 0);
2418b5975d6bSopenharmony_ci+
2419b5975d6bSopenharmony_ci+  /* Construct a serialised `aay` GVariant which is `b'\0' * 256`. This has to
2420b5975d6bSopenharmony_ci+   * be a non-normal form of `[[] * 128]`, with 2-byte-long offset table
2421b5975d6bSopenharmony_ci+   * entries, because each offset table entry has to be able to reference all of
2422b5975d6bSopenharmony_ci+   * the byte boundaries in the container. All the entries in the offset table
2423b5975d6bSopenharmony_ci+   * are zero, so all the elements of the array are zero-sized. */
2424b5975d6bSopenharmony_ci+  data = data_owned = g_malloc0 (256);
2425b5975d6bSopenharmony_ci+  aay_deserialised = g_variant_new_from_data (G_VARIANT_TYPE ("aay"),
2426b5975d6bSopenharmony_ci+                                              data,
2427b5975d6bSopenharmony_ci+                                              256,
2428b5975d6bSopenharmony_ci+                                              FALSE,
2429b5975d6bSopenharmony_ci+                                              g_free,
2430b5975d6bSopenharmony_ci+                                              g_steal_pointer (&data_owned));
2431b5975d6bSopenharmony_ci+
2432b5975d6bSopenharmony_ci+  g_assert_false (g_variant_is_normal_form (aay_deserialised));
2433b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_n_children (aay_deserialised), ==, 128);
2434b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (aay_deserialised), ==, 256);
2435b5975d6bSopenharmony_ci+
2436b5975d6bSopenharmony_ci+  data = g_variant_get_data (aay_deserialised);
2437b5975d6bSopenharmony_ci+  for (i = 0; i < g_variant_get_size (aay_deserialised); i++)
2438b5975d6bSopenharmony_ci+    g_assert_cmpuint (data[i], ==, 0);
2439b5975d6bSopenharmony_ci+
2440b5975d6bSopenharmony_ci+  /* Get its normal form. That should change the serialised size. */
2441b5975d6bSopenharmony_ci+  aay_normalised = g_variant_get_normal_form (aay_deserialised);
2442b5975d6bSopenharmony_ci+
2443b5975d6bSopenharmony_ci+  g_assert_true (g_variant_is_normal_form (aay_normalised));
2444b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_n_children (aay_normalised), ==, 128);
2445b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (aay_normalised), ==, 128);
2446b5975d6bSopenharmony_ci+
2447b5975d6bSopenharmony_ci+  data = g_variant_get_data (aay_normalised);
2448b5975d6bSopenharmony_ci+  for (i = 0; i < g_variant_get_size (aay_normalised); i++)
2449b5975d6bSopenharmony_ci+    g_assert_cmpuint (data[i], ==, 0);
2450b5975d6bSopenharmony_ci+
2451b5975d6bSopenharmony_ci+  g_variant_unref (aay_normalised);
2452b5975d6bSopenharmony_ci+  g_variant_unref (aay_deserialised);
2453b5975d6bSopenharmony_ci+  g_variant_unref (aay_constructed);
2454b5975d6bSopenharmony_ci+}
2455b5975d6bSopenharmony_ci+
2456b5975d6bSopenharmony_ci /* Test that a tuple with invalidly large values in its offset table is
2457b5975d6bSopenharmony_ci  * normalised successfully without looping infinitely. */
2458b5975d6bSopenharmony_ci static void
2459b5975d6bSopenharmony_ci@@ -5428,6 +5508,98 @@ test_normal_checking_tuple_offsets4 (void)
2460b5975d6bSopenharmony_ci   g_variant_unref (variant);
2461b5975d6bSopenharmony_ci }
2462b5975d6bSopenharmony_ci 
2463b5975d6bSopenharmony_ci+/* Test that an otherwise-valid serialised GVariant is considered non-normal if
2464b5975d6bSopenharmony_ci+ * its offset table entries are too wide.
2465b5975d6bSopenharmony_ci+ *
2466b5975d6bSopenharmony_ci+ * See §2.3.6 (Framing Offsets) of the GVariant specification. */
2467b5975d6bSopenharmony_ci+static void
2468b5975d6bSopenharmony_ci+test_normal_checking_tuple_offsets_minimal_sized (void)
2469b5975d6bSopenharmony_ci+{
2470b5975d6bSopenharmony_ci+  GString *type_string = NULL;
2471b5975d6bSopenharmony_ci+  GVariantBuilder builder;
2472b5975d6bSopenharmony_ci+  gsize i;
2473b5975d6bSopenharmony_ci+  GVariant *ray_constructed = NULL;
2474b5975d6bSopenharmony_ci+  const guint8 *data = NULL;
2475b5975d6bSopenharmony_ci+  guint8 *data_owned = NULL;
2476b5975d6bSopenharmony_ci+  GVariant *ray_deserialised = NULL;
2477b5975d6bSopenharmony_ci+  GVariant *ray_normalised = NULL;
2478b5975d6bSopenharmony_ci+
2479b5975d6bSopenharmony_ci+  /* Construct a tuple of type (ay…ay), consisting of 129 members which are each
2480b5975d6bSopenharmony_ci+   * an empty array, i.e. `([] * 129)`. This is chosen because the inner
2481b5975d6bSopenharmony_ci+   * members are variable sized, so the outer tuple must have an offset table,
2482b5975d6bSopenharmony_ci+   * but they are also zero-sized when serialised. So the serialised
2483b5975d6bSopenharmony_ci+   * representation of @ray_constructed consists entirely of its offset table,
2484b5975d6bSopenharmony_ci+   * which is entirely zeroes.
2485b5975d6bSopenharmony_ci+   *
2486b5975d6bSopenharmony_ci+   * The tuple is chosen to be 129 members long because that means it has 128
2487b5975d6bSopenharmony_ci+   * offset table entries which are 1 byte long each. If the members in the
2488b5975d6bSopenharmony_ci+   * tuple were non-zero-sized (to the extent that the overall tuple is ≥256
2489b5975d6bSopenharmony_ci+   * bytes long), the offset table entries would end up being 2 bytes long.
2490b5975d6bSopenharmony_ci+   *
2491b5975d6bSopenharmony_ci+   * 129 members are used unlike 128 array elements in
2492b5975d6bSopenharmony_ci+   * test_normal_checking_array_offsets_minimal_sized(), because the last member
2493b5975d6bSopenharmony_ci+   * in a tuple never needs an offset table entry. */
2494b5975d6bSopenharmony_ci+  type_string = g_string_new ("");
2495b5975d6bSopenharmony_ci+  g_string_append_c (type_string, '(');
2496b5975d6bSopenharmony_ci+  for (i = 0; i < 129; i++)
2497b5975d6bSopenharmony_ci+    g_string_append (type_string, "ay");
2498b5975d6bSopenharmony_ci+  g_string_append_c (type_string, ')');
2499b5975d6bSopenharmony_ci+
2500b5975d6bSopenharmony_ci+  g_variant_builder_init (&builder, G_VARIANT_TYPE (type_string->str));
2501b5975d6bSopenharmony_ci+
2502b5975d6bSopenharmony_ci+  for (i = 0; i < 129; i++)
2503b5975d6bSopenharmony_ci+    g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
2504b5975d6bSopenharmony_ci+
2505b5975d6bSopenharmony_ci+  ray_constructed = g_variant_builder_end (&builder);
2506b5975d6bSopenharmony_ci+
2507b5975d6bSopenharmony_ci+  /* Verify that the constructed tuple is in normal form, and its serialised
2508b5975d6bSopenharmony_ci+   * form is `b'\0' * 128`. */
2509b5975d6bSopenharmony_ci+  g_assert_true (g_variant_is_normal_form (ray_constructed));
2510b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_n_children (ray_constructed), ==, 129);
2511b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (ray_constructed), ==, 128);
2512b5975d6bSopenharmony_ci+
2513b5975d6bSopenharmony_ci+  data = g_variant_get_data (ray_constructed);
2514b5975d6bSopenharmony_ci+  for (i = 0; i < g_variant_get_size (ray_constructed); i++)
2515b5975d6bSopenharmony_ci+    g_assert_cmpuint (data[i], ==, 0);
2516b5975d6bSopenharmony_ci+
2517b5975d6bSopenharmony_ci+  /* Construct a serialised `(ay…ay)` GVariant which is `b'\0' * 256`. This has
2518b5975d6bSopenharmony_ci+   * to be a non-normal form of `([] * 129)`, with 2-byte-long offset table
2519b5975d6bSopenharmony_ci+   * entries, because each offset table entry has to be able to reference all of
2520b5975d6bSopenharmony_ci+   * the byte boundaries in the container. All the entries in the offset table
2521b5975d6bSopenharmony_ci+   * are zero, so all the members of the tuple are zero-sized. */
2522b5975d6bSopenharmony_ci+  data = data_owned = g_malloc0 (256);
2523b5975d6bSopenharmony_ci+  ray_deserialised = g_variant_new_from_data (G_VARIANT_TYPE (type_string->str),
2524b5975d6bSopenharmony_ci+                                              data,
2525b5975d6bSopenharmony_ci+                                              256,
2526b5975d6bSopenharmony_ci+                                              FALSE,
2527b5975d6bSopenharmony_ci+                                              g_free,
2528b5975d6bSopenharmony_ci+                                              g_steal_pointer (&data_owned));
2529b5975d6bSopenharmony_ci+
2530b5975d6bSopenharmony_ci+  g_assert_false (g_variant_is_normal_form (ray_deserialised));
2531b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_n_children (ray_deserialised), ==, 129);
2532b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (ray_deserialised), ==, 256);
2533b5975d6bSopenharmony_ci+
2534b5975d6bSopenharmony_ci+  data = g_variant_get_data (ray_deserialised);
2535b5975d6bSopenharmony_ci+  for (i = 0; i < g_variant_get_size (ray_deserialised); i++)
2536b5975d6bSopenharmony_ci+    g_assert_cmpuint (data[i], ==, 0);
2537b5975d6bSopenharmony_ci+
2538b5975d6bSopenharmony_ci+  /* Get its normal form. That should change the serialised size. */
2539b5975d6bSopenharmony_ci+  ray_normalised = g_variant_get_normal_form (ray_deserialised);
2540b5975d6bSopenharmony_ci+
2541b5975d6bSopenharmony_ci+  g_assert_true (g_variant_is_normal_form (ray_normalised));
2542b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_n_children (ray_normalised), ==, 129);
2543b5975d6bSopenharmony_ci+  g_assert_cmpuint (g_variant_get_size (ray_normalised), ==, 128);
2544b5975d6bSopenharmony_ci+
2545b5975d6bSopenharmony_ci+  data = g_variant_get_data (ray_normalised);
2546b5975d6bSopenharmony_ci+  for (i = 0; i < g_variant_get_size (ray_normalised); i++)
2547b5975d6bSopenharmony_ci+    g_assert_cmpuint (data[i], ==, 0);
2548b5975d6bSopenharmony_ci+
2549b5975d6bSopenharmony_ci+  g_variant_unref (ray_normalised);
2550b5975d6bSopenharmony_ci+  g_variant_unref (ray_deserialised);
2551b5975d6bSopenharmony_ci+  g_variant_unref (ray_constructed);
2552b5975d6bSopenharmony_ci+  g_string_free (type_string, TRUE);
2553b5975d6bSopenharmony_ci+}
2554b5975d6bSopenharmony_ci+
2555b5975d6bSopenharmony_ci /* Test that an empty object path is normalised successfully to the base object
2556b5975d6bSopenharmony_ci  * path, ‘/’. */
2557b5975d6bSopenharmony_ci static void
2558b5975d6bSopenharmony_ci@@ -5576,6 +5748,8 @@ main (int argc, char **argv)
2559b5975d6bSopenharmony_ci                    test_normal_checking_array_offsets);
2560b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/array-offsets2",
2561b5975d6bSopenharmony_ci                    test_normal_checking_array_offsets2);
2562b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/array-offsets/minimal-sized",
2563b5975d6bSopenharmony_ci+                   test_normal_checking_array_offsets_minimal_sized);
2564b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
2565b5975d6bSopenharmony_ci                    test_normal_checking_tuple_offsets);
2566b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/tuple-offsets2",
2567b5975d6bSopenharmony_ci@@ -5584,6 +5758,8 @@ main (int argc, char **argv)
2568b5975d6bSopenharmony_ci                    test_normal_checking_tuple_offsets3);
2569b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/tuple-offsets4",
2570b5975d6bSopenharmony_ci                    test_normal_checking_tuple_offsets4);
2571b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized",
2572b5975d6bSopenharmony_ci+                   test_normal_checking_tuple_offsets_minimal_sized);
2573b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/normal-checking/empty-object-path",
2574b5975d6bSopenharmony_ci                    test_normal_checking_empty_object_path);
2575b5975d6bSopenharmony_ci 
2576b5975d6bSopenharmony_ci-- 
2577b5975d6bSopenharmony_ciGitLab
2578b5975d6bSopenharmony_ci
2579b5975d6bSopenharmony_ci
2580b5975d6bSopenharmony_ciFrom 4c4cf568f0f710baf0bd04d52df715636bc6b971 Mon Sep 17 00:00:00 2001
2581b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
2582b5975d6bSopenharmony_ciDate: Thu, 27 Oct 2022 16:13:54 +0100
2583b5975d6bSopenharmony_ciSubject: [PATCH 17/18] gvariant: Fix g_variant_byteswap() returning non-normal
2584b5975d6bSopenharmony_ci data sometimes
2585b5975d6bSopenharmony_ciMIME-Version: 1.0
2586b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
2587b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
2588b5975d6bSopenharmony_ci
2589b5975d6bSopenharmony_ciIf `g_variant_byteswap()` was called on a non-normal variant of a type
2590b5975d6bSopenharmony_ciwhich doesn’t need byteswapping, it would return a non-normal output.
2591b5975d6bSopenharmony_ci
2592b5975d6bSopenharmony_ciThat contradicts the documentation, which says that the return value is
2593b5975d6bSopenharmony_cialways in normal form.
2594b5975d6bSopenharmony_ci
2595b5975d6bSopenharmony_ciFix the code so it matches the documentation.
2596b5975d6bSopenharmony_ci
2597b5975d6bSopenharmony_ciIncludes a unit test.
2598b5975d6bSopenharmony_ci
2599b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
2600b5975d6bSopenharmony_ci
2601b5975d6bSopenharmony_ciHelps: #2797
2602b5975d6bSopenharmony_ci---
2603b5975d6bSopenharmony_ci glib/gvariant.c       |  8 +++++---
2604b5975d6bSopenharmony_ci glib/tests/gvariant.c | 24 ++++++++++++++++++++++++
2605b5975d6bSopenharmony_ci 2 files changed, 29 insertions(+), 3 deletions(-)
2606b5975d6bSopenharmony_ci
2607b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
2608b5975d6bSopenharmony_ciindex 356e199a0f..f7b2e97036 100644
2609b5975d6bSopenharmony_ci--- a/glib/gvariant.c
2610b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
2611b5975d6bSopenharmony_ci@@ -6084,14 +6084,16 @@ g_variant_byteswap (GVariant *value)
2612b5975d6bSopenharmony_ci       g_variant_serialised_byteswap (serialised);
2613b5975d6bSopenharmony_ci 
2614b5975d6bSopenharmony_ci       bytes = g_bytes_new_take (serialised.data, serialised.size);
2615b5975d6bSopenharmony_ci-      new = g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE);
2616b5975d6bSopenharmony_ci+      new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE));
2617b5975d6bSopenharmony_ci       g_bytes_unref (bytes);
2618b5975d6bSopenharmony_ci     }
2619b5975d6bSopenharmony_ci   else
2620b5975d6bSopenharmony_ci     /* contains no multi-byte data */
2621b5975d6bSopenharmony_ci-    new = value;
2622b5975d6bSopenharmony_ci+    new = g_variant_get_normal_form (value);
2623b5975d6bSopenharmony_ci 
2624b5975d6bSopenharmony_ci-  return g_variant_ref_sink (new);
2625b5975d6bSopenharmony_ci+  g_assert (g_variant_is_trusted (new));
2626b5975d6bSopenharmony_ci+
2627b5975d6bSopenharmony_ci+  return g_steal_pointer (&new);
2628b5975d6bSopenharmony_ci }
2629b5975d6bSopenharmony_ci 
2630b5975d6bSopenharmony_ci /**
2631b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
2632b5975d6bSopenharmony_ciindex d4893ed407..1e7ed16cc9 100644
2633b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
2634b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
2635b5975d6bSopenharmony_ci@@ -3826,6 +3826,29 @@ test_gv_byteswap (void)
2636b5975d6bSopenharmony_ci   g_free (string);
2637b5975d6bSopenharmony_ci }
2638b5975d6bSopenharmony_ci 
2639b5975d6bSopenharmony_ci+static void
2640b5975d6bSopenharmony_ci+test_gv_byteswap_non_normal_non_aligned (void)
2641b5975d6bSopenharmony_ci+{
2642b5975d6bSopenharmony_ci+  const guint8 data[] = { 0x02 };
2643b5975d6bSopenharmony_ci+  GVariant *v = NULL;
2644b5975d6bSopenharmony_ci+  GVariant *v_byteswapped = NULL;
2645b5975d6bSopenharmony_ci+
2646b5975d6bSopenharmony_ci+  g_test_summary ("Test that calling g_variant_byteswap() on a variant which "
2647b5975d6bSopenharmony_ci+                  "is in non-normal form and doesn’t need byteswapping returns "
2648b5975d6bSopenharmony_ci+                  "the same variant in normal form.");
2649b5975d6bSopenharmony_ci+
2650b5975d6bSopenharmony_ci+  v = g_variant_new_from_data (G_VARIANT_TYPE_BOOLEAN, data, sizeof (data), FALSE, NULL, NULL);
2651b5975d6bSopenharmony_ci+  g_assert_false (g_variant_is_normal_form (v));
2652b5975d6bSopenharmony_ci+
2653b5975d6bSopenharmony_ci+  v_byteswapped = g_variant_byteswap (v);
2654b5975d6bSopenharmony_ci+  g_assert_true (g_variant_is_normal_form (v_byteswapped));
2655b5975d6bSopenharmony_ci+
2656b5975d6bSopenharmony_ci+  g_assert_cmpvariant (v, v_byteswapped);
2657b5975d6bSopenharmony_ci+
2658b5975d6bSopenharmony_ci+  g_variant_unref (v);
2659b5975d6bSopenharmony_ci+  g_variant_unref (v_byteswapped);
2660b5975d6bSopenharmony_ci+}
2661b5975d6bSopenharmony_ci+
2662b5975d6bSopenharmony_ci static void
2663b5975d6bSopenharmony_ci test_parser (void)
2664b5975d6bSopenharmony_ci {
2665b5975d6bSopenharmony_ci@@ -5711,6 +5734,7 @@ main (int argc, char **argv)
2666b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/builder-memory", test_builder_memory);
2667b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/hashing", test_hashing);
2668b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/byteswap", test_gv_byteswap);
2669b5975d6bSopenharmony_ci+  g_test_add_func ("/gvariant/byteswap/non-normal-non-aligned", test_gv_byteswap_non_normal_non_aligned);
2670b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/parser", test_parses);
2671b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/parser/integer-bounds", test_parser_integer_bounds);
2672b5975d6bSopenharmony_ci   g_test_add_func ("/gvariant/parser/recursion", test_parser_recursion);
2673b5975d6bSopenharmony_ci-- 
2674b5975d6bSopenharmony_ciGitLab
2675b5975d6bSopenharmony_ci
2676b5975d6bSopenharmony_ci
2677b5975d6bSopenharmony_ciFrom a70a16b28bf78403dc86ae798c291ba167573d4a Mon Sep 17 00:00:00 2001
2678b5975d6bSopenharmony_ciFrom: Philip Withnall <pwithnall@endlessos.org>
2679b5975d6bSopenharmony_ciDate: Thu, 27 Oct 2022 22:53:13 +0100
2680b5975d6bSopenharmony_ciSubject: [PATCH 18/18] gvariant: Allow g_variant_byteswap() to operate on
2681b5975d6bSopenharmony_ci tree-form variants
2682b5975d6bSopenharmony_ciMIME-Version: 1.0
2683b5975d6bSopenharmony_ciContent-Type: text/plain; charset=UTF-8
2684b5975d6bSopenharmony_ciContent-Transfer-Encoding: 8bit
2685b5975d6bSopenharmony_ci
2686b5975d6bSopenharmony_ciThis avoids needing to always serialise a variant before byteswapping it.
2687b5975d6bSopenharmony_ciWith variants in non-normal forms, serialisation can result in a large
2688b5975d6bSopenharmony_ciincrease in size of the variant, and a lot of allocations for leaf
2689b5975d6bSopenharmony_ci`GVariant`s. This can lead to a denial of service attack.
2690b5975d6bSopenharmony_ci
2691b5975d6bSopenharmony_ciAvoid that by changing byteswapping so that it happens on the tree form
2692b5975d6bSopenharmony_ciof the variant if the input is in non-normal form. If the input is in
2693b5975d6bSopenharmony_cinormal form (either serialised or in tree form), continue using the
2694b5975d6bSopenharmony_ciexisting code as byteswapping an already-serialised normal variant is
2695b5975d6bSopenharmony_ciabout 3× faster than byteswapping on the equivalent tree form.
2696b5975d6bSopenharmony_ci
2697b5975d6bSopenharmony_ciThe existing unit tests cover byteswapping well, but need some
2698b5975d6bSopenharmony_ciadaptation so that they operate on tree form variants too.
2699b5975d6bSopenharmony_ci
2700b5975d6bSopenharmony_ciI considered dropping the serialised byteswapping code and doing all
2701b5975d6bSopenharmony_cibyteswapping on tree-form variants, as that would make maintenance
2702b5975d6bSopenharmony_cisimpler (avoiding having two parallel implementations of byteswapping).
2703b5975d6bSopenharmony_ciHowever, most inputs to `g_variant_byteswap()` are likely to be
2704b5975d6bSopenharmony_ciserialised variants (coming from a byte array of input from some foreign
2705b5975d6bSopenharmony_cisource) and most of them are going to be in normal form (as corruption
2706b5975d6bSopenharmony_ciand malicious action are rare). So getting rid of the serialised
2707b5975d6bSopenharmony_cibyteswapping code would impose quite a performance penalty on the common
2708b5975d6bSopenharmony_cicase.
2709b5975d6bSopenharmony_ci
2710b5975d6bSopenharmony_ciSigned-off-by: Philip Withnall <pwithnall@endlessos.org>
2711b5975d6bSopenharmony_ci
2712b5975d6bSopenharmony_ciFixes: #2797
2713b5975d6bSopenharmony_ci---
2714b5975d6bSopenharmony_ci glib/gvariant.c       | 87 ++++++++++++++++++++++++++++++++-----------
2715b5975d6bSopenharmony_ci glib/tests/gvariant.c | 57 ++++++++++++++++++++++++----
2716b5975d6bSopenharmony_ci 2 files changed, 115 insertions(+), 29 deletions(-)
2717b5975d6bSopenharmony_ci
2718b5975d6bSopenharmony_cidiff --git a/glib/gvariant.c b/glib/gvariant.c
2719b5975d6bSopenharmony_ciindex f7b2e97036..5fef88d58d 100644
2720b5975d6bSopenharmony_ci--- a/glib/gvariant.c
2721b5975d6bSopenharmony_ci+++ b/glib/gvariant.c
2722b5975d6bSopenharmony_ci@@ -5852,7 +5852,8 @@ g_variant_iter_loop (GVariantIter *iter,
2723b5975d6bSopenharmony_ci 
2724b5975d6bSopenharmony_ci /* Serialized data {{{1 */
2725b5975d6bSopenharmony_ci static GVariant *
2726b5975d6bSopenharmony_ci-g_variant_deep_copy (GVariant *value)
2727b5975d6bSopenharmony_ci+g_variant_deep_copy (GVariant *value,
2728b5975d6bSopenharmony_ci+                     gboolean  byteswap)
2729b5975d6bSopenharmony_ci {
2730b5975d6bSopenharmony_ci   switch (g_variant_classify (value))
2731b5975d6bSopenharmony_ci     {
2732b5975d6bSopenharmony_ci@@ -5869,7 +5870,7 @@ g_variant_deep_copy (GVariant *value)
2733b5975d6bSopenharmony_ci         for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++)
2734b5975d6bSopenharmony_ci           {
2735b5975d6bSopenharmony_ci             GVariant *child = g_variant_get_child_value (value, i);
2736b5975d6bSopenharmony_ci-            g_variant_builder_add_value (&builder, g_variant_deep_copy (child));
2737b5975d6bSopenharmony_ci+            g_variant_builder_add_value (&builder, g_variant_deep_copy (child, byteswap));
2738b5975d6bSopenharmony_ci             g_variant_unref (child);
2739b5975d6bSopenharmony_ci           }
2740b5975d6bSopenharmony_ci 
2741b5975d6bSopenharmony_ci@@ -5920,7 +5921,7 @@ g_variant_deep_copy (GVariant *value)
2742b5975d6bSopenharmony_ci                  * be non-normal for reasons other than invalid offset table
2743b5975d6bSopenharmony_ci                  * entries. As they are all the same type, they will all have
2744b5975d6bSopenharmony_ci                  * the same default value though, so keep that around. */
2745b5975d6bSopenharmony_ci-                g_variant_builder_add_value (&builder, g_variant_deep_copy (child));
2746b5975d6bSopenharmony_ci+                g_variant_builder_add_value (&builder, g_variant_deep_copy (child, byteswap));
2747b5975d6bSopenharmony_ci               }
2748b5975d6bSopenharmony_ci             else if (child == NULL && first_invalid_child_deep_copy != NULL)
2749b5975d6bSopenharmony_ci               {
2750b5975d6bSopenharmony_ci@@ -5929,7 +5930,7 @@ g_variant_deep_copy (GVariant *value)
2751b5975d6bSopenharmony_ci             else if (child == NULL)
2752b5975d6bSopenharmony_ci               {
2753b5975d6bSopenharmony_ci                 child = g_variant_get_child_value (value, i);
2754b5975d6bSopenharmony_ci-                first_invalid_child_deep_copy = g_variant_ref_sink (g_variant_deep_copy (child));
2755b5975d6bSopenharmony_ci+                first_invalid_child_deep_copy = g_variant_ref_sink (g_variant_deep_copy (child, byteswap));
2756b5975d6bSopenharmony_ci                 g_variant_builder_add_value (&builder, first_invalid_child_deep_copy);
2757b5975d6bSopenharmony_ci               }
2758b5975d6bSopenharmony_ci 
2759b5975d6bSopenharmony_ci@@ -5948,28 +5949,63 @@ g_variant_deep_copy (GVariant *value)
2760b5975d6bSopenharmony_ci       return g_variant_new_byte (g_variant_get_byte (value));
2761b5975d6bSopenharmony_ci 
2762b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_INT16:
2763b5975d6bSopenharmony_ci-      return g_variant_new_int16 (g_variant_get_int16 (value));
2764b5975d6bSopenharmony_ci+      if (byteswap)
2765b5975d6bSopenharmony_ci+        return g_variant_new_int16 (GUINT16_SWAP_LE_BE (g_variant_get_int16 (value)));
2766b5975d6bSopenharmony_ci+      else
2767b5975d6bSopenharmony_ci+        return g_variant_new_int16 (g_variant_get_int16 (value));
2768b5975d6bSopenharmony_ci 
2769b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_UINT16:
2770b5975d6bSopenharmony_ci-      return g_variant_new_uint16 (g_variant_get_uint16 (value));
2771b5975d6bSopenharmony_ci+      if (byteswap)
2772b5975d6bSopenharmony_ci+        return g_variant_new_uint16 (GUINT16_SWAP_LE_BE (g_variant_get_uint16 (value)));
2773b5975d6bSopenharmony_ci+      else
2774b5975d6bSopenharmony_ci+        return g_variant_new_uint16 (g_variant_get_uint16 (value));
2775b5975d6bSopenharmony_ci 
2776b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_INT32:
2777b5975d6bSopenharmony_ci-      return g_variant_new_int32 (g_variant_get_int32 (value));
2778b5975d6bSopenharmony_ci+      if (byteswap)
2779b5975d6bSopenharmony_ci+        return g_variant_new_int32 (GUINT32_SWAP_LE_BE (g_variant_get_int32 (value)));
2780b5975d6bSopenharmony_ci+      else
2781b5975d6bSopenharmony_ci+        return g_variant_new_int32 (g_variant_get_int32 (value));
2782b5975d6bSopenharmony_ci 
2783b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_UINT32:
2784b5975d6bSopenharmony_ci-      return g_variant_new_uint32 (g_variant_get_uint32 (value));
2785b5975d6bSopenharmony_ci+      if (byteswap)
2786b5975d6bSopenharmony_ci+        return g_variant_new_uint32 (GUINT32_SWAP_LE_BE (g_variant_get_uint32 (value)));
2787b5975d6bSopenharmony_ci+      else
2788b5975d6bSopenharmony_ci+        return g_variant_new_uint32 (g_variant_get_uint32 (value));
2789b5975d6bSopenharmony_ci 
2790b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_INT64:
2791b5975d6bSopenharmony_ci-      return g_variant_new_int64 (g_variant_get_int64 (value));
2792b5975d6bSopenharmony_ci+      if (byteswap)
2793b5975d6bSopenharmony_ci+        return g_variant_new_int64 (GUINT64_SWAP_LE_BE (g_variant_get_int64 (value)));
2794b5975d6bSopenharmony_ci+      else
2795b5975d6bSopenharmony_ci+        return g_variant_new_int64 (g_variant_get_int64 (value));
2796b5975d6bSopenharmony_ci 
2797b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_UINT64:
2798b5975d6bSopenharmony_ci-      return g_variant_new_uint64 (g_variant_get_uint64 (value));
2799b5975d6bSopenharmony_ci+      if (byteswap)
2800b5975d6bSopenharmony_ci+        return g_variant_new_uint64 (GUINT64_SWAP_LE_BE (g_variant_get_uint64 (value)));
2801b5975d6bSopenharmony_ci+      else
2802b5975d6bSopenharmony_ci+        return g_variant_new_uint64 (g_variant_get_uint64 (value));
2803b5975d6bSopenharmony_ci 
2804b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_HANDLE:
2805b5975d6bSopenharmony_ci-      return g_variant_new_handle (g_variant_get_handle (value));
2806b5975d6bSopenharmony_ci+      if (byteswap)
2807b5975d6bSopenharmony_ci+        return g_variant_new_handle (GUINT32_SWAP_LE_BE (g_variant_get_handle (value)));
2808b5975d6bSopenharmony_ci+      else
2809b5975d6bSopenharmony_ci+        return g_variant_new_handle (g_variant_get_handle (value));
2810b5975d6bSopenharmony_ci 
2811b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_DOUBLE:
2812b5975d6bSopenharmony_ci-      return g_variant_new_double (g_variant_get_double (value));
2813b5975d6bSopenharmony_ci+      if (byteswap)
2814b5975d6bSopenharmony_ci+        {
2815b5975d6bSopenharmony_ci+          /* We have to convert the double to a uint64 here using a union,
2816b5975d6bSopenharmony_ci+           * because a cast will round it numerically. */
2817b5975d6bSopenharmony_ci+          union
2818b5975d6bSopenharmony_ci+            {
2819b5975d6bSopenharmony_ci+              guint64 u64;
2820b5975d6bSopenharmony_ci+              gdouble dbl;
2821b5975d6bSopenharmony_ci+            } u1, u2;
2822b5975d6bSopenharmony_ci+          u1.dbl = g_variant_get_double (value);
2823b5975d6bSopenharmony_ci+          u2.u64 = GUINT64_SWAP_LE_BE (u1.u64);
2824b5975d6bSopenharmony_ci+          return g_variant_new_double (u2.dbl);
2825b5975d6bSopenharmony_ci+        }
2826b5975d6bSopenharmony_ci+      else
2827b5975d6bSopenharmony_ci+        return g_variant_new_double (g_variant_get_double (value));
2828b5975d6bSopenharmony_ci 
2829b5975d6bSopenharmony_ci     case G_VARIANT_CLASS_STRING:
2830b5975d6bSopenharmony_ci       return g_variant_new_string (g_variant_get_string (value, NULL));
2831b5975d6bSopenharmony_ci@@ -6026,7 +6062,7 @@ g_variant_get_normal_form (GVariant *value)
2832b5975d6bSopenharmony_ci   if (g_variant_is_normal_form (value))
2833b5975d6bSopenharmony_ci     return g_variant_ref (value);
2834b5975d6bSopenharmony_ci 
2835b5975d6bSopenharmony_ci-  trusted = g_variant_deep_copy (value);
2836b5975d6bSopenharmony_ci+  trusted = g_variant_deep_copy (value, FALSE);
2837b5975d6bSopenharmony_ci   g_assert (g_variant_is_trusted (trusted));
2838b5975d6bSopenharmony_ci 
2839b5975d6bSopenharmony_ci   return g_variant_ref_sink (trusted);
2840b5975d6bSopenharmony_ci@@ -6046,6 +6082,11 @@ g_variant_get_normal_form (GVariant *value)
2841b5975d6bSopenharmony_ci  * contain multi-byte numeric data.  That include strings, booleans,
2842b5975d6bSopenharmony_ci  * bytes and containers containing only these things (recursively).
2843b5975d6bSopenharmony_ci  *
2844b5975d6bSopenharmony_ci+ * While this function can safely handle untrusted, non-normal data, it is
2845b5975d6bSopenharmony_ci+ * recommended to check whether the input is in normal form beforehand, using
2846b5975d6bSopenharmony_ci+ * g_variant_is_normal_form(), and to reject non-normal inputs if your
2847b5975d6bSopenharmony_ci+ * application can be strict about what inputs it rejects.
2848b5975d6bSopenharmony_ci+ *
2849b5975d6bSopenharmony_ci  * The returned value is always in normal form and is marked as trusted.
2850b5975d6bSopenharmony_ci  *
2851b5975d6bSopenharmony_ci  * Returns: (transfer full): the byteswapped form of @value
2852b5975d6bSopenharmony_ci@@ -6064,22 +6105,21 @@ g_variant_byteswap (GVariant *value)
2853b5975d6bSopenharmony_ci 
2854b5975d6bSopenharmony_ci   g_variant_type_info_query (type_info, &alignment, NULL);
2855b5975d6bSopenharmony_ci 
2856b5975d6bSopenharmony_ci-  if (alignment)
2857b5975d6bSopenharmony_ci-    /* (potentially) contains multi-byte numeric data */
2858b5975d6bSopenharmony_ci+  if (alignment && g_variant_is_normal_form (value))
2859b5975d6bSopenharmony_ci     {
2860b5975d6bSopenharmony_ci+      /* (potentially) contains multi-byte numeric data, but is also already in
2861b5975d6bSopenharmony_ci+       * normal form so we can use a faster byteswapping codepath on the
2862b5975d6bSopenharmony_ci+       * serialised data */
2863b5975d6bSopenharmony_ci       GVariantSerialised serialised = { 0, };
2864b5975d6bSopenharmony_ci-      GVariant *trusted;
2865b5975d6bSopenharmony_ci       GBytes *bytes;
2866b5975d6bSopenharmony_ci 
2867b5975d6bSopenharmony_ci-      trusted = g_variant_get_normal_form (value);
2868b5975d6bSopenharmony_ci-      serialised.type_info = g_variant_get_type_info (trusted);
2869b5975d6bSopenharmony_ci-      serialised.size = g_variant_get_size (trusted);
2870b5975d6bSopenharmony_ci+      serialised.type_info = g_variant_get_type_info (value);
2871b5975d6bSopenharmony_ci+      serialised.size = g_variant_get_size (value);
2872b5975d6bSopenharmony_ci       serialised.data = g_malloc (serialised.size);
2873b5975d6bSopenharmony_ci-      serialised.depth = g_variant_get_depth (trusted);
2874b5975d6bSopenharmony_ci+      serialised.depth = g_variant_get_depth (value);
2875b5975d6bSopenharmony_ci       serialised.ordered_offsets_up_to = G_MAXSIZE;  /* operating on the normal form */
2876b5975d6bSopenharmony_ci       serialised.checked_offsets_up_to = G_MAXSIZE;
2877b5975d6bSopenharmony_ci-      g_variant_store (trusted, serialised.data);
2878b5975d6bSopenharmony_ci-      g_variant_unref (trusted);
2879b5975d6bSopenharmony_ci+      g_variant_store (value, serialised.data);
2880b5975d6bSopenharmony_ci 
2881b5975d6bSopenharmony_ci       g_variant_serialised_byteswap (serialised);
2882b5975d6bSopenharmony_ci 
2883b5975d6bSopenharmony_ci@@ -6087,6 +6127,9 @@ g_variant_byteswap (GVariant *value)
2884b5975d6bSopenharmony_ci       new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE));
2885b5975d6bSopenharmony_ci       g_bytes_unref (bytes);
2886b5975d6bSopenharmony_ci     }
2887b5975d6bSopenharmony_ci+  else if (alignment)
2888b5975d6bSopenharmony_ci+    /* (potentially) contains multi-byte numeric data */
2889b5975d6bSopenharmony_ci+    new = g_variant_ref_sink (g_variant_deep_copy (value, TRUE));
2890b5975d6bSopenharmony_ci   else
2891b5975d6bSopenharmony_ci     /* contains no multi-byte data */
2892b5975d6bSopenharmony_ci     new = g_variant_get_normal_form (value);
2893b5975d6bSopenharmony_cidiff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
2894b5975d6bSopenharmony_ciindex 1e7ed16cc9..3357488a4f 100644
2895b5975d6bSopenharmony_ci--- a/glib/tests/gvariant.c
2896b5975d6bSopenharmony_ci+++ b/glib/tests/gvariant.c
2897b5975d6bSopenharmony_ci@@ -2288,24 +2288,67 @@ serialise_tree (TreeInstance       *tree,
2898b5975d6bSopenharmony_ci static void
2899b5975d6bSopenharmony_ci test_byteswap (void)
2900b5975d6bSopenharmony_ci {
2901b5975d6bSopenharmony_ci-  GVariantSerialised one = { 0, }, two = { 0, };
2902b5975d6bSopenharmony_ci+  GVariantSerialised one = { 0, }, two = { 0, }, three = { 0, };
2903b5975d6bSopenharmony_ci   TreeInstance *tree;
2904b5975d6bSopenharmony_ci-
2905b5975d6bSopenharmony_ci+  GVariant *one_variant = NULL;
2906b5975d6bSopenharmony_ci+  GVariant *two_variant = NULL;
2907b5975d6bSopenharmony_ci+  GVariant *two_byteswapped = NULL;
2908b5975d6bSopenharmony_ci+  GVariant *three_variant = NULL;
2909b5975d6bSopenharmony_ci+  GVariant *three_byteswapped = NULL;
2910b5975d6bSopenharmony_ci+  guint8 *three_data_copy = NULL;
2911b5975d6bSopenharmony_ci+  gsize three_size_copy = 0;
2912b5975d6bSopenharmony_ci+
2913b5975d6bSopenharmony_ci+  /* Write a tree out twice, once normally and once byteswapped. */
2914b5975d6bSopenharmony_ci   tree = tree_instance_new (NULL, 3);
2915b5975d6bSopenharmony_ci   serialise_tree (tree, &one);
2916b5975d6bSopenharmony_ci 
2917b5975d6bSopenharmony_ci+  one_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (one.type_info)),
2918b5975d6bSopenharmony_ci+                                         one.data, one.size, FALSE, NULL, NULL);
2919b5975d6bSopenharmony_ci+
2920b5975d6bSopenharmony_ci   i_am_writing_byteswapped = TRUE;
2921b5975d6bSopenharmony_ci   serialise_tree (tree, &two);
2922b5975d6bSopenharmony_ci+  serialise_tree (tree, &three);
2923b5975d6bSopenharmony_ci   i_am_writing_byteswapped = FALSE;
2924b5975d6bSopenharmony_ci 
2925b5975d6bSopenharmony_ci-  g_variant_serialised_byteswap (two);
2926b5975d6bSopenharmony_ci-
2927b5975d6bSopenharmony_ci-  g_assert_cmpmem (one.data, one.size, two.data, two.size);
2928b5975d6bSopenharmony_ci-  g_assert_cmpuint (one.depth, ==, two.depth);
2929b5975d6bSopenharmony_ci-
2930b5975d6bSopenharmony_ci+  /* Swap the first byteswapped one back using the function we want to test. */
2931b5975d6bSopenharmony_ci+  two_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (two.type_info)),
2932b5975d6bSopenharmony_ci+                                         two.data, two.size, FALSE, NULL, NULL);
2933b5975d6bSopenharmony_ci+  two_byteswapped = g_variant_byteswap (two_variant);
2934b5975d6bSopenharmony_ci+
2935b5975d6bSopenharmony_ci+  /* Make the second byteswapped one non-normal (hopefully), and then byteswap
2936b5975d6bSopenharmony_ci+   * it back using the function we want to test in its non-normal mode.
2937b5975d6bSopenharmony_ci+   * This might not work because it’s not necessarily possible to make an
2938b5975d6bSopenharmony_ci+   * arbitrary random variant non-normal. Adding a single zero byte to the end
2939b5975d6bSopenharmony_ci+   * often makes something non-normal but still readable. */
2940b5975d6bSopenharmony_ci+  three_size_copy = three.size + 1;
2941b5975d6bSopenharmony_ci+  three_data_copy = g_malloc (three_size_copy);
2942b5975d6bSopenharmony_ci+  memcpy (three_data_copy, three.data, three.size);
2943b5975d6bSopenharmony_ci+  three_data_copy[three.size] = '\0';
2944b5975d6bSopenharmony_ci+
2945b5975d6bSopenharmony_ci+  three_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (three.type_info)),
2946b5975d6bSopenharmony_ci+                                           three_data_copy, three_size_copy, FALSE, NULL, NULL);
2947b5975d6bSopenharmony_ci+  three_byteswapped = g_variant_byteswap (three_variant);
2948b5975d6bSopenharmony_ci+
2949b5975d6bSopenharmony_ci+  /* Check they’re the same. We can always compare @one_variant and
2950b5975d6bSopenharmony_ci+   * @two_byteswapped. We can only compare @two_byteswapped and
2951b5975d6bSopenharmony_ci+   * @three_byteswapped if @two_variant and @three_variant are equal: in that
2952b5975d6bSopenharmony_ci+   * case, the corruption to @three_variant was enough to make it non-normal but
2953b5975d6bSopenharmony_ci+   * not enough to change its value. */
2954b5975d6bSopenharmony_ci+  g_assert_cmpvariant (one_variant, two_byteswapped);
2955b5975d6bSopenharmony_ci+
2956b5975d6bSopenharmony_ci+  if (g_variant_equal (two_variant, three_variant))
2957b5975d6bSopenharmony_ci+    g_assert_cmpvariant (two_byteswapped, three_byteswapped);
2958b5975d6bSopenharmony_ci+
2959b5975d6bSopenharmony_ci+  g_variant_unref (three_byteswapped);
2960b5975d6bSopenharmony_ci+  g_variant_unref (three_variant);
2961b5975d6bSopenharmony_ci+  g_variant_unref (two_byteswapped);
2962b5975d6bSopenharmony_ci+  g_variant_unref (two_variant);
2963b5975d6bSopenharmony_ci+  g_variant_unref (one_variant);
2964b5975d6bSopenharmony_ci   tree_instance_free (tree);
2965b5975d6bSopenharmony_ci   g_free (one.data);
2966b5975d6bSopenharmony_ci   g_free (two.data);
2967b5975d6bSopenharmony_ci+  g_free (three.data);
2968b5975d6bSopenharmony_ci+  g_free (three_data_copy);
2969b5975d6bSopenharmony_ci }
2970b5975d6bSopenharmony_ci 
2971b5975d6bSopenharmony_ci static void
2972b5975d6bSopenharmony_ci-- 
2973b5975d6bSopenharmony_ciGitLab
2974b5975d6bSopenharmony_ci
2975