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 (¤t, 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