diff options
10 files changed, 1877 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0001.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0001.patch new file mode 100644 index 0000000000..2b7536c42d --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0001.patch | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | From 1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: William Manley <will@stb-tester.com> | ||
| 3 | Date: Wed, 9 Aug 2023 10:04:49 +0000 | ||
| 4 | Subject: [PATCH] gvariant-core: Consolidate construction of | ||
| 5 | `GVariantSerialised` | ||
| 6 | |||
| 7 | So I only need to change it in one place. | ||
| 8 | |||
| 9 | This introduces no functional changes. | ||
| 10 | |||
| 11 | Helps: #2121 | ||
| 12 | |||
| 13 | CVE: CVE-2023-32665 | ||
| 14 | |||
| 15 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1] | ||
| 16 | |||
| 17 | Signed-off-by: Soumya <soumya.sambu@windriver.com> | ||
| 18 | --- | ||
| 19 | glib/gvariant-core.c | 49 ++++++++++++++++++++++---------------------- | ||
| 20 | 1 file changed, 25 insertions(+), 24 deletions(-) | ||
| 21 | |||
| 22 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 23 | index a31d396..496f2e2 100644 | ||
| 24 | --- a/glib/gvariant-core.c | ||
| 25 | +++ b/glib/gvariant-core.c | ||
| 26 | @@ -349,6 +349,27 @@ g_variant_ensure_size (GVariant *value) | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | +/* < private > | ||
| 31 | + * g_variant_to_serialised: | ||
| 32 | + * @value: a #GVariant | ||
| 33 | + * | ||
| 34 | + * Gets a GVariantSerialised for a GVariant in state STATE_SERIALISED. | ||
| 35 | + */ | ||
| 36 | +inline static GVariantSerialised | ||
| 37 | +g_variant_to_serialised (GVariant *value) | ||
| 38 | +{ | ||
| 39 | + g_assert (value->state & STATE_SERIALISED); | ||
| 40 | + { | ||
| 41 | + GVariantSerialised serialised = { | ||
| 42 | + value->type_info, | ||
| 43 | + (gpointer) value->contents.serialised.data, | ||
| 44 | + value->size, | ||
| 45 | + value->depth, | ||
| 46 | + }; | ||
| 47 | + return serialised; | ||
| 48 | + } | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | /* < private > | ||
| 52 | * g_variant_serialise: | ||
| 53 | * @value: a #GVariant | ||
| 54 | @@ -1007,16 +1028,8 @@ g_variant_n_children (GVariant *value) | ||
| 55 | g_variant_lock (value); | ||
| 56 | |||
| 57 | if (value->state & STATE_SERIALISED) | ||
| 58 | - { | ||
| 59 | - GVariantSerialised serialised = { | ||
| 60 | - value->type_info, | ||
| 61 | - (gpointer) value->contents.serialised.data, | ||
| 62 | - value->size, | ||
| 63 | - value->depth, | ||
| 64 | - }; | ||
| 65 | - | ||
| 66 | - n_children = g_variant_serialised_n_children (serialised); | ||
| 67 | - } | ||
| 68 | + n_children = g_variant_serialised_n_children ( | ||
| 69 | + g_variant_to_serialised (value)); | ||
| 70 | else | ||
| 71 | n_children = value->contents.tree.n_children; | ||
| 72 | |||
| 73 | @@ -1083,12 +1096,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 74 | } | ||
| 75 | |||
| 76 | { | ||
| 77 | - GVariantSerialised serialised = { | ||
| 78 | - value->type_info, | ||
| 79 | - (gpointer) value->contents.serialised.data, | ||
| 80 | - value->size, | ||
| 81 | - value->depth, | ||
| 82 | - }; | ||
| 83 | + GVariantSerialised serialised = g_variant_to_serialised (value); | ||
| 84 | GVariantSerialised s_child; | ||
| 85 | GVariant *child; | ||
| 86 | |||
| 87 | @@ -1201,14 +1209,7 @@ g_variant_is_normal_form (GVariant *value) | ||
| 88 | |||
| 89 | if (value->state & STATE_SERIALISED) | ||
| 90 | { | ||
| 91 | - GVariantSerialised serialised = { | ||
| 92 | - value->type_info, | ||
| 93 | - (gpointer) value->contents.serialised.data, | ||
| 94 | - value->size, | ||
| 95 | - value->depth | ||
| 96 | - }; | ||
| 97 | - | ||
| 98 | - if (g_variant_serialised_is_normal (serialised)) | ||
| 99 | + if (g_variant_serialised_is_normal (g_variant_to_serialised (value))) | ||
| 100 | value->state |= STATE_TRUSTED; | ||
| 101 | } | ||
| 102 | else | ||
| 103 | -- | ||
| 104 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0002.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0002.patch new file mode 100644 index 0000000000..4eff85a5f3 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0002.patch | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | From 446e69f5edd72deb2196dee36bbaf8056caf6948 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: William Manley <will@stb-tester.com> | ||
| 3 | Date: Wed, 9 Aug 2023 10:39:34 +0000 | ||
| 4 | Subject: [PATCH] gvariant-serialiser: Factor out functions for dealing with | ||
| 5 | framing offsets | ||
| 6 | |||
| 7 | This introduces no functional changes. | ||
| 8 | |||
| 9 | Helps: #2121 | ||
| 10 | |||
| 11 | CVE: CVE-2023-32665 | ||
| 12 | |||
| 13 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/446e69f5edd72deb2196dee36bbaf8056caf6948] | ||
| 14 | |||
| 15 | Signed-off-by: Soumya <soumya.sambu@windriver.com> | ||
| 16 | --- | ||
| 17 | glib/gvariant-serialiser.c | 108 +++++++++++++++++++------------------ | ||
| 18 | 1 file changed, 57 insertions(+), 51 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 21 | index 7b13381..e71248e 100644 | ||
| 22 | --- a/glib/gvariant-serialiser.c | ||
| 23 | +++ b/glib/gvariant-serialiser.c | ||
| 24 | @@ -633,30 +633,62 @@ gvs_calculate_total_size (gsize body_size, | ||
| 25 | return body_size + 8 * offsets; | ||
| 26 | } | ||
| 27 | |||
| 28 | +struct Offsets | ||
| 29 | +{ | ||
| 30 | + gsize data_size; | ||
| 31 | + | ||
| 32 | + guchar *array; | ||
| 33 | + gsize length; | ||
| 34 | + guint offset_size; | ||
| 35 | + | ||
| 36 | + gboolean is_normal; | ||
| 37 | +}; | ||
| 38 | + | ||
| 39 | static gsize | ||
| 40 | -gvs_variable_sized_array_n_children (GVariantSerialised value) | ||
| 41 | +gvs_offsets_get_offset_n (struct Offsets *offsets, | ||
| 42 | + gsize n) | ||
| 43 | +{ | ||
| 44 | + return gvs_read_unaligned_le ( | ||
| 45 | + offsets->array + (offsets->offset_size * n), offsets->offset_size); | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +static struct Offsets | ||
| 49 | +gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value) | ||
| 50 | { | ||
| 51 | + struct Offsets out = { 0, }; | ||
| 52 | gsize offsets_array_size; | ||
| 53 | - gsize offset_size; | ||
| 54 | gsize last_end; | ||
| 55 | |||
| 56 | if (value.size == 0) | ||
| 57 | - return 0; | ||
| 58 | - | ||
| 59 | - offset_size = gvs_get_offset_size (value.size); | ||
| 60 | + { | ||
| 61 | + out.is_normal = TRUE; | ||
| 62 | + return out; | ||
| 63 | + } | ||
| 64 | |||
| 65 | - last_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 66 | - offset_size, offset_size); | ||
| 67 | + out.offset_size = gvs_get_offset_size (value.size); | ||
| 68 | + last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size, | ||
| 69 | + out.offset_size); | ||
| 70 | |||
| 71 | if (last_end > value.size) | ||
| 72 | - return 0; | ||
| 73 | + return out; /* offsets not normal */ | ||
| 74 | |||
| 75 | offsets_array_size = value.size - last_end; | ||
| 76 | |||
| 77 | - if (offsets_array_size % offset_size) | ||
| 78 | - return 0; | ||
| 79 | + if (offsets_array_size % out.offset_size) | ||
| 80 | + return out; /* offsets not normal */ | ||
| 81 | + | ||
| 82 | + out.data_size = last_end; | ||
| 83 | + out.array = value.data + last_end; | ||
| 84 | + out.length = offsets_array_size / out.offset_size; | ||
| 85 | + out.is_normal = TRUE; | ||
| 86 | |||
| 87 | - return offsets_array_size / offset_size; | ||
| 88 | + return out; | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +static gsize | ||
| 92 | +gvs_variable_sized_array_n_children (GVariantSerialised value) | ||
| 93 | +{ | ||
| 94 | + return gvs_variable_sized_array_get_frame_offsets (value).length; | ||
| 95 | } | ||
| 96 | |||
| 97 | static GVariantSerialised | ||
| 98 | @@ -664,8 +696,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 99 | gsize index_) | ||
| 100 | { | ||
| 101 | GVariantSerialised child = { 0, }; | ||
| 102 | - gsize offset_size; | ||
| 103 | - gsize last_end; | ||
| 104 | + | ||
| 105 | + struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value); | ||
| 106 | + | ||
| 107 | gsize start; | ||
| 108 | gsize end; | ||
| 109 | |||
| 110 | @@ -673,18 +706,11 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 111 | g_variant_type_info_ref (child.type_info); | ||
| 112 | child.depth = value.depth + 1; | ||
| 113 | |||
| 114 | - offset_size = gvs_get_offset_size (value.size); | ||
| 115 | - | ||
| 116 | - last_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 117 | - offset_size, offset_size); | ||
| 118 | - | ||
| 119 | if (index_ > 0) | ||
| 120 | { | ||
| 121 | guint alignment; | ||
| 122 | |||
| 123 | - start = gvs_read_unaligned_le (value.data + last_end + | ||
| 124 | - (offset_size * (index_ - 1)), | ||
| 125 | - offset_size); | ||
| 126 | + start = gvs_offsets_get_offset_n (&offsets, index_ - 1); | ||
| 127 | |||
| 128 | g_variant_type_info_query (child.type_info, &alignment, NULL); | ||
| 129 | start += (-start) & alignment; | ||
| 130 | @@ -692,11 +718,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 131 | else | ||
| 132 | start = 0; | ||
| 133 | |||
| 134 | - end = gvs_read_unaligned_le (value.data + last_end + | ||
| 135 | - (offset_size * index_), | ||
| 136 | - offset_size); | ||
| 137 | + end = gvs_offsets_get_offset_n (&offsets, index_); | ||
| 138 | |||
| 139 | - if (start < end && end <= value.size && end <= last_end) | ||
| 140 | + if (start < end && end <= value.size && end <= offsets.data_size) | ||
| 141 | { | ||
| 142 | child.data = value.data + start; | ||
| 143 | child.size = end - start; | ||
| 144 | @@ -768,34 +792,16 @@ static gboolean | ||
| 145 | gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 146 | { | ||
| 147 | GVariantSerialised child = { 0, }; | ||
| 148 | - gsize offsets_array_size; | ||
| 149 | - guchar *offsets_array; | ||
| 150 | - guint offset_size; | ||
| 151 | guint alignment; | ||
| 152 | - gsize last_end; | ||
| 153 | - gsize length; | ||
| 154 | gsize offset; | ||
| 155 | gsize i; | ||
| 156 | |||
| 157 | - if (value.size == 0) | ||
| 158 | - return TRUE; | ||
| 159 | - | ||
| 160 | - offset_size = gvs_get_offset_size (value.size); | ||
| 161 | - last_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 162 | - offset_size, offset_size); | ||
| 163 | + struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value); | ||
| 164 | |||
| 165 | - if (last_end > value.size) | ||
| 166 | + if (!offsets.is_normal) | ||
| 167 | return FALSE; | ||
| 168 | |||
| 169 | - offsets_array_size = value.size - last_end; | ||
| 170 | - | ||
| 171 | - if (offsets_array_size % offset_size) | ||
| 172 | - return FALSE; | ||
| 173 | - | ||
| 174 | - offsets_array = value.data + value.size - offsets_array_size; | ||
| 175 | - length = offsets_array_size / offset_size; | ||
| 176 | - | ||
| 177 | - if (length == 0) | ||
| 178 | + if (value.size != 0 && offsets.length == 0) | ||
| 179 | return FALSE; | ||
| 180 | |||
| 181 | child.type_info = g_variant_type_info_element (value.type_info); | ||
| 182 | @@ -803,14 +809,14 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 183 | child.depth = value.depth + 1; | ||
| 184 | offset = 0; | ||
| 185 | |||
| 186 | - for (i = 0; i < length; i++) | ||
| 187 | + for (i = 0; i < offsets.length; i++) | ||
| 188 | { | ||
| 189 | gsize this_end; | ||
| 190 | |||
| 191 | - this_end = gvs_read_unaligned_le (offsets_array + offset_size * i, | ||
| 192 | - offset_size); | ||
| 193 | + this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i, | ||
| 194 | + offsets.offset_size); | ||
| 195 | |||
| 196 | - if (this_end < offset || this_end > last_end) | ||
| 197 | + if (this_end < offset || this_end > offsets.data_size) | ||
| 198 | return FALSE; | ||
| 199 | |||
| 200 | while (offset & alignment) | ||
| 201 | @@ -832,7 +838,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 202 | offset = this_end; | ||
| 203 | } | ||
| 204 | |||
| 205 | - g_assert (offset == last_end); | ||
| 206 | + g_assert (offset == offsets.data_size); | ||
| 207 | |||
| 208 | return TRUE; | ||
| 209 | } | ||
| 210 | -- | ||
| 211 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0003.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0003.patch new file mode 100644 index 0000000000..183c6b20e7 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0003.patch | |||
| @@ -0,0 +1,418 @@ | |||
| 1 | From ade71fb544391b2e33e1859645726bfee0d5eaaf Mon Sep 17 00:00:00 2001 | ||
| 2 | From: William Manley <will@stb-tester.com> | ||
| 3 | Date: Wed, 16 Aug 2023 03:12:21 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Don't allow child elements to overlap with each | ||
| 5 | other | ||
| 6 | |||
| 7 | If different elements of a variable sized array can overlap with each | ||
| 8 | other then we can cause a `GVariant` to normalise to a much larger type. | ||
| 9 | |||
| 10 | This commit changes the behaviour of `GVariant` with non-normal form data. If | ||
| 11 | an invalid frame offset is found all subsequent elements are given their | ||
| 12 | default value. | ||
| 13 | |||
| 14 | When retrieving an element at index `n` we scan the frame offsets up to index | ||
| 15 | `n` and if they are not in order we return an element with the default value | ||
| 16 | for that type. This guarantees that elements don't overlap with each | ||
| 17 | other. We remember the offset we've scanned up to so we don't need to | ||
| 18 | repeat this work on subsequent accesses. We skip these checks for trusted | ||
| 19 | data. | ||
| 20 | |||
| 21 | Unfortunately this makes random access of untrusted data O(n) — at least | ||
| 22 | on first access. It doesn't affect the algorithmic complexity of accessing | ||
| 23 | elements in order, such as when using the `GVariantIter` interface. Also: | ||
| 24 | the cost of validation will be amortised as the `GVariant` instance is | ||
| 25 | continued to be used. | ||
| 26 | |||
| 27 | I've implemented this with 4 different functions, 1 for each element size, | ||
| 28 | rather than looping calling `gvs_read_unaligned_le` in the hope that the | ||
| 29 | compiler will find it easy to optimise and should produce fairly tight | ||
| 30 | code. | ||
| 31 | |||
| 32 | Fixes: #2121 | ||
| 33 | |||
| 34 | CVE: CVE-2023-32665 | ||
| 35 | |||
| 36 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/ade71fb544391b2e33e1859645726bfee0d5eaaf] | ||
| 37 | |||
| 38 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
| 39 | --- | ||
| 40 | glib/gvariant-core.c | 35 ++++++++++++++++ | ||
| 41 | glib/gvariant-serialiser.c | 86 ++++++++++++++++++++++++++++++++++++-- | ||
| 42 | glib/gvariant-serialiser.h | 8 ++++ | ||
| 43 | glib/tests/gvariant.c | 45 ++++++++++++++++++++ | ||
| 44 | 4 files changed, 171 insertions(+), 3 deletions(-) | ||
| 45 | |||
| 46 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 47 | index 496f2e2..4e0b2b5 100644 | ||
| 48 | --- a/glib/gvariant-core.c | ||
| 49 | +++ b/glib/gvariant-core.c | ||
| 50 | @@ -65,6 +65,7 @@ struct _GVariant | ||
| 51 | { | ||
| 52 | GBytes *bytes; | ||
| 53 | gconstpointer data; | ||
| 54 | + gsize ordered_offsets_up_to; | ||
| 55 | } serialised; | ||
| 56 | |||
| 57 | struct | ||
| 58 | @@ -162,6 +163,24 @@ struct _GVariant | ||
| 59 | * if .data pointed to the appropriate number of nul | ||
| 60 | * bytes. | ||
| 61 | * | ||
| 62 | + * .ordered_offsets_up_to: If ordered_offsets_up_to == n this means that all | ||
| 63 | + * the frame offsets up to and including the frame | ||
| 64 | + * offset determining the end of element n are in | ||
| 65 | + * order. This guarantees that the bytes of element | ||
| 66 | + * n don't overlap with any previous element. | ||
| 67 | + * | ||
| 68 | + * For trusted data this is set to G_MAXSIZE and we | ||
| 69 | + * don't check that the frame offsets are in order. | ||
| 70 | + * | ||
| 71 | + * Note: This doesn't imply the offsets are good in | ||
| 72 | + * any way apart from their ordering. In particular | ||
| 73 | + * offsets may be out of bounds for this value or | ||
| 74 | + * may imply that the data overlaps the frame | ||
| 75 | + * offsets themselves. | ||
| 76 | + * | ||
| 77 | + * This field is only relevant for arrays of non | ||
| 78 | + * fixed width types. | ||
| 79 | + * | ||
| 80 | * .tree: Only valid when the instance is in tree form. | ||
| 81 | * | ||
| 82 | * Note that accesses from other threads could result in | ||
| 83 | @@ -365,6 +384,7 @@ g_variant_to_serialised (GVariant *value) | ||
| 84 | (gpointer) value->contents.serialised.data, | ||
| 85 | value->size, | ||
| 86 | value->depth, | ||
| 87 | + value->contents.serialised.ordered_offsets_up_to, | ||
| 88 | }; | ||
| 89 | return serialised; | ||
| 90 | } | ||
| 91 | @@ -396,6 +416,7 @@ g_variant_serialise (GVariant *value, | ||
| 92 | serialised.size = value->size; | ||
| 93 | serialised.data = data; | ||
| 94 | serialised.depth = value->depth; | ||
| 95 | + serialised.ordered_offsets_up_to = 0; | ||
| 96 | |||
| 97 | children = (gpointer *) value->contents.tree.children; | ||
| 98 | n_children = value->contents.tree.n_children; | ||
| 99 | @@ -439,6 +460,15 @@ g_variant_fill_gvs (GVariantSerialised *serialised, | ||
| 100 | g_assert (serialised->size == value->size); | ||
| 101 | serialised->depth = value->depth; | ||
| 102 | |||
| 103 | + if (value->state & STATE_SERIALISED) | ||
| 104 | + { | ||
| 105 | + serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to; | ||
| 106 | + } | ||
| 107 | + else | ||
| 108 | + { | ||
| 109 | + serialised->ordered_offsets_up_to = 0; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | if (serialised->data) | ||
| 113 | /* g_variant_store() is a public API, so it | ||
| 114 | * it will reacquire the lock if it needs to. | ||
| 115 | @@ -481,6 +511,7 @@ g_variant_ensure_serialised (GVariant *value) | ||
| 116 | bytes = g_bytes_new_take (data, value->size); | ||
| 117 | value->contents.serialised.data = g_bytes_get_data (bytes, NULL); | ||
| 118 | value->contents.serialised.bytes = bytes; | ||
| 119 | + value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE; | ||
| 120 | value->state |= STATE_SERIALISED; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | @@ -561,6 +592,7 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 124 | serialised.type_info = value->type_info; | ||
| 125 | serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size); | ||
| 126 | serialised.depth = 0; | ||
| 127 | + serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 128 | |||
| 129 | if (!g_variant_serialised_check (serialised)) | ||
| 130 | { | ||
| 131 | @@ -611,6 +643,8 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 132 | value->contents.serialised.data = g_bytes_get_data (bytes, &value->size); | ||
| 133 | } | ||
| 134 | |||
| 135 | + value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 136 | + | ||
| 137 | g_clear_pointer (&owned_bytes, g_bytes_unref); | ||
| 138 | |||
| 139 | return value; | ||
| 140 | @@ -1130,6 +1164,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 141 | child->contents.serialised.bytes = | ||
| 142 | g_bytes_ref (value->contents.serialised.bytes); | ||
| 143 | child->contents.serialised.data = s_child.data; | ||
| 144 | + child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; | ||
| 145 | |||
| 146 | return child; | ||
| 147 | } | ||
| 148 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 149 | index e71248e..6fb3f2f 100644 | ||
| 150 | --- a/glib/gvariant-serialiser.c | ||
| 151 | +++ b/glib/gvariant-serialiser.c | ||
| 152 | @@ -1,6 +1,7 @@ | ||
| 153 | /* | ||
| 154 | * Copyright © 2007, 2008 Ryan Lortie | ||
| 155 | * Copyright © 2010 Codethink Limited | ||
| 156 | + * Copyright © 2020 William Manley | ||
| 157 | * | ||
| 158 | * This library is free software; you can redistribute it and/or | ||
| 159 | * modify it under the terms of the GNU Lesser General Public | ||
| 160 | @@ -264,6 +265,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, | ||
| 161 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 162 | g_variant_type_info_ref (value.type_info); | ||
| 163 | value.depth++; | ||
| 164 | + value.ordered_offsets_up_to = 0; | ||
| 165 | |||
| 166 | return value; | ||
| 167 | } | ||
| 168 | @@ -295,7 +297,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, | ||
| 169 | { | ||
| 170 | if (n_children) | ||
| 171 | { | ||
| 172 | - GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1 }; | ||
| 173 | + GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 }; | ||
| 174 | |||
| 175 | gvs_filler (&child, children[0]); | ||
| 176 | } | ||
| 177 | @@ -317,6 +319,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) | ||
| 178 | /* proper element size: "Just". recurse to the child. */ | ||
| 179 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 180 | value.depth++; | ||
| 181 | + value.ordered_offsets_up_to = 0; | ||
| 182 | |||
| 183 | return g_variant_serialised_is_normal (value); | ||
| 184 | } | ||
| 185 | @@ -358,6 +361,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, | ||
| 186 | value.data = NULL; | ||
| 187 | |||
| 188 | value.depth++; | ||
| 189 | + value.ordered_offsets_up_to = 0; | ||
| 190 | |||
| 191 | return value; | ||
| 192 | } | ||
| 193 | @@ -388,7 +392,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, | ||
| 194 | { | ||
| 195 | if (n_children) | ||
| 196 | { | ||
| 197 | - GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1 }; | ||
| 198 | + GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 }; | ||
| 199 | |||
| 200 | /* write the data for the child. */ | ||
| 201 | gvs_filler (&child, children[0]); | ||
| 202 | @@ -408,6 +412,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value) | ||
| 203 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 204 | value.size--; | ||
| 205 | value.depth++; | ||
| 206 | + value.ordered_offsets_up_to = 0; | ||
| 207 | |||
| 208 | return g_variant_serialised_is_normal (value); | ||
| 209 | } | ||
| 210 | @@ -691,6 +696,32 @@ gvs_variable_sized_array_n_children (GVariantSerialised value) | ||
| 211 | return gvs_variable_sized_array_get_frame_offsets (value).length; | ||
| 212 | } | ||
| 213 | |||
| 214 | +/* Find the index of the first out-of-order element in @data, assuming that | ||
| 215 | + * @data is an array of elements of given @type, starting at index @start and | ||
| 216 | + * containing a further @len-@start elements. */ | ||
| 217 | +#define DEFINE_FIND_UNORDERED(type) \ | ||
| 218 | + static gsize \ | ||
| 219 | + find_unordered_##type (const guint8 *data, gsize start, gsize len) \ | ||
| 220 | + { \ | ||
| 221 | + gsize off; \ | ||
| 222 | + type current, previous; \ | ||
| 223 | + \ | ||
| 224 | + memcpy (&previous, data + start * sizeof (current), sizeof (current)); \ | ||
| 225 | + for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \ | ||
| 226 | + { \ | ||
| 227 | + memcpy (¤t, data + off, sizeof (current)); \ | ||
| 228 | + if (current < previous) \ | ||
| 229 | + break; \ | ||
| 230 | + previous = current; \ | ||
| 231 | + } \ | ||
| 232 | + return off / sizeof (current) - 1; \ | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | +DEFINE_FIND_UNORDERED (guint8); | ||
| 236 | +DEFINE_FIND_UNORDERED (guint16); | ||
| 237 | +DEFINE_FIND_UNORDERED (guint32); | ||
| 238 | +DEFINE_FIND_UNORDERED (guint64); | ||
| 239 | + | ||
| 240 | static GVariantSerialised | ||
| 241 | gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 242 | gsize index_) | ||
| 243 | @@ -706,6 +737,49 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 244 | g_variant_type_info_ref (child.type_info); | ||
| 245 | child.depth = value.depth + 1; | ||
| 246 | |||
| 247 | + /* If the requested @index_ is beyond the set of indices whose framing offsets | ||
| 248 | + * have been checked, check the remaining offsets to see whether they’re | ||
| 249 | + * normal (in order, no overlapping array elements). */ | ||
| 250 | + if (index_ > value.ordered_offsets_up_to) | ||
| 251 | + { | ||
| 252 | + switch (offsets.offset_size) | ||
| 253 | + { | ||
| 254 | + case 1: | ||
| 255 | + { | ||
| 256 | + value.ordered_offsets_up_to = find_unordered_guint8 ( | ||
| 257 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 258 | + break; | ||
| 259 | + } | ||
| 260 | + case 2: | ||
| 261 | + { | ||
| 262 | + value.ordered_offsets_up_to = find_unordered_guint16 ( | ||
| 263 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 264 | + break; | ||
| 265 | + } | ||
| 266 | + case 4: | ||
| 267 | + { | ||
| 268 | + value.ordered_offsets_up_to = find_unordered_guint32 ( | ||
| 269 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 270 | + break; | ||
| 271 | + } | ||
| 272 | + case 8: | ||
| 273 | + { | ||
| 274 | + value.ordered_offsets_up_to = find_unordered_guint64 ( | ||
| 275 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 276 | + break; | ||
| 277 | + } | ||
| 278 | + default: | ||
| 279 | + /* gvs_get_offset_size() only returns maximum 8 */ | ||
| 280 | + g_assert_not_reached (); | ||
| 281 | + } | ||
| 282 | + } | ||
| 283 | + | ||
| 284 | + if (index_ > value.ordered_offsets_up_to) | ||
| 285 | + { | ||
| 286 | + /* Offsets are invalid somewhere, so return an empty child. */ | ||
| 287 | + return child; | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | if (index_ > 0) | ||
| 291 | { | ||
| 292 | guint alignment; | ||
| 293 | @@ -840,6 +914,9 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 294 | |||
| 295 | g_assert (offset == offsets.data_size); | ||
| 296 | |||
| 297 | + /* All offsets have now been checked. */ | ||
| 298 | + value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 299 | + | ||
| 300 | return TRUE; | ||
| 301 | } | ||
| 302 | |||
| 303 | @@ -1072,7 +1149,7 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 304 | for (i = 0; i < length; i++) | ||
| 305 | { | ||
| 306 | const GVariantMemberInfo *member_info; | ||
| 307 | - GVariantSerialised child; | ||
| 308 | + GVariantSerialised child = { 0, }; | ||
| 309 | gsize fixed_size; | ||
| 310 | guint alignment; | ||
| 311 | gsize end; | ||
| 312 | @@ -1132,6 +1209,9 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 313 | offset = end; | ||
| 314 | } | ||
| 315 | |||
| 316 | + /* All element bounds have been checked above. */ | ||
| 317 | + value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 318 | + | ||
| 319 | { | ||
| 320 | gsize fixed_size; | ||
| 321 | guint alignment; | ||
| 322 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
| 323 | index 859cb7b..3ab83b3 100644 | ||
| 324 | --- a/glib/gvariant-serialiser.h | ||
| 325 | +++ b/glib/gvariant-serialiser.h | ||
| 326 | @@ -29,6 +29,14 @@ typedef struct | ||
| 327 | guchar *data; | ||
| 328 | gsize size; | ||
| 329 | gsize depth; /* same semantics as GVariant.depth */ | ||
| 330 | + /* If ordered_offsets_up_to == n this means that all the frame offsets up to and | ||
| 331 | + * including the frame offset determining the end of element n are in order. | ||
| 332 | + * This guarantees that the bytes of element n don't overlap with any previous | ||
| 333 | + * element. | ||
| 334 | + * | ||
| 335 | + * This is both read and set by g_variant_serialised_get_child for arrays of | ||
| 336 | + * non-fixed-width types */ | ||
| 337 | + gsize ordered_offsets_up_to; | ||
| 338 | } GVariantSerialised; | ||
| 339 | |||
| 340 | /* deserialization */ | ||
| 341 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 342 | index 0110f26..291f796 100644 | ||
| 343 | --- a/glib/tests/gvariant.c | ||
| 344 | +++ b/glib/tests/gvariant.c | ||
| 345 | @@ -1,5 +1,6 @@ | ||
| 346 | /* | ||
| 347 | * Copyright © 2010 Codethink Limited | ||
| 348 | + * Copyright © 2020 William Manley | ||
| 349 | * | ||
| 350 | * This library is free software; you can redistribute it and/or | ||
| 351 | * modify it under the terms of the GNU Lesser General Public | ||
| 352 | @@ -1279,6 +1280,7 @@ random_instance_filler (GVariantSerialised *serialised, | ||
| 353 | serialised->size = instance->size; | ||
| 354 | |||
| 355 | serialised->depth = 0; | ||
| 356 | + serialised->ordered_offsets_up_to = 0; | ||
| 357 | |||
| 358 | g_assert_true (serialised->type_info == instance->type_info); | ||
| 359 | g_assert_cmpuint (serialised->size, ==, instance->size); | ||
| 360 | @@ -5023,6 +5025,47 @@ test_normal_checking_array_offsets (void) | ||
| 361 | g_variant_unref (variant); | ||
| 362 | } | ||
| 363 | |||
| 364 | +/* This is a regression test that we can't have non-normal values that take up | ||
| 365 | + * significantly more space than the normal equivalent, by specifying the | ||
| 366 | + * offset table entries so that array elements overlap. | ||
| 367 | + * | ||
| 368 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_832242 */ | ||
| 369 | +static void | ||
| 370 | +test_normal_checking_array_offsets2 (void) | ||
| 371 | +{ | ||
| 372 | + const guint8 data[] = { | ||
| 373 | + 'h', 'i', '\0', | ||
| 374 | + 0x03, 0x00, 0x03, | ||
| 375 | + 0x06, 0x00, 0x06, | ||
| 376 | + 0x09, 0x00, 0x09, | ||
| 377 | + 0x0c, 0x00, 0x0c, | ||
| 378 | + 0x0f, 0x00, 0x0f, | ||
| 379 | + 0x12, 0x00, 0x12, | ||
| 380 | + 0x15, 0x00, 0x15, | ||
| 381 | + }; | ||
| 382 | + gsize size = sizeof (data); | ||
| 383 | + const GVariantType *aaaaaaas = G_VARIANT_TYPE ("aaaaaaas"); | ||
| 384 | + GVariant *variant = NULL; | ||
| 385 | + GVariant *normal_variant = NULL; | ||
| 386 | + GVariant *expected = NULL; | ||
| 387 | + | ||
| 388 | + variant = g_variant_new_from_data (aaaaaaas, data, size, FALSE, NULL, NULL); | ||
| 389 | + g_assert_nonnull (variant); | ||
| 390 | + | ||
| 391 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 392 | + g_assert_nonnull (normal_variant); | ||
| 393 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 2); | ||
| 394 | + | ||
| 395 | + expected = g_variant_new_parsed ( | ||
| 396 | + "[[[[[[['hi', '', ''], [], []], [], []], [], []], [], []], [], []], [], []]"); | ||
| 397 | + g_assert_cmpvariant (expected, variant); | ||
| 398 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 399 | + | ||
| 400 | + g_variant_unref (expected); | ||
| 401 | + g_variant_unref (normal_variant); | ||
| 402 | + g_variant_unref (variant); | ||
| 403 | +} | ||
| 404 | + | ||
| 405 | /* Test that a tuple with invalidly large values in its offset table is | ||
| 406 | * normalised successfully without looping infinitely. */ | ||
| 407 | static void | ||
| 408 | @@ -5189,6 +5232,8 @@ main (int argc, char **argv) | ||
| 409 | test_normal_checking_tuples); | ||
| 410 | g_test_add_func ("/gvariant/normal-checking/array-offsets", | ||
| 411 | test_normal_checking_array_offsets); | ||
| 412 | + g_test_add_func ("/gvariant/normal-checking/array-offsets2", | ||
| 413 | + test_normal_checking_array_offsets2); | ||
| 414 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets", | ||
| 415 | test_normal_checking_tuple_offsets); | ||
| 416 | g_test_add_func ("/gvariant/normal-checking/empty-object-path", | ||
| 417 | -- | ||
| 418 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0004.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0004.patch new file mode 100644 index 0000000000..791efdee87 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0004.patch | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | From 345cae9c1aa7bf6752039225ef4c8d8d69fa8d76 Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Fri, 11 Aug 2023 04:09:12 +0000 | ||
| 4 | Subject: [PATCH] gvariant-serialiser: Factor out code to get bounds of a tuple | ||
| 5 | member | ||
| 6 | |||
| 7 | This introduces no functional changes. | ||
| 8 | |||
| 9 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 10 | |||
| 11 | Helps: #2121 | ||
| 12 | |||
| 13 | CVE: CVE-2023-32665 | ||
| 14 | |||
| 15 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/345cae9c1aa7bf6752039225ef4c8d8d69fa8d76] | ||
| 16 | |||
| 17 | Signed-off-by: Soumya <soumya.sambu@windriver.com> | ||
| 18 | --- | ||
| 19 | glib/gvariant-serialiser.c | 73 ++++++++++++++++++++++++-------------- | ||
| 20 | 1 file changed, 46 insertions(+), 27 deletions(-) | ||
| 21 | |||
| 22 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 23 | index 2932427..1c23eab 100644 | ||
| 24 | --- a/glib/gvariant-serialiser.c | ||
| 25 | +++ b/glib/gvariant-serialiser.c | ||
| 26 | @@ -946,6 +946,51 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 27 | * for the tuple. See the notes in gvarianttypeinfo.h. | ||
| 28 | */ | ||
| 29 | |||
| 30 | +static void | ||
| 31 | +gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 32 | + gsize index_, | ||
| 33 | + gsize offset_size, | ||
| 34 | + gsize *out_member_start, | ||
| 35 | + gsize *out_member_end) | ||
| 36 | +{ | ||
| 37 | + const GVariantMemberInfo *member_info; | ||
| 38 | + gsize member_start, member_end; | ||
| 39 | + | ||
| 40 | + member_info = g_variant_type_info_member_info (value.type_info, index_); | ||
| 41 | + | ||
| 42 | + if (member_info->i + 1) | ||
| 43 | + member_start = gvs_read_unaligned_le (value.data + value.size - | ||
| 44 | + offset_size * (member_info->i + 1), | ||
| 45 | + offset_size); | ||
| 46 | + else | ||
| 47 | + member_start = 0; | ||
| 48 | + | ||
| 49 | + member_start += member_info->a; | ||
| 50 | + member_start &= member_info->b; | ||
| 51 | + member_start |= member_info->c; | ||
| 52 | + | ||
| 53 | + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) | ||
| 54 | + member_end = value.size - offset_size * (member_info->i + 1); | ||
| 55 | + | ||
| 56 | + else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 57 | + { | ||
| 58 | + gsize fixed_size; | ||
| 59 | + | ||
| 60 | + g_variant_type_info_query (member_info->type_info, NULL, &fixed_size); | ||
| 61 | + member_end = member_start + fixed_size; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + else /* G_VARIANT_MEMBER_ENDING_OFFSET */ | ||
| 65 | + member_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 66 | + offset_size * (member_info->i + 2), | ||
| 67 | + offset_size); | ||
| 68 | + | ||
| 69 | + if (out_member_start != NULL) | ||
| 70 | + *out_member_start = member_start; | ||
| 71 | + if (out_member_end != NULL) | ||
| 72 | + *out_member_end = member_end; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | static gsize | ||
| 76 | gvs_tuple_n_children (GVariantSerialised value) | ||
| 77 | { | ||
| 78 | @@ -1001,33 +1046,7 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | - if (member_info->i + 1) | ||
| 83 | - start = gvs_read_unaligned_le (value.data + value.size - | ||
| 84 | - offset_size * (member_info->i + 1), | ||
| 85 | - offset_size); | ||
| 86 | - else | ||
| 87 | - start = 0; | ||
| 88 | - | ||
| 89 | - start += member_info->a; | ||
| 90 | - start &= member_info->b; | ||
| 91 | - start |= member_info->c; | ||
| 92 | - | ||
| 93 | - if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) | ||
| 94 | - end = value.size - offset_size * (member_info->i + 1); | ||
| 95 | - | ||
| 96 | - else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 97 | - { | ||
| 98 | - gsize fixed_size; | ||
| 99 | - | ||
| 100 | - g_variant_type_info_query (child.type_info, NULL, &fixed_size); | ||
| 101 | - end = start + fixed_size; | ||
| 102 | - child.size = fixed_size; | ||
| 103 | - } | ||
| 104 | - | ||
| 105 | - else /* G_VARIANT_MEMBER_ENDING_OFFSET */ | ||
| 106 | - end = gvs_read_unaligned_le (value.data + value.size - | ||
| 107 | - offset_size * (member_info->i + 2), | ||
| 108 | - offset_size); | ||
| 109 | + gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); | ||
| 110 | |||
| 111 | /* The child should not extend into the offset table. */ | ||
| 112 | if (index_ != g_variant_type_info_n_members (value.type_info) - 1) | ||
| 113 | -- | ||
| 114 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0005.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0005.patch new file mode 100644 index 0000000000..6c71c20819 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0005.patch | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | From 73d0aa81c2575a5c9ae77dcb94da919579014fc0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Fri, 11 Aug 2023 04:13:02 +0000 | ||
| 4 | Subject: [PATCH] gvariant-serialiser: Rework child size calculation | ||
| 5 | |||
| 6 | This reduces a few duplicate calls to `g_variant_type_info_query()` and | ||
| 7 | explains why they’re needed. | ||
| 8 | |||
| 9 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 10 | |||
| 11 | Helps: #2121 | ||
| 12 | |||
| 13 | CVE: CVE-2023-32665 | ||
| 14 | |||
| 15 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/73d0aa81c2575a5c9ae77dcb94da919579014fc0] | ||
| 16 | |||
| 17 | Signed-off-by: Soumya <soumya.sambu@windriver.com> | ||
| 18 | --- | ||
| 19 | glib/gvariant-serialiser.c | 31 +++++++++---------------------- | ||
| 20 | 1 file changed, 9 insertions(+), 22 deletions(-) | ||
| 21 | |||
| 22 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 23 | index 1c23eab..b63e99f 100644 | ||
| 24 | --- a/glib/gvariant-serialiser.c | ||
| 25 | +++ b/glib/gvariant-serialiser.c | ||
| 26 | @@ -1011,14 +1011,18 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 27 | child.depth = value.depth + 1; | ||
| 28 | offset_size = gvs_get_offset_size (value.size); | ||
| 29 | |||
| 30 | + /* Ensure the size is set for fixed-sized children, or | ||
| 31 | + * g_variant_serialised_check() will fail, even if we return | ||
| 32 | + * (child.data == NULL) to indicate an error. */ | ||
| 33 | + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 34 | + g_variant_type_info_query (child.type_info, NULL, &child.size); | ||
| 35 | + | ||
| 36 | /* tuples are the only (potentially) fixed-sized containers, so the | ||
| 37 | * only ones that have to deal with the possibility of having %NULL | ||
| 38 | * data with a non-zero %size if errors occurred elsewhere. | ||
| 39 | */ | ||
| 40 | if G_UNLIKELY (value.data == NULL && value.size != 0) | ||
| 41 | { | ||
| 42 | - g_variant_type_info_query (child.type_info, NULL, &child.size); | ||
| 43 | - | ||
| 44 | /* this can only happen in fixed-sized tuples, | ||
| 45 | * so the child must also be fixed sized. | ||
| 46 | */ | ||
| 47 | @@ -1036,29 +1040,12 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 48 | else | ||
| 49 | { | ||
| 50 | if (offset_size * (member_info->i + 1) > value.size) | ||
| 51 | - { | ||
| 52 | - /* if the child is fixed size, return its size. | ||
| 53 | - * if child is not fixed-sized, return size = 0. | ||
| 54 | - */ | ||
| 55 | - g_variant_type_info_query (child.type_info, NULL, &child.size); | ||
| 56 | - | ||
| 57 | - return child; | ||
| 58 | - } | ||
| 59 | + return child; | ||
| 60 | } | ||
| 61 | |||
| 62 | - gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); | ||
| 63 | - | ||
| 64 | /* The child should not extend into the offset table. */ | ||
| 65 | - if (index_ != g_variant_type_info_n_members (value.type_info) - 1) | ||
| 66 | - { | ||
| 67 | - GVariantSerialised last_child; | ||
| 68 | - last_child = gvs_tuple_get_child (value, | ||
| 69 | - g_variant_type_info_n_members (value.type_info) - 1); | ||
| 70 | - last_end = last_child.data + last_child.size - value.data; | ||
| 71 | - g_variant_type_info_unref (last_child.type_info); | ||
| 72 | - } | ||
| 73 | - else | ||
| 74 | - last_end = end; | ||
| 75 | + gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); | ||
| 76 | + gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end); | ||
| 77 | |||
| 78 | if (start < end && end <= value.size && end <= last_end) | ||
| 79 | { | ||
| 80 | -- | ||
| 81 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0006.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0006.patch new file mode 100644 index 0000000000..194ce15287 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0006.patch | |||
| @@ -0,0 +1,397 @@ | |||
| 1 | From 7cf6f5b69146d20948d42f0c476688fe17fef787 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Wed, 16 Aug 2023 12:09:06 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Don't allow child elements of a tuple to overlap | ||
| 5 | each other | ||
| 6 | |||
| 7 | This is similar to the earlier commit which prevents child elements of a | ||
| 8 | variable-sized array from overlapping each other, but this time for | ||
| 9 | tuples. It is based heavily on ideas by William Manley. | ||
| 10 | |||
| 11 | Tuples are slightly different from variable-sized arrays in that they | ||
| 12 | contain a mixture of fixed and variable sized elements. All but one of | ||
| 13 | the variable sized elements have an entry in the frame offsets table. | ||
| 14 | This means that if we were to just check the ordering of the frame | ||
| 15 | offsets table, the variable sized elements could still overlap | ||
| 16 | interleaving fixed sized elements, which would be bad. | ||
| 17 | |||
| 18 | Therefore we have to check the elements rather than the frame offsets. | ||
| 19 | |||
| 20 | The logic of checking the elements up to the index currently being | ||
| 21 | requested, and caching the result in `ordered_offsets_up_to`, means that | ||
| 22 | the algorithmic cost implications are the same for this commit as for | ||
| 23 | variable-sized arrays: an O(N) cost for these checks is amortised out | ||
| 24 | over N accesses to O(1) per access. | ||
| 25 | |||
| 26 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 27 | |||
| 28 | Fixes: #2121 | ||
| 29 | |||
| 30 | CVE: CVE-2023-32665 | ||
| 31 | |||
| 32 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/7cf6f5b69146d20948d42f0c476688fe17fef787] | ||
| 33 | |||
| 34 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
| 35 | --- | ||
| 36 | glib/gvariant-core.c | 6 +- | ||
| 37 | glib/gvariant-serialiser.c | 40 ++++++++ | ||
| 38 | glib/gvariant-serialiser.h | 7 +- | ||
| 39 | glib/gvariant.c | 1 + | ||
| 40 | glib/tests/gvariant.c | 181 +++++++++++++++++++++++++++++++++++++ | ||
| 41 | 5 files changed, 232 insertions(+), 3 deletions(-) | ||
| 42 | |||
| 43 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 44 | index 4e0b2b5..c57ee77 100644 | ||
| 45 | --- a/glib/gvariant-core.c | ||
| 46 | +++ b/glib/gvariant-core.c | ||
| 47 | @@ -1,6 +1,7 @@ | ||
| 48 | /* | ||
| 49 | * Copyright © 2007, 2008 Ryan Lortie | ||
| 50 | * Copyright © 2010 Codethink Limited | ||
| 51 | + * Copyright © 2022 Endless OS Foundation, LLC | ||
| 52 | * | ||
| 53 | * This library is free software; you can redistribute it and/or | ||
| 54 | * modify it under the terms of the GNU Lesser General Public | ||
| 55 | @@ -179,7 +180,7 @@ struct _GVariant | ||
| 56 | * offsets themselves. | ||
| 57 | * | ||
| 58 | * This field is only relevant for arrays of non | ||
| 59 | - * fixed width types. | ||
| 60 | + * fixed width types and for tuples. | ||
| 61 | * | ||
| 62 | * .tree: Only valid when the instance is in tree form. | ||
| 63 | * | ||
| 64 | @@ -1139,6 +1140,9 @@ g_variant_get_child_value (GVariant *value, | ||
| 65 | */ | ||
| 66 | s_child = g_variant_serialised_get_child (serialised, index_); | ||
| 67 | |||
| 68 | + /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */ | ||
| 69 | + value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to); | ||
| 70 | + | ||
| 71 | /* Check whether this would cause nesting too deep. If so, return a fake | ||
| 72 | * child. The only situation we expect this to happen in is with a variant, | ||
| 73 | * as all other deeply-nested types have a static type, and hence should | ||
| 74 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 75 | index 2493e76..d46d05c 100644 | ||
| 76 | --- a/glib/gvariant-serialiser.c | ||
| 77 | +++ b/glib/gvariant-serialiser.c | ||
| 78 | @@ -942,6 +942,10 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 79 | * for the tuple. See the notes in gvarianttypeinfo.h. | ||
| 80 | */ | ||
| 81 | |||
| 82 | +/* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that | ||
| 83 | + * condition may not hold true for invalid serialised variants. The caller is | ||
| 84 | + * responsible for checking the returned values and handling invalid ones | ||
| 85 | + * appropriately. */ | ||
| 86 | static void | ||
| 87 | gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 88 | gsize index_, | ||
| 89 | @@ -1028,6 +1032,42 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 90 | return child; | ||
| 91 | } | ||
| 92 | |||
| 93 | + /* If the requested @index_ is beyond the set of indices whose framing offsets | ||
| 94 | + * have been checked, check the remaining offsets to see whether they’re | ||
| 95 | + * normal (in order, no overlapping tuple elements). | ||
| 96 | + * | ||
| 97 | + * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check | ||
| 98 | + * all the tuple *elements* here, not just all the framing offsets, since | ||
| 99 | + * tuples contain a mix of elements which use framing offsets and ones which | ||
| 100 | + * don’t. None of them are allowed to overlap. */ | ||
| 101 | + if (index_ > value.ordered_offsets_up_to) | ||
| 102 | + { | ||
| 103 | + gsize i, prev_i_end = 0; | ||
| 104 | + | ||
| 105 | + if (value.ordered_offsets_up_to > 0) | ||
| 106 | + gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end); | ||
| 107 | + | ||
| 108 | + for (i = value.ordered_offsets_up_to; i <= index_; i++) | ||
| 109 | + { | ||
| 110 | + gsize i_start, i_end; | ||
| 111 | + | ||
| 112 | + gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end); | ||
| 113 | + | ||
| 114 | + if (i_start > i_end || i_start < prev_i_end || i_end > value.size) | ||
| 115 | + break; | ||
| 116 | + | ||
| 117 | + prev_i_end = i_end; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + value.ordered_offsets_up_to = i - 1; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + if (index_ > value.ordered_offsets_up_to) | ||
| 124 | + { | ||
| 125 | + /* Offsets are invalid somewhere, so return an empty child. */ | ||
| 126 | + return child; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET) | ||
| 130 | { | ||
| 131 | if (offset_size * (member_info->i + 2) > value.size) | ||
| 132 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
| 133 | index 3ab83b3..03826f9 100644 | ||
| 134 | --- a/glib/gvariant-serialiser.h | ||
| 135 | +++ b/glib/gvariant-serialiser.h | ||
| 136 | @@ -34,8 +34,11 @@ typedef struct | ||
| 137 | * This guarantees that the bytes of element n don't overlap with any previous | ||
| 138 | * element. | ||
| 139 | * | ||
| 140 | - * This is both read and set by g_variant_serialised_get_child for arrays of | ||
| 141 | - * non-fixed-width types */ | ||
| 142 | + * This is both read and set by g_variant_serialised_get_child() for arrays of | ||
| 143 | + * non-fixed-width types, and for tuples. | ||
| 144 | + * | ||
| 145 | + * Even when dealing with tuples, @ordered_offsets_up_to is an element index, | ||
| 146 | + * rather than an index into the frame offsets. */ | ||
| 147 | gsize ordered_offsets_up_to; | ||
| 148 | } GVariantSerialised; | ||
| 149 | |||
| 150 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 151 | index 42ffc9a..f645e05 100644 | ||
| 152 | --- a/glib/gvariant.c | ||
| 153 | +++ b/glib/gvariant.c | ||
| 154 | @@ -5997,6 +5997,7 @@ g_variant_byteswap (GVariant *value) | ||
| 155 | serialised.size = g_variant_get_size (trusted); | ||
| 156 | serialised.data = g_malloc (serialised.size); | ||
| 157 | serialised.depth = g_variant_get_depth (trusted); | ||
| 158 | + serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ | ||
| 159 | g_variant_store (trusted, serialised.data); | ||
| 160 | g_variant_unref (trusted); | ||
| 161 | |||
| 162 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 163 | index 291f796..3ddff96 100644 | ||
| 164 | --- a/glib/tests/gvariant.c | ||
| 165 | +++ b/glib/tests/gvariant.c | ||
| 166 | @@ -1,6 +1,7 @@ | ||
| 167 | /* | ||
| 168 | * Copyright © 2010 Codethink Limited | ||
| 169 | * Copyright © 2020 William Manley | ||
| 170 | + * Copyright © 2022 Endless OS Foundation, LLC | ||
| 171 | * | ||
| 172 | * This library is free software; you can redistribute it and/or | ||
| 173 | * modify it under the terms of the GNU Lesser General Public | ||
| 174 | @@ -1447,6 +1448,7 @@ test_maybe (void) | ||
| 175 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 176 | serialised.size = needed_size; | ||
| 177 | serialised.depth = 0; | ||
| 178 | + serialised.ordered_offsets_up_to = 0; | ||
| 179 | |||
| 180 | g_variant_serialiser_serialise (serialised, | ||
| 181 | random_instance_filler, | ||
| 182 | @@ -1570,6 +1572,7 @@ test_array (void) | ||
| 183 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 184 | serialised.size = needed_size; | ||
| 185 | serialised.depth = 0; | ||
| 186 | + serialised.ordered_offsets_up_to = 0; | ||
| 187 | |||
| 188 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 189 | (gpointer *) instances, n_children); | ||
| 190 | @@ -1734,6 +1737,7 @@ test_tuple (void) | ||
| 191 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 192 | serialised.size = needed_size; | ||
| 193 | serialised.depth = 0; | ||
| 194 | + serialised.ordered_offsets_up_to = 0; | ||
| 195 | |||
| 196 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 197 | (gpointer *) instances, n_children); | ||
| 198 | @@ -1830,6 +1834,7 @@ test_variant (void) | ||
| 199 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 200 | serialised.size = needed_size; | ||
| 201 | serialised.depth = 0; | ||
| 202 | + serialised.ordered_offsets_up_to = 0; | ||
| 203 | |||
| 204 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 205 | (gpointer *) &instance, 1); | ||
| 206 | @@ -5090,6 +5095,176 @@ test_normal_checking_tuple_offsets (void) | ||
| 207 | g_variant_unref (variant); | ||
| 208 | } | ||
| 209 | |||
| 210 | +/* This is a regression test that we can't have non-normal values that take up | ||
| 211 | + * significantly more space than the normal equivalent, by specifying the | ||
| 212 | + * offset table entries so that tuple elements overlap. | ||
| 213 | + * | ||
| 214 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838503 and | ||
| 215 | + * https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838513 */ | ||
| 216 | +static void | ||
| 217 | +test_normal_checking_tuple_offsets2 (void) | ||
| 218 | +{ | ||
| 219 | + const GVariantType *data_type = G_VARIANT_TYPE ("(yyaiyyaiyy)"); | ||
| 220 | + const guint8 data[] = { | ||
| 221 | + 0x12, 0x34, 0x56, 0x78, 0x01, | ||
| 222 | + /* | ||
| 223 | + ^───────────────────┘ | ||
| 224 | + | ||
| 225 | + ^^^^^^^^^^ 1st yy | ||
| 226 | + ^^^^^^^^^^ 2nd yy | ||
| 227 | + ^^^^^^^^^^ 3rd yy | ||
| 228 | + ^^^^ Framing offsets | ||
| 229 | + */ | ||
| 230 | + | ||
| 231 | + /* If this variant was encoded normally, it would be something like this: | ||
| 232 | + * 0x12, 0x34, pad, pad, [array bytes], 0x56, 0x78, pad, pad, [array bytes], 0x9A, 0xBC, 0xXX | ||
| 233 | + * ^─────────────────────────────────────────────────────┘ | ||
| 234 | + * | ||
| 235 | + * ^^^^^^^^^^ 1st yy | ||
| 236 | + * ^^^^^^^^^^ 2nd yy | ||
| 237 | + * ^^^^^^^^^^ 3rd yy | ||
| 238 | + * ^^^^ Framing offsets | ||
| 239 | + */ | ||
| 240 | + }; | ||
| 241 | + gsize size = sizeof (data); | ||
| 242 | + GVariant *variant = NULL; | ||
| 243 | + GVariant *normal_variant = NULL; | ||
| 244 | + GVariant *expected = NULL; | ||
| 245 | + | ||
| 246 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 247 | + g_assert_nonnull (variant); | ||
| 248 | + | ||
| 249 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 250 | + g_assert_nonnull (normal_variant); | ||
| 251 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); | ||
| 252 | + | ||
| 253 | + expected = g_variant_new_parsed ( | ||
| 254 | + "@(yyaiyyaiyy) (0x12, 0x34, [], 0x00, 0x00, [], 0x00, 0x00)"); | ||
| 255 | + g_assert_cmpvariant (expected, variant); | ||
| 256 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 257 | + | ||
| 258 | + g_variant_unref (expected); | ||
| 259 | + g_variant_unref (normal_variant); | ||
| 260 | + g_variant_unref (variant); | ||
| 261 | +} | ||
| 262 | + | ||
| 263 | +/* This is a regression test that overlapping entries in the offset table are | ||
| 264 | + * decoded consistently, even though they’re non-normal. | ||
| 265 | + * | ||
| 266 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */ | ||
| 267 | +static void | ||
| 268 | +test_normal_checking_tuple_offsets3 (void) | ||
| 269 | +{ | ||
| 270 | + /* The expected decoding of this non-normal byte stream is complex. See | ||
| 271 | + * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant | ||
| 272 | + * specification. | ||
| 273 | + * | ||
| 274 | + * The rule “Child Values Overlapping Framing Offsets” from the specification | ||
| 275 | + * says that the first `ay` must be decoded as `[0x01]` even though it | ||
| 276 | + * overlaps the first byte of the offset table. However, since commit | ||
| 277 | + * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow | ||
| 278 | + * this as it’s exploitable. So the first `ay` must be given a default value. | ||
| 279 | + * | ||
| 280 | + * The second and third `ay`s must be given default values because of rule | ||
| 281 | + * “End Boundary Precedes Start Boundary”. | ||
| 282 | + * | ||
| 283 | + * The `i` must be given a default value because of rule “Start or End | ||
| 284 | + * Boundary of a Child Falls Outside the Container”. | ||
| 285 | + */ | ||
| 286 | + const GVariantType *data_type = G_VARIANT_TYPE ("(ayayiay)"); | ||
| 287 | + const guint8 data[] = { | ||
| 288 | + 0x01, 0x00, 0x02, | ||
| 289 | + /* | ||
| 290 | + ^──┘ | ||
| 291 | + | ||
| 292 | + ^^^^^^^^^^ 1st ay, bytes 0-2 (but given a default value anyway, see above) | ||
| 293 | + 2nd ay, bytes 2-0 | ||
| 294 | + i, bytes 0-4 | ||
| 295 | + 3rd ay, bytes 4-1 | ||
| 296 | + ^^^^^^^^^^ Framing offsets | ||
| 297 | + */ | ||
| 298 | + }; | ||
| 299 | + gsize size = sizeof (data); | ||
| 300 | + GVariant *variant = NULL; | ||
| 301 | + GVariant *normal_variant = NULL; | ||
| 302 | + GVariant *expected = NULL; | ||
| 303 | + | ||
| 304 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 305 | + g_assert_nonnull (variant); | ||
| 306 | + | ||
| 307 | + g_assert_false (g_variant_is_normal_form (variant)); | ||
| 308 | + | ||
| 309 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 310 | + g_assert_nonnull (normal_variant); | ||
| 311 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); | ||
| 312 | + | ||
| 313 | + expected = g_variant_new_parsed ("@(ayayiay) ([], [], 0, [])"); | ||
| 314 | + g_assert_cmpvariant (expected, variant); | ||
| 315 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 316 | + | ||
| 317 | + g_variant_unref (expected); | ||
| 318 | + g_variant_unref (normal_variant); | ||
| 319 | + g_variant_unref (variant); | ||
| 320 | +} | ||
| 321 | + | ||
| 322 | +/* This is a regression test that overlapping entries in the offset table are | ||
| 323 | + * decoded consistently, even though they’re non-normal. | ||
| 324 | + * | ||
| 325 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */ | ||
| 326 | +static void | ||
| 327 | +test_normal_checking_tuple_offsets4 (void) | ||
| 328 | +{ | ||
| 329 | + /* The expected decoding of this non-normal byte stream is complex. See | ||
| 330 | + * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant | ||
| 331 | + * specification. | ||
| 332 | + * | ||
| 333 | + * The rule “Child Values Overlapping Framing Offsets” from the specification | ||
| 334 | + * says that the first `ay` must be decoded as `[0x01]` even though it | ||
| 335 | + * overlaps the first byte of the offset table. However, since commit | ||
| 336 | + * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow | ||
| 337 | + * this as it’s exploitable. So the first `ay` must be given a default value. | ||
| 338 | + * | ||
| 339 | + * The second `ay` must be given a default value because of rule “End Boundary | ||
| 340 | + * Precedes Start Boundary”. | ||
| 341 | + * | ||
| 342 | + * The third `ay` must be given a default value because its framing offsets | ||
| 343 | + * overlap that of the first `ay`. | ||
| 344 | + */ | ||
| 345 | + const GVariantType *data_type = G_VARIANT_TYPE ("(ayayay)"); | ||
| 346 | + const guint8 data[] = { | ||
| 347 | + 0x01, 0x00, 0x02, | ||
| 348 | + /* | ||
| 349 | + ^──┘ | ||
| 350 | + | ||
| 351 | + ^^^^^^^^^^ 1st ay, bytes 0-2 (but given a default value anyway, see above) | ||
| 352 | + 2nd ay, bytes 2-0 | ||
| 353 | + 3rd ay, bytes 0-1 | ||
| 354 | + ^^^^^^^^^^ Framing offsets | ||
| 355 | + */ | ||
| 356 | + }; | ||
| 357 | + gsize size = sizeof (data); | ||
| 358 | + GVariant *variant = NULL; | ||
| 359 | + GVariant *normal_variant = NULL; | ||
| 360 | + GVariant *expected = NULL; | ||
| 361 | + | ||
| 362 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 363 | + g_assert_nonnull (variant); | ||
| 364 | + | ||
| 365 | + g_assert_false (g_variant_is_normal_form (variant)); | ||
| 366 | + | ||
| 367 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 368 | + g_assert_nonnull (normal_variant); | ||
| 369 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); | ||
| 370 | + | ||
| 371 | + expected = g_variant_new_parsed ("@(ayayay) ([], [], [])"); | ||
| 372 | + g_assert_cmpvariant (expected, variant); | ||
| 373 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 374 | + | ||
| 375 | + g_variant_unref (expected); | ||
| 376 | + g_variant_unref (normal_variant); | ||
| 377 | + g_variant_unref (variant); | ||
| 378 | +} | ||
| 379 | + | ||
| 380 | /* Test that an empty object path is normalised successfully to the base object | ||
| 381 | * path, ‘/’. */ | ||
| 382 | static void | ||
| 383 | @@ -5236,6 +5411,12 @@ main (int argc, char **argv) | ||
| 384 | test_normal_checking_array_offsets2); | ||
| 385 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets", | ||
| 386 | test_normal_checking_tuple_offsets); | ||
| 387 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets2", | ||
| 388 | + test_normal_checking_tuple_offsets2); | ||
| 389 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets3", | ||
| 390 | + test_normal_checking_tuple_offsets3); | ||
| 391 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", | ||
| 392 | + test_normal_checking_tuple_offsets4); | ||
| 393 | g_test_add_func ("/gvariant/normal-checking/empty-object-path", | ||
| 394 | test_normal_checking_empty_object_path); | ||
| 395 | |||
| 396 | -- | ||
| 397 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0007.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0007.patch new file mode 100644 index 0000000000..8a408ab030 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0007.patch | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | From e6490c84e84ba9f182fbd83b51ff4f9f5a0a1793 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Wed, 16 Aug 2023 03:42:47 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Port g_variant_deep_copy() to count its iterations | ||
| 5 | directly | ||
| 6 | |||
| 7 | This is equivalent to what `GVariantIter` does, but it means that | ||
| 8 | `g_variant_deep_copy()` is making its own `g_variant_get_child_value()` | ||
| 9 | calls. | ||
| 10 | |||
| 11 | This will be useful in an upcoming commit, where those child values will | ||
| 12 | be inspected a little more deeply. | ||
| 13 | |||
| 14 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 15 | |||
| 16 | Helps: #2121 | ||
| 17 | |||
| 18 | CVE: CVE-2023-32665 | ||
| 19 | |||
| 20 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/e6490c84e84ba9f182fbd83b51ff4f9f5a0a1793] | ||
| 21 | |||
| 22 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
| 23 | --- | ||
| 24 | glib/gvariant.c | 7 +++---- | ||
| 25 | 1 file changed, 3 insertions(+), 4 deletions(-) | ||
| 26 | |||
| 27 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 28 | index 42ffc9a..ca13cc1 100644 | ||
| 29 | --- a/glib/gvariant.c | ||
| 30 | +++ b/glib/gvariant.c | ||
| 31 | @@ -5850,14 +5850,13 @@ g_variant_deep_copy (GVariant *value) | ||
| 32 | case G_VARIANT_CLASS_VARIANT: | ||
| 33 | { | ||
| 34 | GVariantBuilder builder; | ||
| 35 | - GVariantIter iter; | ||
| 36 | - GVariant *child; | ||
| 37 | + gsize i, n_children; | ||
| 38 | |||
| 39 | g_variant_builder_init (&builder, g_variant_get_type (value)); | ||
| 40 | - g_variant_iter_init (&iter, value); | ||
| 41 | |||
| 42 | - while ((child = g_variant_iter_next_value (&iter))) | ||
| 43 | + for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++) | ||
| 44 | { | ||
| 45 | + GVariant *child = g_variant_get_child_value (value, i); | ||
| 46 | g_variant_builder_add_value (&builder, g_variant_deep_copy (child)); | ||
| 47 | g_variant_unref (child); | ||
| 48 | } | ||
| 49 | -- | ||
| 50 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch new file mode 100644 index 0000000000..9b074a543d --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch | |||
| @@ -0,0 +1,395 @@ | |||
| 1 | From d1a293c4e29880b8d17bb826c9a426a440ca4a91 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Thu, 17 Aug 2023 01:30:38 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Track checked and ordered offsets independently | ||
| 5 | |||
| 6 | The past few commits introduced the concept of known-good offsets in the | ||
| 7 | offset table (which is used for variable-width arrays and tuples). | ||
| 8 | Good offsets are ones which are non-overlapping with all the previous | ||
| 9 | offsets in the table. | ||
| 10 | |||
| 11 | If a bad offset is encountered when indexing into the array or tuple, | ||
| 12 | the cached known-good offset index will not be increased. In this way, | ||
| 13 | all child variants at and beyond the first bad offset can be returned as | ||
| 14 | default values rather than dereferencing potentially invalid data. | ||
| 15 | |||
| 16 | In this case, there was no information about the fact that the indexes | ||
| 17 | between the highest known-good index and the requested one had been | ||
| 18 | checked already. That could lead to a pathological case where an offset | ||
| 19 | table with an invalid first offset is repeatedly checked in full when | ||
| 20 | trying to access higher-indexed children. | ||
| 21 | |||
| 22 | Avoid that by storing the index of the highest checked offset in the | ||
| 23 | table, as well as the index of the highest good/ordered offset. | ||
| 24 | |||
| 25 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 26 | |||
| 27 | Helps: #2121 | ||
| 28 | |||
| 29 | CVE: CVE-2023-32665 | ||
| 30 | |||
| 31 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/d1a293c4e29880b8d17bb826c9a426a440ca4a91] | ||
| 32 | |||
| 33 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
| 34 | --- | ||
| 35 | glib/gvariant-core.c | 28 ++++++++++++++++++++++++ | ||
| 36 | glib/gvariant-serialiser.c | 44 +++++++++++++++++++++++++++----------- | ||
| 37 | glib/gvariant-serialiser.h | 9 ++++++++ | ||
| 38 | glib/gvariant.c | 1 + | ||
| 39 | glib/tests/gvariant.c | 5 +++++ | ||
| 40 | 5 files changed, 75 insertions(+), 12 deletions(-) | ||
| 41 | |||
| 42 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 43 | index c57ee77..7b71efc 100644 | ||
| 44 | --- a/glib/gvariant-core.c | ||
| 45 | +++ b/glib/gvariant-core.c | ||
| 46 | @@ -67,6 +67,7 @@ struct _GVariant | ||
| 47 | GBytes *bytes; | ||
| 48 | gconstpointer data; | ||
| 49 | gsize ordered_offsets_up_to; | ||
| 50 | + gsize checked_offsets_up_to; | ||
| 51 | } serialised; | ||
| 52 | |||
| 53 | struct | ||
| 54 | @@ -182,6 +183,24 @@ struct _GVariant | ||
| 55 | * This field is only relevant for arrays of non | ||
| 56 | * fixed width types and for tuples. | ||
| 57 | * | ||
| 58 | + * .checked_offsets_up_to: Similarly to .ordered_offsets_up_to, this stores | ||
| 59 | + * the index of the highest element, n, whose frame | ||
| 60 | + * offsets (and all the preceding frame offsets) | ||
| 61 | + * have been checked for validity. | ||
| 62 | + * | ||
| 63 | + * It is always the case that | ||
| 64 | + * .checked_offsets_up_to ≥ .ordered_offsets_up_to. | ||
| 65 | + * | ||
| 66 | + * If .checked_offsets_up_to == .ordered_offsets_up_to, | ||
| 67 | + * then a bad offset has not been found so far. | ||
| 68 | + * | ||
| 69 | + * If .checked_offsets_up_to > .ordered_offsets_up_to, | ||
| 70 | + * then a bad offset has been found at | ||
| 71 | + * (.ordered_offsets_up_to + 1). | ||
| 72 | + * | ||
| 73 | + * This field is only relevant for arrays of non | ||
| 74 | + * fixed width types and for tuples. | ||
| 75 | + * | ||
| 76 | * .tree: Only valid when the instance is in tree form. | ||
| 77 | * | ||
| 78 | * Note that accesses from other threads could result in | ||
| 79 | @@ -386,6 +405,7 @@ g_variant_to_serialised (GVariant *value) | ||
| 80 | value->size, | ||
| 81 | value->depth, | ||
| 82 | value->contents.serialised.ordered_offsets_up_to, | ||
| 83 | + value->contents.serialised.checked_offsets_up_to, | ||
| 84 | }; | ||
| 85 | return serialised; | ||
| 86 | } | ||
| 87 | @@ -418,6 +438,7 @@ g_variant_serialise (GVariant *value, | ||
| 88 | serialised.data = data; | ||
| 89 | serialised.depth = value->depth; | ||
| 90 | serialised.ordered_offsets_up_to = 0; | ||
| 91 | + serialised.checked_offsets_up_to = 0; | ||
| 92 | |||
| 93 | children = (gpointer *) value->contents.tree.children; | ||
| 94 | n_children = value->contents.tree.n_children; | ||
| 95 | @@ -464,10 +485,12 @@ g_variant_fill_gvs (GVariantSerialised *serialised, | ||
| 96 | if (value->state & STATE_SERIALISED) | ||
| 97 | { | ||
| 98 | serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to; | ||
| 99 | + serialised->checked_offsets_up_to = value->contents.serialised.checked_offsets_up_to; | ||
| 100 | } | ||
| 101 | else | ||
| 102 | { | ||
| 103 | serialised->ordered_offsets_up_to = 0; | ||
| 104 | + serialised->checked_offsets_up_to = 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (serialised->data) | ||
| 108 | @@ -513,6 +536,7 @@ g_variant_ensure_serialised (GVariant *value) | ||
| 109 | value->contents.serialised.data = g_bytes_get_data (bytes, NULL); | ||
| 110 | value->contents.serialised.bytes = bytes; | ||
| 111 | value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE; | ||
| 112 | + value->contents.serialised.checked_offsets_up_to = G_MAXSIZE; | ||
| 113 | value->state |= STATE_SERIALISED; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | @@ -594,6 +618,7 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 117 | serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size); | ||
| 118 | serialised.depth = 0; | ||
| 119 | serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 120 | + serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 121 | |||
| 122 | if (!g_variant_serialised_check (serialised)) | ||
| 123 | { | ||
| 124 | @@ -645,6 +670,7 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 125 | } | ||
| 126 | |||
| 127 | value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 128 | + value->contents.serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 129 | |||
| 130 | g_clear_pointer (&owned_bytes, g_bytes_unref); | ||
| 131 | |||
| 132 | @@ -1142,6 +1168,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 133 | |||
| 134 | /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */ | ||
| 135 | value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to); | ||
| 136 | + value->contents.serialised.checked_offsets_up_to = MAX (value->contents.serialised.checked_offsets_up_to, serialised.checked_offsets_up_to); | ||
| 137 | |||
| 138 | /* Check whether this would cause nesting too deep. If so, return a fake | ||
| 139 | * child. The only situation we expect this to happen in is with a variant, | ||
| 140 | @@ -1169,6 +1196,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 141 | g_bytes_ref (value->contents.serialised.bytes); | ||
| 142 | child->contents.serialised.data = s_child.data; | ||
| 143 | child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; | ||
| 144 | + child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to; | ||
| 145 | |||
| 146 | return child; | ||
| 147 | } | ||
| 148 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 149 | index d46d05c..9c7f12a 100644 | ||
| 150 | --- a/glib/gvariant-serialiser.c | ||
| 151 | +++ b/glib/gvariant-serialiser.c | ||
| 152 | @@ -120,6 +120,8 @@ | ||
| 153 | * | ||
| 154 | * @depth has no restrictions; the depth of a top-level serialized #GVariant is | ||
| 155 | * zero, and it increases for each level of nested child. | ||
| 156 | + * | ||
| 157 | + * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to | ||
| 158 | */ | ||
| 159 | |||
| 160 | /* < private > | ||
| 161 | @@ -147,6 +149,9 @@ g_variant_serialised_check (GVariantSerialised serialised) | ||
| 162 | !(serialised.size == 0 || serialised.data != NULL)) | ||
| 163 | return FALSE; | ||
| 164 | |||
| 165 | + if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to) | ||
| 166 | + return FALSE; | ||
| 167 | + | ||
| 168 | /* Depending on the native alignment requirements of the machine, the | ||
| 169 | * compiler will insert either 3 or 7 padding bytes after the char. | ||
| 170 | * This will result in the sizeof() the struct being 12 or 16. | ||
| 171 | @@ -266,6 +271,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, | ||
| 172 | g_variant_type_info_ref (value.type_info); | ||
| 173 | value.depth++; | ||
| 174 | value.ordered_offsets_up_to = 0; | ||
| 175 | + value.checked_offsets_up_to = 0; | ||
| 176 | |||
| 177 | return value; | ||
| 178 | } | ||
| 179 | @@ -297,7 +303,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, | ||
| 180 | { | ||
| 181 | if (n_children) | ||
| 182 | { | ||
| 183 | - GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 }; | ||
| 184 | + GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 }; | ||
| 185 | |||
| 186 | gvs_filler (&child, children[0]); | ||
| 187 | } | ||
| 188 | @@ -320,6 +326,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) | ||
| 189 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 190 | value.depth++; | ||
| 191 | value.ordered_offsets_up_to = 0; | ||
| 192 | + value.checked_offsets_up_to = 0; | ||
| 193 | |||
| 194 | return g_variant_serialised_is_normal (value); | ||
| 195 | } | ||
| 196 | @@ -362,6 +369,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, | ||
| 197 | |||
| 198 | value.depth++; | ||
| 199 | value.ordered_offsets_up_to = 0; | ||
| 200 | + value.checked_offsets_up_to = 0; | ||
| 201 | |||
| 202 | return value; | ||
| 203 | } | ||
| 204 | @@ -392,7 +400,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, | ||
| 205 | { | ||
| 206 | if (n_children) | ||
| 207 | { | ||
| 208 | - GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 }; | ||
| 209 | + GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 }; | ||
| 210 | |||
| 211 | /* write the data for the child. */ | ||
| 212 | gvs_filler (&child, children[0]); | ||
| 213 | @@ -413,6 +421,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value) | ||
| 214 | value.size--; | ||
| 215 | value.depth++; | ||
| 216 | value.ordered_offsets_up_to = 0; | ||
| 217 | + value.checked_offsets_up_to = 0; | ||
| 218 | |||
| 219 | return g_variant_serialised_is_normal (value); | ||
| 220 | } | ||
| 221 | @@ -739,39 +748,46 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 222 | |||
| 223 | /* If the requested @index_ is beyond the set of indices whose framing offsets | ||
| 224 | * have been checked, check the remaining offsets to see whether they’re | ||
| 225 | - * normal (in order, no overlapping array elements). */ | ||
| 226 | - if (index_ > value.ordered_offsets_up_to) | ||
| 227 | + * normal (in order, no overlapping array elements). | ||
| 228 | + * | ||
| 229 | + * Don’t bother checking if the highest known-good offset is lower than the | ||
| 230 | + * highest checked offset, as that means there’s an invalid element at that | ||
| 231 | + * index, so there’s no need to check further. */ | ||
| 232 | + if (index_ > value.checked_offsets_up_to && | ||
| 233 | + value.ordered_offsets_up_to == value.checked_offsets_up_to) | ||
| 234 | { | ||
| 235 | switch (offsets.offset_size) | ||
| 236 | { | ||
| 237 | case 1: | ||
| 238 | { | ||
| 239 | value.ordered_offsets_up_to = find_unordered_guint8 ( | ||
| 240 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 241 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | case 2: | ||
| 245 | { | ||
| 246 | value.ordered_offsets_up_to = find_unordered_guint16 ( | ||
| 247 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 248 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 249 | break; | ||
| 250 | } | ||
| 251 | case 4: | ||
| 252 | { | ||
| 253 | value.ordered_offsets_up_to = find_unordered_guint32 ( | ||
| 254 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 255 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 256 | break; | ||
| 257 | } | ||
| 258 | case 8: | ||
| 259 | { | ||
| 260 | value.ordered_offsets_up_to = find_unordered_guint64 ( | ||
| 261 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 262 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | default: | ||
| 266 | /* gvs_get_offset_size() only returns maximum 8 */ | ||
| 267 | g_assert_not_reached (); | ||
| 268 | } | ||
| 269 | + | ||
| 270 | + value.checked_offsets_up_to = index_; | ||
| 271 | } | ||
| 272 | |||
| 273 | if (index_ > value.ordered_offsets_up_to) | ||
| 274 | @@ -916,6 +932,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 275 | |||
| 276 | /* All offsets have now been checked. */ | ||
| 277 | value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 278 | + value.checked_offsets_up_to = G_MAXSIZE; | ||
| 279 | |||
| 280 | return TRUE; | ||
| 281 | } | ||
| 282 | @@ -1040,14 +1057,15 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 283 | * all the tuple *elements* here, not just all the framing offsets, since | ||
| 284 | * tuples contain a mix of elements which use framing offsets and ones which | ||
| 285 | * don’t. None of them are allowed to overlap. */ | ||
| 286 | - if (index_ > value.ordered_offsets_up_to) | ||
| 287 | + if (index_ > value.checked_offsets_up_to && | ||
| 288 | + value.ordered_offsets_up_to == value.checked_offsets_up_to) | ||
| 289 | { | ||
| 290 | gsize i, prev_i_end = 0; | ||
| 291 | |||
| 292 | - if (value.ordered_offsets_up_to > 0) | ||
| 293 | - gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end); | ||
| 294 | + if (value.checked_offsets_up_to > 0) | ||
| 295 | + gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end); | ||
| 296 | |||
| 297 | - for (i = value.ordered_offsets_up_to; i <= index_; i++) | ||
| 298 | + for (i = value.checked_offsets_up_to; i <= index_; i++) | ||
| 299 | { | ||
| 300 | gsize i_start, i_end; | ||
| 301 | |||
| 302 | @@ -1060,6 +1078,7 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 303 | } | ||
| 304 | |||
| 305 | value.ordered_offsets_up_to = i - 1; | ||
| 306 | + value.checked_offsets_up_to = index_; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (index_ > value.ordered_offsets_up_to) | ||
| 310 | @@ -1257,6 +1276,7 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 311 | |||
| 312 | /* All element bounds have been checked above. */ | ||
| 313 | value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 314 | + value.checked_offsets_up_to = G_MAXSIZE; | ||
| 315 | |||
| 316 | { | ||
| 317 | gsize fixed_size; | ||
| 318 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
| 319 | index 03826f9..2423e01 100644 | ||
| 320 | --- a/glib/gvariant-serialiser.h | ||
| 321 | +++ b/glib/gvariant-serialiser.h | ||
| 322 | @@ -40,6 +40,15 @@ typedef struct | ||
| 323 | * Even when dealing with tuples, @ordered_offsets_up_to is an element index, | ||
| 324 | * rather than an index into the frame offsets. */ | ||
| 325 | gsize ordered_offsets_up_to; | ||
| 326 | + | ||
| 327 | + /* Similar to @ordered_offsets_up_to. This gives the index of the child element | ||
| 328 | + * whose frame offset is the highest in the offset table which has been | ||
| 329 | + * checked so far. | ||
| 330 | + * | ||
| 331 | + * This is always ≥ @ordered_offsets_up_to. It is always an element index. | ||
| 332 | + * | ||
| 333 | + * See documentation in gvariant-core.c for `struct GVariant` for details. */ | ||
| 334 | + gsize checked_offsets_up_to; | ||
| 335 | } GVariantSerialised; | ||
| 336 | |||
| 337 | /* deserialization */ | ||
| 338 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 339 | index 1b1cbdc..2e288af 100644 | ||
| 340 | --- a/glib/gvariant.c | ||
| 341 | +++ b/glib/gvariant.c | ||
| 342 | @@ -5997,6 +5997,7 @@ g_variant_byteswap (GVariant *value) | ||
| 343 | serialised.data = g_malloc (serialised.size); | ||
| 344 | serialised.depth = g_variant_get_depth (trusted); | ||
| 345 | serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ | ||
| 346 | + serialised.checked_offsets_up_to = G_MAXSIZE; | ||
| 347 | g_variant_store (trusted, serialised.data); | ||
| 348 | g_variant_unref (trusted); | ||
| 349 | |||
| 350 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 351 | index 3ddff96..31a7dde 100644 | ||
| 352 | --- a/glib/tests/gvariant.c | ||
| 353 | +++ b/glib/tests/gvariant.c | ||
| 354 | @@ -1282,6 +1282,7 @@ random_instance_filler (GVariantSerialised *serialised, | ||
| 355 | |||
| 356 | serialised->depth = 0; | ||
| 357 | serialised->ordered_offsets_up_to = 0; | ||
| 358 | + serialised->checked_offsets_up_to = 0; | ||
| 359 | |||
| 360 | g_assert_true (serialised->type_info == instance->type_info); | ||
| 361 | g_assert_cmpuint (serialised->size, ==, instance->size); | ||
| 362 | @@ -1449,6 +1450,7 @@ test_maybe (void) | ||
| 363 | serialised.size = needed_size; | ||
| 364 | serialised.depth = 0; | ||
| 365 | serialised.ordered_offsets_up_to = 0; | ||
| 366 | + serialised.checked_offsets_up_to = 0; | ||
| 367 | |||
| 368 | g_variant_serialiser_serialise (serialised, | ||
| 369 | random_instance_filler, | ||
| 370 | @@ -1573,6 +1575,7 @@ test_array (void) | ||
| 371 | serialised.size = needed_size; | ||
| 372 | serialised.depth = 0; | ||
| 373 | serialised.ordered_offsets_up_to = 0; | ||
| 374 | + serialised.checked_offsets_up_to = 0; | ||
| 375 | |||
| 376 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 377 | (gpointer *) instances, n_children); | ||
| 378 | @@ -1738,6 +1741,7 @@ test_tuple (void) | ||
| 379 | serialised.size = needed_size; | ||
| 380 | serialised.depth = 0; | ||
| 381 | serialised.ordered_offsets_up_to = 0; | ||
| 382 | + serialised.checked_offsets_up_to = 0; | ||
| 383 | |||
| 384 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 385 | (gpointer *) instances, n_children); | ||
| 386 | @@ -1835,6 +1839,7 @@ test_variant (void) | ||
| 387 | serialised.size = needed_size; | ||
| 388 | serialised.depth = 0; | ||
| 389 | serialised.ordered_offsets_up_to = 0; | ||
| 390 | + serialised.checked_offsets_up_to = 0; | ||
| 391 | |||
| 392 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 393 | (gpointer *) &instance, 1); | ||
| 394 | -- | ||
| 395 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0009.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0009.patch new file mode 100644 index 0000000000..7a43b138f3 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0009.patch | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | From 298a537d5f6783e55d87e40011ee3fd3b22b72f9 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Thu, 17 Aug 2023 01:39:01 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Zero-initialise various GVariantSerialised objects | ||
| 5 | |||
| 6 | The following few commits will add a couple of new fields to | ||
| 7 | `GVariantSerialised`, and they should be zero-filled by default. | ||
| 8 | |||
| 9 | Try and pre-empt that a bit by zero-filling `GVariantSerialised` by | ||
| 10 | default in a few places. | ||
| 11 | |||
| 12 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 13 | |||
| 14 | Helps: #2121 | ||
| 15 | |||
| 16 | CVE: CVE-2023-32665 | ||
| 17 | |||
| 18 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/298a537d5f6783e55d87e40011ee3fd3b22b72f9] | ||
| 19 | |||
| 20 | Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> | ||
| 21 | --- | ||
| 22 | glib/gvariant.c | 2 +- | ||
| 23 | glib/tests/gvariant.c | 12 ++++++------ | ||
| 24 | 2 files changed, 7 insertions(+), 7 deletions(-) | ||
| 25 | |||
| 26 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 27 | index 2e288af..30a3280 100644 | ||
| 28 | --- a/glib/gvariant.c | ||
| 29 | +++ b/glib/gvariant.c | ||
| 30 | @@ -5987,7 +5987,7 @@ g_variant_byteswap (GVariant *value) | ||
| 31 | if (alignment) | ||
| 32 | /* (potentially) contains multi-byte numeric data */ | ||
| 33 | { | ||
| 34 | - GVariantSerialised serialised; | ||
| 35 | + GVariantSerialised serialised = { 0, }; | ||
| 36 | GVariant *trusted; | ||
| 37 | GBytes *bytes; | ||
| 38 | |||
| 39 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 40 | index 31a7dde..2f33a3e 100644 | ||
| 41 | --- a/glib/tests/gvariant.c | ||
| 42 | +++ b/glib/tests/gvariant.c | ||
| 43 | @@ -1442,7 +1442,7 @@ test_maybe (void) | ||
| 44 | |||
| 45 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 46 | { | ||
| 47 | - GVariantSerialised serialised; | ||
| 48 | + GVariantSerialised serialised = { 0, }; | ||
| 49 | GVariantSerialised child; | ||
| 50 | |||
| 51 | serialised.type_info = type_info; | ||
| 52 | @@ -1568,7 +1568,7 @@ test_array (void) | ||
| 53 | |||
| 54 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 55 | { | ||
| 56 | - GVariantSerialised serialised; | ||
| 57 | + GVariantSerialised serialised = { 0, }; | ||
| 58 | |||
| 59 | serialised.type_info = array_info; | ||
| 60 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 61 | @@ -1734,7 +1734,7 @@ test_tuple (void) | ||
| 62 | |||
| 63 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 64 | { | ||
| 65 | - GVariantSerialised serialised; | ||
| 66 | + GVariantSerialised serialised = { 0, }; | ||
| 67 | |||
| 68 | serialised.type_info = type_info; | ||
| 69 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 70 | @@ -1831,7 +1831,7 @@ test_variant (void) | ||
| 71 | |||
| 72 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 73 | { | ||
| 74 | - GVariantSerialised serialised; | ||
| 75 | + GVariantSerialised serialised = { 0, }; | ||
| 76 | GVariantSerialised child; | ||
| 77 | |||
| 78 | serialised.type_info = type_info; | ||
| 79 | @@ -2280,7 +2280,7 @@ serialise_tree (TreeInstance *tree, | ||
| 80 | static void | ||
| 81 | test_byteswap (void) | ||
| 82 | { | ||
| 83 | - GVariantSerialised one, two; | ||
| 84 | + GVariantSerialised one = { 0, }, two = { 0, }; | ||
| 85 | TreeInstance *tree; | ||
| 86 | |||
| 87 | tree = tree_instance_new (NULL, 3); | ||
| 88 | @@ -2354,7 +2354,7 @@ test_serialiser_children (void) | ||
| 89 | static void | ||
| 90 | test_fuzz (gdouble *fuzziness) | ||
| 91 | { | ||
| 92 | - GVariantSerialised serialised; | ||
| 93 | + GVariantSerialised serialised = { 0, }; | ||
| 94 | TreeInstance *tree; | ||
| 95 | |||
| 96 | /* make an instance */ | ||
| 97 | -- | ||
| 98 | 2.40.0 | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb index b5ab6502a3..b04b5f0a44 100644 --- a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb +++ b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb | |||
| @@ -17,6 +17,15 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \ | |||
| 17 | file://0001-meson-Run-atomics-test-on-clang-as-well.patch \ | 17 | file://0001-meson-Run-atomics-test-on-clang-as-well.patch \ |
| 18 | file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \ | 18 | file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \ |
| 19 | file://0001-gio-tests-g-file-info-don-t-assume-million-in-one-ev.patch \ | 19 | file://0001-gio-tests-g-file-info-don-t-assume-million-in-one-ev.patch \ |
| 20 | file://CVE-2023-32665-0001.patch \ | ||
| 21 | file://CVE-2023-32665-0002.patch \ | ||
| 22 | file://CVE-2023-32665-0003.patch \ | ||
| 23 | file://CVE-2023-32665-0004.patch \ | ||
| 24 | file://CVE-2023-32665-0005.patch \ | ||
| 25 | file://CVE-2023-32665-0006.patch \ | ||
| 26 | file://CVE-2023-32665-0007.patch \ | ||
| 27 | file://CVE-2023-32665-0008.patch \ | ||
| 28 | file://CVE-2023-32665-0009.patch \ | ||
| 20 | " | 29 | " |
| 21 | SRC_URI:append:class-native = " file://relocate-modules.patch" | 30 | SRC_URI:append:class-native = " file://relocate-modules.patch" |
| 22 | 31 | ||
