diff options
| author | Siddharth Doshi <sdoshi@mvista.com> | 2023-10-15 21:00:39 +0530 |
|---|---|---|
| committer | Steve Sakoman <steve@sakoman.com> | 2023-10-20 05:35:30 -1000 |
| commit | aa99487732ab1ae453becdda08a3e72de0b7b269 (patch) | |
| tree | 4e116f258212e3f01bcc04c3f1882916252b4cdf | |
| parent | 8ae21cd487a6147c3a2c9c2c0f0b2d5d149b7caf (diff) | |
| download | poky-aa99487732ab1ae453becdda08a3e72de0b7b269.tar.gz | |
glib-2.0: Fix multiple vulnerabilities
CVE's Fixed:
CVE-2023-29499: glib: GVariant offset table entry size is not checked in is_normal()
CVE-2023-32611: glib: g_variant_byteswap() can take a long time with some non-normal inputs
CVE-2023-32636: glib: Timeout in fuzz_variant_text
CVE-2023-32643: glib: Heap-buffer-overflow in g_variant_serialised_get_child
CVE-2023-32665: glib: GVariant deserialisation does not match spec for non-normal data
(From OE-Core rev: b576beba80d44e67762d46bf3bc2f14c05bc0f6b)
Signed-off-by: Siddharth Doshi <sdoshi@mvista.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
15 files changed, 2710 insertions, 0 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch new file mode 100644 index 0000000000..ce90586290 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-29499.patch | |||
| @@ -0,0 +1,290 @@ | |||
| 1 | From 5f4485c4ff57fdefb1661531788def7ca5a47328 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Thu, 17 Aug 2023 04:19:44 +0000 | ||
| 4 | Subject: [PATCH] gvariant-serialiser: Check offset table entry size is minimal | ||
| 5 | |||
| 6 | The entries in an offset table (which is used for variable sized arrays | ||
| 7 | and tuples containing variable sized members) are sized so that they can | ||
| 8 | address every byte in the overall variant. | ||
| 9 | |||
| 10 | The specification requires that for a variant to be in normal form, its | ||
| 11 | offset table entries must be the minimum width such that they can | ||
| 12 | address every byte in the variant. | ||
| 13 | |||
| 14 | That minimality requirement was not checked in | ||
| 15 | `g_variant_is_normal_form()`, leading to two different byte arrays being | ||
| 16 | interpreted as the normal form of a given variant tree. That kind of | ||
| 17 | confusion could potentially be exploited, and is certainly a bug. | ||
| 18 | |||
| 19 | Fix it by adding the necessary checks on offset table entry width, and | ||
| 20 | unit tests. | ||
| 21 | |||
| 22 | Spotted by William Manley. | ||
| 23 | |||
| 24 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 25 | |||
| 26 | Fixes: #2794 | ||
| 27 | |||
| 28 | CVE: CVE-2023-29499 | ||
| 29 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/5f4485c4ff57fdefb1661531788def7ca5a47328] | ||
| 30 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 31 | --- | ||
| 32 | glib/gvariant-serialiser.c | 19 +++- | ||
| 33 | glib/tests/gvariant.c | 176 +++++++++++++++++++++++++++++++++++++ | ||
| 34 | 2 files changed, 194 insertions(+), 1 deletion(-) | ||
| 35 | |||
| 36 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 37 | index 0bf7243..5aa2cbc 100644 | ||
| 38 | --- a/glib/gvariant-serialiser.c | ||
| 39 | +++ b/glib/gvariant-serialiser.c | ||
| 40 | @@ -694,6 +694,10 @@ gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value) | ||
| 41 | out.data_size = last_end; | ||
| 42 | out.array = value.data + last_end; | ||
| 43 | out.length = offsets_array_size / out.offset_size; | ||
| 44 | + | ||
| 45 | + if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size) | ||
| 46 | + return out; /* offset size not minimal */ | ||
| 47 | + | ||
| 48 | out.is_normal = TRUE; | ||
| 49 | |||
| 50 | return out; | ||
| 51 | @@ -1201,6 +1205,7 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 52 | gsize length; | ||
| 53 | gsize offset; | ||
| 54 | gsize i; | ||
| 55 | + gsize offset_table_size; | ||
| 56 | |||
| 57 | /* as per the comment in gvs_tuple_get_child() */ | ||
| 58 | if G_UNLIKELY (value.data == NULL && value.size != 0) | ||
| 59 | @@ -1305,7 +1310,19 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | - return offset_ptr == offset; | ||
| 64 | + /* @offset_ptr has been counting backwards from the end of the variant, to | ||
| 65 | + * find the beginning of the offset table. @offset has been counting forwards | ||
| 66 | + * from the beginning of the variant to find the end of the data. They should | ||
| 67 | + * have met in the middle. */ | ||
| 68 | + if (offset_ptr != offset) | ||
| 69 | + return FALSE; | ||
| 70 | + | ||
| 71 | + offset_table_size = value.size - offset_ptr; | ||
| 72 | + if (value.size > 0 && | ||
| 73 | + gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size) | ||
| 74 | + return FALSE; /* offset size not minimal */ | ||
| 75 | + | ||
| 76 | + return TRUE; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* Variants {{{2 | ||
| 80 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 81 | index d640c81..4ce0e4f 100644 | ||
| 82 | --- a/glib/tests/gvariant.c | ||
| 83 | +++ b/glib/tests/gvariant.c | ||
| 84 | @@ -5092,6 +5092,86 @@ test_normal_checking_array_offsets2 (void) | ||
| 85 | g_variant_unref (variant); | ||
| 86 | } | ||
| 87 | |||
| 88 | +/* Test that an otherwise-valid serialised GVariant is considered non-normal if | ||
| 89 | + * its offset table entries are too wide. | ||
| 90 | + * | ||
| 91 | + * See §2.3.6 (Framing Offsets) of the GVariant specification. */ | ||
| 92 | +static void | ||
| 93 | +test_normal_checking_array_offsets_minimal_sized (void) | ||
| 94 | +{ | ||
| 95 | + GVariantBuilder builder; | ||
| 96 | + gsize i; | ||
| 97 | + GVariant *aay_constructed = NULL; | ||
| 98 | + const guint8 *data = NULL; | ||
| 99 | + guint8 *data_owned = NULL; | ||
| 100 | + GVariant *aay_deserialised = NULL; | ||
| 101 | + GVariant *aay_normalised = NULL; | ||
| 102 | + | ||
| 103 | + /* Construct an array of type aay, consisting of 128 elements which are each | ||
| 104 | + * an empty array, i.e. `[[] * 128]`. This is chosen because the inner | ||
| 105 | + * elements are variable sized (making the outer array variable sized, so it | ||
| 106 | + * must have an offset table), but they are also zero-sized when serialised. | ||
| 107 | + * So the serialised representation of @aay_constructed consists entirely of | ||
| 108 | + * its offset table, which is entirely zeroes. | ||
| 109 | + * | ||
| 110 | + * The array is chosen to be 128 elements long because that means offset | ||
| 111 | + * table entries which are 1 byte long. If the elements in the array were | ||
| 112 | + * non-zero-sized (to the extent that the overall array is ≥256 bytes long), | ||
| 113 | + * the offset table entries would end up being 2 bytes long. */ | ||
| 114 | + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay")); | ||
| 115 | + | ||
| 116 | + for (i = 0; i < 128; i++) | ||
| 117 | + g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0)); | ||
| 118 | + | ||
| 119 | + aay_constructed = g_variant_builder_end (&builder); | ||
| 120 | + | ||
| 121 | + /* Verify that the constructed array is in normal form, and its serialised | ||
| 122 | + * form is `b'\0' * 128`. */ | ||
| 123 | + g_assert_true (g_variant_is_normal_form (aay_constructed)); | ||
| 124 | + g_assert_cmpuint (g_variant_n_children (aay_constructed), ==, 128); | ||
| 125 | + g_assert_cmpuint (g_variant_get_size (aay_constructed), ==, 128); | ||
| 126 | + | ||
| 127 | + data = g_variant_get_data (aay_constructed); | ||
| 128 | + for (i = 0; i < g_variant_get_size (aay_constructed); i++) | ||
| 129 | + g_assert_cmpuint (data[i], ==, 0); | ||
| 130 | + | ||
| 131 | + /* Construct a serialised `aay` GVariant which is `b'\0' * 256`. This has to | ||
| 132 | + * be a non-normal form of `[[] * 128]`, with 2-byte-long offset table | ||
| 133 | + * entries, because each offset table entry has to be able to reference all of | ||
| 134 | + * the byte boundaries in the container. All the entries in the offset table | ||
| 135 | + * are zero, so all the elements of the array are zero-sized. */ | ||
| 136 | + data = data_owned = g_malloc0 (256); | ||
| 137 | + aay_deserialised = g_variant_new_from_data (G_VARIANT_TYPE ("aay"), | ||
| 138 | + data, | ||
| 139 | + 256, | ||
| 140 | + FALSE, | ||
| 141 | + g_free, | ||
| 142 | + g_steal_pointer (&data_owned)); | ||
| 143 | + | ||
| 144 | + g_assert_false (g_variant_is_normal_form (aay_deserialised)); | ||
| 145 | + g_assert_cmpuint (g_variant_n_children (aay_deserialised), ==, 128); | ||
| 146 | + g_assert_cmpuint (g_variant_get_size (aay_deserialised), ==, 256); | ||
| 147 | + | ||
| 148 | + data = g_variant_get_data (aay_deserialised); | ||
| 149 | + for (i = 0; i < g_variant_get_size (aay_deserialised); i++) | ||
| 150 | + g_assert_cmpuint (data[i], ==, 0); | ||
| 151 | + | ||
| 152 | + /* Get its normal form. That should change the serialised size. */ | ||
| 153 | + aay_normalised = g_variant_get_normal_form (aay_deserialised); | ||
| 154 | + | ||
| 155 | + g_assert_true (g_variant_is_normal_form (aay_normalised)); | ||
| 156 | + g_assert_cmpuint (g_variant_n_children (aay_normalised), ==, 128); | ||
| 157 | + g_assert_cmpuint (g_variant_get_size (aay_normalised), ==, 128); | ||
| 158 | + | ||
| 159 | + data = g_variant_get_data (aay_normalised); | ||
| 160 | + for (i = 0; i < g_variant_get_size (aay_normalised); i++) | ||
| 161 | + g_assert_cmpuint (data[i], ==, 0); | ||
| 162 | + | ||
| 163 | + g_variant_unref (aay_normalised); | ||
| 164 | + g_variant_unref (aay_deserialised); | ||
| 165 | + g_variant_unref (aay_constructed); | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | /* Test that a tuple with invalidly large values in its offset table is | ||
| 169 | * normalised successfully without looping infinitely. */ | ||
| 170 | static void | ||
| 171 | @@ -5286,6 +5366,98 @@ test_normal_checking_tuple_offsets4 (void) | ||
| 172 | g_variant_unref (variant); | ||
| 173 | } | ||
| 174 | |||
| 175 | +/* Test that an otherwise-valid serialised GVariant is considered non-normal if | ||
| 176 | + * its offset table entries are too wide. | ||
| 177 | + * | ||
| 178 | + * See §2.3.6 (Framing Offsets) of the GVariant specification. */ | ||
| 179 | +static void | ||
| 180 | +test_normal_checking_tuple_offsets_minimal_sized (void) | ||
| 181 | +{ | ||
| 182 | + GString *type_string = NULL; | ||
| 183 | + GVariantBuilder builder; | ||
| 184 | + gsize i; | ||
| 185 | + GVariant *ray_constructed = NULL; | ||
| 186 | + const guint8 *data = NULL; | ||
| 187 | + guint8 *data_owned = NULL; | ||
| 188 | + GVariant *ray_deserialised = NULL; | ||
| 189 | + GVariant *ray_normalised = NULL; | ||
| 190 | + | ||
| 191 | + /* Construct a tuple of type (ay…ay), consisting of 129 members which are each | ||
| 192 | + * an empty array, i.e. `([] * 129)`. This is chosen because the inner | ||
| 193 | + * members are variable sized, so the outer tuple must have an offset table, | ||
| 194 | + * but they are also zero-sized when serialised. So the serialised | ||
| 195 | + * representation of @ray_constructed consists entirely of its offset table, | ||
| 196 | + * which is entirely zeroes. | ||
| 197 | + * | ||
| 198 | + * The tuple is chosen to be 129 members long because that means it has 128 | ||
| 199 | + * offset table entries which are 1 byte long each. If the members in the | ||
| 200 | + * tuple were non-zero-sized (to the extent that the overall tuple is ≥256 | ||
| 201 | + * bytes long), the offset table entries would end up being 2 bytes long. | ||
| 202 | + * | ||
| 203 | + * 129 members are used unlike 128 array elements in | ||
| 204 | + * test_normal_checking_array_offsets_minimal_sized(), because the last member | ||
| 205 | + * in a tuple never needs an offset table entry. */ | ||
| 206 | + type_string = g_string_new (""); | ||
| 207 | + g_string_append_c (type_string, '('); | ||
| 208 | + for (i = 0; i < 129; i++) | ||
| 209 | + g_string_append (type_string, "ay"); | ||
| 210 | + g_string_append_c (type_string, ')'); | ||
| 211 | + | ||
| 212 | + g_variant_builder_init (&builder, G_VARIANT_TYPE (type_string->str)); | ||
| 213 | + | ||
| 214 | + for (i = 0; i < 129; i++) | ||
| 215 | + g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0)); | ||
| 216 | + | ||
| 217 | + ray_constructed = g_variant_builder_end (&builder); | ||
| 218 | + | ||
| 219 | + /* Verify that the constructed tuple is in normal form, and its serialised | ||
| 220 | + * form is `b'\0' * 128`. */ | ||
| 221 | + g_assert_true (g_variant_is_normal_form (ray_constructed)); | ||
| 222 | + g_assert_cmpuint (g_variant_n_children (ray_constructed), ==, 129); | ||
| 223 | + g_assert_cmpuint (g_variant_get_size (ray_constructed), ==, 128); | ||
| 224 | + | ||
| 225 | + data = g_variant_get_data (ray_constructed); | ||
| 226 | + for (i = 0; i < g_variant_get_size (ray_constructed); i++) | ||
| 227 | + g_assert_cmpuint (data[i], ==, 0); | ||
| 228 | + | ||
| 229 | + /* Construct a serialised `(ay…ay)` GVariant which is `b'\0' * 256`. This has | ||
| 230 | + * to be a non-normal form of `([] * 129)`, with 2-byte-long offset table | ||
| 231 | + * entries, because each offset table entry has to be able to reference all of | ||
| 232 | + * the byte boundaries in the container. All the entries in the offset table | ||
| 233 | + * are zero, so all the members of the tuple are zero-sized. */ | ||
| 234 | + data = data_owned = g_malloc0 (256); | ||
| 235 | + ray_deserialised = g_variant_new_from_data (G_VARIANT_TYPE (type_string->str), | ||
| 236 | + data, | ||
| 237 | + 256, | ||
| 238 | + FALSE, | ||
| 239 | + g_free, | ||
| 240 | + g_steal_pointer (&data_owned)); | ||
| 241 | + | ||
| 242 | + g_assert_false (g_variant_is_normal_form (ray_deserialised)); | ||
| 243 | + g_assert_cmpuint (g_variant_n_children (ray_deserialised), ==, 129); | ||
| 244 | + g_assert_cmpuint (g_variant_get_size (ray_deserialised), ==, 256); | ||
| 245 | + | ||
| 246 | + data = g_variant_get_data (ray_deserialised); | ||
| 247 | + for (i = 0; i < g_variant_get_size (ray_deserialised); i++) | ||
| 248 | + g_assert_cmpuint (data[i], ==, 0); | ||
| 249 | + | ||
| 250 | + /* Get its normal form. That should change the serialised size. */ | ||
| 251 | + ray_normalised = g_variant_get_normal_form (ray_deserialised); | ||
| 252 | + | ||
| 253 | + g_assert_true (g_variant_is_normal_form (ray_normalised)); | ||
| 254 | + g_assert_cmpuint (g_variant_n_children (ray_normalised), ==, 129); | ||
| 255 | + g_assert_cmpuint (g_variant_get_size (ray_normalised), ==, 128); | ||
| 256 | + | ||
| 257 | + data = g_variant_get_data (ray_normalised); | ||
| 258 | + for (i = 0; i < g_variant_get_size (ray_normalised); i++) | ||
| 259 | + g_assert_cmpuint (data[i], ==, 0); | ||
| 260 | + | ||
| 261 | + g_variant_unref (ray_normalised); | ||
| 262 | + g_variant_unref (ray_deserialised); | ||
| 263 | + g_variant_unref (ray_constructed); | ||
| 264 | + g_string_free (type_string, TRUE); | ||
| 265 | +} | ||
| 266 | + | ||
| 267 | /* Test that an empty object path is normalised successfully to the base object | ||
| 268 | * path, ‘/’. */ | ||
| 269 | static void | ||
| 270 | @@ -5431,6 +5603,8 @@ main (int argc, char **argv) | ||
| 271 | test_normal_checking_array_offsets); | ||
| 272 | g_test_add_func ("/gvariant/normal-checking/array-offsets2", | ||
| 273 | test_normal_checking_array_offsets2); | ||
| 274 | + g_test_add_func ("/gvariant/normal-checking/array-offsets/minimal-sized", | ||
| 275 | + test_normal_checking_array_offsets_minimal_sized); | ||
| 276 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets", | ||
| 277 | test_normal_checking_tuple_offsets); | ||
| 278 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets2", | ||
| 279 | @@ -5439,6 +5613,8 @@ main (int argc, char **argv) | ||
| 280 | test_normal_checking_tuple_offsets3); | ||
| 281 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", | ||
| 282 | test_normal_checking_tuple_offsets4); | ||
| 283 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized", | ||
| 284 | + test_normal_checking_tuple_offsets_minimal_sized); | ||
| 285 | g_test_add_func ("/gvariant/normal-checking/empty-object-path", | ||
| 286 | test_normal_checking_empty_object_path); | ||
| 287 | |||
| 288 | -- | ||
| 289 | 2.24.4 | ||
| 290 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch new file mode 100644 index 0000000000..b2187f2af9 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0001.patch | |||
| @@ -0,0 +1,89 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1] | ||
| 15 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 16 | --- | ||
| 17 | glib/gvariant.c | 8 +++++--- | ||
| 18 | glib/tests/gvariant.c | 24 ++++++++++++++++++++++++ | ||
| 19 | 2 files changed, 29 insertions(+), 3 deletions(-) | ||
| 20 | |||
| 21 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 22 | index 8ba701e..4dbd9e8 100644 | ||
| 23 | --- a/glib/gvariant.c | ||
| 24 | +++ b/glib/gvariant.c | ||
| 25 | @@ -5952,14 +5952,16 @@ g_variant_byteswap (GVariant *value) | ||
| 26 | g_variant_serialised_byteswap (serialised); | ||
| 27 | |||
| 28 | bytes = g_bytes_new_take (serialised.data, serialised.size); | ||
| 29 | - new = g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE); | ||
| 30 | + new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE)); | ||
| 31 | g_bytes_unref (bytes); | ||
| 32 | } | ||
| 33 | else | ||
| 34 | /* contains no multi-byte data */ | ||
| 35 | - new = value; | ||
| 36 | + new = g_variant_get_normal_form (value); | ||
| 37 | |||
| 38 | - return g_variant_ref_sink (new); | ||
| 39 | + g_assert (g_variant_is_trusted (new)); | ||
| 40 | + | ||
| 41 | + return g_steal_pointer (&new); | ||
| 42 | } | ||
| 43 | |||
| 44 | /** | ||
| 45 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 46 | index 4ce0e4f..3dda08e 100644 | ||
| 47 | --- a/glib/tests/gvariant.c | ||
| 48 | +++ b/glib/tests/gvariant.c | ||
| 49 | @@ -3834,6 +3834,29 @@ test_gv_byteswap (void) | ||
| 50 | g_free (string); | ||
| 51 | } | ||
| 52 | |||
| 53 | +static void | ||
| 54 | +test_gv_byteswap_non_normal_non_aligned (void) | ||
| 55 | +{ | ||
| 56 | + const guint8 data[] = { 0x02 }; | ||
| 57 | + GVariant *v = NULL; | ||
| 58 | + GVariant *v_byteswapped = NULL; | ||
| 59 | + | ||
| 60 | + g_test_summary ("Test that calling g_variant_byteswap() on a variant which " | ||
| 61 | + "is in non-normal form and doesn’t need byteswapping returns " | ||
| 62 | + "the same variant in normal form."); | ||
| 63 | + | ||
| 64 | + v = g_variant_new_from_data (G_VARIANT_TYPE_BOOLEAN, data, sizeof (data), FALSE, NULL, NULL); | ||
| 65 | + g_assert_false (g_variant_is_normal_form (v)); | ||
| 66 | + | ||
| 67 | + v_byteswapped = g_variant_byteswap (v); | ||
| 68 | + g_assert_true (g_variant_is_normal_form (v_byteswapped)); | ||
| 69 | + | ||
| 70 | + g_assert_cmpvariant (v, v_byteswapped); | ||
| 71 | + | ||
| 72 | + g_variant_unref (v); | ||
| 73 | + g_variant_unref (v_byteswapped); | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | static void | ||
| 77 | test_parser (void) | ||
| 78 | { | ||
| 79 | @@ -5570,6 +5593,7 @@ main (int argc, char **argv) | ||
| 80 | g_test_add_func ("/gvariant/builder-memory", test_builder_memory); | ||
| 81 | g_test_add_func ("/gvariant/hashing", test_hashing); | ||
| 82 | g_test_add_func ("/gvariant/byteswap", test_gv_byteswap); | ||
| 83 | + g_test_add_func ("/gvariant/byteswap/non-normal-non-aligned", test_gv_byteswap_non_normal_non_aligned); | ||
| 84 | g_test_add_func ("/gvariant/parser", test_parses); | ||
| 85 | g_test_add_func ("/gvariant/parser/integer-bounds", test_parser_integer_bounds); | ||
| 86 | g_test_add_func ("/gvariant/parser/recursion", test_parser_recursion); | ||
| 87 | -- | ||
| 88 | 2.24.4 | ||
| 89 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch new file mode 100644 index 0000000000..9167ea624f --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32611-0002.patch | |||
| @@ -0,0 +1,255 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/446e69f5edd72deb2196dee36bbaf8056caf6948] | ||
| 13 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 14 | --- | ||
| 15 | glib/gvariant.c | 81 +++++++++++++++++++++++++++++++++---------- | ||
| 16 | glib/tests/gvariant.c | 57 ++++++++++++++++++++++++++---- | ||
| 17 | 2 files changed, 112 insertions(+), 26 deletions(-) | ||
| 18 | |||
| 19 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 20 | index 4dbd9e8..a80c2c9 100644 | ||
| 21 | --- a/glib/gvariant.c | ||
| 22 | +++ b/glib/gvariant.c | ||
| 23 | @@ -5788,7 +5788,8 @@ g_variant_iter_loop (GVariantIter *iter, | ||
| 24 | |||
| 25 | /* Serialised data {{{1 */ | ||
| 26 | static GVariant * | ||
| 27 | -g_variant_deep_copy (GVariant *value) | ||
| 28 | +g_variant_deep_copy (GVariant *value, | ||
| 29 | + gboolean byteswap) | ||
| 30 | { | ||
| 31 | switch (g_variant_classify (value)) | ||
| 32 | { | ||
| 33 | @@ -5806,7 +5807,7 @@ g_variant_deep_copy (GVariant *value) | ||
| 34 | for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++) | ||
| 35 | { | ||
| 36 | GVariant *child = g_variant_get_child_value (value, i); | ||
| 37 | - g_variant_builder_add_value (&builder, g_variant_deep_copy (child)); | ||
| 38 | + g_variant_builder_add_value (&builder, g_variant_deep_copy (child, byteswap)); | ||
| 39 | g_variant_unref (child); | ||
| 40 | } | ||
| 41 | |||
| 42 | @@ -5820,28 +5821,63 @@ g_variant_deep_copy (GVariant *value) | ||
| 43 | return g_variant_new_byte (g_variant_get_byte (value)); | ||
| 44 | |||
| 45 | case G_VARIANT_CLASS_INT16: | ||
| 46 | - return g_variant_new_int16 (g_variant_get_int16 (value)); | ||
| 47 | + if (byteswap) | ||
| 48 | + return g_variant_new_int16 (GUINT16_SWAP_LE_BE (g_variant_get_int16 (value))); | ||
| 49 | + else | ||
| 50 | + return g_variant_new_int16 (g_variant_get_int16 (value)); | ||
| 51 | |||
| 52 | case G_VARIANT_CLASS_UINT16: | ||
| 53 | - return g_variant_new_uint16 (g_variant_get_uint16 (value)); | ||
| 54 | + if (byteswap) | ||
| 55 | + return g_variant_new_uint16 (GUINT16_SWAP_LE_BE (g_variant_get_uint16 (value))); | ||
| 56 | + else | ||
| 57 | + return g_variant_new_uint16 (g_variant_get_uint16 (value)); | ||
| 58 | |||
| 59 | case G_VARIANT_CLASS_INT32: | ||
| 60 | - return g_variant_new_int32 (g_variant_get_int32 (value)); | ||
| 61 | + if (byteswap) | ||
| 62 | + return g_variant_new_int32 (GUINT32_SWAP_LE_BE (g_variant_get_int32 (value))); | ||
| 63 | + else | ||
| 64 | + return g_variant_new_int32 (g_variant_get_int32 (value)); | ||
| 65 | |||
| 66 | case G_VARIANT_CLASS_UINT32: | ||
| 67 | - return g_variant_new_uint32 (g_variant_get_uint32 (value)); | ||
| 68 | + if (byteswap) | ||
| 69 | + return g_variant_new_uint32 (GUINT32_SWAP_LE_BE (g_variant_get_uint32 (value))); | ||
| 70 | + else | ||
| 71 | + return g_variant_new_uint32 (g_variant_get_uint32 (value)); | ||
| 72 | |||
| 73 | case G_VARIANT_CLASS_INT64: | ||
| 74 | - return g_variant_new_int64 (g_variant_get_int64 (value)); | ||
| 75 | + if (byteswap) | ||
| 76 | + return g_variant_new_int64 (GUINT64_SWAP_LE_BE (g_variant_get_int64 (value))); | ||
| 77 | + else | ||
| 78 | + return g_variant_new_int64 (g_variant_get_int64 (value)); | ||
| 79 | |||
| 80 | case G_VARIANT_CLASS_UINT64: | ||
| 81 | - return g_variant_new_uint64 (g_variant_get_uint64 (value)); | ||
| 82 | + if (byteswap) | ||
| 83 | + return g_variant_new_uint64 (GUINT64_SWAP_LE_BE (g_variant_get_uint64 (value))); | ||
| 84 | + else | ||
| 85 | + return g_variant_new_uint64 (g_variant_get_uint64 (value)); | ||
| 86 | |||
| 87 | case G_VARIANT_CLASS_HANDLE: | ||
| 88 | - return g_variant_new_handle (g_variant_get_handle (value)); | ||
| 89 | + if (byteswap) | ||
| 90 | + return g_variant_new_handle (GUINT32_SWAP_LE_BE (g_variant_get_handle (value))); | ||
| 91 | + else | ||
| 92 | + return g_variant_new_handle (g_variant_get_handle (value)); | ||
| 93 | |||
| 94 | case G_VARIANT_CLASS_DOUBLE: | ||
| 95 | - return g_variant_new_double (g_variant_get_double (value)); | ||
| 96 | + if (byteswap) | ||
| 97 | + { | ||
| 98 | + /* We have to convert the double to a uint64 here using a union, | ||
| 99 | + * because a cast will round it numerically. */ | ||
| 100 | + union | ||
| 101 | + { | ||
| 102 | + guint64 u64; | ||
| 103 | + gdouble dbl; | ||
| 104 | + } u1, u2; | ||
| 105 | + u1.dbl = g_variant_get_double (value); | ||
| 106 | + u2.u64 = GUINT64_SWAP_LE_BE (u1.u64); | ||
| 107 | + return g_variant_new_double (u2.dbl); | ||
| 108 | + } | ||
| 109 | + else | ||
| 110 | + return g_variant_new_double (g_variant_get_double (value)); | ||
| 111 | |||
| 112 | case G_VARIANT_CLASS_STRING: | ||
| 113 | return g_variant_new_string (g_variant_get_string (value, NULL)); | ||
| 114 | @@ -5896,7 +5932,7 @@ g_variant_get_normal_form (GVariant *value) | ||
| 115 | if (g_variant_is_normal_form (value)) | ||
| 116 | return g_variant_ref (value); | ||
| 117 | |||
| 118 | - trusted = g_variant_deep_copy (value); | ||
| 119 | + trusted = g_variant_deep_copy (value, FALSE); | ||
| 120 | g_assert (g_variant_is_trusted (trusted)); | ||
| 121 | |||
| 122 | return g_variant_ref_sink (trusted); | ||
| 123 | @@ -5916,6 +5952,11 @@ g_variant_get_normal_form (GVariant *value) | ||
| 124 | * contain multi-byte numeric data. That include strings, booleans, | ||
| 125 | * bytes and containers containing only these things (recursively). | ||
| 126 | * | ||
| 127 | + * While this function can safely handle untrusted, non-normal data, it is | ||
| 128 | + * recommended to check whether the input is in normal form beforehand, using | ||
| 129 | + * g_variant_is_normal_form(), and to reject non-normal inputs if your | ||
| 130 | + * application can be strict about what inputs it rejects. | ||
| 131 | + * | ||
| 132 | * The returned value is always in normal form and is marked as trusted. | ||
| 133 | * | ||
| 134 | * Returns: (transfer full): the byteswapped form of @value | ||
| 135 | @@ -5933,21 +5974,20 @@ g_variant_byteswap (GVariant *value) | ||
| 136 | |||
| 137 | g_variant_type_info_query (type_info, &alignment, NULL); | ||
| 138 | |||
| 139 | - if (alignment) | ||
| 140 | - /* (potentially) contains multi-byte numeric data */ | ||
| 141 | + if (alignment && g_variant_is_normal_form (value)) | ||
| 142 | { | ||
| 143 | + /* (potentially) contains multi-byte numeric data, but is also already in | ||
| 144 | + * normal form so we can use a faster byteswapping codepath on the | ||
| 145 | + * serialised data */ | ||
| 146 | GVariantSerialised serialised = { 0, }; | ||
| 147 | - GVariant *trusted; | ||
| 148 | GBytes *bytes; | ||
| 149 | |||
| 150 | - trusted = g_variant_get_normal_form (value); | ||
| 151 | - serialised.type_info = g_variant_get_type_info (trusted); | ||
| 152 | - serialised.size = g_variant_get_size (trusted); | ||
| 153 | + serialised.type_info = g_variant_get_type_info (value); | ||
| 154 | + serialised.size = g_variant_get_size (value); | ||
| 155 | serialised.data = g_malloc (serialised.size); | ||
| 156 | serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ | ||
| 157 | serialised.checked_offsets_up_to = G_MAXSIZE; | ||
| 158 | - g_variant_store (trusted, serialised.data); | ||
| 159 | - g_variant_unref (trusted); | ||
| 160 | + g_variant_store (value, serialised.data); | ||
| 161 | |||
| 162 | g_variant_serialised_byteswap (serialised); | ||
| 163 | |||
| 164 | @@ -5955,6 +5995,9 @@ g_variant_byteswap (GVariant *value) | ||
| 165 | new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE)); | ||
| 166 | g_bytes_unref (bytes); | ||
| 167 | } | ||
| 168 | + else if (alignment) | ||
| 169 | + /* (potentially) contains multi-byte numeric data */ | ||
| 170 | + new = g_variant_ref_sink (g_variant_deep_copy (value, TRUE)); | ||
| 171 | else | ||
| 172 | /* contains no multi-byte data */ | ||
| 173 | new = g_variant_get_normal_form (value); | ||
| 174 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 175 | index 3dda08e..679dd40 100644 | ||
| 176 | --- a/glib/tests/gvariant.c | ||
| 177 | +++ b/glib/tests/gvariant.c | ||
| 178 | @@ -2284,24 +2284,67 @@ serialise_tree (TreeInstance *tree, | ||
| 179 | static void | ||
| 180 | test_byteswap (void) | ||
| 181 | { | ||
| 182 | - GVariantSerialised one = { 0, }, two = { 0, }; | ||
| 183 | + GVariantSerialised one = { 0, }, two = { 0, }, three = { 0, }; | ||
| 184 | TreeInstance *tree; | ||
| 185 | - | ||
| 186 | + GVariant *one_variant = NULL; | ||
| 187 | + GVariant *two_variant = NULL; | ||
| 188 | + GVariant *two_byteswapped = NULL; | ||
| 189 | + GVariant *three_variant = NULL; | ||
| 190 | + GVariant *three_byteswapped = NULL; | ||
| 191 | + guint8 *three_data_copy = NULL; | ||
| 192 | + gsize three_size_copy = 0; | ||
| 193 | + | ||
| 194 | + /* Write a tree out twice, once normally and once byteswapped. */ | ||
| 195 | tree = tree_instance_new (NULL, 3); | ||
| 196 | serialise_tree (tree, &one); | ||
| 197 | |||
| 198 | + one_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (one.type_info)), | ||
| 199 | + one.data, one.size, FALSE, NULL, NULL); | ||
| 200 | + | ||
| 201 | i_am_writing_byteswapped = TRUE; | ||
| 202 | serialise_tree (tree, &two); | ||
| 203 | + serialise_tree (tree, &three); | ||
| 204 | i_am_writing_byteswapped = FALSE; | ||
| 205 | |||
| 206 | - g_variant_serialised_byteswap (two); | ||
| 207 | - | ||
| 208 | - g_assert_cmpmem (one.data, one.size, two.data, two.size); | ||
| 209 | - g_assert_cmpuint (one.depth, ==, two.depth); | ||
| 210 | - | ||
| 211 | + /* Swap the first byteswapped one back using the function we want to test. */ | ||
| 212 | + two_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (two.type_info)), | ||
| 213 | + two.data, two.size, FALSE, NULL, NULL); | ||
| 214 | + two_byteswapped = g_variant_byteswap (two_variant); | ||
| 215 | + | ||
| 216 | + /* Make the second byteswapped one non-normal (hopefully), and then byteswap | ||
| 217 | + * it back using the function we want to test in its non-normal mode. | ||
| 218 | + * This might not work because it’s not necessarily possible to make an | ||
| 219 | + * arbitrary random variant non-normal. Adding a single zero byte to the end | ||
| 220 | + * often makes something non-normal but still readable. */ | ||
| 221 | + three_size_copy = three.size + 1; | ||
| 222 | + three_data_copy = g_malloc (three_size_copy); | ||
| 223 | + memcpy (three_data_copy, three.data, three.size); | ||
| 224 | + three_data_copy[three.size] = '\0'; | ||
| 225 | + | ||
| 226 | + three_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (three.type_info)), | ||
| 227 | + three_data_copy, three_size_copy, FALSE, NULL, NULL); | ||
| 228 | + three_byteswapped = g_variant_byteswap (three_variant); | ||
| 229 | + | ||
| 230 | + /* Check they’re the same. We can always compare @one_variant and | ||
| 231 | + * @two_byteswapped. We can only compare @two_byteswapped and | ||
| 232 | + * @three_byteswapped if @two_variant and @three_variant are equal: in that | ||
| 233 | + * case, the corruption to @three_variant was enough to make it non-normal but | ||
| 234 | + * not enough to change its value. */ | ||
| 235 | + g_assert_cmpvariant (one_variant, two_byteswapped); | ||
| 236 | + | ||
| 237 | + if (g_variant_equal (two_variant, three_variant)) | ||
| 238 | + g_assert_cmpvariant (two_byteswapped, three_byteswapped); | ||
| 239 | + | ||
| 240 | + g_variant_unref (three_byteswapped); | ||
| 241 | + g_variant_unref (three_variant); | ||
| 242 | + g_variant_unref (two_byteswapped); | ||
| 243 | + g_variant_unref (two_variant); | ||
| 244 | + g_variant_unref (one_variant); | ||
| 245 | tree_instance_free (tree); | ||
| 246 | g_free (one.data); | ||
| 247 | g_free (two.data); | ||
| 248 | + g_free (three.data); | ||
| 249 | + g_free (three_data_copy); | ||
| 250 | } | ||
| 251 | |||
| 252 | static void | ||
| 253 | -- | ||
| 254 | 2.24.4 | ||
| 255 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32636.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32636.patch new file mode 100644 index 0000000000..533142b22a --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32636.patch | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | From 21a204147b16539b3eda3143b32844c49e29f4d4 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Thu, 17 Aug 2023 11:33:49 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Propagate trust when getting a child of a | ||
| 5 | serialised variant | ||
| 6 | |||
| 7 | If a variant is trusted, that means all its children are trusted, so | ||
| 8 | ensure that their checked offsets are set as such. | ||
| 9 | |||
| 10 | This allows a lot of the offset table checks to be avoided when getting | ||
| 11 | children from trusted serialised tuples, which speeds things up. | ||
| 12 | |||
| 13 | No unit test is included because this is just a performance fix. If | ||
| 14 | there are other slownesses, or regressions, in serialised `GVariant` | ||
| 15 | performance, the fuzzing setup will catch them like it did this one. | ||
| 16 | |||
| 17 | This change does reduce the time to run the oss-fuzz reproducer from 80s | ||
| 18 | to about 0.7s on my machine. | ||
| 19 | |||
| 20 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 21 | |||
| 22 | Fixes: #2841 | ||
| 23 | oss-fuzz#54314 | ||
| 24 | |||
| 25 | CVE: CVE-2023-32636 | ||
| 26 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/21a204147b16539b3eda3143b32844c49e29f4d4] | ||
| 27 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 28 | --- | ||
| 29 | glib/gvariant-core.c | 4 ++-- | ||
| 30 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
| 31 | |||
| 32 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 33 | index 1b9d5cc..ed57c70 100644 | ||
| 34 | --- a/glib/gvariant-core.c | ||
| 35 | +++ b/glib/gvariant-core.c | ||
| 36 | @@ -1173,8 +1173,8 @@ g_variant_get_child_value (GVariant *value, | ||
| 37 | child->contents.serialised.bytes = | ||
| 38 | g_bytes_ref (value->contents.serialised.bytes); | ||
| 39 | child->contents.serialised.data = s_child.data; | ||
| 40 | - child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; | ||
| 41 | - child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to; | ||
| 42 | + child->contents.serialised.ordered_offsets_up_to = (value->state & STATE_TRUSTED) ? G_MAXSIZE : s_child.ordered_offsets_up_to; | ||
| 43 | + child->contents.serialised.checked_offsets_up_to = (value->state & STATE_TRUSTED) ? G_MAXSIZE : s_child.checked_offsets_up_to; | ||
| 44 | |||
| 45 | return child; | ||
| 46 | } | ||
| 47 | -- | ||
| 48 | 2.24.4 | ||
| 49 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32643.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32643.patch new file mode 100644 index 0000000000..9c0867bf5f --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32643.patch | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | From 78da5faccb3e065116b75b3ff87ff55381da6c76 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Thu, 17 Aug 2023 11:24:43 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Check offset table doesn't fall outside variant | ||
| 5 | bounds | ||
| 6 | |||
| 7 | When dereferencing the first entry in the offset table for a tuple, | ||
| 8 | check that it doesn’t fall outside the bounds of the variant first. | ||
| 9 | |||
| 10 | This prevents an out-of-bounds read from some non-normal tuples. | ||
| 11 | |||
| 12 | This bug was introduced in commit 73d0aa81c2575a5c9ae77d. | ||
| 13 | |||
| 14 | Includes a unit test, although the test will likely only catch the | ||
| 15 | original bug if run with asan enabled. | ||
| 16 | |||
| 17 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 18 | |||
| 19 | Fixes: #2840 | ||
| 20 | oss-fuzz#54302 | ||
| 21 | |||
| 22 | CVE: CVE-2023-32643 | ||
| 23 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/78da5faccb3e065116b75b3ff87ff55381da6c76] | ||
| 24 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 25 | --- | ||
| 26 | glib/gvariant-serialiser.c | 12 ++++++-- | ||
| 27 | glib/tests/gvariant.c | 63 ++++++++++++++++++++++++++++++++++++++ | ||
| 28 | 2 files changed, 72 insertions(+), 3 deletions(-) | ||
| 29 | |||
| 30 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 31 | index 5aa2cbc..4e50ed7 100644 | ||
| 32 | --- a/glib/gvariant-serialiser.c | ||
| 33 | +++ b/glib/gvariant-serialiser.c | ||
| 34 | @@ -979,7 +979,8 @@ gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 35 | |||
| 36 | member_info = g_variant_type_info_member_info (value.type_info, index_); | ||
| 37 | |||
| 38 | - if (member_info->i + 1) | ||
| 39 | + if (member_info->i + 1 && | ||
| 40 | + offset_size * (member_info->i + 1) <= value.size) | ||
| 41 | member_start = gvs_read_unaligned_le (value.data + value.size - | ||
| 42 | offset_size * (member_info->i + 1), | ||
| 43 | offset_size); | ||
| 44 | @@ -990,7 +991,8 @@ gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 45 | member_start &= member_info->b; | ||
| 46 | member_start |= member_info->c; | ||
| 47 | |||
| 48 | - if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) | ||
| 49 | + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST && | ||
| 50 | + offset_size * (member_info->i + 1) <= value.size) | ||
| 51 | member_end = value.size - offset_size * (member_info->i + 1); | ||
| 52 | |||
| 53 | else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 54 | @@ -1001,11 +1003,15 @@ gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 55 | member_end = member_start + fixed_size; | ||
| 56 | } | ||
| 57 | |||
| 58 | - else /* G_VARIANT_MEMBER_ENDING_OFFSET */ | ||
| 59 | + else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET && | ||
| 60 | + offset_size * (member_info->i + 2) <= value.size) | ||
| 61 | member_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 62 | offset_size * (member_info->i + 2), | ||
| 63 | offset_size); | ||
| 64 | |||
| 65 | + else /* invalid */ | ||
| 66 | + member_end = G_MAXSIZE; | ||
| 67 | + | ||
| 68 | if (out_member_start != NULL) | ||
| 69 | *out_member_start = member_start; | ||
| 70 | if (out_member_end != NULL) | ||
| 71 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 72 | index 679dd40..2eca8be 100644 | ||
| 73 | --- a/glib/tests/gvariant.c | ||
| 74 | +++ b/glib/tests/gvariant.c | ||
| 75 | @@ -5432,6 +5432,67 @@ test_normal_checking_tuple_offsets4 (void) | ||
| 76 | g_variant_unref (variant); | ||
| 77 | } | ||
| 78 | |||
| 79 | +/* This is a regression test that dereferencing the first element in the offset | ||
| 80 | + * table doesn’t dereference memory before the start of the GVariant. The first | ||
| 81 | + * element in the offset table gives the offset of the final member in the | ||
| 82 | + * tuple (the offset table is stored in reverse), and the position of this final | ||
| 83 | + * member is needed to check that none of the tuple members overlap with the | ||
| 84 | + * offset table | ||
| 85 | + * | ||
| 86 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2840 */ | ||
| 87 | +static void | ||
| 88 | +test_normal_checking_tuple_offsets5 (void) | ||
| 89 | +{ | ||
| 90 | + /* A tuple of type (sss) in normal form would have an offset table with two | ||
| 91 | + * entries: | ||
| 92 | + * - The first entry (lowest index in the table) gives the offset of the | ||
| 93 | + * third `s` in the tuple, as the offset table is reversed compared to the | ||
| 94 | + * tuple members. | ||
| 95 | + * - The second entry (highest index in the table) gives the offset of the | ||
| 96 | + * second `s` in the tuple. | ||
| 97 | + * - The offset of the first `s` in the tuple is always 0. | ||
| 98 | + * | ||
| 99 | + * See §2.5.4 (Structures) of the GVariant specification for details, noting | ||
| 100 | + * that the table is only layed out this way because all three members of the | ||
| 101 | + * tuple have non-fixed sizes. | ||
| 102 | + * | ||
| 103 | + * It’s not clear whether the 0xaa data of this variant is part of the strings | ||
| 104 | + * in the tuple, or part of the offset table. It doesn’t really matter. This | ||
| 105 | + * is a regression test to check that the code to validate the offset table | ||
| 106 | + * doesn’t unconditionally try to access the first entry in the offset table | ||
| 107 | + * by subtracting the table size from the end of the GVariant data. | ||
| 108 | + * | ||
| 109 | + * In this non-normal case, that would result in an address off the start of | ||
| 110 | + * the GVariant data, and an out-of-bounds read, because the GVariant is one | ||
| 111 | + * byte long, but the offset table is calculated as two bytes long (with 1B | ||
| 112 | + * sized entries) from the tuple’s type. | ||
| 113 | + */ | ||
| 114 | + const GVariantType *data_type = G_VARIANT_TYPE ("(sss)"); | ||
| 115 | + const guint8 data[] = { 0xaa }; | ||
| 116 | + gsize size = sizeof (data); | ||
| 117 | + GVariant *variant = NULL; | ||
| 118 | + GVariant *normal_variant = NULL; | ||
| 119 | + GVariant *expected = NULL; | ||
| 120 | + | ||
| 121 | + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2840"); | ||
| 122 | + | ||
| 123 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 124 | + g_assert_nonnull (variant); | ||
| 125 | + | ||
| 126 | + g_assert_false (g_variant_is_normal_form (variant)); | ||
| 127 | + | ||
| 128 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 129 | + g_assert_nonnull (normal_variant); | ||
| 130 | + | ||
| 131 | + expected = g_variant_new_parsed ("('', '', '')"); | ||
| 132 | + g_assert_cmpvariant (expected, variant); | ||
| 133 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 134 | + | ||
| 135 | + g_variant_unref (expected); | ||
| 136 | + g_variant_unref (normal_variant); | ||
| 137 | + g_variant_unref (variant); | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | /* Test that an otherwise-valid serialised GVariant is considered non-normal if | ||
| 141 | * its offset table entries are too wide. | ||
| 142 | * | ||
| 143 | @@ -5680,6 +5741,8 @@ main (int argc, char **argv) | ||
| 144 | test_normal_checking_tuple_offsets3); | ||
| 145 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", | ||
| 146 | test_normal_checking_tuple_offsets4); | ||
| 147 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets5", | ||
| 148 | + test_normal_checking_tuple_offsets5); | ||
| 149 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized", | ||
| 150 | test_normal_checking_tuple_offsets_minimal_sized); | ||
| 151 | g_test_add_func ("/gvariant/normal-checking/empty-object-path", | ||
| 152 | -- | ||
| 153 | 2.24.4 | ||
| 154 | |||
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..9fc58341cb --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0001.patch | |||
| @@ -0,0 +1,103 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1] | ||
| 15 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 16 | --- | ||
| 17 | glib/gvariant-core.c | 49 ++++++++++++++++++++++---------------------- | ||
| 18 | 1 file changed, 25 insertions(+), 24 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 21 | index 9397573..aa0e0a0 100644 | ||
| 22 | --- a/glib/gvariant-core.c | ||
| 23 | +++ b/glib/gvariant-core.c | ||
| 24 | @@ -349,6 +349,27 @@ g_variant_ensure_size (GVariant *value) | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | +/* < private > | ||
| 29 | + * g_variant_to_serialised: | ||
| 30 | + * @value: a #GVariant | ||
| 31 | + * | ||
| 32 | + * Gets a GVariantSerialised for a GVariant in state STATE_SERIALISED. | ||
| 33 | + */ | ||
| 34 | +inline static GVariantSerialised | ||
| 35 | +g_variant_to_serialised (GVariant *value) | ||
| 36 | +{ | ||
| 37 | + g_assert (value->state & STATE_SERIALISED); | ||
| 38 | + { | ||
| 39 | + GVariantSerialised serialised = { | ||
| 40 | + value->type_info, | ||
| 41 | + (gpointer) value->contents.serialised.data, | ||
| 42 | + value->size, | ||
| 43 | + value->depth, | ||
| 44 | + }; | ||
| 45 | + return serialised; | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | /* < private > | ||
| 50 | * g_variant_serialise: | ||
| 51 | * @value: a #GVariant | ||
| 52 | @@ -991,16 +1012,8 @@ g_variant_n_children (GVariant *value) | ||
| 53 | g_variant_lock (value); | ||
| 54 | |||
| 55 | if (value->state & STATE_SERIALISED) | ||
| 56 | - { | ||
| 57 | - GVariantSerialised serialised = { | ||
| 58 | - value->type_info, | ||
| 59 | - (gpointer) value->contents.serialised.data, | ||
| 60 | - value->size, | ||
| 61 | - value->depth, | ||
| 62 | - }; | ||
| 63 | - | ||
| 64 | - n_children = g_variant_serialised_n_children (serialised); | ||
| 65 | - } | ||
| 66 | + n_children = g_variant_serialised_n_children ( | ||
| 67 | + g_variant_to_serialised (value)); | ||
| 68 | else | ||
| 69 | n_children = value->contents.tree.n_children; | ||
| 70 | |||
| 71 | @@ -1061,12 +1074,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 72 | } | ||
| 73 | |||
| 74 | { | ||
| 75 | - GVariantSerialised serialised = { | ||
| 76 | - value->type_info, | ||
| 77 | - (gpointer) value->contents.serialised.data, | ||
| 78 | - value->size, | ||
| 79 | - value->depth, | ||
| 80 | - }; | ||
| 81 | + GVariantSerialised serialised = g_variant_to_serialised (value); | ||
| 82 | GVariantSerialised s_child; | ||
| 83 | GVariant *child; | ||
| 84 | |||
| 85 | @@ -1179,14 +1187,7 @@ g_variant_is_normal_form (GVariant *value) | ||
| 86 | |||
| 87 | if (value->state & STATE_SERIALISED) | ||
| 88 | { | ||
| 89 | - GVariantSerialised serialised = { | ||
| 90 | - value->type_info, | ||
| 91 | - (gpointer) value->contents.serialised.data, | ||
| 92 | - value->size, | ||
| 93 | - value->depth | ||
| 94 | - }; | ||
| 95 | - | ||
| 96 | - if (g_variant_serialised_is_normal (serialised)) | ||
| 97 | + if (g_variant_serialised_is_normal (g_variant_to_serialised (value))) | ||
| 98 | value->state |= STATE_TRUSTED; | ||
| 99 | } | ||
| 100 | else | ||
| 101 | -- | ||
| 102 | 2.24.4 | ||
| 103 | |||
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..0e96b8d457 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0002.patch | |||
| @@ -0,0 +1,210 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/446e69f5edd72deb2196dee36bbaf8056caf6948] | ||
| 13 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 14 | --- | ||
| 15 | glib/gvariant-serialiser.c | 108 +++++++++++++++++++------------------ | ||
| 16 | 1 file changed, 57 insertions(+), 51 deletions(-) | ||
| 17 | |||
| 18 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 19 | index 83e9d85..c7c2114 100644 | ||
| 20 | --- a/glib/gvariant-serialiser.c | ||
| 21 | +++ b/glib/gvariant-serialiser.c | ||
| 22 | @@ -633,30 +633,62 @@ gvs_calculate_total_size (gsize body_size, | ||
| 23 | return body_size + 8 * offsets; | ||
| 24 | } | ||
| 25 | |||
| 26 | +struct Offsets | ||
| 27 | +{ | ||
| 28 | + gsize data_size; | ||
| 29 | + | ||
| 30 | + guchar *array; | ||
| 31 | + gsize length; | ||
| 32 | + guint offset_size; | ||
| 33 | + | ||
| 34 | + gboolean is_normal; | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | static gsize | ||
| 38 | -gvs_variable_sized_array_n_children (GVariantSerialised value) | ||
| 39 | +gvs_offsets_get_offset_n (struct Offsets *offsets, | ||
| 40 | + gsize n) | ||
| 41 | +{ | ||
| 42 | + return gvs_read_unaligned_le ( | ||
| 43 | + offsets->array + (offsets->offset_size * n), offsets->offset_size); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +static struct Offsets | ||
| 47 | +gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value) | ||
| 48 | { | ||
| 49 | + struct Offsets out = { 0, }; | ||
| 50 | gsize offsets_array_size; | ||
| 51 | - gsize offset_size; | ||
| 52 | gsize last_end; | ||
| 53 | |||
| 54 | if (value.size == 0) | ||
| 55 | - return 0; | ||
| 56 | - | ||
| 57 | - offset_size = gvs_get_offset_size (value.size); | ||
| 58 | + { | ||
| 59 | + out.is_normal = TRUE; | ||
| 60 | + return out; | ||
| 61 | + } | ||
| 62 | |||
| 63 | - last_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 64 | - offset_size, offset_size); | ||
| 65 | + out.offset_size = gvs_get_offset_size (value.size); | ||
| 66 | + last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size, | ||
| 67 | + out.offset_size); | ||
| 68 | |||
| 69 | if (last_end > value.size) | ||
| 70 | - return 0; | ||
| 71 | + return out; /* offsets not normal */ | ||
| 72 | |||
| 73 | offsets_array_size = value.size - last_end; | ||
| 74 | |||
| 75 | - if (offsets_array_size % offset_size) | ||
| 76 | - return 0; | ||
| 77 | + if (offsets_array_size % out.offset_size) | ||
| 78 | + return out; /* offsets not normal */ | ||
| 79 | + | ||
| 80 | + out.data_size = last_end; | ||
| 81 | + out.array = value.data + last_end; | ||
| 82 | + out.length = offsets_array_size / out.offset_size; | ||
| 83 | + out.is_normal = TRUE; | ||
| 84 | |||
| 85 | - return offsets_array_size / offset_size; | ||
| 86 | + return out; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +static gsize | ||
| 90 | +gvs_variable_sized_array_n_children (GVariantSerialised value) | ||
| 91 | +{ | ||
| 92 | + return gvs_variable_sized_array_get_frame_offsets (value).length; | ||
| 93 | } | ||
| 94 | |||
| 95 | static GVariantSerialised | ||
| 96 | @@ -664,8 +696,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 97 | gsize index_) | ||
| 98 | { | ||
| 99 | GVariantSerialised child = { 0, }; | ||
| 100 | - gsize offset_size; | ||
| 101 | - gsize last_end; | ||
| 102 | + | ||
| 103 | + struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value); | ||
| 104 | + | ||
| 105 | gsize start; | ||
| 106 | gsize end; | ||
| 107 | |||
| 108 | @@ -673,18 +706,11 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 109 | g_variant_type_info_ref (child.type_info); | ||
| 110 | child.depth = value.depth + 1; | ||
| 111 | |||
| 112 | - offset_size = gvs_get_offset_size (value.size); | ||
| 113 | - | ||
| 114 | - last_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 115 | - offset_size, offset_size); | ||
| 116 | - | ||
| 117 | if (index_ > 0) | ||
| 118 | { | ||
| 119 | guint alignment; | ||
| 120 | |||
| 121 | - start = gvs_read_unaligned_le (value.data + last_end + | ||
| 122 | - (offset_size * (index_ - 1)), | ||
| 123 | - offset_size); | ||
| 124 | + start = gvs_offsets_get_offset_n (&offsets, index_ - 1); | ||
| 125 | |||
| 126 | g_variant_type_info_query (child.type_info, &alignment, NULL); | ||
| 127 | start += (-start) & alignment; | ||
| 128 | @@ -692,11 +718,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 129 | else | ||
| 130 | start = 0; | ||
| 131 | |||
| 132 | - end = gvs_read_unaligned_le (value.data + last_end + | ||
| 133 | - (offset_size * index_), | ||
| 134 | - offset_size); | ||
| 135 | + end = gvs_offsets_get_offset_n (&offsets, index_); | ||
| 136 | |||
| 137 | - if (start < end && end <= value.size && end <= last_end) | ||
| 138 | + if (start < end && end <= value.size && end <= offsets.data_size) | ||
| 139 | { | ||
| 140 | child.data = value.data + start; | ||
| 141 | child.size = end - start; | ||
| 142 | @@ -768,34 +792,16 @@ static gboolean | ||
| 143 | gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 144 | { | ||
| 145 | GVariantSerialised child = { 0, }; | ||
| 146 | - gsize offsets_array_size; | ||
| 147 | - guchar *offsets_array; | ||
| 148 | - guint offset_size; | ||
| 149 | guint alignment; | ||
| 150 | - gsize last_end; | ||
| 151 | - gsize length; | ||
| 152 | gsize offset; | ||
| 153 | gsize i; | ||
| 154 | |||
| 155 | - if (value.size == 0) | ||
| 156 | - return TRUE; | ||
| 157 | - | ||
| 158 | - offset_size = gvs_get_offset_size (value.size); | ||
| 159 | - last_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 160 | - offset_size, offset_size); | ||
| 161 | + struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value); | ||
| 162 | |||
| 163 | - if (last_end > value.size) | ||
| 164 | + if (!offsets.is_normal) | ||
| 165 | return FALSE; | ||
| 166 | |||
| 167 | - offsets_array_size = value.size - last_end; | ||
| 168 | - | ||
| 169 | - if (offsets_array_size % offset_size) | ||
| 170 | - return FALSE; | ||
| 171 | - | ||
| 172 | - offsets_array = value.data + value.size - offsets_array_size; | ||
| 173 | - length = offsets_array_size / offset_size; | ||
| 174 | - | ||
| 175 | - if (length == 0) | ||
| 176 | + if (value.size != 0 && offsets.length == 0) | ||
| 177 | return FALSE; | ||
| 178 | |||
| 179 | child.type_info = g_variant_type_info_element (value.type_info); | ||
| 180 | @@ -803,14 +809,14 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 181 | child.depth = value.depth + 1; | ||
| 182 | offset = 0; | ||
| 183 | |||
| 184 | - for (i = 0; i < length; i++) | ||
| 185 | + for (i = 0; i < offsets.length; i++) | ||
| 186 | { | ||
| 187 | gsize this_end; | ||
| 188 | |||
| 189 | - this_end = gvs_read_unaligned_le (offsets_array + offset_size * i, | ||
| 190 | - offset_size); | ||
| 191 | + this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i, | ||
| 192 | + offsets.offset_size); | ||
| 193 | |||
| 194 | - if (this_end < offset || this_end > last_end) | ||
| 195 | + if (this_end < offset || this_end > offsets.data_size) | ||
| 196 | return FALSE; | ||
| 197 | |||
| 198 | while (offset & alignment) | ||
| 199 | @@ -832,7 +838,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 200 | offset = this_end; | ||
| 201 | } | ||
| 202 | |||
| 203 | - g_assert (offset == last_end); | ||
| 204 | + g_assert (offset == offsets.data_size); | ||
| 205 | |||
| 206 | return TRUE; | ||
| 207 | } | ||
| 208 | -- | ||
| 209 | 2.24.4 | ||
| 210 | |||
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..e361cc7aad --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0003.patch | |||
| @@ -0,0 +1,417 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/ade71fb544391b2e33e1859645726bfee0d5eaaf] | ||
| 36 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 37 | --- | ||
| 38 | glib/gvariant-core.c | 35 ++++++++++++++++ | ||
| 39 | glib/gvariant-serialiser.c | 86 ++++++++++++++++++++++++++++++++++++-- | ||
| 40 | glib/gvariant-serialiser.h | 8 ++++ | ||
| 41 | glib/tests/gvariant.c | 45 ++++++++++++++++++++ | ||
| 42 | 4 files changed, 171 insertions(+), 3 deletions(-) | ||
| 43 | |||
| 44 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 45 | index aa0e0a0..9b51e15 100644 | ||
| 46 | --- a/glib/gvariant-core.c | ||
| 47 | +++ b/glib/gvariant-core.c | ||
| 48 | @@ -65,6 +65,7 @@ struct _GVariant | ||
| 49 | { | ||
| 50 | GBytes *bytes; | ||
| 51 | gconstpointer data; | ||
| 52 | + gsize ordered_offsets_up_to; | ||
| 53 | } serialised; | ||
| 54 | |||
| 55 | struct | ||
| 56 | @@ -162,6 +163,24 @@ struct _GVariant | ||
| 57 | * if .data pointed to the appropriate number of nul | ||
| 58 | * bytes. | ||
| 59 | * | ||
| 60 | + * .ordered_offsets_up_to: If ordered_offsets_up_to == n this means that all | ||
| 61 | + * the frame offsets up to and including the frame | ||
| 62 | + * offset determining the end of element n are in | ||
| 63 | + * order. This guarantees that the bytes of element | ||
| 64 | + * n don't overlap with any previous element. | ||
| 65 | + * | ||
| 66 | + * For trusted data this is set to G_MAXSIZE and we | ||
| 67 | + * don't check that the frame offsets are in order. | ||
| 68 | + * | ||
| 69 | + * Note: This doesn't imply the offsets are good in | ||
| 70 | + * any way apart from their ordering. In particular | ||
| 71 | + * offsets may be out of bounds for this value or | ||
| 72 | + * may imply that the data overlaps the frame | ||
| 73 | + * offsets themselves. | ||
| 74 | + * | ||
| 75 | + * This field is only relevant for arrays of non | ||
| 76 | + * fixed width types. | ||
| 77 | + * | ||
| 78 | * .tree: Only valid when the instance is in tree form. | ||
| 79 | * | ||
| 80 | * Note that accesses from other threads could result in | ||
| 81 | @@ -365,6 +384,7 @@ g_variant_to_serialised (GVariant *value) | ||
| 82 | (gpointer) value->contents.serialised.data, | ||
| 83 | value->size, | ||
| 84 | value->depth, | ||
| 85 | + value->contents.serialised.ordered_offsets_up_to, | ||
| 86 | }; | ||
| 87 | return serialised; | ||
| 88 | } | ||
| 89 | @@ -396,6 +416,7 @@ g_variant_serialise (GVariant *value, | ||
| 90 | serialised.size = value->size; | ||
| 91 | serialised.data = data; | ||
| 92 | serialised.depth = value->depth; | ||
| 93 | + serialised.ordered_offsets_up_to = 0; | ||
| 94 | |||
| 95 | children = (gpointer *) value->contents.tree.children; | ||
| 96 | n_children = value->contents.tree.n_children; | ||
| 97 | @@ -439,6 +460,15 @@ g_variant_fill_gvs (GVariantSerialised *serialised, | ||
| 98 | g_assert (serialised->size == value->size); | ||
| 99 | serialised->depth = value->depth; | ||
| 100 | |||
| 101 | + if (value->state & STATE_SERIALISED) | ||
| 102 | + { | ||
| 103 | + serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to; | ||
| 104 | + } | ||
| 105 | + else | ||
| 106 | + { | ||
| 107 | + serialised->ordered_offsets_up_to = 0; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | if (serialised->data) | ||
| 111 | /* g_variant_store() is a public API, so it | ||
| 112 | * it will reacquire the lock if it needs to. | ||
| 113 | @@ -481,6 +511,7 @@ g_variant_ensure_serialised (GVariant *value) | ||
| 114 | bytes = g_bytes_new_take (data, value->size); | ||
| 115 | value->contents.serialised.data = g_bytes_get_data (bytes, NULL); | ||
| 116 | value->contents.serialised.bytes = bytes; | ||
| 117 | + value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE; | ||
| 118 | value->state |= STATE_SERIALISED; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | @@ -561,6 +592,7 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 122 | serialised.type_info = value->type_info; | ||
| 123 | serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size); | ||
| 124 | serialised.depth = 0; | ||
| 125 | + serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 126 | |||
| 127 | if (!g_variant_serialised_check (serialised)) | ||
| 128 | { | ||
| 129 | @@ -610,6 +642,8 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 130 | value->contents.serialised.data = g_bytes_get_data (bytes, &value->size); | ||
| 131 | } | ||
| 132 | |||
| 133 | + value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 134 | + | ||
| 135 | g_clear_pointer (&owned_bytes, g_bytes_unref); | ||
| 136 | |||
| 137 | return value; | ||
| 138 | @@ -1108,6 +1142,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 139 | child->contents.serialised.bytes = | ||
| 140 | g_bytes_ref (value->contents.serialised.bytes); | ||
| 141 | child->contents.serialised.data = s_child.data; | ||
| 142 | + child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; | ||
| 143 | |||
| 144 | return child; | ||
| 145 | } | ||
| 146 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 147 | index c7c2114..fe0b1a4 100644 | ||
| 148 | --- a/glib/gvariant-serialiser.c | ||
| 149 | +++ b/glib/gvariant-serialiser.c | ||
| 150 | @@ -1,6 +1,7 @@ | ||
| 151 | /* | ||
| 152 | * Copyright © 2007, 2008 Ryan Lortie | ||
| 153 | * Copyright © 2010 Codethink Limited | ||
| 154 | + * Copyright © 2020 William Manley | ||
| 155 | * | ||
| 156 | * This library is free software; you can redistribute it and/or | ||
| 157 | * modify it under the terms of the GNU Lesser General Public | ||
| 158 | @@ -264,6 +265,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, | ||
| 159 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 160 | g_variant_type_info_ref (value.type_info); | ||
| 161 | value.depth++; | ||
| 162 | + value.ordered_offsets_up_to = 0; | ||
| 163 | |||
| 164 | return value; | ||
| 165 | } | ||
| 166 | @@ -295,7 +297,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, | ||
| 167 | { | ||
| 168 | if (n_children) | ||
| 169 | { | ||
| 170 | - GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1 }; | ||
| 171 | + GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 }; | ||
| 172 | |||
| 173 | gvs_filler (&child, children[0]); | ||
| 174 | } | ||
| 175 | @@ -317,6 +319,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) | ||
| 176 | /* proper element size: "Just". recurse to the child. */ | ||
| 177 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 178 | value.depth++; | ||
| 179 | + value.ordered_offsets_up_to = 0; | ||
| 180 | |||
| 181 | return g_variant_serialised_is_normal (value); | ||
| 182 | } | ||
| 183 | @@ -358,6 +361,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, | ||
| 184 | value.data = NULL; | ||
| 185 | |||
| 186 | value.depth++; | ||
| 187 | + value.ordered_offsets_up_to = 0; | ||
| 188 | |||
| 189 | return value; | ||
| 190 | } | ||
| 191 | @@ -388,7 +392,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, | ||
| 192 | { | ||
| 193 | if (n_children) | ||
| 194 | { | ||
| 195 | - GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1 }; | ||
| 196 | + GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 }; | ||
| 197 | |||
| 198 | /* write the data for the child. */ | ||
| 199 | gvs_filler (&child, children[0]); | ||
| 200 | @@ -408,6 +412,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value) | ||
| 201 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 202 | value.size--; | ||
| 203 | value.depth++; | ||
| 204 | + value.ordered_offsets_up_to = 0; | ||
| 205 | |||
| 206 | return g_variant_serialised_is_normal (value); | ||
| 207 | } | ||
| 208 | @@ -691,6 +696,32 @@ gvs_variable_sized_array_n_children (GVariantSerialised value) | ||
| 209 | return gvs_variable_sized_array_get_frame_offsets (value).length; | ||
| 210 | } | ||
| 211 | |||
| 212 | +/* Find the index of the first out-of-order element in @data, assuming that | ||
| 213 | + * @data is an array of elements of given @type, starting at index @start and | ||
| 214 | + * containing a further @len-@start elements. */ | ||
| 215 | +#define DEFINE_FIND_UNORDERED(type) \ | ||
| 216 | + static gsize \ | ||
| 217 | + find_unordered_##type (const guint8 *data, gsize start, gsize len) \ | ||
| 218 | + { \ | ||
| 219 | + gsize off; \ | ||
| 220 | + type current, previous; \ | ||
| 221 | + \ | ||
| 222 | + memcpy (&previous, data + start * sizeof (current), sizeof (current)); \ | ||
| 223 | + for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \ | ||
| 224 | + { \ | ||
| 225 | + memcpy (¤t, data + off, sizeof (current)); \ | ||
| 226 | + if (current < previous) \ | ||
| 227 | + break; \ | ||
| 228 | + previous = current; \ | ||
| 229 | + } \ | ||
| 230 | + return off / sizeof (current) - 1; \ | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | +DEFINE_FIND_UNORDERED (guint8); | ||
| 234 | +DEFINE_FIND_UNORDERED (guint16); | ||
| 235 | +DEFINE_FIND_UNORDERED (guint32); | ||
| 236 | +DEFINE_FIND_UNORDERED (guint64); | ||
| 237 | + | ||
| 238 | static GVariantSerialised | ||
| 239 | gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 240 | gsize index_) | ||
| 241 | @@ -706,6 +737,49 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 242 | g_variant_type_info_ref (child.type_info); | ||
| 243 | child.depth = value.depth + 1; | ||
| 244 | |||
| 245 | + /* If the requested @index_ is beyond the set of indices whose framing offsets | ||
| 246 | + * have been checked, check the remaining offsets to see whether they’re | ||
| 247 | + * normal (in order, no overlapping array elements). */ | ||
| 248 | + if (index_ > value.ordered_offsets_up_to) | ||
| 249 | + { | ||
| 250 | + switch (offsets.offset_size) | ||
| 251 | + { | ||
| 252 | + case 1: | ||
| 253 | + { | ||
| 254 | + value.ordered_offsets_up_to = find_unordered_guint8 ( | ||
| 255 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 256 | + break; | ||
| 257 | + } | ||
| 258 | + case 2: | ||
| 259 | + { | ||
| 260 | + value.ordered_offsets_up_to = find_unordered_guint16 ( | ||
| 261 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 262 | + break; | ||
| 263 | + } | ||
| 264 | + case 4: | ||
| 265 | + { | ||
| 266 | + value.ordered_offsets_up_to = find_unordered_guint32 ( | ||
| 267 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 268 | + break; | ||
| 269 | + } | ||
| 270 | + case 8: | ||
| 271 | + { | ||
| 272 | + value.ordered_offsets_up_to = find_unordered_guint64 ( | ||
| 273 | + offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 274 | + break; | ||
| 275 | + } | ||
| 276 | + default: | ||
| 277 | + /* gvs_get_offset_size() only returns maximum 8 */ | ||
| 278 | + g_assert_not_reached (); | ||
| 279 | + } | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + if (index_ > value.ordered_offsets_up_to) | ||
| 283 | + { | ||
| 284 | + /* Offsets are invalid somewhere, so return an empty child. */ | ||
| 285 | + return child; | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | if (index_ > 0) | ||
| 289 | { | ||
| 290 | guint alignment; | ||
| 291 | @@ -840,6 +914,9 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 292 | |||
| 293 | g_assert (offset == offsets.data_size); | ||
| 294 | |||
| 295 | + /* All offsets have now been checked. */ | ||
| 296 | + value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 297 | + | ||
| 298 | return TRUE; | ||
| 299 | } | ||
| 300 | |||
| 301 | @@ -1072,7 +1149,7 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 302 | for (i = 0; i < length; i++) | ||
| 303 | { | ||
| 304 | const GVariantMemberInfo *member_info; | ||
| 305 | - GVariantSerialised child; | ||
| 306 | + GVariantSerialised child = { 0, }; | ||
| 307 | gsize fixed_size; | ||
| 308 | guint alignment; | ||
| 309 | gsize end; | ||
| 310 | @@ -1132,6 +1209,9 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 311 | offset = end; | ||
| 312 | } | ||
| 313 | |||
| 314 | + /* All element bounds have been checked above. */ | ||
| 315 | + value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 316 | + | ||
| 317 | { | ||
| 318 | gsize fixed_size; | ||
| 319 | guint alignment; | ||
| 320 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
| 321 | index 81343e9..99d18ef 100644 | ||
| 322 | --- a/glib/gvariant-serialiser.h | ||
| 323 | +++ b/glib/gvariant-serialiser.h | ||
| 324 | @@ -29,6 +29,14 @@ typedef struct | ||
| 325 | guchar *data; | ||
| 326 | gsize size; | ||
| 327 | gsize depth; /* same semantics as GVariant.depth */ | ||
| 328 | + /* If ordered_offsets_up_to == n this means that all the frame offsets up to and | ||
| 329 | + * including the frame offset determining the end of element n are in order. | ||
| 330 | + * This guarantees that the bytes of element n don't overlap with any previous | ||
| 331 | + * element. | ||
| 332 | + * | ||
| 333 | + * This is both read and set by g_variant_serialised_get_child for arrays of | ||
| 334 | + * non-fixed-width types */ | ||
| 335 | + gsize ordered_offsets_up_to; | ||
| 336 | } GVariantSerialised; | ||
| 337 | |||
| 338 | /* deserialisation */ | ||
| 339 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 340 | index 0e5ec8e..967e9a1 100644 | ||
| 341 | --- a/glib/tests/gvariant.c | ||
| 342 | +++ b/glib/tests/gvariant.c | ||
| 343 | @@ -1,5 +1,6 @@ | ||
| 344 | /* | ||
| 345 | * Copyright © 2010 Codethink Limited | ||
| 346 | + * Copyright © 2020 William Manley | ||
| 347 | * | ||
| 348 | * This library is free software; you can redistribute it and/or | ||
| 349 | * modify it under the terms of the GNU Lesser General Public | ||
| 350 | @@ -1283,6 +1284,7 @@ random_instance_filler (GVariantSerialised *serialised, | ||
| 351 | serialised->size = instance->size; | ||
| 352 | |||
| 353 | serialised->depth = 0; | ||
| 354 | + serialised->ordered_offsets_up_to = 0; | ||
| 355 | |||
| 356 | g_assert_true (serialised->type_info == instance->type_info); | ||
| 357 | g_assert_cmpuint (serialised->size, ==, instance->size); | ||
| 358 | @@ -5039,6 +5041,47 @@ test_normal_checking_array_offsets (void) | ||
| 359 | g_variant_unref (variant); | ||
| 360 | } | ||
| 361 | |||
| 362 | +/* This is a regression test that we can't have non-normal values that take up | ||
| 363 | + * significantly more space than the normal equivalent, by specifying the | ||
| 364 | + * offset table entries so that array elements overlap. | ||
| 365 | + * | ||
| 366 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_832242 */ | ||
| 367 | +static void | ||
| 368 | +test_normal_checking_array_offsets2 (void) | ||
| 369 | +{ | ||
| 370 | + const guint8 data[] = { | ||
| 371 | + 'h', 'i', '\0', | ||
| 372 | + 0x03, 0x00, 0x03, | ||
| 373 | + 0x06, 0x00, 0x06, | ||
| 374 | + 0x09, 0x00, 0x09, | ||
| 375 | + 0x0c, 0x00, 0x0c, | ||
| 376 | + 0x0f, 0x00, 0x0f, | ||
| 377 | + 0x12, 0x00, 0x12, | ||
| 378 | + 0x15, 0x00, 0x15, | ||
| 379 | + }; | ||
| 380 | + gsize size = sizeof (data); | ||
| 381 | + const GVariantType *aaaaaaas = G_VARIANT_TYPE ("aaaaaaas"); | ||
| 382 | + GVariant *variant = NULL; | ||
| 383 | + GVariant *normal_variant = NULL; | ||
| 384 | + GVariant *expected = NULL; | ||
| 385 | + | ||
| 386 | + variant = g_variant_new_from_data (aaaaaaas, data, size, FALSE, NULL, NULL); | ||
| 387 | + g_assert_nonnull (variant); | ||
| 388 | + | ||
| 389 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 390 | + g_assert_nonnull (normal_variant); | ||
| 391 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 2); | ||
| 392 | + | ||
| 393 | + expected = g_variant_new_parsed ( | ||
| 394 | + "[[[[[[['hi', '', ''], [], []], [], []], [], []], [], []], [], []], [], []]"); | ||
| 395 | + g_assert_cmpvariant (expected, variant); | ||
| 396 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 397 | + | ||
| 398 | + g_variant_unref (expected); | ||
| 399 | + g_variant_unref (normal_variant); | ||
| 400 | + g_variant_unref (variant); | ||
| 401 | +} | ||
| 402 | + | ||
| 403 | /* Test that a tuple with invalidly large values in its offset table is | ||
| 404 | * normalised successfully without looping infinitely. */ | ||
| 405 | static void | ||
| 406 | @@ -5206,6 +5249,8 @@ main (int argc, char **argv) | ||
| 407 | test_normal_checking_tuples); | ||
| 408 | g_test_add_func ("/gvariant/normal-checking/array-offsets", | ||
| 409 | test_normal_checking_array_offsets); | ||
| 410 | + g_test_add_func ("/gvariant/normal-checking/array-offsets2", | ||
| 411 | + test_normal_checking_array_offsets2); | ||
| 412 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets", | ||
| 413 | test_normal_checking_tuple_offsets); | ||
| 414 | g_test_add_func ("/gvariant/normal-checking/empty-object-path", | ||
| 415 | -- | ||
| 416 | 2.24.4 | ||
| 417 | |||
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..c057729aae --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0004.patch | |||
| @@ -0,0 +1,113 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/345cae9c1aa7bf6752039225ef4c8d8d69fa8d76] | ||
| 15 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 16 | --- | ||
| 17 | glib/gvariant-serialiser.c | 73 ++++++++++++++++++++++++-------------- | ||
| 18 | 1 file changed, 46 insertions(+), 27 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 21 | index fe0b1a4..6f9b366 100644 | ||
| 22 | --- a/glib/gvariant-serialiser.c | ||
| 23 | +++ b/glib/gvariant-serialiser.c | ||
| 24 | @@ -942,6 +942,51 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 25 | * for the tuple. See the notes in gvarianttypeinfo.h. | ||
| 26 | */ | ||
| 27 | |||
| 28 | +static void | ||
| 29 | +gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 30 | + gsize index_, | ||
| 31 | + gsize offset_size, | ||
| 32 | + gsize *out_member_start, | ||
| 33 | + gsize *out_member_end) | ||
| 34 | +{ | ||
| 35 | + const GVariantMemberInfo *member_info; | ||
| 36 | + gsize member_start, member_end; | ||
| 37 | + | ||
| 38 | + member_info = g_variant_type_info_member_info (value.type_info, index_); | ||
| 39 | + | ||
| 40 | + if (member_info->i + 1) | ||
| 41 | + member_start = gvs_read_unaligned_le (value.data + value.size - | ||
| 42 | + offset_size * (member_info->i + 1), | ||
| 43 | + offset_size); | ||
| 44 | + else | ||
| 45 | + member_start = 0; | ||
| 46 | + | ||
| 47 | + member_start += member_info->a; | ||
| 48 | + member_start &= member_info->b; | ||
| 49 | + member_start |= member_info->c; | ||
| 50 | + | ||
| 51 | + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) | ||
| 52 | + member_end = value.size - offset_size * (member_info->i + 1); | ||
| 53 | + | ||
| 54 | + else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 55 | + { | ||
| 56 | + gsize fixed_size; | ||
| 57 | + | ||
| 58 | + g_variant_type_info_query (member_info->type_info, NULL, &fixed_size); | ||
| 59 | + member_end = member_start + fixed_size; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + else /* G_VARIANT_MEMBER_ENDING_OFFSET */ | ||
| 63 | + member_end = gvs_read_unaligned_le (value.data + value.size - | ||
| 64 | + offset_size * (member_info->i + 2), | ||
| 65 | + offset_size); | ||
| 66 | + | ||
| 67 | + if (out_member_start != NULL) | ||
| 68 | + *out_member_start = member_start; | ||
| 69 | + if (out_member_end != NULL) | ||
| 70 | + *out_member_end = member_end; | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | static gsize | ||
| 74 | gvs_tuple_n_children (GVariantSerialised value) | ||
| 75 | { | ||
| 76 | @@ -997,33 +1042,7 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | - if (member_info->i + 1) | ||
| 81 | - start = gvs_read_unaligned_le (value.data + value.size - | ||
| 82 | - offset_size * (member_info->i + 1), | ||
| 83 | - offset_size); | ||
| 84 | - else | ||
| 85 | - start = 0; | ||
| 86 | - | ||
| 87 | - start += member_info->a; | ||
| 88 | - start &= member_info->b; | ||
| 89 | - start |= member_info->c; | ||
| 90 | - | ||
| 91 | - if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) | ||
| 92 | - end = value.size - offset_size * (member_info->i + 1); | ||
| 93 | - | ||
| 94 | - else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 95 | - { | ||
| 96 | - gsize fixed_size; | ||
| 97 | - | ||
| 98 | - g_variant_type_info_query (child.type_info, NULL, &fixed_size); | ||
| 99 | - end = start + fixed_size; | ||
| 100 | - child.size = fixed_size; | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - else /* G_VARIANT_MEMBER_ENDING_OFFSET */ | ||
| 104 | - end = gvs_read_unaligned_le (value.data + value.size - | ||
| 105 | - offset_size * (member_info->i + 2), | ||
| 106 | - offset_size); | ||
| 107 | + gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); | ||
| 108 | |||
| 109 | /* The child should not extend into the offset table. */ | ||
| 110 | if (index_ != g_variant_type_info_n_members (value.type_info) - 1) | ||
| 111 | -- | ||
| 112 | 2.24.4 | ||
| 113 | |||
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..7e516b07ab --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0005.patch | |||
| @@ -0,0 +1,80 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/73d0aa81c2575a5c9ae77dcb94da919579014fc0] | ||
| 15 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 16 | --- | ||
| 17 | glib/gvariant-serialiser.c | 31 +++++++++---------------------- | ||
| 18 | 1 file changed, 9 insertions(+), 22 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 21 | index 6f9b366..fb75923 100644 | ||
| 22 | --- a/glib/gvariant-serialiser.c | ||
| 23 | +++ b/glib/gvariant-serialiser.c | ||
| 24 | @@ -1007,14 +1007,18 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 25 | child.depth = value.depth + 1; | ||
| 26 | offset_size = gvs_get_offset_size (value.size); | ||
| 27 | |||
| 28 | + /* Ensure the size is set for fixed-sized children, or | ||
| 29 | + * g_variant_serialised_check() will fail, even if we return | ||
| 30 | + * (child.data == NULL) to indicate an error. */ | ||
| 31 | + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) | ||
| 32 | + g_variant_type_info_query (child.type_info, NULL, &child.size); | ||
| 33 | + | ||
| 34 | /* tuples are the only (potentially) fixed-sized containers, so the | ||
| 35 | * only ones that have to deal with the possibility of having %NULL | ||
| 36 | * data with a non-zero %size if errors occurred elsewhere. | ||
| 37 | */ | ||
| 38 | if G_UNLIKELY (value.data == NULL && value.size != 0) | ||
| 39 | { | ||
| 40 | - g_variant_type_info_query (child.type_info, NULL, &child.size); | ||
| 41 | - | ||
| 42 | /* this can only happen in fixed-sized tuples, | ||
| 43 | * so the child must also be fixed sized. | ||
| 44 | */ | ||
| 45 | @@ -1032,29 +1036,12 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 46 | else | ||
| 47 | { | ||
| 48 | if (offset_size * (member_info->i + 1) > value.size) | ||
| 49 | - { | ||
| 50 | - /* if the child is fixed size, return its size. | ||
| 51 | - * if child is not fixed-sized, return size = 0. | ||
| 52 | - */ | ||
| 53 | - g_variant_type_info_query (child.type_info, NULL, &child.size); | ||
| 54 | - | ||
| 55 | - return child; | ||
| 56 | - } | ||
| 57 | + return child; | ||
| 58 | } | ||
| 59 | |||
| 60 | - gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); | ||
| 61 | - | ||
| 62 | /* The child should not extend into the offset table. */ | ||
| 63 | - if (index_ != g_variant_type_info_n_members (value.type_info) - 1) | ||
| 64 | - { | ||
| 65 | - GVariantSerialised last_child; | ||
| 66 | - last_child = gvs_tuple_get_child (value, | ||
| 67 | - g_variant_type_info_n_members (value.type_info) - 1); | ||
| 68 | - last_end = last_child.data + last_child.size - value.data; | ||
| 69 | - g_variant_type_info_unref (last_child.type_info); | ||
| 70 | - } | ||
| 71 | - else | ||
| 72 | - last_end = end; | ||
| 73 | + gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); | ||
| 74 | + gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end); | ||
| 75 | |||
| 76 | if (start < end && end <= value.size && end <= last_end) | ||
| 77 | { | ||
| 78 | -- | ||
| 79 | 2.24.4 | ||
| 80 | |||
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..8558a7911f --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0006.patch | |||
| @@ -0,0 +1,396 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/7cf6f5b69146d20948d42f0c476688fe17fef787] | ||
| 32 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 33 | --- | ||
| 34 | glib/gvariant-core.c | 6 +- | ||
| 35 | glib/gvariant-serialiser.c | 40 ++++++++ | ||
| 36 | glib/gvariant-serialiser.h | 7 +- | ||
| 37 | glib/gvariant.c | 1 + | ||
| 38 | glib/tests/gvariant.c | 181 +++++++++++++++++++++++++++++++++++++ | ||
| 39 | 5 files changed, 232 insertions(+), 3 deletions(-) | ||
| 40 | |||
| 41 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 42 | index 9b51e15..b951cd9 100644 | ||
| 43 | --- a/glib/gvariant-core.c | ||
| 44 | +++ b/glib/gvariant-core.c | ||
| 45 | @@ -1,6 +1,7 @@ | ||
| 46 | /* | ||
| 47 | * Copyright © 2007, 2008 Ryan Lortie | ||
| 48 | * Copyright © 2010 Codethink Limited | ||
| 49 | + * Copyright © 2022 Endless OS Foundation, LLC | ||
| 50 | * | ||
| 51 | * This library is free software; you can redistribute it and/or | ||
| 52 | * modify it under the terms of the GNU Lesser General Public | ||
| 53 | @@ -179,7 +180,7 @@ struct _GVariant | ||
| 54 | * offsets themselves. | ||
| 55 | * | ||
| 56 | * This field is only relevant for arrays of non | ||
| 57 | - * fixed width types. | ||
| 58 | + * fixed width types and for tuples. | ||
| 59 | * | ||
| 60 | * .tree: Only valid when the instance is in tree form. | ||
| 61 | * | ||
| 62 | @@ -1117,6 +1118,9 @@ g_variant_get_child_value (GVariant *value, | ||
| 63 | */ | ||
| 64 | s_child = g_variant_serialised_get_child (serialised, index_); | ||
| 65 | |||
| 66 | + /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */ | ||
| 67 | + value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to); | ||
| 68 | + | ||
| 69 | /* Check whether this would cause nesting too deep. If so, return a fake | ||
| 70 | * child. The only situation we expect this to happen in is with a variant, | ||
| 71 | * as all other deeply-nested types have a static type, and hence should | ||
| 72 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 73 | index fb75923..cd4a3e6 100644 | ||
| 74 | --- a/glib/gvariant-serialiser.c | ||
| 75 | +++ b/glib/gvariant-serialiser.c | ||
| 76 | @@ -942,6 +942,10 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 77 | * for the tuple. See the notes in gvarianttypeinfo.h. | ||
| 78 | */ | ||
| 79 | |||
| 80 | +/* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that | ||
| 81 | + * condition may not hold true for invalid serialised variants. The caller is | ||
| 82 | + * responsible for checking the returned values and handling invalid ones | ||
| 83 | + * appropriately. */ | ||
| 84 | static void | ||
| 85 | gvs_tuple_get_member_bounds (GVariantSerialised value, | ||
| 86 | gsize index_, | ||
| 87 | @@ -1028,6 +1032,42 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 88 | return child; | ||
| 89 | } | ||
| 90 | |||
| 91 | + /* If the requested @index_ is beyond the set of indices whose framing offsets | ||
| 92 | + * have been checked, check the remaining offsets to see whether they’re | ||
| 93 | + * normal (in order, no overlapping tuple elements). | ||
| 94 | + * | ||
| 95 | + * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check | ||
| 96 | + * all the tuple *elements* here, not just all the framing offsets, since | ||
| 97 | + * tuples contain a mix of elements which use framing offsets and ones which | ||
| 98 | + * don’t. None of them are allowed to overlap. */ | ||
| 99 | + if (index_ > value.ordered_offsets_up_to) | ||
| 100 | + { | ||
| 101 | + gsize i, prev_i_end = 0; | ||
| 102 | + | ||
| 103 | + if (value.ordered_offsets_up_to > 0) | ||
| 104 | + gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end); | ||
| 105 | + | ||
| 106 | + for (i = value.ordered_offsets_up_to; i <= index_; i++) | ||
| 107 | + { | ||
| 108 | + gsize i_start, i_end; | ||
| 109 | + | ||
| 110 | + gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end); | ||
| 111 | + | ||
| 112 | + if (i_start > i_end || i_start < prev_i_end || i_end > value.size) | ||
| 113 | + break; | ||
| 114 | + | ||
| 115 | + prev_i_end = i_end; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + value.ordered_offsets_up_to = i - 1; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + if (index_ > value.ordered_offsets_up_to) | ||
| 122 | + { | ||
| 123 | + /* Offsets are invalid somewhere, so return an empty child. */ | ||
| 124 | + return child; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET) | ||
| 128 | { | ||
| 129 | if (offset_size * (member_info->i + 2) > value.size) | ||
| 130 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
| 131 | index 99d18ef..144aec8 100644 | ||
| 132 | --- a/glib/gvariant-serialiser.h | ||
| 133 | +++ b/glib/gvariant-serialiser.h | ||
| 134 | @@ -34,8 +34,11 @@ typedef struct | ||
| 135 | * This guarantees that the bytes of element n don't overlap with any previous | ||
| 136 | * element. | ||
| 137 | * | ||
| 138 | - * This is both read and set by g_variant_serialised_get_child for arrays of | ||
| 139 | - * non-fixed-width types */ | ||
| 140 | + * This is both read and set by g_variant_serialised_get_child() for arrays of | ||
| 141 | + * non-fixed-width types, and for tuples. | ||
| 142 | + * | ||
| 143 | + * Even when dealing with tuples, @ordered_offsets_up_to is an element index, | ||
| 144 | + * rather than an index into the frame offsets. */ | ||
| 145 | gsize ordered_offsets_up_to; | ||
| 146 | } GVariantSerialised; | ||
| 147 | |||
| 148 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 149 | index d6f68a9..cdb428e 100644 | ||
| 150 | --- a/glib/gvariant.c | ||
| 151 | +++ b/glib/gvariant.c | ||
| 152 | @@ -5945,6 +5945,7 @@ g_variant_byteswap (GVariant *value) | ||
| 153 | serialised.type_info = g_variant_get_type_info (trusted); | ||
| 154 | serialised.size = g_variant_get_size (trusted); | ||
| 155 | serialised.data = g_malloc (serialised.size); | ||
| 156 | + serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ | ||
| 157 | g_variant_store (trusted, serialised.data); | ||
| 158 | g_variant_unref (trusted); | ||
| 159 | |||
| 160 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 161 | index 967e9a1..a84b02e 100644 | ||
| 162 | --- a/glib/tests/gvariant.c | ||
| 163 | +++ b/glib/tests/gvariant.c | ||
| 164 | @@ -1,6 +1,7 @@ | ||
| 165 | /* | ||
| 166 | * Copyright © 2010 Codethink Limited | ||
| 167 | * Copyright © 2020 William Manley | ||
| 168 | + * Copyright © 2022 Endless OS Foundation, LLC | ||
| 169 | * | ||
| 170 | * This library is free software; you can redistribute it and/or | ||
| 171 | * modify it under the terms of the GNU Lesser General Public | ||
| 172 | @@ -1451,6 +1452,7 @@ test_maybe (void) | ||
| 173 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 174 | serialised.size = needed_size; | ||
| 175 | serialised.depth = 0; | ||
| 176 | + serialised.ordered_offsets_up_to = 0; | ||
| 177 | |||
| 178 | g_variant_serialiser_serialise (serialised, | ||
| 179 | random_instance_filler, | ||
| 180 | @@ -1574,6 +1576,7 @@ test_array (void) | ||
| 181 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 182 | serialised.size = needed_size; | ||
| 183 | serialised.depth = 0; | ||
| 184 | + serialised.ordered_offsets_up_to = 0; | ||
| 185 | |||
| 186 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 187 | (gpointer *) instances, n_children); | ||
| 188 | @@ -1738,6 +1741,7 @@ test_tuple (void) | ||
| 189 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 190 | serialised.size = needed_size; | ||
| 191 | serialised.depth = 0; | ||
| 192 | + serialised.ordered_offsets_up_to = 0; | ||
| 193 | |||
| 194 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 195 | (gpointer *) instances, n_children); | ||
| 196 | @@ -1834,6 +1838,7 @@ test_variant (void) | ||
| 197 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 198 | serialised.size = needed_size; | ||
| 199 | serialised.depth = 0; | ||
| 200 | + serialised.ordered_offsets_up_to = 0; | ||
| 201 | |||
| 202 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 203 | (gpointer *) &instance, 1); | ||
| 204 | @@ -5106,6 +5111,176 @@ test_normal_checking_tuple_offsets (void) | ||
| 205 | g_variant_unref (variant); | ||
| 206 | } | ||
| 207 | |||
| 208 | +/* This is a regression test that we can't have non-normal values that take up | ||
| 209 | + * significantly more space than the normal equivalent, by specifying the | ||
| 210 | + * offset table entries so that tuple elements overlap. | ||
| 211 | + * | ||
| 212 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838503 and | ||
| 213 | + * https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838513 */ | ||
| 214 | +static void | ||
| 215 | +test_normal_checking_tuple_offsets2 (void) | ||
| 216 | +{ | ||
| 217 | + const GVariantType *data_type = G_VARIANT_TYPE ("(yyaiyyaiyy)"); | ||
| 218 | + const guint8 data[] = { | ||
| 219 | + 0x12, 0x34, 0x56, 0x78, 0x01, | ||
| 220 | + /* | ||
| 221 | + ^───────────────────┘ | ||
| 222 | + | ||
| 223 | + ^^^^^^^^^^ 1st yy | ||
| 224 | + ^^^^^^^^^^ 2nd yy | ||
| 225 | + ^^^^^^^^^^ 3rd yy | ||
| 226 | + ^^^^ Framing offsets | ||
| 227 | + */ | ||
| 228 | + | ||
| 229 | + /* If this variant was encoded normally, it would be something like this: | ||
| 230 | + * 0x12, 0x34, pad, pad, [array bytes], 0x56, 0x78, pad, pad, [array bytes], 0x9A, 0xBC, 0xXX | ||
| 231 | + * ^─────────────────────────────────────────────────────┘ | ||
| 232 | + * | ||
| 233 | + * ^^^^^^^^^^ 1st yy | ||
| 234 | + * ^^^^^^^^^^ 2nd yy | ||
| 235 | + * ^^^^^^^^^^ 3rd yy | ||
| 236 | + * ^^^^ Framing offsets | ||
| 237 | + */ | ||
| 238 | + }; | ||
| 239 | + gsize size = sizeof (data); | ||
| 240 | + GVariant *variant = NULL; | ||
| 241 | + GVariant *normal_variant = NULL; | ||
| 242 | + GVariant *expected = NULL; | ||
| 243 | + | ||
| 244 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 245 | + g_assert_nonnull (variant); | ||
| 246 | + | ||
| 247 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 248 | + g_assert_nonnull (normal_variant); | ||
| 249 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); | ||
| 250 | + | ||
| 251 | + expected = g_variant_new_parsed ( | ||
| 252 | + "@(yyaiyyaiyy) (0x12, 0x34, [], 0x00, 0x00, [], 0x00, 0x00)"); | ||
| 253 | + g_assert_cmpvariant (expected, variant); | ||
| 254 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 255 | + | ||
| 256 | + g_variant_unref (expected); | ||
| 257 | + g_variant_unref (normal_variant); | ||
| 258 | + g_variant_unref (variant); | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +/* This is a regression test that overlapping entries in the offset table are | ||
| 262 | + * decoded consistently, even though they’re non-normal. | ||
| 263 | + * | ||
| 264 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */ | ||
| 265 | +static void | ||
| 266 | +test_normal_checking_tuple_offsets3 (void) | ||
| 267 | +{ | ||
| 268 | + /* The expected decoding of this non-normal byte stream is complex. See | ||
| 269 | + * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant | ||
| 270 | + * specification. | ||
| 271 | + * | ||
| 272 | + * The rule “Child Values Overlapping Framing Offsets” from the specification | ||
| 273 | + * says that the first `ay` must be decoded as `[0x01]` even though it | ||
| 274 | + * overlaps the first byte of the offset table. However, since commit | ||
| 275 | + * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow | ||
| 276 | + * this as it’s exploitable. So the first `ay` must be given a default value. | ||
| 277 | + * | ||
| 278 | + * The second and third `ay`s must be given default values because of rule | ||
| 279 | + * “End Boundary Precedes Start Boundary”. | ||
| 280 | + * | ||
| 281 | + * The `i` must be given a default value because of rule “Start or End | ||
| 282 | + * Boundary of a Child Falls Outside the Container”. | ||
| 283 | + */ | ||
| 284 | + const GVariantType *data_type = G_VARIANT_TYPE ("(ayayiay)"); | ||
| 285 | + const guint8 data[] = { | ||
| 286 | + 0x01, 0x00, 0x02, | ||
| 287 | + /* | ||
| 288 | + ^──┘ | ||
| 289 | + | ||
| 290 | + ^^^^^^^^^^ 1st ay, bytes 0-2 (but given a default value anyway, see above) | ||
| 291 | + 2nd ay, bytes 2-0 | ||
| 292 | + i, bytes 0-4 | ||
| 293 | + 3rd ay, bytes 4-1 | ||
| 294 | + ^^^^^^^^^^ Framing offsets | ||
| 295 | + */ | ||
| 296 | + }; | ||
| 297 | + gsize size = sizeof (data); | ||
| 298 | + GVariant *variant = NULL; | ||
| 299 | + GVariant *normal_variant = NULL; | ||
| 300 | + GVariant *expected = NULL; | ||
| 301 | + | ||
| 302 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 303 | + g_assert_nonnull (variant); | ||
| 304 | + | ||
| 305 | + g_assert_false (g_variant_is_normal_form (variant)); | ||
| 306 | + | ||
| 307 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 308 | + g_assert_nonnull (normal_variant); | ||
| 309 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); | ||
| 310 | + | ||
| 311 | + expected = g_variant_new_parsed ("@(ayayiay) ([], [], 0, [])"); | ||
| 312 | + g_assert_cmpvariant (expected, variant); | ||
| 313 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 314 | + | ||
| 315 | + g_variant_unref (expected); | ||
| 316 | + g_variant_unref (normal_variant); | ||
| 317 | + g_variant_unref (variant); | ||
| 318 | +} | ||
| 319 | + | ||
| 320 | +/* This is a regression test that overlapping entries in the offset table are | ||
| 321 | + * decoded consistently, even though they’re non-normal. | ||
| 322 | + * | ||
| 323 | + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */ | ||
| 324 | +static void | ||
| 325 | +test_normal_checking_tuple_offsets4 (void) | ||
| 326 | +{ | ||
| 327 | + /* The expected decoding of this non-normal byte stream is complex. See | ||
| 328 | + * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant | ||
| 329 | + * specification. | ||
| 330 | + * | ||
| 331 | + * The rule “Child Values Overlapping Framing Offsets” from the specification | ||
| 332 | + * says that the first `ay` must be decoded as `[0x01]` even though it | ||
| 333 | + * overlaps the first byte of the offset table. However, since commit | ||
| 334 | + * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow | ||
| 335 | + * this as it’s exploitable. So the first `ay` must be given a default value. | ||
| 336 | + * | ||
| 337 | + * The second `ay` must be given a default value because of rule “End Boundary | ||
| 338 | + * Precedes Start Boundary”. | ||
| 339 | + * | ||
| 340 | + * The third `ay` must be given a default value because its framing offsets | ||
| 341 | + * overlap that of the first `ay`. | ||
| 342 | + */ | ||
| 343 | + const GVariantType *data_type = G_VARIANT_TYPE ("(ayayay)"); | ||
| 344 | + const guint8 data[] = { | ||
| 345 | + 0x01, 0x00, 0x02, | ||
| 346 | + /* | ||
| 347 | + ^──┘ | ||
| 348 | + | ||
| 349 | + ^^^^^^^^^^ 1st ay, bytes 0-2 (but given a default value anyway, see above) | ||
| 350 | + 2nd ay, bytes 2-0 | ||
| 351 | + 3rd ay, bytes 0-1 | ||
| 352 | + ^^^^^^^^^^ Framing offsets | ||
| 353 | + */ | ||
| 354 | + }; | ||
| 355 | + gsize size = sizeof (data); | ||
| 356 | + GVariant *variant = NULL; | ||
| 357 | + GVariant *normal_variant = NULL; | ||
| 358 | + GVariant *expected = NULL; | ||
| 359 | + | ||
| 360 | + variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); | ||
| 361 | + g_assert_nonnull (variant); | ||
| 362 | + | ||
| 363 | + g_assert_false (g_variant_is_normal_form (variant)); | ||
| 364 | + | ||
| 365 | + normal_variant = g_variant_get_normal_form (variant); | ||
| 366 | + g_assert_nonnull (normal_variant); | ||
| 367 | + g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); | ||
| 368 | + | ||
| 369 | + expected = g_variant_new_parsed ("@(ayayay) ([], [], [])"); | ||
| 370 | + g_assert_cmpvariant (expected, variant); | ||
| 371 | + g_assert_cmpvariant (expected, normal_variant); | ||
| 372 | + | ||
| 373 | + g_variant_unref (expected); | ||
| 374 | + g_variant_unref (normal_variant); | ||
| 375 | + g_variant_unref (variant); | ||
| 376 | +} | ||
| 377 | + | ||
| 378 | /* Test that an empty object path is normalised successfully to the base object | ||
| 379 | * path, ‘/’. */ | ||
| 380 | static void | ||
| 381 | @@ -5253,6 +5428,12 @@ main (int argc, char **argv) | ||
| 382 | test_normal_checking_array_offsets2); | ||
| 383 | g_test_add_func ("/gvariant/normal-checking/tuple-offsets", | ||
| 384 | test_normal_checking_tuple_offsets); | ||
| 385 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets2", | ||
| 386 | + test_normal_checking_tuple_offsets2); | ||
| 387 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets3", | ||
| 388 | + test_normal_checking_tuple_offsets3); | ||
| 389 | + g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", | ||
| 390 | + test_normal_checking_tuple_offsets4); | ||
| 391 | g_test_add_func ("/gvariant/normal-checking/empty-object-path", | ||
| 392 | test_normal_checking_empty_object_path); | ||
| 393 | |||
| 394 | -- | ||
| 395 | 2.24.4 | ||
| 396 | |||
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..83d0205160 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0007.patch | |||
| @@ -0,0 +1,49 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/e6490c84e84ba9f182fbd83b51ff4f9f5a0a1793] | ||
| 20 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 21 | --- | ||
| 22 | glib/gvariant.c | 7 +++---- | ||
| 23 | 1 file changed, 3 insertions(+), 4 deletions(-) | ||
| 24 | |||
| 25 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 26 | index cdb428e..fdd36be 100644 | ||
| 27 | --- a/glib/gvariant.c | ||
| 28 | +++ b/glib/gvariant.c | ||
| 29 | @@ -5799,14 +5799,13 @@ g_variant_deep_copy (GVariant *value) | ||
| 30 | case G_VARIANT_CLASS_VARIANT: | ||
| 31 | { | ||
| 32 | GVariantBuilder builder; | ||
| 33 | - GVariantIter iter; | ||
| 34 | - GVariant *child; | ||
| 35 | + gsize i, n_children; | ||
| 36 | |||
| 37 | g_variant_builder_init (&builder, g_variant_get_type (value)); | ||
| 38 | - g_variant_iter_init (&iter, value); | ||
| 39 | |||
| 40 | - while ((child = g_variant_iter_next_value (&iter))) | ||
| 41 | + for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++) | ||
| 42 | { | ||
| 43 | + GVariant *child = g_variant_get_child_value (value, i); | ||
| 44 | g_variant_builder_add_value (&builder, g_variant_deep_copy (child)); | ||
| 45 | g_variant_unref (child); | ||
| 46 | } | ||
| 47 | -- | ||
| 48 | 2.24.4 | ||
| 49 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch new file mode 100644 index 0000000000..f098548618 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0008.patch | |||
| @@ -0,0 +1,394 @@ | |||
| 1 | From d1a293c4e29880b8d17bb826c9a426a440ca4a91 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@endlessos.org> | ||
| 3 | Date: Thu, 17 Aug 2023 01:30:38 +0000 | ||
| 4 | Subject: [PATCH] gvariant: Track checked and ordered offsets independently | ||
| 5 | |||
| 6 | The past few commits introduced the concept of known-good offsets in the | ||
| 7 | offset table (which is used for variable-width arrays and tuples). | ||
| 8 | Good offsets are ones which are non-overlapping with all the previous | ||
| 9 | offsets in the table. | ||
| 10 | |||
| 11 | If a bad offset is encountered when indexing into the array or tuple, | ||
| 12 | the cached known-good offset index will not be increased. In this way, | ||
| 13 | all child variants at and beyond the first bad offset can be returned as | ||
| 14 | default values rather than dereferencing potentially invalid data. | ||
| 15 | |||
| 16 | In this case, there was no information about the fact that the indexes | ||
| 17 | between the highest known-good index and the requested one had been | ||
| 18 | checked already. That could lead to a pathological case where an offset | ||
| 19 | table with an invalid first offset is repeatedly checked in full when | ||
| 20 | trying to access higher-indexed children. | ||
| 21 | |||
| 22 | Avoid that by storing the index of the highest checked offset in the | ||
| 23 | table, as well as the index of the highest good/ordered offset. | ||
| 24 | |||
| 25 | Signed-off-by: Philip Withnall <pwithnall@endlessos.org> | ||
| 26 | |||
| 27 | Helps: #2121 | ||
| 28 | |||
| 29 | CVE: CVE-2023-32665 | ||
| 30 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/d1a293c4e29880b8d17bb826c9a426a440ca4a91] | ||
| 31 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 32 | --- | ||
| 33 | glib/gvariant-core.c | 28 ++++++++++++++++++++++++ | ||
| 34 | glib/gvariant-serialiser.c | 44 +++++++++++++++++++++++++++----------- | ||
| 35 | glib/gvariant-serialiser.h | 9 ++++++++ | ||
| 36 | glib/gvariant.c | 1 + | ||
| 37 | glib/tests/gvariant.c | 5 +++++ | ||
| 38 | 5 files changed, 75 insertions(+), 12 deletions(-) | ||
| 39 | |||
| 40 | diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c | ||
| 41 | index b951cd9..1b9d5cc 100644 | ||
| 42 | --- a/glib/gvariant-core.c | ||
| 43 | +++ b/glib/gvariant-core.c | ||
| 44 | @@ -67,6 +67,7 @@ struct _GVariant | ||
| 45 | GBytes *bytes; | ||
| 46 | gconstpointer data; | ||
| 47 | gsize ordered_offsets_up_to; | ||
| 48 | + gsize checked_offsets_up_to; | ||
| 49 | } serialised; | ||
| 50 | |||
| 51 | struct | ||
| 52 | @@ -182,6 +183,24 @@ struct _GVariant | ||
| 53 | * This field is only relevant for arrays of non | ||
| 54 | * fixed width types and for tuples. | ||
| 55 | * | ||
| 56 | + * .checked_offsets_up_to: Similarly to .ordered_offsets_up_to, this stores | ||
| 57 | + * the index of the highest element, n, whose frame | ||
| 58 | + * offsets (and all the preceding frame offsets) | ||
| 59 | + * have been checked for validity. | ||
| 60 | + * | ||
| 61 | + * It is always the case that | ||
| 62 | + * .checked_offsets_up_to ≥ .ordered_offsets_up_to. | ||
| 63 | + * | ||
| 64 | + * If .checked_offsets_up_to == .ordered_offsets_up_to, | ||
| 65 | + * then a bad offset has not been found so far. | ||
| 66 | + * | ||
| 67 | + * If .checked_offsets_up_to > .ordered_offsets_up_to, | ||
| 68 | + * then a bad offset has been found at | ||
| 69 | + * (.ordered_offsets_up_to + 1). | ||
| 70 | + * | ||
| 71 | + * This field is only relevant for arrays of non | ||
| 72 | + * fixed width types and for tuples. | ||
| 73 | + * | ||
| 74 | * .tree: Only valid when the instance is in tree form. | ||
| 75 | * | ||
| 76 | * Note that accesses from other threads could result in | ||
| 77 | @@ -386,6 +405,7 @@ g_variant_to_serialised (GVariant *value) | ||
| 78 | value->size, | ||
| 79 | value->depth, | ||
| 80 | value->contents.serialised.ordered_offsets_up_to, | ||
| 81 | + value->contents.serialised.checked_offsets_up_to, | ||
| 82 | }; | ||
| 83 | return serialised; | ||
| 84 | } | ||
| 85 | @@ -418,6 +438,7 @@ g_variant_serialise (GVariant *value, | ||
| 86 | serialised.data = data; | ||
| 87 | serialised.depth = value->depth; | ||
| 88 | serialised.ordered_offsets_up_to = 0; | ||
| 89 | + serialised.checked_offsets_up_to = 0; | ||
| 90 | |||
| 91 | children = (gpointer *) value->contents.tree.children; | ||
| 92 | n_children = value->contents.tree.n_children; | ||
| 93 | @@ -464,10 +485,12 @@ g_variant_fill_gvs (GVariantSerialised *serialised, | ||
| 94 | if (value->state & STATE_SERIALISED) | ||
| 95 | { | ||
| 96 | serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to; | ||
| 97 | + serialised->checked_offsets_up_to = value->contents.serialised.checked_offsets_up_to; | ||
| 98 | } | ||
| 99 | else | ||
| 100 | { | ||
| 101 | serialised->ordered_offsets_up_to = 0; | ||
| 102 | + serialised->checked_offsets_up_to = 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | if (serialised->data) | ||
| 106 | @@ -513,6 +536,7 @@ g_variant_ensure_serialised (GVariant *value) | ||
| 107 | value->contents.serialised.data = g_bytes_get_data (bytes, NULL); | ||
| 108 | value->contents.serialised.bytes = bytes; | ||
| 109 | value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE; | ||
| 110 | + value->contents.serialised.checked_offsets_up_to = G_MAXSIZE; | ||
| 111 | value->state |= STATE_SERIALISED; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | @@ -594,6 +618,7 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 115 | serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size); | ||
| 116 | serialised.depth = 0; | ||
| 117 | serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 118 | + serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 119 | |||
| 120 | if (!g_variant_serialised_check (serialised)) | ||
| 121 | { | ||
| 122 | @@ -644,6 +669,7 @@ g_variant_new_from_bytes (const GVariantType *type, | ||
| 123 | } | ||
| 124 | |||
| 125 | value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 126 | + value->contents.serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0; | ||
| 127 | |||
| 128 | g_clear_pointer (&owned_bytes, g_bytes_unref); | ||
| 129 | |||
| 130 | @@ -1120,6 +1146,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 131 | |||
| 132 | /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */ | ||
| 133 | value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to); | ||
| 134 | + value->contents.serialised.checked_offsets_up_to = MAX (value->contents.serialised.checked_offsets_up_to, serialised.checked_offsets_up_to); | ||
| 135 | |||
| 136 | /* Check whether this would cause nesting too deep. If so, return a fake | ||
| 137 | * child. The only situation we expect this to happen in is with a variant, | ||
| 138 | @@ -1147,6 +1174,7 @@ g_variant_get_child_value (GVariant *value, | ||
| 139 | g_bytes_ref (value->contents.serialised.bytes); | ||
| 140 | child->contents.serialised.data = s_child.data; | ||
| 141 | child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; | ||
| 142 | + child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to; | ||
| 143 | |||
| 144 | return child; | ||
| 145 | } | ||
| 146 | diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c | ||
| 147 | index cd4a3e6..0bf7243 100644 | ||
| 148 | --- a/glib/gvariant-serialiser.c | ||
| 149 | +++ b/glib/gvariant-serialiser.c | ||
| 150 | @@ -120,6 +120,8 @@ | ||
| 151 | * | ||
| 152 | * @depth has no restrictions; the depth of a top-level serialised #GVariant is | ||
| 153 | * zero, and it increases for each level of nested child. | ||
| 154 | + * | ||
| 155 | + * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to | ||
| 156 | */ | ||
| 157 | |||
| 158 | /* < private > | ||
| 159 | @@ -147,6 +149,9 @@ g_variant_serialised_check (GVariantSerialised serialised) | ||
| 160 | !(serialised.size == 0 || serialised.data != NULL)) | ||
| 161 | return FALSE; | ||
| 162 | |||
| 163 | + if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to) | ||
| 164 | + return FALSE; | ||
| 165 | + | ||
| 166 | /* Depending on the native alignment requirements of the machine, the | ||
| 167 | * compiler will insert either 3 or 7 padding bytes after the char. | ||
| 168 | * This will result in the sizeof() the struct being 12 or 16. | ||
| 169 | @@ -266,6 +271,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, | ||
| 170 | g_variant_type_info_ref (value.type_info); | ||
| 171 | value.depth++; | ||
| 172 | value.ordered_offsets_up_to = 0; | ||
| 173 | + value.checked_offsets_up_to = 0; | ||
| 174 | |||
| 175 | return value; | ||
| 176 | } | ||
| 177 | @@ -297,7 +303,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, | ||
| 178 | { | ||
| 179 | if (n_children) | ||
| 180 | { | ||
| 181 | - GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 }; | ||
| 182 | + GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 }; | ||
| 183 | |||
| 184 | gvs_filler (&child, children[0]); | ||
| 185 | } | ||
| 186 | @@ -320,6 +326,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) | ||
| 187 | value.type_info = g_variant_type_info_element (value.type_info); | ||
| 188 | value.depth++; | ||
| 189 | value.ordered_offsets_up_to = 0; | ||
| 190 | + value.checked_offsets_up_to = 0; | ||
| 191 | |||
| 192 | return g_variant_serialised_is_normal (value); | ||
| 193 | } | ||
| 194 | @@ -362,6 +369,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, | ||
| 195 | |||
| 196 | value.depth++; | ||
| 197 | value.ordered_offsets_up_to = 0; | ||
| 198 | + value.checked_offsets_up_to = 0; | ||
| 199 | |||
| 200 | return value; | ||
| 201 | } | ||
| 202 | @@ -392,7 +400,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, | ||
| 203 | { | ||
| 204 | if (n_children) | ||
| 205 | { | ||
| 206 | - GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 }; | ||
| 207 | + GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 }; | ||
| 208 | |||
| 209 | /* write the data for the child. */ | ||
| 210 | gvs_filler (&child, children[0]); | ||
| 211 | @@ -413,6 +421,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value) | ||
| 212 | value.size--; | ||
| 213 | value.depth++; | ||
| 214 | value.ordered_offsets_up_to = 0; | ||
| 215 | + value.checked_offsets_up_to = 0; | ||
| 216 | |||
| 217 | return g_variant_serialised_is_normal (value); | ||
| 218 | } | ||
| 219 | @@ -739,39 +748,46 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, | ||
| 220 | |||
| 221 | /* If the requested @index_ is beyond the set of indices whose framing offsets | ||
| 222 | * have been checked, check the remaining offsets to see whether they’re | ||
| 223 | - * normal (in order, no overlapping array elements). */ | ||
| 224 | - if (index_ > value.ordered_offsets_up_to) | ||
| 225 | + * normal (in order, no overlapping array elements). | ||
| 226 | + * | ||
| 227 | + * Don’t bother checking if the highest known-good offset is lower than the | ||
| 228 | + * highest checked offset, as that means there’s an invalid element at that | ||
| 229 | + * index, so there’s no need to check further. */ | ||
| 230 | + if (index_ > value.checked_offsets_up_to && | ||
| 231 | + value.ordered_offsets_up_to == value.checked_offsets_up_to) | ||
| 232 | { | ||
| 233 | switch (offsets.offset_size) | ||
| 234 | { | ||
| 235 | case 1: | ||
| 236 | { | ||
| 237 | value.ordered_offsets_up_to = find_unordered_guint8 ( | ||
| 238 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 239 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | case 2: | ||
| 243 | { | ||
| 244 | value.ordered_offsets_up_to = find_unordered_guint16 ( | ||
| 245 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 246 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | case 4: | ||
| 250 | { | ||
| 251 | value.ordered_offsets_up_to = find_unordered_guint32 ( | ||
| 252 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 253 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 254 | break; | ||
| 255 | } | ||
| 256 | case 8: | ||
| 257 | { | ||
| 258 | value.ordered_offsets_up_to = find_unordered_guint64 ( | ||
| 259 | - offsets.array, value.ordered_offsets_up_to, index_ + 1); | ||
| 260 | + offsets.array, value.checked_offsets_up_to, index_ + 1); | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | default: | ||
| 264 | /* gvs_get_offset_size() only returns maximum 8 */ | ||
| 265 | g_assert_not_reached (); | ||
| 266 | } | ||
| 267 | + | ||
| 268 | + value.checked_offsets_up_to = index_; | ||
| 269 | } | ||
| 270 | |||
| 271 | if (index_ > value.ordered_offsets_up_to) | ||
| 272 | @@ -916,6 +932,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) | ||
| 273 | |||
| 274 | /* All offsets have now been checked. */ | ||
| 275 | value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 276 | + value.checked_offsets_up_to = G_MAXSIZE; | ||
| 277 | |||
| 278 | return TRUE; | ||
| 279 | } | ||
| 280 | @@ -1040,14 +1057,15 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 281 | * all the tuple *elements* here, not just all the framing offsets, since | ||
| 282 | * tuples contain a mix of elements which use framing offsets and ones which | ||
| 283 | * don’t. None of them are allowed to overlap. */ | ||
| 284 | - if (index_ > value.ordered_offsets_up_to) | ||
| 285 | + if (index_ > value.checked_offsets_up_to && | ||
| 286 | + value.ordered_offsets_up_to == value.checked_offsets_up_to) | ||
| 287 | { | ||
| 288 | gsize i, prev_i_end = 0; | ||
| 289 | |||
| 290 | - if (value.ordered_offsets_up_to > 0) | ||
| 291 | - gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end); | ||
| 292 | + if (value.checked_offsets_up_to > 0) | ||
| 293 | + gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end); | ||
| 294 | |||
| 295 | - for (i = value.ordered_offsets_up_to; i <= index_; i++) | ||
| 296 | + for (i = value.checked_offsets_up_to; i <= index_; i++) | ||
| 297 | { | ||
| 298 | gsize i_start, i_end; | ||
| 299 | |||
| 300 | @@ -1060,6 +1078,7 @@ gvs_tuple_get_child (GVariantSerialised value, | ||
| 301 | } | ||
| 302 | |||
| 303 | value.ordered_offsets_up_to = i - 1; | ||
| 304 | + value.checked_offsets_up_to = index_; | ||
| 305 | } | ||
| 306 | |||
| 307 | if (index_ > value.ordered_offsets_up_to) | ||
| 308 | @@ -1257,6 +1276,7 @@ gvs_tuple_is_normal (GVariantSerialised value) | ||
| 309 | |||
| 310 | /* All element bounds have been checked above. */ | ||
| 311 | value.ordered_offsets_up_to = G_MAXSIZE; | ||
| 312 | + value.checked_offsets_up_to = G_MAXSIZE; | ||
| 313 | |||
| 314 | { | ||
| 315 | gsize fixed_size; | ||
| 316 | diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h | ||
| 317 | index 144aec8..e132451 100644 | ||
| 318 | --- a/glib/gvariant-serialiser.h | ||
| 319 | +++ b/glib/gvariant-serialiser.h | ||
| 320 | @@ -40,6 +40,15 @@ typedef struct | ||
| 321 | * Even when dealing with tuples, @ordered_offsets_up_to is an element index, | ||
| 322 | * rather than an index into the frame offsets. */ | ||
| 323 | gsize ordered_offsets_up_to; | ||
| 324 | + | ||
| 325 | + /* Similar to @ordered_offsets_up_to. This gives the index of the child element | ||
| 326 | + * whose frame offset is the highest in the offset table which has been | ||
| 327 | + * checked so far. | ||
| 328 | + * | ||
| 329 | + * This is always ≥ @ordered_offsets_up_to. It is always an element index. | ||
| 330 | + * | ||
| 331 | + * See documentation in gvariant-core.c for `struct GVariant` for details. */ | ||
| 332 | + gsize checked_offsets_up_to; | ||
| 333 | } GVariantSerialised; | ||
| 334 | |||
| 335 | /* deserialisation */ | ||
| 336 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 337 | index fdd36be..f910bd4 100644 | ||
| 338 | --- a/glib/gvariant.c | ||
| 339 | +++ b/glib/gvariant.c | ||
| 340 | @@ -5945,6 +5945,7 @@ g_variant_byteswap (GVariant *value) | ||
| 341 | serialised.size = g_variant_get_size (trusted); | ||
| 342 | serialised.data = g_malloc (serialised.size); | ||
| 343 | serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ | ||
| 344 | + serialised.checked_offsets_up_to = G_MAXSIZE; | ||
| 345 | g_variant_store (trusted, serialised.data); | ||
| 346 | g_variant_unref (trusted); | ||
| 347 | |||
| 348 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 349 | index a84b02e..640f3c0 100644 | ||
| 350 | --- a/glib/tests/gvariant.c | ||
| 351 | +++ b/glib/tests/gvariant.c | ||
| 352 | @@ -1286,6 +1286,7 @@ random_instance_filler (GVariantSerialised *serialised, | ||
| 353 | |||
| 354 | serialised->depth = 0; | ||
| 355 | serialised->ordered_offsets_up_to = 0; | ||
| 356 | + serialised->checked_offsets_up_to = 0; | ||
| 357 | |||
| 358 | g_assert_true (serialised->type_info == instance->type_info); | ||
| 359 | g_assert_cmpuint (serialised->size, ==, instance->size); | ||
| 360 | @@ -1453,6 +1454,7 @@ test_maybe (void) | ||
| 361 | serialised.size = needed_size; | ||
| 362 | serialised.depth = 0; | ||
| 363 | serialised.ordered_offsets_up_to = 0; | ||
| 364 | + serialised.checked_offsets_up_to = 0; | ||
| 365 | |||
| 366 | g_variant_serialiser_serialise (serialised, | ||
| 367 | random_instance_filler, | ||
| 368 | @@ -1577,6 +1579,7 @@ test_array (void) | ||
| 369 | serialised.size = needed_size; | ||
| 370 | serialised.depth = 0; | ||
| 371 | serialised.ordered_offsets_up_to = 0; | ||
| 372 | + serialised.checked_offsets_up_to = 0; | ||
| 373 | |||
| 374 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 375 | (gpointer *) instances, n_children); | ||
| 376 | @@ -1742,6 +1745,7 @@ test_tuple (void) | ||
| 377 | serialised.size = needed_size; | ||
| 378 | serialised.depth = 0; | ||
| 379 | serialised.ordered_offsets_up_to = 0; | ||
| 380 | + serialised.checked_offsets_up_to = 0; | ||
| 381 | |||
| 382 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 383 | (gpointer *) instances, n_children); | ||
| 384 | @@ -1839,6 +1843,7 @@ test_variant (void) | ||
| 385 | serialised.size = needed_size; | ||
| 386 | serialised.depth = 0; | ||
| 387 | serialised.ordered_offsets_up_to = 0; | ||
| 388 | + serialised.checked_offsets_up_to = 0; | ||
| 389 | |||
| 390 | g_variant_serialiser_serialise (serialised, random_instance_filler, | ||
| 391 | (gpointer *) &instance, 1); | ||
| 392 | -- | ||
| 393 | 2.24.4 | ||
| 394 | |||
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..a523e60b91 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2023-32665-0009.patch | |||
| @@ -0,0 +1,97 @@ | |||
| 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 | Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/298a537d5f6783e55d87e40011ee3fd3b22b72f9] | ||
| 18 | Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> | ||
| 19 | --- | ||
| 20 | glib/gvariant.c | 2 +- | ||
| 21 | glib/tests/gvariant.c | 12 ++++++------ | ||
| 22 | 2 files changed, 7 insertions(+), 7 deletions(-) | ||
| 23 | |||
| 24 | diff --git a/glib/gvariant.c b/glib/gvariant.c | ||
| 25 | index f910bd4..8ba701e 100644 | ||
| 26 | --- a/glib/gvariant.c | ||
| 27 | +++ b/glib/gvariant.c | ||
| 28 | @@ -5936,7 +5936,7 @@ g_variant_byteswap (GVariant *value) | ||
| 29 | if (alignment) | ||
| 30 | /* (potentially) contains multi-byte numeric data */ | ||
| 31 | { | ||
| 32 | - GVariantSerialised serialised; | ||
| 33 | + GVariantSerialised serialised = { 0, }; | ||
| 34 | GVariant *trusted; | ||
| 35 | GBytes *bytes; | ||
| 36 | |||
| 37 | diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c | ||
| 38 | index 640f3c0..d640c81 100644 | ||
| 39 | --- a/glib/tests/gvariant.c | ||
| 40 | +++ b/glib/tests/gvariant.c | ||
| 41 | @@ -1446,7 +1446,7 @@ test_maybe (void) | ||
| 42 | |||
| 43 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 44 | { | ||
| 45 | - GVariantSerialised serialised; | ||
| 46 | + GVariantSerialised serialised = { 0, }; | ||
| 47 | GVariantSerialised child; | ||
| 48 | |||
| 49 | serialised.type_info = type_info; | ||
| 50 | @@ -1572,7 +1572,7 @@ test_array (void) | ||
| 51 | |||
| 52 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 53 | { | ||
| 54 | - GVariantSerialised serialised; | ||
| 55 | + GVariantSerialised serialised = { 0, }; | ||
| 56 | |||
| 57 | serialised.type_info = array_info; | ||
| 58 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 59 | @@ -1738,7 +1738,7 @@ test_tuple (void) | ||
| 60 | |||
| 61 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 62 | { | ||
| 63 | - GVariantSerialised serialised; | ||
| 64 | + GVariantSerialised serialised = { 0, }; | ||
| 65 | |||
| 66 | serialised.type_info = type_info; | ||
| 67 | serialised.data = flavoured_malloc (needed_size, flavour); | ||
| 68 | @@ -1835,7 +1835,7 @@ test_variant (void) | ||
| 69 | |||
| 70 | for (flavour = 0; flavour < 8; flavour += alignment) | ||
| 71 | { | ||
| 72 | - GVariantSerialised serialised; | ||
| 73 | + GVariantSerialised serialised = { 0, }; | ||
| 74 | GVariantSerialised child; | ||
| 75 | |||
| 76 | serialised.type_info = type_info; | ||
| 77 | @@ -2284,7 +2284,7 @@ serialise_tree (TreeInstance *tree, | ||
| 78 | static void | ||
| 79 | test_byteswap (void) | ||
| 80 | { | ||
| 81 | - GVariantSerialised one, two; | ||
| 82 | + GVariantSerialised one = { 0, }, two = { 0, }; | ||
| 83 | TreeInstance *tree; | ||
| 84 | |||
| 85 | tree = tree_instance_new (NULL, 3); | ||
| 86 | @@ -2358,7 +2358,7 @@ test_serialiser_children (void) | ||
| 87 | static void | ||
| 88 | test_fuzz (gdouble *fuzziness) | ||
| 89 | { | ||
| 90 | - GVariantSerialised serialised; | ||
| 91 | + GVariantSerialised serialised = { 0, }; | ||
| 92 | TreeInstance *tree; | ||
| 93 | |||
| 94 | /* make an instance */ | ||
| 95 | -- | ||
| 96 | 2.24.4 | ||
| 97 | |||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.62.6.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.62.6.bb index c2145bc6c2..60a6b843c1 100644 --- a/meta/recipes-core/glib-2.0/glib-2.0_2.62.6.bb +++ b/meta/recipes-core/glib-2.0/glib-2.0_2.62.6.bb | |||
| @@ -42,6 +42,20 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \ | |||
| 42 | file://CVE-2021-28153-3.patch \ | 42 | file://CVE-2021-28153-3.patch \ |
| 43 | file://CVE-2021-28153-4.patch \ | 43 | file://CVE-2021-28153-4.patch \ |
| 44 | file://CVE-2021-28153-5.patch \ | 44 | file://CVE-2021-28153-5.patch \ |
| 45 | file://CVE-2023-32665-0001.patch \ | ||
| 46 | file://CVE-2023-32665-0002.patch \ | ||
| 47 | file://CVE-2023-32665-0003.patch \ | ||
| 48 | file://CVE-2023-32665-0004.patch \ | ||
| 49 | file://CVE-2023-32665-0005.patch \ | ||
| 50 | file://CVE-2023-32665-0006.patch \ | ||
| 51 | file://CVE-2023-32665-0007.patch \ | ||
| 52 | file://CVE-2023-32665-0008.patch \ | ||
| 53 | file://CVE-2023-32665-0009.patch \ | ||
| 54 | file://CVE-2023-29499.patch \ | ||
| 55 | file://CVE-2023-32611-0001.patch \ | ||
| 56 | file://CVE-2023-32611-0002.patch \ | ||
| 57 | file://CVE-2023-32643.patch \ | ||
| 58 | file://CVE-2023-32636.patch \ | ||
| 45 | " | 59 | " |
| 46 | 60 | ||
| 47 | SRC_URI_append_class-native = " file://relocate-modules.patch" | 61 | SRC_URI_append_class-native = " file://relocate-modules.patch" |
