diff options
Diffstat (limited to 'meta/recipes-core/glib-2.0')
40 files changed, 5248 insertions, 1 deletions
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27218.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27218.patch new file mode 100644 index 0000000000..6257763d8d --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27218.patch @@ -0,0 +1,129 @@ +Backport of: + +From 0f384c88a241bbbd884487b1c40b7b75f1e638d3 Mon Sep 17 00:00:00 2001 +From: Krzesimir Nowak <qdlacz@gmail.com> +Date: Wed, 10 Feb 2021 23:51:07 +0100 +Subject: [PATCH] gbytearray: Do not accept too large byte arrays + +GByteArray uses guint for storing the length of the byte array, but it +also has a constructor (g_byte_array_new_take) that takes length as a +gsize. gsize may be larger than guint (64 bits for gsize vs 32 bits +for guint). It is possible to call the function with a value greater +than G_MAXUINT, which will result in silent length truncation. This +may happen as a result of unreffing GBytes into GByteArray, so rather +be loud about it. + +(Test case tweaked by Philip Withnall.) + +(Backport 2.66: Add #include gstrfuncsprivate.h in the test case for +`g_memdup2()`.) + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27218 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + glib/garray.c | 6 ++++++ + glib/gbytes.c | 4 ++++ + glib/tests/bytes.c | 35 ++++++++++++++++++++++++++++++++++- + 3 files changed, 44 insertions(+), 1 deletion(-) + +--- a/glib/garray.c ++++ b/glib/garray.c +@@ -2234,6 +2234,10 @@ g_byte_array_steal (GByteArray *array, + * Create byte array containing the data. The data will be owned by the array + * and will be freed with g_free(), i.e. it could be allocated using g_strdup(). + * ++ * Do not use it if @len is greater than %G_MAXUINT. #GByteArray ++ * stores the length of its data in #guint, which may be shorter than ++ * #gsize. ++ * + * Since: 2.32 + * + * Returns: (transfer full): a new #GByteArray +@@ -2245,6 +2249,8 @@ g_byte_array_new_take (guint8 *data, + GByteArray *array; + GRealArray *real; + ++ g_return_val_if_fail (len <= G_MAXUINT, NULL); ++ + array = g_byte_array_new (); + real = (GRealArray *)array; + g_assert (real->data == NULL); +--- a/glib/gbytes.c ++++ b/glib/gbytes.c +@@ -519,6 +519,10 @@ g_bytes_unref_to_data (GBytes *bytes, + * g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes(). In all + * other cases the data is copied. + * ++ * Do not use it if @bytes contains more than %G_MAXUINT ++ * bytes. #GByteArray stores the length of its data in #guint, which ++ * may be shorter than #gsize, that @bytes is using. ++ * + * Returns: (transfer full): a new mutable #GByteArray containing the same byte data + * + * Since: 2.32 +--- a/glib/tests/bytes.c ++++ b/glib/tests/bytes.c +@@ -10,12 +10,12 @@ + */ + + #undef G_DISABLE_ASSERT +-#undef G_LOG_DOMAIN + + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include "glib.h" ++#include "glib/gstrfuncsprivate.h" + + /* Keep in sync with glib/gbytes.c */ + struct _GBytes +@@ -334,6 +334,38 @@ test_to_array_transferred (void) + } + + static void ++test_to_array_transferred_oversize (void) ++{ ++ g_test_message ("g_bytes_unref_to_array() can only take GBytes up to " ++ "G_MAXUINT in length; test that longer ones are rejected"); ++ ++ if (sizeof (guint) >= sizeof (gsize)) ++ { ++ g_test_skip ("Skipping test as guint is not smaller than gsize"); ++ } ++ else if (g_test_undefined ()) ++ { ++ GByteArray *array = NULL; ++ GBytes *bytes = NULL; ++ gpointer data = g_memdup2 (NYAN, N_NYAN); ++ gsize len = ((gsize) G_MAXUINT) + 1; ++ ++ bytes = g_bytes_new_take (data, len); ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed"); ++ array = g_bytes_unref_to_array (g_steal_pointer (&bytes)); ++ g_test_assert_expected_messages (); ++ g_assert_null (array); ++ ++ g_free (data); ++ } ++ else ++ { ++ g_test_skip ("Skipping test as testing undefined behaviour is disabled"); ++ } ++} ++ ++static void + test_to_array_two_refs (void) + { + gconstpointer memory; +@@ -410,6 +442,7 @@ main (int argc, char *argv[]) + g_test_add_func ("/bytes/to-array/transfered", test_to_array_transferred); + g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs); + g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc); ++ g_test_add_func ("/bytes/to-array/transferred/oversize", test_to_array_transferred_oversize); + g_test_add_func ("/bytes/null", test_null); + + return g_test_run (); diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-01.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-01.patch new file mode 100644 index 0000000000..2af9dd6aa4 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-01.patch @@ -0,0 +1,170 @@ +Backport of: + +From 5e5f75a77e399c638be66d74e5daa8caeb433e00 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:30:52 +0000 +Subject: [PATCH 01/11] gstrfuncs: Add internal g_memdup2() function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will replace the existing `g_memdup()` function for use within +GLib. It has an unavoidable security flaw of taking its `byte_size` +argument as a `guint` rather than as a `gsize`. Most callers will +expect it to be a `gsize`, and may pass in large values which could +silently be truncated, resulting in an undersize allocation compared +to what the caller expects. + +This could lead to a classic buffer overflow vulnerability for many +callers of `g_memdup()`. + +`g_memdup2()`, in comparison, takes its `byte_size` as a `gsize`. + +Spotted by Kevin Backhouse of GHSL. + +In GLib 2.68, `g_memdup2()` will be a new public API. In this version +for backport to older stable releases, it’s a new `static inline` API +in a private header, so that use of `g_memdup()` within GLib can be +fixed without adding a new API in a stable release series. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: GHSL-2021-045 +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + docs/reference/glib/meson.build | 1 + + glib/gstrfuncsprivate.h | 55 +++++++++++++++++++++++++++++++++ + glib/meson.build | 1 + + glib/tests/strfuncs.c | 23 ++++++++++++++ + 4 files changed, 80 insertions(+) + create mode 100644 glib/gstrfuncsprivate.h + +--- a/docs/reference/glib/meson.build ++++ b/docs/reference/glib/meson.build +@@ -22,6 +22,7 @@ if get_option('gtk_doc') + 'gprintfint.h', + 'gmirroringtable.h', + 'gscripttable.h', ++ 'gstrfuncsprivate.h', + 'glib-mirroring-tab', + 'gnulib', + 'pcre', +--- /dev/null ++++ b/glib/gstrfuncsprivate.h +@@ -0,0 +1,55 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <glib.h> ++#include <string.h> ++ ++/* ++ * g_memdup2: ++ * @mem: (nullable): the memory to copy. ++ * @byte_size: the number of bytes to copy. ++ * ++ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it ++ * from @mem. If @mem is %NULL it returns %NULL. ++ * ++ * This replaces g_memdup(), which was prone to integer overflows when ++ * converting the argument from a #gsize to a #guint. ++ * ++ * This static inline version is a backport of the new public API from ++ * GLib 2.68, kept internal to GLib for backport to older stable releases. ++ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2319. ++ * ++ * Returns: (nullable): a pointer to the newly-allocated copy of the memory, ++ * or %NULL if @mem is %NULL. ++ * Since: 2.68 ++ */ ++static inline gpointer ++g_memdup2 (gconstpointer mem, ++ gsize byte_size) ++{ ++ gpointer new_mem; ++ ++ if (mem && byte_size != 0) ++ { ++ new_mem = g_malloc (byte_size); ++ memcpy (new_mem, mem, byte_size); ++ } ++ else ++ new_mem = NULL; ++ ++ return new_mem; ++} +--- a/glib/meson.build ++++ b/glib/meson.build +@@ -268,6 +268,7 @@ glib_sources = files( + 'gslist.c', + 'gstdio.c', + 'gstrfuncs.c', ++ 'gstrfuncsprivate.h', + 'gstring.c', + 'gstringchunk.c', + 'gtestutils.c', +--- a/glib/tests/strfuncs.c ++++ b/glib/tests/strfuncs.c +@@ -32,6 +32,8 @@ + #include <string.h> + #include "glib.h" + ++#include "gstrfuncsprivate.h" ++ + #if defined (_MSC_VER) && (_MSC_VER <= 1800) + #define isnan(x) _isnan(x) + +@@ -219,6 +221,26 @@ test_memdup (void) + g_free (str_dup); + } + ++/* Testing g_memdup2() function with various positive and negative cases */ ++static void ++test_memdup2 (void) ++{ ++ gchar *str_dup = NULL; ++ const gchar *str = "The quick brown fox jumps over the lazy dog"; ++ ++ /* Testing negative cases */ ++ g_assert_null (g_memdup2 (NULL, 1024)); ++ g_assert_null (g_memdup2 (str, 0)); ++ g_assert_null (g_memdup2 (NULL, 0)); ++ ++ /* Testing normal usage cases */ ++ str_dup = g_memdup2 (str, strlen (str) + 1); ++ g_assert_nonnull (str_dup); ++ g_assert_cmpstr (str, ==, str_dup); ++ ++ g_free (str_dup); ++} ++ + /* Testing g_strpcpy() function with various positive and negative cases */ + static void + test_stpcpy (void) +@@ -2523,6 +2545,7 @@ main (int argc, + g_test_add_func ("/strfuncs/has-prefix", test_has_prefix); + g_test_add_func ("/strfuncs/has-suffix", test_has_suffix); + g_test_add_func ("/strfuncs/memdup", test_memdup); ++ g_test_add_func ("/strfuncs/memdup2", test_memdup2); + g_test_add_func ("/strfuncs/stpcpy", test_stpcpy); + g_test_add_func ("/strfuncs/str_match_string", test_str_match_string); + g_test_add_func ("/strfuncs/str_tokenize_and_fold", test_str_tokenize_and_fold); diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-02.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-02.patch new file mode 100644 index 0000000000..20137ea5f3 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-02.patch @@ -0,0 +1,249 @@ +From be8834340a2d928ece82025463ae23dee2c333d0 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:37:56 +0000 +Subject: [PATCH 02/11] gio: Use g_memdup2() instead of g_memdup() in obvious + places +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Convert all the call sites which use `g_memdup()`’s length argument +trivially (for example, by passing a `sizeof()`), so that they use +`g_memdup2()` instead. + +In almost all of these cases the use of `g_memdup()` would not have +caused problems, but it will soon be deprecated, so best port away from +it. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gdbusconnection.c | 5 +++-- + gio/gdbusinterfaceskeleton.c | 3 ++- + gio/gfile.c | 7 ++++--- + gio/gsettingsschema.c | 5 +++-- + gio/gwin32registrykey.c | 8 +++++--- + gio/tests/async-close-output-stream.c | 6 ++++-- + gio/tests/gdbus-export.c | 5 +++-- + gio/win32/gwinhttpfile.c | 9 +++++---- + 8 files changed, 29 insertions(+), 19 deletions(-) + +--- a/gio/gdbusconnection.c ++++ b/gio/gdbusconnection.c +@@ -110,6 +110,7 @@ + #include "gasyncinitable.h" + #include "giostream.h" + #include "gasyncresult.h" ++#include "gstrfuncsprivate.h" + #include "gtask.h" + #include "gmarshal-internal.h" + +@@ -4007,7 +4008,7 @@ _g_dbus_interface_vtable_copy (const GDB + /* Don't waste memory by copying padding - remember to update this + * when changing struct _GDBusInterfaceVTable in gdbusconnection.h + */ +- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer)); ++ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer)); + } + + static void +@@ -4024,7 +4025,7 @@ _g_dbus_subtree_vtable_copy (const GDBus + /* Don't waste memory by copying padding - remember to update this + * when changing struct _GDBusSubtreeVTable in gdbusconnection.h + */ +- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer)); ++ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer)); + } + + static void +--- a/gio/gdbusinterfaceskeleton.c ++++ b/gio/gdbusinterfaceskeleton.c +@@ -28,6 +28,7 @@ + #include "gdbusmethodinvocation.h" + #include "gdbusconnection.h" + #include "gmarshal-internal.h" ++#include "gstrfuncsprivate.h" + #include "gtask.h" + #include "gioerror.h" + +@@ -701,7 +702,7 @@ add_connection_locked (GDBusInterfaceSke + * properly before building the hooked_vtable, so we create it + * once at the last minute. + */ +- interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable)); ++ interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable)); + interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call; + } + +--- a/gio/gfile.c ++++ b/gio/gfile.c +@@ -60,6 +60,7 @@ + #include "gasyncresult.h" + #include "gioerror.h" + #include "glibintl.h" ++#include "gstrfuncsprivate.h" + + + /** +@@ -7854,7 +7855,7 @@ measure_disk_usage_progress (gboolean re + g_main_context_invoke_full (g_task_get_context (task), + g_task_get_priority (task), + measure_disk_usage_invoke_progress, +- g_memdup (&progress, sizeof progress), ++ g_memdup2 (&progress, sizeof progress), + g_free); + } + +@@ -7872,7 +7873,7 @@ measure_disk_usage_thread (GTask + data->progress_callback ? measure_disk_usage_progress : NULL, task, + &result.disk_usage, &result.num_dirs, &result.num_files, + &error)) +- g_task_return_pointer (task, g_memdup (&result, sizeof result), g_free); ++ g_task_return_pointer (task, g_memdup2 (&result, sizeof result), g_free); + else + g_task_return_error (task, error); + } +@@ -7896,7 +7897,7 @@ g_file_real_measure_disk_usage_async (GF + + task = g_task_new (file, cancellable, callback, user_data); + g_task_set_source_tag (task, g_file_real_measure_disk_usage_async); +- g_task_set_task_data (task, g_memdup (&data, sizeof data), g_free); ++ g_task_set_task_data (task, g_memdup2 (&data, sizeof data), g_free); + g_task_set_priority (task, io_priority); + + g_task_run_in_thread (task, measure_disk_usage_thread); +--- a/gio/gsettingsschema.c ++++ b/gio/gsettingsschema.c +@@ -20,6 +20,7 @@ + + #include "gsettingsschema-internal.h" + #include "gsettings.h" ++#include "gstrfuncsprivate.h" + + #include "gvdb/gvdb-reader.h" + #include "strinfo.c" +@@ -1067,9 +1068,9 @@ g_settings_schema_list_children (GSettin + + if (g_str_has_suffix (key, "/")) + { +- gint length = strlen (key); ++ gsize length = strlen (key); + +- strv[j] = g_memdup (key, length); ++ strv[j] = g_memdup2 (key, length); + strv[j][length - 1] = '\0'; + j++; + } +--- a/gio/gwin32registrykey.c ++++ b/gio/gwin32registrykey.c +@@ -28,6 +28,8 @@ + #include <ntstatus.h> + #include <winternl.h> + ++#include "gstrfuncsprivate.h" ++ + #ifndef _WDMDDK_ + typedef enum _KEY_INFORMATION_CLASS { + KeyBasicInformation, +@@ -247,7 +249,7 @@ g_win32_registry_value_iter_copy (const + new_iter->value_name_size = iter->value_name_size; + + if (iter->value_data != NULL) +- new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size); ++ new_iter->value_data = g_memdup2 (iter->value_data, iter->value_data_size); + + new_iter->value_data_size = iter->value_data_size; + +@@ -268,8 +270,8 @@ g_win32_registry_value_iter_copy (const + new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize; + + if (iter->value_data_expanded_u8 != NULL) +- new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8, +- iter->value_data_expanded_charsize); ++ new_iter->value_data_expanded_u8 = g_memdup2 (iter->value_data_expanded_u8, ++ iter->value_data_expanded_charsize); + + new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize; + +--- a/gio/tests/async-close-output-stream.c ++++ b/gio/tests/async-close-output-stream.c +@@ -24,6 +24,8 @@ + #include <stdlib.h> + #include <string.h> + ++#include "gstrfuncsprivate.h" ++ + #define DATA_TO_WRITE "Hello world\n" + + typedef struct +@@ -147,9 +149,9 @@ prepare_data (SetupData *data, + + data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream)); + +- g_assert_cmpint (data->expected_size, >, 0); ++ g_assert_cmpuint (data->expected_size, >, 0); + +- data->expected_output = g_memdup (written, (guint)data->expected_size); ++ data->expected_output = g_memdup2 (written, data->expected_size); + + /* then recreate the streams and prepare them for the asynchronous close */ + destroy_streams (data); +--- a/gio/tests/gdbus-export.c ++++ b/gio/tests/gdbus-export.c +@@ -23,6 +23,7 @@ + #include <string.h> + + #include "gdbus-tests.h" ++#include "gstrfuncsprivate.h" + + /* all tests rely on a shared mainloop */ + static GMainLoop *loop = NULL; +@@ -671,7 +672,7 @@ subtree_introspect (GDBusConnection + g_assert_not_reached (); + } + +- return g_memdup (interfaces, 2 * sizeof (void *)); ++ return g_memdup2 (interfaces, 2 * sizeof (void *)); + } + + static const GDBusInterfaceVTable * +@@ -727,7 +728,7 @@ dynamic_subtree_introspect (GDBusConnect + { + const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL }; + +- return g_memdup (interfaces, 2 * sizeof (void *)); ++ return g_memdup2 (interfaces, 2 * sizeof (void *)); + } + + static const GDBusInterfaceVTable * +--- a/gio/win32/gwinhttpfile.c ++++ b/gio/win32/gwinhttpfile.c +@@ -29,6 +29,7 @@ + #include "gio/gfile.h" + #include "gio/gfileattribute.h" + #include "gio/gfileinfo.h" ++#include "gstrfuncsprivate.h" + #include "gwinhttpfile.h" + #include "gwinhttpfileinputstream.h" + #include "gwinhttpfileoutputstream.h" +@@ -393,10 +394,10 @@ + child = g_object_new (G_TYPE_WINHTTP_FILE, NULL); + child->vfs = winhttp_file->vfs; + child->url = winhttp_file->url; +- child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2); +- child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2); +- child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2); +- child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2); ++ child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2); ++ child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2); ++ child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2); ++ child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2); + child->url.lpszUrlPath = wnew_path; + child->url.dwUrlPathLength = wcslen (wnew_path); + child->url.lpszExtraInfo = NULL; diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-03.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-03.patch new file mode 100644 index 0000000000..eceff161a6 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-03.patch @@ -0,0 +1,131 @@ +From 6110caea45b235420b98cd41d845cc92238f6781 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:39:25 +0000 +Subject: [PATCH 03/11] gobject: Use g_memdup2() instead of g_memdup() in + obvious places +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Convert all the call sites which use `g_memdup()`’s length argument +trivially (for example, by passing a `sizeof()`), so that they use +`g_memdup2()` instead. + +In almost all of these cases the use of `g_memdup()` would not have +caused problems, but it will soon be deprecated, so best port away from +it. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gobject/gsignal.c | 3 ++- + gobject/gtype.c | 9 +++++---- + gobject/gtypemodule.c | 3 ++- + gobject/tests/param.c | 4 +++- + 4 files changed, 12 insertions(+), 7 deletions(-) + +--- a/gobject/gsignal.c ++++ b/gobject/gsignal.c +@@ -28,6 +28,7 @@ + #include <signal.h> + + #include "gsignal.h" ++#include "gstrfuncsprivate.h" + #include "gtype-private.h" + #include "gbsearcharray.h" + #include "gvaluecollector.h" +@@ -1809,7 +1810,7 @@ g_signal_newv (const gchar *signal + node->single_va_closure_is_valid = FALSE; + node->flags = signal_flags & G_SIGNAL_FLAGS_MASK; + node->n_params = n_params; +- node->param_types = g_memdup (param_types, sizeof (GType) * n_params); ++ node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params); + node->return_type = return_type; + node->class_closure_bsa = NULL; + if (accumulator) +--- a/gobject/gtype.c ++++ b/gobject/gtype.c +@@ -33,6 +33,7 @@ + + #include "glib-private.h" + #include "gconstructor.h" ++#include "gstrfuncsprivate.h" + + #ifdef G_OS_WIN32 + #include <windows.h> +@@ -1470,7 +1471,7 @@ type_add_interface_Wm (TypeNode + iholder->next = iface_node_get_holders_L (iface); + iface_node_set_holders_W (iface, iholder); + iholder->instance_type = NODE_TYPE (node); +- iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL; ++ iholder->info = info ? g_memdup2 (info, sizeof (*info)) : NULL; + iholder->plugin = plugin; + + /* create an iface entry for this type */ +@@ -1731,7 +1732,7 @@ type_iface_retrieve_holder_info_Wm (Type + INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface)); + + check_interface_info_I (iface, instance_type, &tmp_info); +- iholder->info = g_memdup (&tmp_info, sizeof (tmp_info)); ++ iholder->info = g_memdup2 (&tmp_info, sizeof (tmp_info)); + } + + return iholder; /* we don't modify write lock upon returning NULL */ +@@ -2016,10 +2017,10 @@ type_iface_vtable_base_init_Wm (TypeNode + IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface); + + if (pentry) +- vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size); ++ vtable = g_memdup2 (pentry->vtable, iface->data->iface.vtable_size); + } + if (!vtable) +- vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size); ++ vtable = g_memdup2 (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size); + entry->vtable = vtable; + vtable->g_type = NODE_TYPE (iface); + vtable->g_instance_type = NODE_TYPE (node); +--- a/gobject/gtypemodule.c ++++ b/gobject/gtypemodule.c +@@ -19,6 +19,7 @@ + + #include <stdlib.h> + ++#include "gstrfuncsprivate.h" + #include "gtypeplugin.h" + #include "gtypemodule.h" + +@@ -436,7 +437,7 @@ g_type_module_register_type (GTypeModule + module_type_info->loaded = TRUE; + module_type_info->info = *type_info; + if (type_info->value_table) +- module_type_info->info.value_table = g_memdup (type_info->value_table, ++ module_type_info->info.value_table = g_memdup2 (type_info->value_table, + sizeof (GTypeValueTable)); + + return module_type_info->type; +--- a/gobject/tests/param.c ++++ b/gobject/tests/param.c +@@ -2,6 +2,8 @@ + #include <glib-object.h> + #include <stdlib.h> + ++#include "gstrfuncsprivate.h" ++ + static void + test_param_value (void) + { +@@ -874,7 +876,7 @@ main (int argc, char *argv[]) + test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d", + data.change_this_flag, data.change_this_type, + data.use_this_flag, data.use_this_type); +- test_data = g_memdup (&data, sizeof (TestParamImplementData)); ++ test_data = g_memdup2 (&data, sizeof (TestParamImplementData)); + g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free); + g_free (test_path); + } diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-04.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-04.patch new file mode 100644 index 0000000000..6a3ac6b552 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-04.patch @@ -0,0 +1,298 @@ +Backport of: + +From 0736b7c1e7cf4232c5d7eb2b0fbfe9be81bd3baa Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:41:21 +0000 +Subject: [PATCH 04/11] glib: Use g_memdup2() instead of g_memdup() in obvious + places +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Convert all the call sites which use `g_memdup()`’s length argument +trivially (for example, by passing a `sizeof()` or an existing `gsize` +variable), so that they use `g_memdup2()` instead. + +In almost all of these cases the use of `g_memdup()` would not have +caused problems, but it will soon be deprecated, so best port away from +it + +In particular, this fixes an overflow within `g_bytes_new()`, identified +as GHSL-2021-045 by GHSL team member Kevin Backhouse. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Fixes: GHSL-2021-045 +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + glib/gbytes.c | 6 ++++-- + glib/gdir.c | 3 ++- + glib/ghash.c | 7 ++++--- + glib/giochannel.c | 5 +++-- + glib/gslice.c | 3 ++- + glib/gtestutils.c | 3 ++- + glib/gvariant.c | 7 ++++--- + glib/gvarianttype.c | 3 ++- + glib/tests/array-test.c | 4 +++- + glib/tests/option-context.c | 6 ++++-- + glib/tests/uri.c | 8 +++++--- + 11 files changed, 35 insertions(+), 20 deletions(-) + +--- a/glib/gbytes.c ++++ b/glib/gbytes.c +@@ -34,6 +34,8 @@ + + #include <string.h> + ++#include "gstrfuncsprivate.h" ++ + /** + * GBytes: + * +@@ -95,7 +97,7 @@ g_bytes_new (gconstpointer data, + { + g_return_val_if_fail (data != NULL || size == 0, NULL); + +- return g_bytes_new_take (g_memdup (data, size), size); ++ return g_bytes_new_take (g_memdup2 (data, size), size); + } + + /** +@@ -499,7 +501,7 @@ g_bytes_unref_to_data (GBytes *bytes, + * Copy: Non g_malloc (or compatible) allocator, or static memory, + * so we have to copy, and then unref. + */ +- result = g_memdup (bytes->data, bytes->size); ++ result = g_memdup2 (bytes->data, bytes->size); + *size = bytes->size; + g_bytes_unref (bytes); + } +--- a/glib/gdir.c ++++ b/glib/gdir.c +@@ -37,6 +37,7 @@ + #include "gconvert.h" + #include "gfileutils.h" + #include "gstrfuncs.h" ++#include "gstrfuncsprivate.h" + #include "gtestutils.h" + #include "glibintl.h" + +@@ -112,7 +113,7 @@ g_dir_open_with_errno (const gchar *path + return NULL; + #endif + +- return g_memdup (&dir, sizeof dir); ++ return g_memdup2 (&dir, sizeof dir); + } + + /** +--- a/glib/ghash.c ++++ b/glib/ghash.c +@@ -34,6 +34,7 @@ + #include "gmacros.h" + #include "glib-private.h" + #include "gstrfuncs.h" ++#include "gstrfuncsprivate.h" + #include "gatomic.h" + #include "gtestutils.h" + #include "gslice.h" +@@ -962,7 +963,7 @@ g_hash_table_ensure_keyval_fits (GHashTa + if (hash_table->have_big_keys) + { + if (key != value) +- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size); ++ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size); + /* Keys and values are both big now, so no need for further checks */ + return; + } +@@ -970,7 +971,7 @@ g_hash_table_ensure_keyval_fits (GHashTa + { + if (key != value) + { +- hash_table->values = g_memdup (hash_table->keys, sizeof (guint) * hash_table->size); ++ hash_table->values = g_memdup2 (hash_table->keys, sizeof (guint) * hash_table->size); + is_a_set = FALSE; + } + } +@@ -998,7 +999,7 @@ g_hash_table_ensure_keyval_fits (GHashTa + + /* Just split if necessary */ + if (is_a_set && key != value) +- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size); ++ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size); + + #endif + } +--- a/glib/giochannel.c ++++ b/glib/giochannel.c +@@ -35,7 +35,7 @@ + #include <errno.h> + + #include "giochannel.h" +- ++#include "gstrfuncsprivate.h" + #include "gstrfuncs.h" + #include "gtestutils.h" + #include "glibintl.h" + +@@ -1673,10 +1674,10 @@ g_io_channel_read_line (GIOChannel *cha + + /* Copy the read bytes (including any embedded nuls) and nul-terminate. + * `USE_BUF (channel)->str` is guaranteed to be nul-terminated as it’s a +- * #GString, so it’s safe to call g_memdup() with +1 length to allocate ++ * #GString, so it’s safe to call g_memdup2() with +1 length to allocate + * a nul-terminator. */ + g_assert (USE_BUF (channel)); +- line = g_memdup (USE_BUF (channel)->str, got_length + 1); ++ line = g_memdup2 (USE_BUF (channel)->str, got_length + 1); + line[got_length] = '\0'; + *str_return = g_steal_pointer (&line); + g_string_erase (USE_BUF (channel), 0, got_length); +--- a/glib/gslice.c ++++ b/glib/gslice.c +@@ -41,6 +41,7 @@ + #include "gmain.h" + #include "gmem.h" /* gslice.h */ + #include "gstrfuncs.h" ++#include "gstrfuncsprivate.h" + #include "gutils.h" + #include "gtrashstack.h" + #include "gtestutils.h" +@@ -350,7 +351,7 @@ g_slice_get_config_state (GSliceConfig c + array[i++] = allocator->contention_counters[address]; + array[i++] = allocator_get_magazine_threshold (allocator, address); + *n_values = i; +- return g_memdup (array, sizeof (array[0]) * *n_values); ++ return g_memdup2 (array, sizeof (array[0]) * *n_values); + default: + return NULL; + } +--- a/glib/gtestutils.c ++++ b/glib/gtestutils.c +@@ -49,6 +49,7 @@ + #include "gpattern.h" + #include "grand.h" + #include "gstrfuncs.h" ++#include "gstrfuncsprivate.h" + #include "gtimer.h" + #include "gslice.h" + #include "gspawn.h" +@@ -3803,7 +3804,7 @@ g_test_log_extract (GTestLogBuffer *tbuf + if (p <= tbuffer->data->str + mlength) + { + g_string_erase (tbuffer->data, 0, mlength); +- tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg))); ++ tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup2 (&msg, sizeof (msg))); + return TRUE; + } + +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -33,6 +33,7 @@ + + #include <string.h> + ++#include "gstrfuncsprivate.h" + + /** + * SECTION:gvariant +@@ -725,7 +726,7 @@ g_variant_new_variant (GVariant *value) + g_variant_ref_sink (value); + + return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT, +- g_memdup (&value, sizeof value), ++ g_memdup2 (&value, sizeof value), + 1, g_variant_is_trusted (value)); + } + +@@ -1229,7 +1230,7 @@ g_variant_new_fixed_array (const GVarian + return NULL; + } + +- data = g_memdup (elements, n_elements * element_size); ++ data = g_memdup2 (elements, n_elements * element_size); + value = g_variant_new_from_data (array_type, data, + n_elements * element_size, + FALSE, g_free, data); +@@ -1908,7 +1909,7 @@ g_variant_dup_bytestring (GVariant *valu + if (length) + *length = size; + +- return g_memdup (original, size + 1); ++ return g_memdup2 (original, size + 1); + } + + /** +--- a/glib/gvarianttype.c ++++ b/glib/gvarianttype.c +@@ -28,6 +28,7 @@ + + #include <string.h> + ++#include "gstrfuncsprivate.h" + + /** + * SECTION:gvarianttype +@@ -1181,7 +1182,7 @@ g_variant_type_new_tuple (const GVariant + g_assert (offset < sizeof buffer); + buffer[offset++] = ')'; + +- return (GVariantType *) g_memdup (buffer, offset); ++ return (GVariantType *) g_memdup2 (buffer, offset); + } + + /** +--- a/glib/tests/array-test.c ++++ b/glib/tests/array-test.c +@@ -29,6 +29,8 @@ + #include <string.h> + #include "glib.h" + ++#include "gstrfuncsprivate.h" ++ + /* Test data to be passed to any function which calls g_array_new(), providing + * the parameters for that call. Most #GArray tests should be repeated for all + * possible values of #ArrayTestData. */ +@@ -1917,7 +1919,7 @@ byte_array_new_take (void) + GByteArray *gbarray; + guint8 *data; + +- data = g_memdup ("woooweeewow", 11); ++ data = g_memdup2 ("woooweeewow", 11); + gbarray = g_byte_array_new_take (data, 11); + g_assert (gbarray->data == data); + g_assert_cmpuint (gbarray->len, ==, 11); +--- a/glib/tests/option-context.c ++++ b/glib/tests/option-context.c +@@ -27,6 +27,8 @@ + #include <string.h> + #include <locale.h> + ++#include "gstrfuncsprivate.h" ++ + static GOptionEntry main_entries[] = { + { "main-switch", 0, 0, + G_OPTION_ARG_NONE, NULL, +@@ -256,7 +258,7 @@ join_stringv (int argc, char **argv) + static char ** + copy_stringv (char **argv, int argc) + { +- return g_memdup (argv, sizeof (char *) * (argc + 1)); ++ return g_memdup2 (argv, sizeof (char *) * (argc + 1)); + } + + static void +@@ -2323,7 +2325,7 @@ test_group_parse (void) + g_option_context_add_group (context, group); + + argv = split_string ("program --test arg1 -f arg2 --group-test arg3 --frob arg4 -z arg5", &argc); +- orig_argv = g_memdup (argv, (argc + 1) * sizeof (char *)); ++ orig_argv = g_memdup2 (argv, (argc + 1) * sizeof (char *)); + + retval = g_option_context_parse (context, &argc, &argv, &error); + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-05.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-05.patch new file mode 100644 index 0000000000..4f86522d00 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-05.patch @@ -0,0 +1,54 @@ +From 0cbad673215ec8a049b7fe2ff44b0beed31b376e Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 16:12:24 +0000 +Subject: [PATCH 05/11] gwinhttpfile: Avoid arithmetic overflow when + calculating a size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The members of `URL_COMPONENTS` (`winhttp_file->url`) are `DWORD`s, i.e. +32-bit unsigned integers. Adding to and multiplying them may cause them +to overflow the unsigned integer bounds, even if the result is passed to +`g_memdup2()` which accepts a `gsize`. + +Cast the `URL_COMPONENTS` members to `gsize` first to ensure that the +arithmetic is done in terms of `gsize`s rather than unsigned integers. + +Spotted by Sebastian Dröge. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/win32/gwinhttpfile.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c +index 3f8fbd838..e0340e247 100644 +--- a/gio/win32/gwinhttpfile.c ++++ b/gio/win32/gwinhttpfile.c +@@ -410,10 +410,10 @@ g_winhttp_file_resolve_relative_path (GFile *file, + child = g_object_new (G_TYPE_WINHTTP_FILE, NULL); + child->vfs = winhttp_file->vfs; + child->url = winhttp_file->url; +- child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2); +- child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2); +- child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2); +- child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2); ++ child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, ((gsize) winhttp_file->url.dwSchemeLength + 1) * 2); ++ child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, ((gsize) winhttp_file->url.dwHostNameLength + 1) * 2); ++ child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, ((gsize) winhttp_file->url.dwUserNameLength + 1) * 2); ++ child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, ((gsize) winhttp_file->url.dwPasswordLength + 1) * 2); + child->url.lpszUrlPath = wnew_path; + child->url.dwUrlPathLength = wcslen (wnew_path); + child->url.lpszExtraInfo = NULL; +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-06.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-06.patch new file mode 100644 index 0000000000..d8043f5e29 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-06.patch @@ -0,0 +1,101 @@ +From f9ee2275cbc312c0b4cdbc338a4fbb76eb36fb9a Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:49:00 +0000 +Subject: [PATCH 06/11] gdatainputstream: Handle stop_chars_len internally as + gsize + +Previously it was handled as a `gssize`, which meant that if the +`stop_chars` string was longer than `G_MAXSSIZE` there would be an +overflow. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gdatainputstream.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c +index 2e7750cb5..2cdcbda19 100644 +--- a/gio/gdatainputstream.c ++++ b/gio/gdatainputstream.c +@@ -27,6 +27,7 @@ + #include "gioenumtypes.h" + #include "gioerror.h" + #include "glibintl.h" ++#include "gstrfuncsprivate.h" + + #include <string.h> + +@@ -856,7 +857,7 @@ static gssize + scan_for_chars (GDataInputStream *stream, + gsize *checked_out, + const char *stop_chars, +- gssize stop_chars_len) ++ gsize stop_chars_len) + { + GBufferedInputStream *bstream; + const char *buffer; +@@ -952,7 +953,7 @@ typedef struct + gsize checked; + + gchar *stop_chars; +- gssize stop_chars_len; ++ gsize stop_chars_len; + gsize length; + } GDataInputStreamReadData; + +@@ -1078,12 +1079,17 @@ g_data_input_stream_read_async (GDataInputStream *stream, + { + GDataInputStreamReadData *data; + GTask *task; ++ gsize stop_chars_len_unsigned; + + data = g_slice_new0 (GDataInputStreamReadData); +- if (stop_chars_len == -1) +- stop_chars_len = strlen (stop_chars); +- data->stop_chars = g_memdup (stop_chars, stop_chars_len); +- data->stop_chars_len = stop_chars_len; ++ ++ if (stop_chars_len < 0) ++ stop_chars_len_unsigned = strlen (stop_chars); ++ else ++ stop_chars_len_unsigned = (gsize) stop_chars_len; ++ ++ data->stop_chars = g_memdup2 (stop_chars, stop_chars_len_unsigned); ++ data->stop_chars_len = stop_chars_len_unsigned; + data->last_saw_cr = FALSE; + + task = g_task_new (stream, cancellable, callback, user_data); +@@ -1338,17 +1344,20 @@ g_data_input_stream_read_upto (GDataInputStream *stream, + gssize found_pos; + gssize res; + char *data_until; ++ gsize stop_chars_len_unsigned; + + g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL); + + if (stop_chars_len < 0) +- stop_chars_len = strlen (stop_chars); ++ stop_chars_len_unsigned = strlen (stop_chars); ++ else ++ stop_chars_len_unsigned = (gsize) stop_chars_len; + + bstream = G_BUFFERED_INPUT_STREAM (stream); + + checked = 0; + +- while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len)) == -1) ++ while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len_unsigned)) == -1) + { + if (g_buffered_input_stream_get_available (bstream) == + g_buffered_input_stream_get_buffer_size (bstream)) +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-07.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-07.patch new file mode 100644 index 0000000000..f183939c45 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-07.patch @@ -0,0 +1,76 @@ +From 2aaf593a9eb96d84fe3be740aca2810a97d95592 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:50:37 +0000 +Subject: [PATCH 07/11] gwin32: Use gsize internally in g_wcsdup() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows it to handle strings up to length `G_MAXSIZE` — previously +it would overflow with such strings. + +Update the several copies of it identically. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gwin32registrykey.c | 34 ++++++++++++++++++++++++++-------- + 2 files changed, 38 insertions(+), 16 deletions(-) + +diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c +index 548a94188..2eb67daf8 100644 +--- a/gio/gwin32registrykey.c ++++ b/gio/gwin32registrykey.c +@@ -127,16 +127,34 @@ typedef enum + G_WIN32_REGISTRY_UPDATED_PATH = 1, + } GWin32RegistryKeyUpdateFlag; + ++static gsize ++g_utf16_len (const gunichar2 *str) ++{ ++ gsize result; ++ ++ for (result = 0; str[0] != 0; str++, result++) ++ ; ++ ++ return result; ++} ++ + static gunichar2 * +-g_wcsdup (const gunichar2 *str, +- gssize str_size) ++g_wcsdup (const gunichar2 *str, gssize str_len) + { +- if (str_size == -1) +- { +- str_size = wcslen (str) + 1; +- str_size *= sizeof (gunichar2); +- } +- return g_memdup (str, str_size); ++ gsize str_len_unsigned; ++ gsize str_size; ++ ++ g_return_val_if_fail (str != NULL, NULL); ++ ++ if (str_len < 0) ++ str_len_unsigned = g_utf16_len (str); ++ else ++ str_len_unsigned = (gsize) str_len; ++ ++ g_assert (str_len_unsigned <= G_MAXSIZE / sizeof (gunichar2) - 1); ++ str_size = (str_len_unsigned + 1) * sizeof (gunichar2); ++ ++ return g_memdup2 (str, str_size); + } + + /** +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-08.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-08.patch new file mode 100644 index 0000000000..ffafc35c07 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-08.patch @@ -0,0 +1,101 @@ +From ba8ca443051f93a74c0d03d62e70402036f967a5 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 13:58:32 +0000 +Subject: [PATCH 08/11] gkeyfilesettingsbackend: Handle long keys when + converting paths + +Previously, the code in `convert_path()` could not handle keys longer +than `G_MAXINT`, and would overflow if that was exceeded. + +Convert the code to use `gsize` and `g_memdup2()` throughout, and +change from identifying the position of the final slash in the string +using a signed offset `i`, to using a pointer to the character (and +`strrchr()`). This allows the slash to be at any position in a +`G_MAXSIZE`-long string, without sacrificing a bit of the offset for +indicating whether a slash was found. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gkeyfilesettingsbackend.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c +index cd5765afd..25b057672 100644 +--- a/gio/gkeyfilesettingsbackend.c ++++ b/gio/gkeyfilesettingsbackend.c +@@ -33,6 +33,7 @@ + #include "gfilemonitor.h" + #include "gsimplepermission.h" + #include "gsettingsbackendinternal.h" ++#include "gstrfuncsprivate.h" + #include "giomodule-priv.h" + #include "gportalsupport.h" + +@@ -145,8 +146,8 @@ convert_path (GKeyfileSettingsBackend *kfsb, + gchar **group, + gchar **basename) + { +- gint key_len = strlen (key); +- gint i; ++ gsize key_len = strlen (key); ++ const gchar *last_slash; + + if (key_len < kfsb->prefix_len || + memcmp (key, kfsb->prefix, kfsb->prefix_len) != 0) +@@ -155,38 +156,36 @@ convert_path (GKeyfileSettingsBackend *kfsb, + key_len -= kfsb->prefix_len; + key += kfsb->prefix_len; + +- for (i = key_len; i >= 0; i--) +- if (key[i] == '/') +- break; ++ last_slash = strrchr (key, '/'); + + if (kfsb->root_group) + { + /* if a root_group was specified, make sure the user hasn't given + * a path that ghosts that group name + */ +- if (i == kfsb->root_group_len && memcmp (key, kfsb->root_group, i) == 0) ++ if (last_slash != NULL && (last_slash - key) == kfsb->root_group_len && memcmp (key, kfsb->root_group, last_slash - key) == 0) + return FALSE; + } + else + { + /* if no root_group was given, ensure that the user gave a path */ +- if (i == -1) ++ if (last_slash == NULL) + return FALSE; + } + + if (group) + { +- if (i >= 0) ++ if (last_slash != NULL) + { +- *group = g_memdup (key, i + 1); +- (*group)[i] = '\0'; ++ *group = g_memdup2 (key, (last_slash - key) + 1); ++ (*group)[(last_slash - key)] = '\0'; + } + else + *group = g_strdup (kfsb->root_group); + } + + if (basename) +- *basename = g_memdup (key + i + 1, key_len - i); ++ *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key)); + + return TRUE; + } +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-09.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-09.patch new file mode 100644 index 0000000000..8efb7c720f --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-09.patch @@ -0,0 +1,100 @@ +From 65ec7f4d6e8832c481f6e00e2eb007b9a60024ce Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 14:00:53 +0000 +Subject: [PATCH 09/11] =?UTF-8?q?gsocket:=20Use=20gsize=20to=20track=20nat?= + =?UTF-8?q?ive=20sockaddr=E2=80=99s=20size?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Don’t use an `int`, that’s potentially too small. In practical terms, +this is not a problem, since no socket address is going to be that big. + +By making these changes we can use `g_memdup2()` without warnings, +though. Fewer warnings is good. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gsocket.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/gio/gsocket.c ++++ b/gio/gsocket.c +@@ -75,6 +75,7 @@ + #include "gcredentialsprivate.h" + #include "glibintl.h" + #include "gioprivate.h" ++#include "gstrfuncsprivate.h" + + #ifdef G_OS_WIN32 + /* For Windows XP runtime compatibility, but use the system's if_nametoindex() if available */ +@@ -174,7 +175,7 @@ static gboolean g_socket_datagram_ba + GError **error); + + static GSocketAddress * +-cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len); ++cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len); + + static gssize + g_socket_receive_message_with_timeout (GSocket *socket, +@@ -260,7 +261,7 @@ struct _GSocketPrivate + struct { + GSocketAddress *addr; + struct sockaddr *native; +- gint native_len; ++ gsize native_len; + guint64 last_used; + } recv_addr_cache[RECV_ADDR_CACHE_SIZE]; + }; +@@ -5259,14 +5260,14 @@ g_socket_send_messages_with_timeout (GSo + } + + static GSocketAddress * +-cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len) ++cache_recv_address (GSocket *socket, struct sockaddr *native, size_t native_len) + { + GSocketAddress *saddr; + gint i; + guint64 oldest_time = G_MAXUINT64; + gint oldest_index = 0; + +- if (native_len <= 0) ++ if (native_len == 0) + return NULL; + + saddr = NULL; +@@ -5274,7 +5275,7 @@ cache_recv_address (GSocket *socket, str + { + GSocketAddress *tmp = socket->priv->recv_addr_cache[i].addr; + gpointer tmp_native = socket->priv->recv_addr_cache[i].native; +- gint tmp_native_len = socket->priv->recv_addr_cache[i].native_len; ++ gsize tmp_native_len = socket->priv->recv_addr_cache[i].native_len; + + if (!tmp) + continue; +@@ -5304,7 +5305,7 @@ cache_recv_address (GSocket *socket, str + g_free (socket->priv->recv_addr_cache[oldest_index].native); + } + +- socket->priv->recv_addr_cache[oldest_index].native = g_memdup (native, native_len); ++ socket->priv->recv_addr_cache[oldest_index].native = g_memdup2 (native, native_len); + socket->priv->recv_addr_cache[oldest_index].native_len = native_len; + socket->priv->recv_addr_cache[oldest_index].addr = g_object_ref (saddr); + socket->priv->recv_addr_cache[oldest_index].last_used = g_get_monotonic_time (); +@@ -5452,6 +5453,9 @@ g_socket_receive_message_with_timeout (G + /* do it */ + while (1) + { ++ /* addrlen has to be of type int because that’s how WSARecvFrom() is defined */ ++ G_STATIC_ASSERT (sizeof addr <= G_MAXINT); ++ + addrlen = sizeof addr; + if (address) + result = WSARecvFrom (socket->priv->fd, diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-10.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-10.patch new file mode 100644 index 0000000000..63fda0b600 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-10.patch @@ -0,0 +1,59 @@ +From 777b95a88f006d39d9fe6d3321db17e7b0d4b9a4 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 14:07:39 +0000 +Subject: [PATCH 10/11] gtlspassword: Forbid very long TLS passwords +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The public API `g_tls_password_set_value_full()` (and the vfunc it +invokes) can only accept a `gssize` length. Ensure that nul-terminated +strings passed to `g_tls_password_set_value()` can’t exceed that length. +Use `g_memdup2()` to avoid an overflow if they’re longer than +`G_MAXUINT` similarly. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gtlspassword.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/gio/gtlspassword.c b/gio/gtlspassword.c +index 1e437a7b6..dbcec41a8 100644 +--- a/gio/gtlspassword.c ++++ b/gio/gtlspassword.c +@@ -23,6 +23,7 @@ + #include "glibintl.h" + + #include "gioenumtypes.h" ++#include "gstrfuncsprivate.h" + #include "gtlspassword.h" + + #include <string.h> +@@ -287,9 +288,14 @@ g_tls_password_set_value (GTlsPassword *password, + g_return_if_fail (G_IS_TLS_PASSWORD (password)); + + if (length < 0) +- length = strlen ((gchar *)value); ++ { ++ /* FIXME: g_tls_password_set_value_full() doesn’t support unsigned gsize */ ++ gsize length_unsigned = strlen ((gchar *) value); ++ g_return_if_fail (length_unsigned > G_MAXSSIZE); ++ length = (gssize) length_unsigned; ++ } + +- g_tls_password_set_value_full (password, g_memdup (value, length), length, g_free); ++ g_tls_password_set_value_full (password, g_memdup2 (value, (gsize) length), length, g_free); + } + + /** +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-11.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-11.patch new file mode 100644 index 0000000000..a620a49269 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-11.patch @@ -0,0 +1,63 @@ +From ecdf91400e9a538695a0895b95ad7e8abcdf1749 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 4 Feb 2021 14:09:40 +0000 +Subject: [PATCH 11/11] giochannel: Forbid very long line terminator strings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The public API `GIOChannel.line_term_len` is only a `guint`. Ensure that +nul-terminated strings passed to `g_io_channel_set_line_term()` can’t +exceed that length. Use `g_memdup2()` to avoid a warning (`g_memdup()` +is due to be deprecated), but not to avoid a bug, since it’s also +limited to `G_MAXUINT`. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> +Helps: #2319 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + glib/giochannel.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/glib/giochannel.c b/glib/giochannel.c +index c6a89d6e0..4dec20f77 100644 +--- a/glib/giochannel.c ++++ b/glib/giochannel.c +@@ -887,16 +887,25 @@ g_io_channel_set_line_term (GIOChannel *channel, + const gchar *line_term, + gint length) + { ++ guint length_unsigned; ++ + g_return_if_fail (channel != NULL); + g_return_if_fail (line_term == NULL || length != 0); /* Disallow "" */ + + if (line_term == NULL) +- length = 0; +- else if (length < 0) +- length = strlen (line_term); ++ length_unsigned = 0; ++ else if (length >= 0) ++ length_unsigned = (guint) length; ++ else ++ { ++ /* FIXME: We’re constrained by line_term_len being a guint here */ ++ gsize length_size = strlen (line_term); ++ g_return_if_fail (length_size > G_MAXUINT); ++ length_unsigned = (guint) length_size; ++ } + + g_free (channel->line_term); +- channel->line_term = line_term ? g_memdup (line_term, length) : NULL; ++ channel->line_term = line_term ? g_memdup2 (line_term, length_unsigned) : NULL; + channel->line_term_len = length; + } + +-- +GitLab + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-1.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-1.patch new file mode 100644 index 0000000000..3047062f54 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-1.patch @@ -0,0 +1,36 @@ +From f8273b9aded135fe07094faebd527e43851aaf6e Mon Sep 17 00:00:00 2001 +From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com> +Date: Sun, 7 Feb 2021 23:32:40 +0100 +Subject: [PATCH 1/5] giochannel: Fix length_size bounds check + +The inverted condition is an obvious error introduced by ecdf91400e9a. + +Fixes https://gitlab.gnome.org/GNOME/glib/-/issues/2323 + +(cherry picked from commit a149bf2f9030168051942124536e303af8ba6176) + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + glib/giochannel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/giochannel.c b/glib/giochannel.c +index 4dec20f77..c3f3102ff 100644 +--- a/glib/giochannel.c ++++ b/glib/giochannel.c +@@ -896,7 +896,7 @@ g_io_channel_set_line_term (GIOChannel *channel, + { + /* FIXME: We’re constrained by line_term_len being a guint here */ + gsize length_size = strlen (line_term); +- g_return_if_fail (length_size > G_MAXUINT); ++ g_return_if_fail (length_size <= G_MAXUINT); + length_unsigned = (guint) length_size; + } + +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-2.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-2.patch new file mode 100644 index 0000000000..2ba26075df --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-2.patch @@ -0,0 +1,38 @@ +From e069c50467712e6d607822afd6b6c15c2c343dff Mon Sep 17 00:00:00 2001 +From: Simon McVittie <smcv@collabora.com> +Date: Mon, 8 Feb 2021 10:34:50 +0000 +Subject: [PATCH 2/5] giochannel: Don't store negative line_term_len in + GIOChannel struct + +Adding test coverage indicated that this was another bug in 0cc11f74. + +Fixes: 0cc11f74 "giochannel: Forbid very long line terminator strings" +Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2323 +Signed-off-by: Simon McVittie <smcv@collabora.com> +(cherry picked from commit 5dc8b0014c03e7491d93b90275ab442e888a9628) + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + glib/giochannel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/glib/giochannel.c b/glib/giochannel.c +index c3f3102ff..19bb06ba6 100644 +--- a/glib/giochannel.c ++++ b/glib/giochannel.c +@@ -902,7 +902,7 @@ g_io_channel_set_line_term (GIOChannel *channel, + + g_free (channel->line_term); + channel->line_term = line_term ? g_memdup2 (line_term, length_unsigned) : NULL; +- channel->line_term_len = length; ++ channel->line_term_len = length_unsigned; + } + + /** +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-4.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-4.patch new file mode 100644 index 0000000000..2c388b4bbb --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-4.patch @@ -0,0 +1,38 @@ +From 4506d1859a863087598c8d122740bae25b65b099 Mon Sep 17 00:00:00 2001 +From: Simon McVittie <smcv@collabora.com> +Date: Mon, 8 Feb 2021 10:04:48 +0000 +Subject: [PATCH 4/5] gtlspassword: Fix inverted assertion + +The intention here was to assert that the length of the password fits +in a gssize. Passwords more than half the size of virtual memory are +probably excessive. + +Fixes: a8b204ff "gtlspassword: Forbid very long TLS passwords" +Signed-off-by: Simon McVittie <smcv@collabora.com> +(cherry picked from commit 61bb52ec42de1082bfb06ce1c737fc295bfe60b8) + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gtlspassword.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gio/gtlspassword.c b/gio/gtlspassword.c +index dbcec41a8..bd86a6dfe 100644 +--- a/gio/gtlspassword.c ++++ b/gio/gtlspassword.c +@@ -291,7 +291,7 @@ g_tls_password_set_value (GTlsPassword *password, + { + /* FIXME: g_tls_password_set_value_full() doesn’t support unsigned gsize */ + gsize length_unsigned = strlen ((gchar *) value); +- g_return_if_fail (length_unsigned > G_MAXSSIZE); ++ g_return_if_fail (length_unsigned <= G_MAXSSIZE); + length = (gssize) length_unsigned; + } + +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-5.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-5.patch new file mode 100644 index 0000000000..356e986fe0 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg1-5.patch @@ -0,0 +1,100 @@ +From 3d1550354c3c6a8491c39881752d51cb7515f2c2 Mon Sep 17 00:00:00 2001 +From: Simon McVittie <smcv@collabora.com> +Date: Mon, 8 Feb 2021 10:22:39 +0000 +Subject: [PATCH 5/5] tls-interaction: Add test coverage for various ways to + set the password + +Signed-off-by: Simon McVittie <smcv@collabora.com> +(cherry picked from commit df4501316ca3903072400504a5ea76498db19538) + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/tests/tls-interaction.c | 55 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/gio/tests/tls-interaction.c b/gio/tests/tls-interaction.c +index 4f0737d7e..5661e8e0d 100644 +--- a/gio/tests/tls-interaction.c ++++ b/gio/tests/tls-interaction.c +@@ -174,6 +174,38 @@ test_interaction_ask_password_finish_failure (GTlsInteraction *interaction, + } + + ++/* Return a copy of @str that is allocated in a silly way, to exercise ++ * custom free-functions. The returned pointer points to a copy of @str ++ * in a buffer of the form "BEFORE \0 str \0 AFTER". */ ++static guchar * ++special_dup (const char *str) ++{ ++ GString *buf = g_string_new ("BEFORE"); ++ guchar *ret; ++ ++ g_string_append_c (buf, '\0'); ++ g_string_append (buf, str); ++ g_string_append_c (buf, '\0'); ++ g_string_append (buf, "AFTER"); ++ ret = (guchar *) g_string_free (buf, FALSE); ++ return ret + strlen ("BEFORE") + 1; ++} ++ ++ ++/* Free a copy of @str that was made with special_dup(), after asserting ++ * that it has not been corrupted. */ ++static void ++special_free (gpointer p) ++{ ++ gchar *s = p; ++ gchar *buf = s - strlen ("BEFORE") - 1; ++ ++ g_assert_cmpstr (buf, ==, "BEFORE"); ++ g_assert_cmpstr (s + strlen (s) + 1, ==, "AFTER"); ++ g_free (buf); ++} ++ ++ + static GTlsInteractionResult + test_interaction_ask_password_sync_success (GTlsInteraction *interaction, + GTlsPassword *password, +@@ -181,6 +213,8 @@ test_interaction_ask_password_sync_success (GTlsInteraction *interaction, + GError **error) + { + TestInteraction *self; ++ const guchar *value; ++ gsize len; + + g_assert (TEST_IS_INTERACTION (interaction)); + self = TEST_INTERACTION (interaction); +@@ -192,6 +226,27 @@ test_interaction_ask_password_sync_success (GTlsInteraction *interaction, + g_assert (error != NULL); + g_assert (*error == NULL); + ++ /* Exercise different ways to set the value */ ++ g_tls_password_set_value (password, (const guchar *) "foo", 4); ++ len = 0; ++ value = g_tls_password_get_value (password, &len); ++ g_assert_cmpmem (value, len, "foo", 4); ++ ++ g_tls_password_set_value (password, (const guchar *) "bar", -1); ++ len = 0; ++ value = g_tls_password_get_value (password, &len); ++ g_assert_cmpmem (value, len, "bar", 3); ++ ++ g_tls_password_set_value_full (password, special_dup ("baa"), 4, special_free); ++ len = 0; ++ value = g_tls_password_get_value (password, &len); ++ g_assert_cmpmem (value, len, "baa", 4); ++ ++ g_tls_password_set_value_full (password, special_dup ("baz"), -1, special_free); ++ len = 0; ++ value = g_tls_password_get_value (password, &len); ++ g_assert_cmpmem (value, len, "baz", 3); ++ + /* Don't do this in real life. Include a null terminator for testing */ + g_tls_password_set_value (password, (const guchar *)"the password", 13); + return G_TLS_INTERACTION_HANDLED; +-- +GitLab + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-1.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-1.patch new file mode 100644 index 0000000000..dd43689aae --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-1.patch @@ -0,0 +1,49 @@ +From cb9ee701ef46c1819eed4e2a4dc181682bdfc176 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 10 Feb 2021 21:16:39 +0000 +Subject: [PATCH 1/3] gkeyfilesettingsbackend: Fix basename handling when group + is unset + +Fix an effective regression in commit +7781a9cbd2fd0aa84bee0f4eee88470640ff6706, which happens when +`convert_path()` is called with a `key` which contains no slashes. In +that case, the `key` is entirely the `basename`. + +Prior to commit 7781a9cb, the code worked through a fluke of `i == -1` +cancelling out with the various additions in the `g_memdup()` call, and +effectively resulting in `g_strdup (key)`. + +Spotted by Guido Berhoerster. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gkeyfilesettingsbackend.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c +index 25b057672..861c3a661 100644 +--- a/gio/gkeyfilesettingsbackend.c ++++ b/gio/gkeyfilesettingsbackend.c +@@ -185,7 +185,12 @@ convert_path (GKeyfileSettingsBackend *kfsb, + } + + if (basename) +- *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key)); ++ { ++ if (last_slash != NULL) ++ *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key)); ++ else ++ *basename = g_strdup (key); ++ } + + return TRUE; + } +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-2.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-2.patch new file mode 100644 index 0000000000..04503641c3 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-2.patch @@ -0,0 +1,43 @@ +From 31e0d403ba635dbbacbfbff74295e5db02558d76 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 10 Feb 2021 21:19:30 +0000 +Subject: [PATCH 2/3] gkeyfilesettingsbackend: Disallow empty key or group + names + +These should never have been allowed; they will result in precondition +failures from the `GKeyFile` later on in the code. + +A test will be added for this shortly. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/gkeyfilesettingsbackend.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c +index 861c3a661..de216e615 100644 +--- a/gio/gkeyfilesettingsbackend.c ++++ b/gio/gkeyfilesettingsbackend.c +@@ -158,6 +158,13 @@ convert_path (GKeyfileSettingsBackend *kfsb, + + last_slash = strrchr (key, '/'); + ++ /* Disallow empty group names or key names */ ++ if (key_len == 0 || ++ (last_slash != NULL && ++ (*(last_slash + 1) == '\0' || ++ last_slash == key))) ++ return FALSE; ++ + if (kfsb->root_group) + { + /* if a root_group was specified, make sure the user hasn't given +-- +GitLab + + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-3.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-3.patch new file mode 100644 index 0000000000..65f59287a8 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-27219-reg2-3.patch @@ -0,0 +1,232 @@ +Backport of: + +From 221c26685354dea2b2732df94404e8e5e77a1591 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 10 Feb 2021 21:21:36 +0000 +Subject: [PATCH 3/3] tests: Add tests for key name handling in the keyfile + backend + +This tests the two recent commits. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-27219 +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/tests/gsettings.c | 170 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 169 insertions(+), 1 deletion(-) + +--- a/gio/tests/gsettings.c ++++ b/gio/tests/gsettings.c +@@ -1,3 +1,4 @@ ++#include <errno.h> + #include <stdlib.h> + #include <locale.h> + #include <libintl.h> +@@ -1740,6 +1741,14 @@ key_changed_cb (GSettings *settings, con + (*b) = TRUE; + } + ++typedef struct ++{ ++ const gchar *path; ++ const gchar *root_group; ++ const gchar *keyfile_group; ++ const gchar *root_path; ++} KeyfileTestData; ++ + /* + * Test that using a keyfile works + */ +@@ -1834,7 +1843,11 @@ test_keyfile (Fixture *fixture, + g_free (str); + + g_settings_set (settings, "farewell", "s", "cheerio"); +- ++ ++ /* Check that empty keys/groups are not allowed. */ ++ g_assert_false (g_settings_is_writable (settings, "")); ++ g_assert_false (g_settings_is_writable (settings, "/")); ++ + /* When executing as root, changing the mode of the keyfile will have + * no effect on the writability of the settings. + */ +@@ -1866,6 +1879,149 @@ test_keyfile (Fixture *fixture, + g_free (keyfile_path); + } + ++/* ++ * Test that using a keyfile works with a schema with no path set. ++ */ ++static void ++test_keyfile_no_path (Fixture *fixture, ++ gconstpointer user_data) ++{ ++ const KeyfileTestData *test_data = user_data; ++ GSettingsBackend *kf_backend; ++ GSettings *settings; ++ GKeyFile *keyfile; ++ gboolean writable; ++ gchar *key = NULL; ++ GError *error = NULL; ++ gchar *keyfile_path = NULL, *store_path = NULL; ++ ++ keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL); ++ store_path = g_build_filename (keyfile_path, "gsettings.store", NULL); ++ kf_backend = g_keyfile_settings_backend_new (store_path, test_data->root_path, test_data->root_group); ++ settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, test_data->path); ++ g_object_unref (kf_backend); ++ ++ g_settings_reset (settings, "test-boolean"); ++ g_assert_true (g_settings_get_boolean (settings, "test-boolean")); ++ ++ writable = g_settings_is_writable (settings, "test-boolean"); ++ g_assert_true (writable); ++ g_settings_set (settings, "test-boolean", "b", FALSE); ++ ++ g_assert_false (g_settings_get_boolean (settings, "test-boolean")); ++ ++ g_settings_delay (settings); ++ g_settings_set (settings, "test-boolean", "b", TRUE); ++ g_settings_apply (settings); ++ ++ keyfile = g_key_file_new (); ++ g_assert_true (g_key_file_load_from_file (keyfile, store_path, 0, NULL)); ++ ++ g_assert_true (g_key_file_get_boolean (keyfile, test_data->keyfile_group, "test-boolean", NULL)); ++ ++ g_key_file_free (keyfile); ++ ++ g_settings_reset (settings, "test-boolean"); ++ g_settings_apply (settings); ++ keyfile = g_key_file_new (); ++ g_assert_true (g_key_file_load_from_file (keyfile, store_path, 0, NULL)); ++ ++ g_assert_false (g_key_file_get_string (keyfile, test_data->keyfile_group, "test-boolean", &error)); ++ g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND); ++ g_clear_error (&error); ++ ++ /* Check that empty keys/groups are not allowed. */ ++ g_assert_false (g_settings_is_writable (settings, "")); ++ g_assert_false (g_settings_is_writable (settings, "/")); ++ ++ /* Keys which ghost the root group name are not allowed. This can only be ++ * tested when the path is `/` as otherwise it acts as a prefix and prevents ++ * any ghosting. */ ++ if (g_str_equal (test_data->path, "/")) ++ { ++ key = g_strdup_printf ("%s/%s", test_data->root_group, ""); ++ g_assert_false (g_settings_is_writable (settings, key)); ++ g_free (key); ++ ++ key = g_strdup_printf ("%s/%s", test_data->root_group, "/"); ++ g_assert_false (g_settings_is_writable (settings, key)); ++ g_free (key); ++ ++ key = g_strdup_printf ("%s/%s", test_data->root_group, "test-boolean"); ++ g_assert_false (g_settings_is_writable (settings, key)); ++ g_free (key); ++ } ++ ++ g_key_file_free (keyfile); ++ g_object_unref (settings); ++ ++ /* Clean up the temporary directory. */ ++ g_assert_cmpint (g_chmod (keyfile_path, 0777) == 0 ? 0 : errno, ==, 0); ++ g_assert_cmpint (g_remove (store_path) == 0 ? 0 : errno, ==, 0); ++ g_assert_cmpint (g_rmdir (keyfile_path) == 0 ? 0 : errno, ==, 0); ++ g_free (store_path); ++ g_free (keyfile_path); ++} ++ ++/* ++ * Test that a keyfile rejects writes to keys outside its root path. ++ */ ++static void ++test_keyfile_outside_root_path (Fixture *fixture, ++ gconstpointer user_data) ++{ ++ GSettingsBackend *kf_backend; ++ GSettings *settings; ++ gchar *keyfile_path = NULL, *store_path = NULL; ++ ++ keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL); ++ store_path = g_build_filename (keyfile_path, "gsettings.store", NULL); ++ kf_backend = g_keyfile_settings_backend_new (store_path, "/tests/basic-types/", "root"); ++ settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, "/tests/"); ++ g_object_unref (kf_backend); ++ ++ g_assert_false (g_settings_is_writable (settings, "test-boolean")); ++ ++ g_object_unref (settings); ++ ++ /* Clean up the temporary directory. The keyfile probably doesn’t exist, so ++ * don’t error on failure. */ ++ g_remove (store_path); ++ g_assert_cmpint (g_rmdir (keyfile_path) == 0 ? 0 : errno, ==, 0); ++ g_free (store_path); ++ g_free (keyfile_path); ++} ++ ++/* ++ * Test that a keyfile rejects writes to keys in the root if no root group is set. ++ */ ++static void ++test_keyfile_no_root_group (Fixture *fixture, ++ gconstpointer user_data) ++{ ++ GSettingsBackend *kf_backend; ++ GSettings *settings; ++ gchar *keyfile_path = NULL, *store_path = NULL; ++ ++ keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL); ++ store_path = g_build_filename (keyfile_path, "gsettings.store", NULL); ++ kf_backend = g_keyfile_settings_backend_new (store_path, "/", NULL); ++ settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, "/"); ++ g_object_unref (kf_backend); ++ ++ g_assert_false (g_settings_is_writable (settings, "test-boolean")); ++ g_assert_true (g_settings_is_writable (settings, "child/test-boolean")); ++ ++ g_object_unref (settings); ++ ++ /* Clean up the temporary directory. The keyfile probably doesn’t exist, so ++ * don’t error on failure. */ ++ g_remove (store_path); ++ g_assert_cmpint (g_rmdir (keyfile_path) == 0 ? 0 : errno, ==, 0); ++ g_free (store_path); ++ g_free (keyfile_path); ++} ++ + /* Test that getting child schemas works + */ + static void +@@ -2844,6 +3000,14 @@ main (int argc, char *argv[]) + gchar *override_text; + gchar *enums; + gint result; ++ const KeyfileTestData keyfile_test_data_explicit_path = { "/tests/", "root", "tests", "/" }; ++ const KeyfileTestData keyfile_test_data_empty_path = { "/", "root", "root", "/" }; ++ const KeyfileTestData keyfile_test_data_long_path = { ++ "/tests/path/is/very/long/and/this/makes/some/comparisons/take/a/different/branch/", ++ "root", ++ "tests/path/is/very/long/and/this/makes/some/comparisons/take/a/different/branch", ++ "/" ++ }; + + /* Meson build sets this */ + #ifdef TEST_LOCALE_PATH +@@ -2967,6 +3131,11 @@ main (int argc, char *argv[]) + } + + g_test_add ("/gsettings/keyfile", Fixture, NULL, setup, test_keyfile, teardown); ++ g_test_add ("/gsettings/keyfile/explicit-path", Fixture, &keyfile_test_data_explicit_path, setup, test_keyfile_no_path, teardown); ++ g_test_add ("/gsettings/keyfile/empty-path", Fixture, &keyfile_test_data_empty_path, setup, test_keyfile_no_path, teardown); ++ g_test_add ("/gsettings/keyfile/long-path", Fixture, &keyfile_test_data_long_path, setup, test_keyfile_no_path, teardown); ++ g_test_add ("/gsettings/keyfile/outside-root-path", Fixture, NULL, setup, test_keyfile_outside_root_path, teardown); ++ g_test_add ("/gsettings/keyfile/no-root-group", Fixture, NULL, setup, test_keyfile_no_root_group, teardown); + g_test_add_func ("/gsettings/child-schema", test_child_schema); + g_test_add_func ("/gsettings/strinfo", test_strinfo); + g_test_add_func ("/gsettings/enums", test_enums); diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-1.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-1.patch new file mode 100644 index 0000000000..c89ca20726 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-1.patch @@ -0,0 +1,27 @@ +From 78420a75aeb70569a8cd79fa0fea7b786b6f785f Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 24 Feb 2021 17:33:38 +0000 +Subject: [PATCH 1/5] glocalfileoutputstream: Fix a typo in a comment + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-28153 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/glocalfileoutputstream.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -851,7 +851,7 @@ handle_overwrite_open (const char *fi + mode = mode_from_flags_or_info (flags, reference_info); + + /* We only need read access to the original file if we are creating a backup. +- * We also add O_CREATE to avoid a race if the file was just removed */ ++ * We also add O_CREAT to avoid a race if the file was just removed */ + if (create_backup || readable) + open_flags = O_RDWR | O_CREAT | O_BINARY; + else diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-2.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-2.patch new file mode 100644 index 0000000000..8a35bab4de --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-2.patch @@ -0,0 +1,42 @@ +From 32d3d02a50e7dcec5f4cf7908e7ac88d575d8fc5 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 24 Feb 2021 17:34:32 +0000 +Subject: [PATCH 2/5] tests: Stop using g_test_bug_base() in file tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since a following commit is going to add a new test which references +Gitlab, so it’s best to move the URI bases inside the test cases. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-28153 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/tests/file.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/gio/tests/file.c ++++ b/gio/tests/file.c +@@ -685,7 +685,7 @@ test_replace_cancel (void) + guint count; + GError *error = NULL; + +- g_test_bug ("629301"); ++ g_test_bug ("https://bugzilla.gnome.org/629301"); + + path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error); + g_assert_no_error (error); +@@ -1784,8 +1784,6 @@ main (int argc, char *argv[]) + { + g_test_init (&argc, &argv, NULL); + +- g_test_bug_base ("http://bugzilla.gnome.org/"); +- + g_test_add_func ("/file/basic", test_basic); + g_test_add_func ("/file/build-filename", test_build_filename); + g_test_add_func ("/file/parent", test_parent); diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-3.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-3.patch new file mode 100644 index 0000000000..a82febd26e --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-3.patch @@ -0,0 +1,57 @@ +Backport of: + +From ce0eb088a68171eed3ac217cb92a72e36eb57d1b Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 10 Mar 2021 16:05:55 +0000 +Subject: [PATCH 3/5] glocalfileoutputstream: Factor out a flag check + +This clarifies the code a little. It introduces no functional changes. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-28153 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/glocalfileoutputstream.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -847,6 +847,7 @@ handle_overwrite_open (const char *fi + int res; + int mode; + int errsv; ++ gboolean replace_destination_set = (flags & G_FILE_CREATE_REPLACE_DESTINATION); + + mode = mode_from_flags_or_info (flags, reference_info); + +@@ -954,7 +955,7 @@ handle_overwrite_open (const char *fi + * to a backup file and rewrite the contents of the file. + */ + +- if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) || ++ if (replace_destination_set || + (!(original_stat.st_nlink > 1) && !is_symlink)) + { + char *dirname, *tmp_filename; +@@ -973,7 +974,7 @@ handle_overwrite_open (const char *fi + + /* try to keep permissions (unless replacing) */ + +- if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) && ++ if (!replace_destination_set && + ( + #ifdef HAVE_FCHOWN + fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 || +@@ -1112,7 +1113,7 @@ handle_overwrite_open (const char *fi + } + } + +- if (flags & G_FILE_CREATE_REPLACE_DESTINATION) ++ if (replace_destination_set) + { + g_close (fd, NULL); + diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-4.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-4.patch new file mode 100644 index 0000000000..5b106e8474 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-4.patch @@ -0,0 +1,265 @@ +Backport of: + +From 317b3b587058a05dca95d56dac26568c5b098d33 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 24 Feb 2021 17:36:07 +0000 +Subject: [PATCH 4/5] glocalfileoutputstream: Fix CREATE_REPLACE_DESTINATION + with symlinks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The `G_FILE_CREATE_REPLACE_DESTINATION` flag is equivalent to unlinking +the destination file and re-creating it from scratch. That did +previously work, but in the process the code would call `open(O_CREAT)` +on the file. If the file was a dangling symlink, this would create the +destination file (empty). That’s not an intended side-effect, and has +security implications if the symlink is controlled by a lower-privileged +process. + +Fix that by not opening the destination file if it’s a symlink, and +adjusting the rest of the code to cope with + - the fact that `fd == -1` is not an error iff `is_symlink` is true, + - and that `original_stat` will contain the `lstat()` results for the + symlink now, rather than the `stat()` results for its target (again, + iff `is_symlink` is true). + +This means that the target of the dangling symlink is no longer created, +which was the bug. The symlink itself continues to be replaced (as +before) with the new file — this is the intended behaviour of +`g_file_replace()`. + +The behaviour for non-symlink cases, or cases where the symlink was not +dangling, should be unchanged. + +Includes a unit test. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Fixes: #2325 + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-28153 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/glocalfileoutputstream.c | 77 ++++++++++++++++++------- + gio/tests/file.c | 108 +++++++++++++++++++++++++++++++++++ + 2 files changed, 163 insertions(+), 22 deletions(-) + +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -875,16 +875,22 @@ handle_overwrite_open (const char *fi + /* Could be a symlink, or it could be a regular ELOOP error, + * but then the next open will fail too. */ + is_symlink = TRUE; +- fd = g_open (filename, open_flags, mode); ++ if (!replace_destination_set) ++ fd = g_open (filename, open_flags, mode); + } +-#else +- fd = g_open (filename, open_flags, mode); +- errsv = errno; ++#else /* if !O_NOFOLLOW */ + /* This is racy, but we do it as soon as possible to minimize the race */ + is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK); ++ ++ if (!is_symlink || !replace_destination_set) ++ { ++ fd = g_open (filename, open_flags, mode); ++ errsv = errno; ++ } + #endif + +- if (fd == -1) ++ if (fd == -1 && ++ (!is_symlink || !replace_destination_set)) + { + char *display_name = g_filename_display_name (filename); + g_set_error (error, G_IO_ERROR, +@@ -898,7 +904,14 @@ handle_overwrite_open (const char *fi + #ifdef G_OS_WIN32 + res = GLIB_PRIVATE_CALL (g_win32_fstat) (fd, &original_stat); + #else +- res = fstat (fd, &original_stat); ++ if (!is_symlink) ++ { ++ res = fstat (fd, &original_stat); ++ } ++ else ++ { ++ res = lstat (filename, &original_stat); ++ } + #endif + errsv = errno; + +@@ -917,16 +930,27 @@ handle_overwrite_open (const char *fi + if (!S_ISREG (original_stat.st_mode)) + { + if (S_ISDIR (original_stat.st_mode)) +- g_set_error_literal (error, +- G_IO_ERROR, +- G_IO_ERROR_IS_DIRECTORY, +- _("Target file is a directory")); +- else +- g_set_error_literal (error, ++ { ++ g_set_error_literal (error, ++ G_IO_ERROR, ++ G_IO_ERROR_IS_DIRECTORY, ++ _("Target file is a directory")); ++ goto err_out; ++ } ++ else if (!is_symlink || ++#ifdef S_ISLNK ++ !S_ISLNK (original_stat.st_mode) ++#else ++ FALSE ++#endif ++ ) ++ { ++ g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_REGULAR_FILE, + _("Target file is not a regular file")); +- goto err_out; ++ goto err_out; ++ } + } + + if (etag != NULL) +@@ -1007,7 +1031,8 @@ handle_overwrite_open (const char *fi + } + } + +- g_close (fd, NULL); ++ if (fd >= 0) ++ g_close (fd, NULL); + *temp_filename = tmp_filename; + return tmpfd; + } +--- a/gio/tests/file.c ++++ b/gio/tests/file.c +@@ -804,6 +804,113 @@ test_replace_cancel (void) + g_object_unref (tmpdir); + } + ++static void ++test_replace_symlink (void) ++{ ++#ifdef G_OS_UNIX ++ gchar *tmpdir_path = NULL; ++ GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL; ++ GFileOutputStream *stream = NULL; ++ const gchar *new_contents = "this is a test message which should be written to source and not target"; ++ gsize n_written; ++ GFileEnumerator *enumerator = NULL; ++ GFileInfo *info = NULL; ++ gchar *contents = NULL; ++ gsize length = 0; ++ GError *local_error = NULL; ++ ++ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2325"); ++ g_test_summary ("Test that G_FILE_CREATE_REPLACE_DESTINATION doesn’t follow symlinks"); ++ ++ /* Create a fresh, empty working directory. */ ++ tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error); ++ g_assert_no_error (local_error); ++ tmpdir = g_file_new_for_path (tmpdir_path); ++ ++ g_test_message ("Using temporary directory %s", tmpdir_path); ++ g_free (tmpdir_path); ++ ++ /* Create symlink `source` which points to `target`. */ ++ source_file = g_file_get_child (tmpdir, "source"); ++ target_file = g_file_get_child (tmpdir, "target"); ++ g_file_make_symbolic_link (source_file, "target", NULL, &local_error); ++ g_assert_no_error (local_error); ++ ++ /* Ensure that `target` doesn’t exist */ ++ g_assert_false (g_file_query_exists (target_file, NULL)); ++ ++ /* Replace the `source` symlink with a regular file using ++ * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without* ++ * following the symlink */ ++ stream = g_file_replace (source_file, NULL, FALSE /* no backup */, ++ G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error); ++ g_assert_no_error (local_error); ++ ++ g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents), ++ &n_written, NULL, &local_error); ++ g_assert_no_error (local_error); ++ g_assert_cmpint (n_written, ==, strlen (new_contents)); ++ ++ g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error); ++ g_assert_no_error (local_error); ++ ++ g_clear_object (&stream); ++ ++ /* At this point, there should still only be one file: `source`. It should ++ * now be a regular file. `target` should not exist. */ ++ enumerator = g_file_enumerate_children (tmpdir, ++ G_FILE_ATTRIBUTE_STANDARD_NAME "," ++ G_FILE_ATTRIBUTE_STANDARD_TYPE, ++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error); ++ g_assert_no_error (local_error); ++ ++ info = g_file_enumerator_next_file (enumerator, NULL, &local_error); ++ g_assert_no_error (local_error); ++ g_assert_nonnull (info); ++ ++ g_assert_cmpstr (g_file_info_get_name (info), ==, "source"); ++ g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR); ++ ++ g_clear_object (&info); ++ ++ info = g_file_enumerator_next_file (enumerator, NULL, &local_error); ++ g_assert_no_error (local_error); ++ g_assert_null (info); ++ ++ g_file_enumerator_close (enumerator, NULL, &local_error); ++ g_assert_no_error (local_error); ++ g_clear_object (&enumerator); ++ ++ /* Double-check that `target` doesn’t exist */ ++ g_assert_false (g_file_query_exists (target_file, NULL)); ++ ++ /* Check the content of `source`. */ ++ g_file_load_contents (source_file, ++ NULL, ++ &contents, ++ &length, ++ NULL, ++ &local_error); ++ g_assert_no_error (local_error); ++ g_assert_cmpstr (contents, ==, new_contents); ++ g_assert_cmpuint (length, ==, strlen (new_contents)); ++ g_free (contents); ++ ++ /* Tidy up. */ ++ g_file_delete (source_file, NULL, &local_error); ++ g_assert_no_error (local_error); ++ ++ g_file_delete (tmpdir, NULL, &local_error); ++ g_assert_no_error (local_error); ++ ++ g_clear_object (&target_file); ++ g_clear_object (&source_file); ++ g_clear_object (&tmpdir); ++#else /* if !G_OS_UNIX */ ++ g_test_skip ("Symlink replacement tests can only be run on Unix") ++#endif ++} ++ + static void + on_file_deleted (GObject *object, + GAsyncResult *result, +@@ -1752,6 +1859,7 @@ main (int argc, char *argv[]) + g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete); + g_test_add_func ("/file/replace-load", test_replace_load); + g_test_add_func ("/file/replace-cancel", test_replace_cancel); ++ g_test_add_func ("/file/replace-symlink", test_replace_symlink); + g_test_add_func ("/file/async-delete", test_async_delete); + #ifdef G_OS_UNIX + g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode); diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-5.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-5.patch new file mode 100644 index 0000000000..2334147f7d --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2021-28153-5.patch @@ -0,0 +1,55 @@ +From 6c6439261bc7a8a0627519848a7222b3e1bd4ffe Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 24 Feb 2021 17:42:24 +0000 +Subject: [PATCH 5/5] glocalfileoutputstream: Add a missing O_CLOEXEC flag to + replace() + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Upstream-Status: Backport [https://mirrors.ocf.berkeley.edu/ubuntu/pool/main/g/glib2.0/glib2.0_2.64.6-1~ubuntu20.04.3.debian.tar.xz] +CVE: CVE-2021-28153 +Signed-off-by: Neetika Singh <Neetika.Singh@kpit.com> +Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com> + +--- + gio/glocalfileoutputstream.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/gio/glocalfileoutputstream.c ++++ b/gio/glocalfileoutputstream.c +@@ -58,6 +58,12 @@ + #define O_BINARY 0 + #endif + ++#ifndef O_CLOEXEC ++#define O_CLOEXEC 0 ++#else ++#define HAVE_O_CLOEXEC 1 ++#endif ++ + struct _GLocalFileOutputStreamPrivate { + char *tmp_filename; + char *original_filename; +@@ -1223,7 +1229,7 @@ _g_local_file_output_stream_replace (con + sync_on_close = FALSE; + + /* If the file doesn't exist, create it */ +- open_flags = O_CREAT | O_EXCL | O_BINARY; ++ open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC; + if (readable) + open_flags |= O_RDWR; + else +@@ -1253,8 +1259,11 @@ _g_local_file_output_stream_replace (con + set_error_from_open_errno (filename, error); + return NULL; + } +- +- ++#if !defined(HAVE_O_CLOEXEC) && defined(F_SETFD) ++ else ++ fcntl (fd, F_SETFD, FD_CLOEXEC); ++#endif ++ + stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); + stream->priv->fd = fd; + stream->priv->sync_on_close = sync_on_close; 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 @@ +From 5f4485c4ff57fdefb1661531788def7ca5a47328 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 17 Aug 2023 04:19:44 +0000 +Subject: [PATCH] gvariant-serialiser: Check offset table entry size is minimal + +The entries in an offset table (which is used for variable sized arrays +and tuples containing variable sized members) are sized so that they can +address every byte in the overall variant. + +The specification requires that for a variant to be in normal form, its +offset table entries must be the minimum width such that they can +address every byte in the variant. + +That minimality requirement was not checked in +`g_variant_is_normal_form()`, leading to two different byte arrays being +interpreted as the normal form of a given variant tree. That kind of +confusion could potentially be exploited, and is certainly a bug. + +Fix it by adding the necessary checks on offset table entry width, and +unit tests. + +Spotted by William Manley. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Fixes: #2794 + +CVE: CVE-2023-29499 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/5f4485c4ff57fdefb1661531788def7ca5a47328] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-serialiser.c | 19 +++- + glib/tests/gvariant.c | 176 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 194 insertions(+), 1 deletion(-) + +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index 0bf7243..5aa2cbc 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -694,6 +694,10 @@ gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value) + out.data_size = last_end; + out.array = value.data + last_end; + out.length = offsets_array_size / out.offset_size; ++ ++ if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size) ++ return out; /* offset size not minimal */ ++ + out.is_normal = TRUE; + + return out; +@@ -1201,6 +1205,7 @@ gvs_tuple_is_normal (GVariantSerialised value) + gsize length; + gsize offset; + gsize i; ++ gsize offset_table_size; + + /* as per the comment in gvs_tuple_get_child() */ + if G_UNLIKELY (value.data == NULL && value.size != 0) +@@ -1305,7 +1310,19 @@ gvs_tuple_is_normal (GVariantSerialised value) + } + } + +- return offset_ptr == offset; ++ /* @offset_ptr has been counting backwards from the end of the variant, to ++ * find the beginning of the offset table. @offset has been counting forwards ++ * from the beginning of the variant to find the end of the data. They should ++ * have met in the middle. */ ++ if (offset_ptr != offset) ++ return FALSE; ++ ++ offset_table_size = value.size - offset_ptr; ++ if (value.size > 0 && ++ gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size) ++ return FALSE; /* offset size not minimal */ ++ ++ return TRUE; + } + + /* Variants {{{2 +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index d640c81..4ce0e4f 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -5092,6 +5092,86 @@ test_normal_checking_array_offsets2 (void) + g_variant_unref (variant); + } + ++/* Test that an otherwise-valid serialised GVariant is considered non-normal if ++ * its offset table entries are too wide. ++ * ++ * See §2.3.6 (Framing Offsets) of the GVariant specification. */ ++static void ++test_normal_checking_array_offsets_minimal_sized (void) ++{ ++ GVariantBuilder builder; ++ gsize i; ++ GVariant *aay_constructed = NULL; ++ const guint8 *data = NULL; ++ guint8 *data_owned = NULL; ++ GVariant *aay_deserialised = NULL; ++ GVariant *aay_normalised = NULL; ++ ++ /* Construct an array of type aay, consisting of 128 elements which are each ++ * an empty array, i.e. `[[] * 128]`. This is chosen because the inner ++ * elements are variable sized (making the outer array variable sized, so it ++ * must have an offset table), but they are also zero-sized when serialised. ++ * So the serialised representation of @aay_constructed consists entirely of ++ * its offset table, which is entirely zeroes. ++ * ++ * The array is chosen to be 128 elements long because that means offset ++ * table entries which are 1 byte long. If the elements in the array were ++ * non-zero-sized (to the extent that the overall array is ≥256 bytes long), ++ * the offset table entries would end up being 2 bytes long. */ ++ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay")); ++ ++ for (i = 0; i < 128; i++) ++ g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0)); ++ ++ aay_constructed = g_variant_builder_end (&builder); ++ ++ /* Verify that the constructed array is in normal form, and its serialised ++ * form is `b'\0' * 128`. */ ++ g_assert_true (g_variant_is_normal_form (aay_constructed)); ++ g_assert_cmpuint (g_variant_n_children (aay_constructed), ==, 128); ++ g_assert_cmpuint (g_variant_get_size (aay_constructed), ==, 128); ++ ++ data = g_variant_get_data (aay_constructed); ++ for (i = 0; i < g_variant_get_size (aay_constructed); i++) ++ g_assert_cmpuint (data[i], ==, 0); ++ ++ /* Construct a serialised `aay` GVariant which is `b'\0' * 256`. This has to ++ * be a non-normal form of `[[] * 128]`, with 2-byte-long offset table ++ * entries, because each offset table entry has to be able to reference all of ++ * the byte boundaries in the container. All the entries in the offset table ++ * are zero, so all the elements of the array are zero-sized. */ ++ data = data_owned = g_malloc0 (256); ++ aay_deserialised = g_variant_new_from_data (G_VARIANT_TYPE ("aay"), ++ data, ++ 256, ++ FALSE, ++ g_free, ++ g_steal_pointer (&data_owned)); ++ ++ g_assert_false (g_variant_is_normal_form (aay_deserialised)); ++ g_assert_cmpuint (g_variant_n_children (aay_deserialised), ==, 128); ++ g_assert_cmpuint (g_variant_get_size (aay_deserialised), ==, 256); ++ ++ data = g_variant_get_data (aay_deserialised); ++ for (i = 0; i < g_variant_get_size (aay_deserialised); i++) ++ g_assert_cmpuint (data[i], ==, 0); ++ ++ /* Get its normal form. That should change the serialised size. */ ++ aay_normalised = g_variant_get_normal_form (aay_deserialised); ++ ++ g_assert_true (g_variant_is_normal_form (aay_normalised)); ++ g_assert_cmpuint (g_variant_n_children (aay_normalised), ==, 128); ++ g_assert_cmpuint (g_variant_get_size (aay_normalised), ==, 128); ++ ++ data = g_variant_get_data (aay_normalised); ++ for (i = 0; i < g_variant_get_size (aay_normalised); i++) ++ g_assert_cmpuint (data[i], ==, 0); ++ ++ g_variant_unref (aay_normalised); ++ g_variant_unref (aay_deserialised); ++ g_variant_unref (aay_constructed); ++} ++ + /* Test that a tuple with invalidly large values in its offset table is + * normalised successfully without looping infinitely. */ + static void +@@ -5286,6 +5366,98 @@ test_normal_checking_tuple_offsets4 (void) + g_variant_unref (variant); + } + ++/* Test that an otherwise-valid serialised GVariant is considered non-normal if ++ * its offset table entries are too wide. ++ * ++ * See §2.3.6 (Framing Offsets) of the GVariant specification. */ ++static void ++test_normal_checking_tuple_offsets_minimal_sized (void) ++{ ++ GString *type_string = NULL; ++ GVariantBuilder builder; ++ gsize i; ++ GVariant *ray_constructed = NULL; ++ const guint8 *data = NULL; ++ guint8 *data_owned = NULL; ++ GVariant *ray_deserialised = NULL; ++ GVariant *ray_normalised = NULL; ++ ++ /* Construct a tuple of type (ay…ay), consisting of 129 members which are each ++ * an empty array, i.e. `([] * 129)`. This is chosen because the inner ++ * members are variable sized, so the outer tuple must have an offset table, ++ * but they are also zero-sized when serialised. So the serialised ++ * representation of @ray_constructed consists entirely of its offset table, ++ * which is entirely zeroes. ++ * ++ * The tuple is chosen to be 129 members long because that means it has 128 ++ * offset table entries which are 1 byte long each. If the members in the ++ * tuple were non-zero-sized (to the extent that the overall tuple is ≥256 ++ * bytes long), the offset table entries would end up being 2 bytes long. ++ * ++ * 129 members are used unlike 128 array elements in ++ * test_normal_checking_array_offsets_minimal_sized(), because the last member ++ * in a tuple never needs an offset table entry. */ ++ type_string = g_string_new (""); ++ g_string_append_c (type_string, '('); ++ for (i = 0; i < 129; i++) ++ g_string_append (type_string, "ay"); ++ g_string_append_c (type_string, ')'); ++ ++ g_variant_builder_init (&builder, G_VARIANT_TYPE (type_string->str)); ++ ++ for (i = 0; i < 129; i++) ++ g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0)); ++ ++ ray_constructed = g_variant_builder_end (&builder); ++ ++ /* Verify that the constructed tuple is in normal form, and its serialised ++ * form is `b'\0' * 128`. */ ++ g_assert_true (g_variant_is_normal_form (ray_constructed)); ++ g_assert_cmpuint (g_variant_n_children (ray_constructed), ==, 129); ++ g_assert_cmpuint (g_variant_get_size (ray_constructed), ==, 128); ++ ++ data = g_variant_get_data (ray_constructed); ++ for (i = 0; i < g_variant_get_size (ray_constructed); i++) ++ g_assert_cmpuint (data[i], ==, 0); ++ ++ /* Construct a serialised `(ay…ay)` GVariant which is `b'\0' * 256`. This has ++ * to be a non-normal form of `([] * 129)`, with 2-byte-long offset table ++ * entries, because each offset table entry has to be able to reference all of ++ * the byte boundaries in the container. All the entries in the offset table ++ * are zero, so all the members of the tuple are zero-sized. */ ++ data = data_owned = g_malloc0 (256); ++ ray_deserialised = g_variant_new_from_data (G_VARIANT_TYPE (type_string->str), ++ data, ++ 256, ++ FALSE, ++ g_free, ++ g_steal_pointer (&data_owned)); ++ ++ g_assert_false (g_variant_is_normal_form (ray_deserialised)); ++ g_assert_cmpuint (g_variant_n_children (ray_deserialised), ==, 129); ++ g_assert_cmpuint (g_variant_get_size (ray_deserialised), ==, 256); ++ ++ data = g_variant_get_data (ray_deserialised); ++ for (i = 0; i < g_variant_get_size (ray_deserialised); i++) ++ g_assert_cmpuint (data[i], ==, 0); ++ ++ /* Get its normal form. That should change the serialised size. */ ++ ray_normalised = g_variant_get_normal_form (ray_deserialised); ++ ++ g_assert_true (g_variant_is_normal_form (ray_normalised)); ++ g_assert_cmpuint (g_variant_n_children (ray_normalised), ==, 129); ++ g_assert_cmpuint (g_variant_get_size (ray_normalised), ==, 128); ++ ++ data = g_variant_get_data (ray_normalised); ++ for (i = 0; i < g_variant_get_size (ray_normalised); i++) ++ g_assert_cmpuint (data[i], ==, 0); ++ ++ g_variant_unref (ray_normalised); ++ g_variant_unref (ray_deserialised); ++ g_variant_unref (ray_constructed); ++ g_string_free (type_string, TRUE); ++} ++ + /* Test that an empty object path is normalised successfully to the base object + * path, ‘/’. */ + static void +@@ -5431,6 +5603,8 @@ main (int argc, char **argv) + test_normal_checking_array_offsets); + g_test_add_func ("/gvariant/normal-checking/array-offsets2", + test_normal_checking_array_offsets2); ++ g_test_add_func ("/gvariant/normal-checking/array-offsets/minimal-sized", ++ test_normal_checking_array_offsets_minimal_sized); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets", + test_normal_checking_tuple_offsets); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets2", +@@ -5439,6 +5613,8 @@ main (int argc, char **argv) + test_normal_checking_tuple_offsets3); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", + test_normal_checking_tuple_offsets4); ++ g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized", ++ test_normal_checking_tuple_offsets_minimal_sized); + g_test_add_func ("/gvariant/normal-checking/empty-object-path", + test_normal_checking_empty_object_path); + +-- +2.24.4 + 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 @@ +From 1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1 Mon Sep 17 00:00:00 2001 +From: William Manley <will@stb-tester.com> +Date: Wed, 9 Aug 2023 10:04:49 +0000 +Subject: [PATCH] gvariant-core: Consolidate construction of + `GVariantSerialised` + +So I only need to change it in one place. + +This introduces no functional changes. + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant.c | 8 +++++--- + glib/tests/gvariant.c | 24 ++++++++++++++++++++++++ + 2 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/glib/gvariant.c b/glib/gvariant.c +index 8ba701e..4dbd9e8 100644 +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -5952,14 +5952,16 @@ g_variant_byteswap (GVariant *value) + g_variant_serialised_byteswap (serialised); + + bytes = g_bytes_new_take (serialised.data, serialised.size); +- new = g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE); ++ new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE)); + g_bytes_unref (bytes); + } + else + /* contains no multi-byte data */ +- new = value; ++ new = g_variant_get_normal_form (value); + +- return g_variant_ref_sink (new); ++ g_assert (g_variant_is_trusted (new)); ++ ++ return g_steal_pointer (&new); + } + + /** +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index 4ce0e4f..3dda08e 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -3834,6 +3834,29 @@ test_gv_byteswap (void) + g_free (string); + } + ++static void ++test_gv_byteswap_non_normal_non_aligned (void) ++{ ++ const guint8 data[] = { 0x02 }; ++ GVariant *v = NULL; ++ GVariant *v_byteswapped = NULL; ++ ++ g_test_summary ("Test that calling g_variant_byteswap() on a variant which " ++ "is in non-normal form and doesn’t need byteswapping returns " ++ "the same variant in normal form."); ++ ++ v = g_variant_new_from_data (G_VARIANT_TYPE_BOOLEAN, data, sizeof (data), FALSE, NULL, NULL); ++ g_assert_false (g_variant_is_normal_form (v)); ++ ++ v_byteswapped = g_variant_byteswap (v); ++ g_assert_true (g_variant_is_normal_form (v_byteswapped)); ++ ++ g_assert_cmpvariant (v, v_byteswapped); ++ ++ g_variant_unref (v); ++ g_variant_unref (v_byteswapped); ++} ++ + static void + test_parser (void) + { +@@ -5570,6 +5593,7 @@ main (int argc, char **argv) + g_test_add_func ("/gvariant/builder-memory", test_builder_memory); + g_test_add_func ("/gvariant/hashing", test_hashing); + g_test_add_func ("/gvariant/byteswap", test_gv_byteswap); ++ g_test_add_func ("/gvariant/byteswap/non-normal-non-aligned", test_gv_byteswap_non_normal_non_aligned); + g_test_add_func ("/gvariant/parser", test_parses); + g_test_add_func ("/gvariant/parser/integer-bounds", test_parser_integer_bounds); + g_test_add_func ("/gvariant/parser/recursion", test_parser_recursion); +-- +2.24.4 + 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 @@ +From 446e69f5edd72deb2196dee36bbaf8056caf6948 Mon Sep 17 00:00:00 2001 +From: William Manley <will@stb-tester.com> +Date: Wed, 9 Aug 2023 10:39:34 +0000 +Subject: [PATCH] gvariant-serialiser: Factor out functions for dealing with + framing offsets + +This introduces no functional changes. + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/446e69f5edd72deb2196dee36bbaf8056caf6948] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant.c | 81 +++++++++++++++++++++++++++++++++---------- + glib/tests/gvariant.c | 57 ++++++++++++++++++++++++++---- + 2 files changed, 112 insertions(+), 26 deletions(-) + +diff --git a/glib/gvariant.c b/glib/gvariant.c +index 4dbd9e8..a80c2c9 100644 +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -5788,7 +5788,8 @@ g_variant_iter_loop (GVariantIter *iter, + + /* Serialised data {{{1 */ + static GVariant * +-g_variant_deep_copy (GVariant *value) ++g_variant_deep_copy (GVariant *value, ++ gboolean byteswap) + { + switch (g_variant_classify (value)) + { +@@ -5806,7 +5807,7 @@ g_variant_deep_copy (GVariant *value) + for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++) + { + GVariant *child = g_variant_get_child_value (value, i); +- g_variant_builder_add_value (&builder, g_variant_deep_copy (child)); ++ g_variant_builder_add_value (&builder, g_variant_deep_copy (child, byteswap)); + g_variant_unref (child); + } + +@@ -5820,28 +5821,63 @@ g_variant_deep_copy (GVariant *value) + return g_variant_new_byte (g_variant_get_byte (value)); + + case G_VARIANT_CLASS_INT16: +- return g_variant_new_int16 (g_variant_get_int16 (value)); ++ if (byteswap) ++ return g_variant_new_int16 (GUINT16_SWAP_LE_BE (g_variant_get_int16 (value))); ++ else ++ return g_variant_new_int16 (g_variant_get_int16 (value)); + + case G_VARIANT_CLASS_UINT16: +- return g_variant_new_uint16 (g_variant_get_uint16 (value)); ++ if (byteswap) ++ return g_variant_new_uint16 (GUINT16_SWAP_LE_BE (g_variant_get_uint16 (value))); ++ else ++ return g_variant_new_uint16 (g_variant_get_uint16 (value)); + + case G_VARIANT_CLASS_INT32: +- return g_variant_new_int32 (g_variant_get_int32 (value)); ++ if (byteswap) ++ return g_variant_new_int32 (GUINT32_SWAP_LE_BE (g_variant_get_int32 (value))); ++ else ++ return g_variant_new_int32 (g_variant_get_int32 (value)); + + case G_VARIANT_CLASS_UINT32: +- return g_variant_new_uint32 (g_variant_get_uint32 (value)); ++ if (byteswap) ++ return g_variant_new_uint32 (GUINT32_SWAP_LE_BE (g_variant_get_uint32 (value))); ++ else ++ return g_variant_new_uint32 (g_variant_get_uint32 (value)); + + case G_VARIANT_CLASS_INT64: +- return g_variant_new_int64 (g_variant_get_int64 (value)); ++ if (byteswap) ++ return g_variant_new_int64 (GUINT64_SWAP_LE_BE (g_variant_get_int64 (value))); ++ else ++ return g_variant_new_int64 (g_variant_get_int64 (value)); + + case G_VARIANT_CLASS_UINT64: +- return g_variant_new_uint64 (g_variant_get_uint64 (value)); ++ if (byteswap) ++ return g_variant_new_uint64 (GUINT64_SWAP_LE_BE (g_variant_get_uint64 (value))); ++ else ++ return g_variant_new_uint64 (g_variant_get_uint64 (value)); + + case G_VARIANT_CLASS_HANDLE: +- return g_variant_new_handle (g_variant_get_handle (value)); ++ if (byteswap) ++ return g_variant_new_handle (GUINT32_SWAP_LE_BE (g_variant_get_handle (value))); ++ else ++ return g_variant_new_handle (g_variant_get_handle (value)); + + case G_VARIANT_CLASS_DOUBLE: +- return g_variant_new_double (g_variant_get_double (value)); ++ if (byteswap) ++ { ++ /* We have to convert the double to a uint64 here using a union, ++ * because a cast will round it numerically. */ ++ union ++ { ++ guint64 u64; ++ gdouble dbl; ++ } u1, u2; ++ u1.dbl = g_variant_get_double (value); ++ u2.u64 = GUINT64_SWAP_LE_BE (u1.u64); ++ return g_variant_new_double (u2.dbl); ++ } ++ else ++ return g_variant_new_double (g_variant_get_double (value)); + + case G_VARIANT_CLASS_STRING: + return g_variant_new_string (g_variant_get_string (value, NULL)); +@@ -5896,7 +5932,7 @@ g_variant_get_normal_form (GVariant *value) + if (g_variant_is_normal_form (value)) + return g_variant_ref (value); + +- trusted = g_variant_deep_copy (value); ++ trusted = g_variant_deep_copy (value, FALSE); + g_assert (g_variant_is_trusted (trusted)); + + return g_variant_ref_sink (trusted); +@@ -5916,6 +5952,11 @@ g_variant_get_normal_form (GVariant *value) + * contain multi-byte numeric data. That include strings, booleans, + * bytes and containers containing only these things (recursively). + * ++ * While this function can safely handle untrusted, non-normal data, it is ++ * recommended to check whether the input is in normal form beforehand, using ++ * g_variant_is_normal_form(), and to reject non-normal inputs if your ++ * application can be strict about what inputs it rejects. ++ * + * The returned value is always in normal form and is marked as trusted. + * + * Returns: (transfer full): the byteswapped form of @value +@@ -5933,21 +5974,20 @@ g_variant_byteswap (GVariant *value) + + g_variant_type_info_query (type_info, &alignment, NULL); + +- if (alignment) +- /* (potentially) contains multi-byte numeric data */ ++ if (alignment && g_variant_is_normal_form (value)) + { ++ /* (potentially) contains multi-byte numeric data, but is also already in ++ * normal form so we can use a faster byteswapping codepath on the ++ * serialised data */ + GVariantSerialised serialised = { 0, }; +- GVariant *trusted; + GBytes *bytes; + +- trusted = g_variant_get_normal_form (value); +- serialised.type_info = g_variant_get_type_info (trusted); +- serialised.size = g_variant_get_size (trusted); ++ serialised.type_info = g_variant_get_type_info (value); ++ serialised.size = g_variant_get_size (value); + serialised.data = g_malloc (serialised.size); + serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ + serialised.checked_offsets_up_to = G_MAXSIZE; +- g_variant_store (trusted, serialised.data); +- g_variant_unref (trusted); ++ g_variant_store (value, serialised.data); + + g_variant_serialised_byteswap (serialised); + +@@ -5955,6 +5995,9 @@ g_variant_byteswap (GVariant *value) + new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE)); + g_bytes_unref (bytes); + } ++ else if (alignment) ++ /* (potentially) contains multi-byte numeric data */ ++ new = g_variant_ref_sink (g_variant_deep_copy (value, TRUE)); + else + /* contains no multi-byte data */ + new = g_variant_get_normal_form (value); +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index 3dda08e..679dd40 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -2284,24 +2284,67 @@ serialise_tree (TreeInstance *tree, + static void + test_byteswap (void) + { +- GVariantSerialised one = { 0, }, two = { 0, }; ++ GVariantSerialised one = { 0, }, two = { 0, }, three = { 0, }; + TreeInstance *tree; +- ++ GVariant *one_variant = NULL; ++ GVariant *two_variant = NULL; ++ GVariant *two_byteswapped = NULL; ++ GVariant *three_variant = NULL; ++ GVariant *three_byteswapped = NULL; ++ guint8 *three_data_copy = NULL; ++ gsize three_size_copy = 0; ++ ++ /* Write a tree out twice, once normally and once byteswapped. */ + tree = tree_instance_new (NULL, 3); + serialise_tree (tree, &one); + ++ one_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (one.type_info)), ++ one.data, one.size, FALSE, NULL, NULL); ++ + i_am_writing_byteswapped = TRUE; + serialise_tree (tree, &two); ++ serialise_tree (tree, &three); + i_am_writing_byteswapped = FALSE; + +- g_variant_serialised_byteswap (two); +- +- g_assert_cmpmem (one.data, one.size, two.data, two.size); +- g_assert_cmpuint (one.depth, ==, two.depth); +- ++ /* Swap the first byteswapped one back using the function we want to test. */ ++ two_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (two.type_info)), ++ two.data, two.size, FALSE, NULL, NULL); ++ two_byteswapped = g_variant_byteswap (two_variant); ++ ++ /* Make the second byteswapped one non-normal (hopefully), and then byteswap ++ * it back using the function we want to test in its non-normal mode. ++ * This might not work because it’s not necessarily possible to make an ++ * arbitrary random variant non-normal. Adding a single zero byte to the end ++ * often makes something non-normal but still readable. */ ++ three_size_copy = three.size + 1; ++ three_data_copy = g_malloc (three_size_copy); ++ memcpy (three_data_copy, three.data, three.size); ++ three_data_copy[three.size] = '\0'; ++ ++ three_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (three.type_info)), ++ three_data_copy, three_size_copy, FALSE, NULL, NULL); ++ three_byteswapped = g_variant_byteswap (three_variant); ++ ++ /* Check they’re the same. We can always compare @one_variant and ++ * @two_byteswapped. We can only compare @two_byteswapped and ++ * @three_byteswapped if @two_variant and @three_variant are equal: in that ++ * case, the corruption to @three_variant was enough to make it non-normal but ++ * not enough to change its value. */ ++ g_assert_cmpvariant (one_variant, two_byteswapped); ++ ++ if (g_variant_equal (two_variant, three_variant)) ++ g_assert_cmpvariant (two_byteswapped, three_byteswapped); ++ ++ g_variant_unref (three_byteswapped); ++ g_variant_unref (three_variant); ++ g_variant_unref (two_byteswapped); ++ g_variant_unref (two_variant); ++ g_variant_unref (one_variant); + tree_instance_free (tree); + g_free (one.data); + g_free (two.data); ++ g_free (three.data); ++ g_free (three_data_copy); + } + + static void +-- +2.24.4 + 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 @@ +From 21a204147b16539b3eda3143b32844c49e29f4d4 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 17 Aug 2023 11:33:49 +0000 +Subject: [PATCH] gvariant: Propagate trust when getting a child of a + serialised variant + +If a variant is trusted, that means all its children are trusted, so +ensure that their checked offsets are set as such. + +This allows a lot of the offset table checks to be avoided when getting +children from trusted serialised tuples, which speeds things up. + +No unit test is included because this is just a performance fix. If +there are other slownesses, or regressions, in serialised `GVariant` +performance, the fuzzing setup will catch them like it did this one. + +This change does reduce the time to run the oss-fuzz reproducer from 80s +to about 0.7s on my machine. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Fixes: #2841 +oss-fuzz#54314 + +CVE: CVE-2023-32636 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/21a204147b16539b3eda3143b32844c49e29f4d4] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c +index 1b9d5cc..ed57c70 100644 +--- a/glib/gvariant-core.c ++++ b/glib/gvariant-core.c +@@ -1173,8 +1173,8 @@ g_variant_get_child_value (GVariant *value, + child->contents.serialised.bytes = + g_bytes_ref (value->contents.serialised.bytes); + child->contents.serialised.data = s_child.data; +- child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; +- child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to; ++ child->contents.serialised.ordered_offsets_up_to = (value->state & STATE_TRUSTED) ? G_MAXSIZE : s_child.ordered_offsets_up_to; ++ child->contents.serialised.checked_offsets_up_to = (value->state & STATE_TRUSTED) ? G_MAXSIZE : s_child.checked_offsets_up_to; + + return child; + } +-- +2.24.4 + 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 @@ +From 78da5faccb3e065116b75b3ff87ff55381da6c76 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 17 Aug 2023 11:24:43 +0000 +Subject: [PATCH] gvariant: Check offset table doesn't fall outside variant + bounds + +When dereferencing the first entry in the offset table for a tuple, +check that it doesn’t fall outside the bounds of the variant first. + +This prevents an out-of-bounds read from some non-normal tuples. + +This bug was introduced in commit 73d0aa81c2575a5c9ae77d. + +Includes a unit test, although the test will likely only catch the +original bug if run with asan enabled. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Fixes: #2840 +oss-fuzz#54302 + +CVE: CVE-2023-32643 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/78da5faccb3e065116b75b3ff87ff55381da6c76] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-serialiser.c | 12 ++++++-- + glib/tests/gvariant.c | 63 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 72 insertions(+), 3 deletions(-) + +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index 5aa2cbc..4e50ed7 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -979,7 +979,8 @@ gvs_tuple_get_member_bounds (GVariantSerialised value, + + member_info = g_variant_type_info_member_info (value.type_info, index_); + +- if (member_info->i + 1) ++ if (member_info->i + 1 && ++ offset_size * (member_info->i + 1) <= value.size) + member_start = gvs_read_unaligned_le (value.data + value.size - + offset_size * (member_info->i + 1), + offset_size); +@@ -990,7 +991,8 @@ gvs_tuple_get_member_bounds (GVariantSerialised value, + member_start &= member_info->b; + member_start |= member_info->c; + +- if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) ++ if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST && ++ offset_size * (member_info->i + 1) <= value.size) + member_end = value.size - offset_size * (member_info->i + 1); + + else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) +@@ -1001,11 +1003,15 @@ gvs_tuple_get_member_bounds (GVariantSerialised value, + member_end = member_start + fixed_size; + } + +- else /* G_VARIANT_MEMBER_ENDING_OFFSET */ ++ else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET && ++ offset_size * (member_info->i + 2) <= value.size) + member_end = gvs_read_unaligned_le (value.data + value.size - + offset_size * (member_info->i + 2), + offset_size); + ++ else /* invalid */ ++ member_end = G_MAXSIZE; ++ + if (out_member_start != NULL) + *out_member_start = member_start; + if (out_member_end != NULL) +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index 679dd40..2eca8be 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -5432,6 +5432,67 @@ test_normal_checking_tuple_offsets4 (void) + g_variant_unref (variant); + } + ++/* This is a regression test that dereferencing the first element in the offset ++ * table doesn’t dereference memory before the start of the GVariant. The first ++ * element in the offset table gives the offset of the final member in the ++ * tuple (the offset table is stored in reverse), and the position of this final ++ * member is needed to check that none of the tuple members overlap with the ++ * offset table ++ * ++ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2840 */ ++static void ++test_normal_checking_tuple_offsets5 (void) ++{ ++ /* A tuple of type (sss) in normal form would have an offset table with two ++ * entries: ++ * - The first entry (lowest index in the table) gives the offset of the ++ * third `s` in the tuple, as the offset table is reversed compared to the ++ * tuple members. ++ * - The second entry (highest index in the table) gives the offset of the ++ * second `s` in the tuple. ++ * - The offset of the first `s` in the tuple is always 0. ++ * ++ * See §2.5.4 (Structures) of the GVariant specification for details, noting ++ * that the table is only layed out this way because all three members of the ++ * tuple have non-fixed sizes. ++ * ++ * It’s not clear whether the 0xaa data of this variant is part of the strings ++ * in the tuple, or part of the offset table. It doesn’t really matter. This ++ * is a regression test to check that the code to validate the offset table ++ * doesn’t unconditionally try to access the first entry in the offset table ++ * by subtracting the table size from the end of the GVariant data. ++ * ++ * In this non-normal case, that would result in an address off the start of ++ * the GVariant data, and an out-of-bounds read, because the GVariant is one ++ * byte long, but the offset table is calculated as two bytes long (with 1B ++ * sized entries) from the tuple’s type. ++ */ ++ const GVariantType *data_type = G_VARIANT_TYPE ("(sss)"); ++ const guint8 data[] = { 0xaa }; ++ gsize size = sizeof (data); ++ GVariant *variant = NULL; ++ GVariant *normal_variant = NULL; ++ GVariant *expected = NULL; ++ ++ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2840"); ++ ++ variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); ++ g_assert_nonnull (variant); ++ ++ g_assert_false (g_variant_is_normal_form (variant)); ++ ++ normal_variant = g_variant_get_normal_form (variant); ++ g_assert_nonnull (normal_variant); ++ ++ expected = g_variant_new_parsed ("('', '', '')"); ++ g_assert_cmpvariant (expected, variant); ++ g_assert_cmpvariant (expected, normal_variant); ++ ++ g_variant_unref (expected); ++ g_variant_unref (normal_variant); ++ g_variant_unref (variant); ++} ++ + /* Test that an otherwise-valid serialised GVariant is considered non-normal if + * its offset table entries are too wide. + * +@@ -5680,6 +5741,8 @@ main (int argc, char **argv) + test_normal_checking_tuple_offsets3); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", + test_normal_checking_tuple_offsets4); ++ g_test_add_func ("/gvariant/normal-checking/tuple-offsets5", ++ test_normal_checking_tuple_offsets5); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized", + test_normal_checking_tuple_offsets_minimal_sized); + g_test_add_func ("/gvariant/normal-checking/empty-object-path", +-- +2.24.4 + 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 @@ +From 1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1 Mon Sep 17 00:00:00 2001 +From: William Manley <will@stb-tester.com> +Date: Wed, 9 Aug 2023 10:04:49 +0000 +Subject: [PATCH] gvariant-core: Consolidate construction of + `GVariantSerialised` + +So I only need to change it in one place. + +This introduces no functional changes. + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/1deacdd4e8e35a5cf1417918ca4f6b0afa6409b1] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-core.c | 49 ++++++++++++++++++++++---------------------- + 1 file changed, 25 insertions(+), 24 deletions(-) + +diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c +index 9397573..aa0e0a0 100644 +--- a/glib/gvariant-core.c ++++ b/glib/gvariant-core.c +@@ -349,6 +349,27 @@ g_variant_ensure_size (GVariant *value) + } + } + ++/* < private > ++ * g_variant_to_serialised: ++ * @value: a #GVariant ++ * ++ * Gets a GVariantSerialised for a GVariant in state STATE_SERIALISED. ++ */ ++inline static GVariantSerialised ++g_variant_to_serialised (GVariant *value) ++{ ++ g_assert (value->state & STATE_SERIALISED); ++ { ++ GVariantSerialised serialised = { ++ value->type_info, ++ (gpointer) value->contents.serialised.data, ++ value->size, ++ value->depth, ++ }; ++ return serialised; ++ } ++} ++ + /* < private > + * g_variant_serialise: + * @value: a #GVariant +@@ -991,16 +1012,8 @@ g_variant_n_children (GVariant *value) + g_variant_lock (value); + + if (value->state & STATE_SERIALISED) +- { +- GVariantSerialised serialised = { +- value->type_info, +- (gpointer) value->contents.serialised.data, +- value->size, +- value->depth, +- }; +- +- n_children = g_variant_serialised_n_children (serialised); +- } ++ n_children = g_variant_serialised_n_children ( ++ g_variant_to_serialised (value)); + else + n_children = value->contents.tree.n_children; + +@@ -1061,12 +1074,7 @@ g_variant_get_child_value (GVariant *value, + } + + { +- GVariantSerialised serialised = { +- value->type_info, +- (gpointer) value->contents.serialised.data, +- value->size, +- value->depth, +- }; ++ GVariantSerialised serialised = g_variant_to_serialised (value); + GVariantSerialised s_child; + GVariant *child; + +@@ -1179,14 +1187,7 @@ g_variant_is_normal_form (GVariant *value) + + if (value->state & STATE_SERIALISED) + { +- GVariantSerialised serialised = { +- value->type_info, +- (gpointer) value->contents.serialised.data, +- value->size, +- value->depth +- }; +- +- if (g_variant_serialised_is_normal (serialised)) ++ if (g_variant_serialised_is_normal (g_variant_to_serialised (value))) + value->state |= STATE_TRUSTED; + } + else +-- +2.24.4 + 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 @@ +From 446e69f5edd72deb2196dee36bbaf8056caf6948 Mon Sep 17 00:00:00 2001 +From: William Manley <will@stb-tester.com> +Date: Wed, 9 Aug 2023 10:39:34 +0000 +Subject: [PATCH] gvariant-serialiser: Factor out functions for dealing with + framing offsets + +This introduces no functional changes. + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/446e69f5edd72deb2196dee36bbaf8056caf6948] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-serialiser.c | 108 +++++++++++++++++++------------------ + 1 file changed, 57 insertions(+), 51 deletions(-) + +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index 83e9d85..c7c2114 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -633,30 +633,62 @@ gvs_calculate_total_size (gsize body_size, + return body_size + 8 * offsets; + } + ++struct Offsets ++{ ++ gsize data_size; ++ ++ guchar *array; ++ gsize length; ++ guint offset_size; ++ ++ gboolean is_normal; ++}; ++ + static gsize +-gvs_variable_sized_array_n_children (GVariantSerialised value) ++gvs_offsets_get_offset_n (struct Offsets *offsets, ++ gsize n) ++{ ++ return gvs_read_unaligned_le ( ++ offsets->array + (offsets->offset_size * n), offsets->offset_size); ++} ++ ++static struct Offsets ++gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value) + { ++ struct Offsets out = { 0, }; + gsize offsets_array_size; +- gsize offset_size; + gsize last_end; + + if (value.size == 0) +- return 0; +- +- offset_size = gvs_get_offset_size (value.size); ++ { ++ out.is_normal = TRUE; ++ return out; ++ } + +- last_end = gvs_read_unaligned_le (value.data + value.size - +- offset_size, offset_size); ++ out.offset_size = gvs_get_offset_size (value.size); ++ last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size, ++ out.offset_size); + + if (last_end > value.size) +- return 0; ++ return out; /* offsets not normal */ + + offsets_array_size = value.size - last_end; + +- if (offsets_array_size % offset_size) +- return 0; ++ if (offsets_array_size % out.offset_size) ++ return out; /* offsets not normal */ ++ ++ out.data_size = last_end; ++ out.array = value.data + last_end; ++ out.length = offsets_array_size / out.offset_size; ++ out.is_normal = TRUE; + +- return offsets_array_size / offset_size; ++ return out; ++} ++ ++static gsize ++gvs_variable_sized_array_n_children (GVariantSerialised value) ++{ ++ return gvs_variable_sized_array_get_frame_offsets (value).length; + } + + static GVariantSerialised +@@ -664,8 +696,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, + gsize index_) + { + GVariantSerialised child = { 0, }; +- gsize offset_size; +- gsize last_end; ++ ++ struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value); ++ + gsize start; + gsize end; + +@@ -673,18 +706,11 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, + g_variant_type_info_ref (child.type_info); + child.depth = value.depth + 1; + +- offset_size = gvs_get_offset_size (value.size); +- +- last_end = gvs_read_unaligned_le (value.data + value.size - +- offset_size, offset_size); +- + if (index_ > 0) + { + guint alignment; + +- start = gvs_read_unaligned_le (value.data + last_end + +- (offset_size * (index_ - 1)), +- offset_size); ++ start = gvs_offsets_get_offset_n (&offsets, index_ - 1); + + g_variant_type_info_query (child.type_info, &alignment, NULL); + start += (-start) & alignment; +@@ -692,11 +718,9 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, + else + start = 0; + +- end = gvs_read_unaligned_le (value.data + last_end + +- (offset_size * index_), +- offset_size); ++ end = gvs_offsets_get_offset_n (&offsets, index_); + +- if (start < end && end <= value.size && end <= last_end) ++ if (start < end && end <= value.size && end <= offsets.data_size) + { + child.data = value.data + start; + child.size = end - start; +@@ -768,34 +792,16 @@ static gboolean + gvs_variable_sized_array_is_normal (GVariantSerialised value) + { + GVariantSerialised child = { 0, }; +- gsize offsets_array_size; +- guchar *offsets_array; +- guint offset_size; + guint alignment; +- gsize last_end; +- gsize length; + gsize offset; + gsize i; + +- if (value.size == 0) +- return TRUE; +- +- offset_size = gvs_get_offset_size (value.size); +- last_end = gvs_read_unaligned_le (value.data + value.size - +- offset_size, offset_size); ++ struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value); + +- if (last_end > value.size) ++ if (!offsets.is_normal) + return FALSE; + +- offsets_array_size = value.size - last_end; +- +- if (offsets_array_size % offset_size) +- return FALSE; +- +- offsets_array = value.data + value.size - offsets_array_size; +- length = offsets_array_size / offset_size; +- +- if (length == 0) ++ if (value.size != 0 && offsets.length == 0) + return FALSE; + + child.type_info = g_variant_type_info_element (value.type_info); +@@ -803,14 +809,14 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) + child.depth = value.depth + 1; + offset = 0; + +- for (i = 0; i < length; i++) ++ for (i = 0; i < offsets.length; i++) + { + gsize this_end; + +- this_end = gvs_read_unaligned_le (offsets_array + offset_size * i, +- offset_size); ++ this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i, ++ offsets.offset_size); + +- if (this_end < offset || this_end > last_end) ++ if (this_end < offset || this_end > offsets.data_size) + return FALSE; + + while (offset & alignment) +@@ -832,7 +838,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) + offset = this_end; + } + +- g_assert (offset == last_end); ++ g_assert (offset == offsets.data_size); + + return TRUE; + } +-- +2.24.4 + 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 @@ +From ade71fb544391b2e33e1859645726bfee0d5eaaf Mon Sep 17 00:00:00 2001 +From: William Manley <will@stb-tester.com> +Date: Wed, 16 Aug 2023 03:12:21 +0000 +Subject: [PATCH] gvariant: Don't allow child elements to overlap with each + other + +If different elements of a variable sized array can overlap with each +other then we can cause a `GVariant` to normalise to a much larger type. + +This commit changes the behaviour of `GVariant` with non-normal form data. If +an invalid frame offset is found all subsequent elements are given their +default value. + +When retrieving an element at index `n` we scan the frame offsets up to index +`n` and if they are not in order we return an element with the default value +for that type. This guarantees that elements don't overlap with each +other. We remember the offset we've scanned up to so we don't need to +repeat this work on subsequent accesses. We skip these checks for trusted +data. + +Unfortunately this makes random access of untrusted data O(n) — at least +on first access. It doesn't affect the algorithmic complexity of accessing +elements in order, such as when using the `GVariantIter` interface. Also: +the cost of validation will be amortised as the `GVariant` instance is +continued to be used. + +I've implemented this with 4 different functions, 1 for each element size, +rather than looping calling `gvs_read_unaligned_le` in the hope that the +compiler will find it easy to optimise and should produce fairly tight +code. + +Fixes: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/ade71fb544391b2e33e1859645726bfee0d5eaaf] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-core.c | 35 ++++++++++++++++ + glib/gvariant-serialiser.c | 86 ++++++++++++++++++++++++++++++++++++-- + glib/gvariant-serialiser.h | 8 ++++ + glib/tests/gvariant.c | 45 ++++++++++++++++++++ + 4 files changed, 171 insertions(+), 3 deletions(-) + +diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c +index aa0e0a0..9b51e15 100644 +--- a/glib/gvariant-core.c ++++ b/glib/gvariant-core.c +@@ -65,6 +65,7 @@ struct _GVariant + { + GBytes *bytes; + gconstpointer data; ++ gsize ordered_offsets_up_to; + } serialised; + + struct +@@ -162,6 +163,24 @@ struct _GVariant + * if .data pointed to the appropriate number of nul + * bytes. + * ++ * .ordered_offsets_up_to: If ordered_offsets_up_to == n this means that all ++ * the frame offsets up to and including the frame ++ * offset determining the end of element n are in ++ * order. This guarantees that the bytes of element ++ * n don't overlap with any previous element. ++ * ++ * For trusted data this is set to G_MAXSIZE and we ++ * don't check that the frame offsets are in order. ++ * ++ * Note: This doesn't imply the offsets are good in ++ * any way apart from their ordering. In particular ++ * offsets may be out of bounds for this value or ++ * may imply that the data overlaps the frame ++ * offsets themselves. ++ * ++ * This field is only relevant for arrays of non ++ * fixed width types. ++ * + * .tree: Only valid when the instance is in tree form. + * + * Note that accesses from other threads could result in +@@ -365,6 +384,7 @@ g_variant_to_serialised (GVariant *value) + (gpointer) value->contents.serialised.data, + value->size, + value->depth, ++ value->contents.serialised.ordered_offsets_up_to, + }; + return serialised; + } +@@ -396,6 +416,7 @@ g_variant_serialise (GVariant *value, + serialised.size = value->size; + serialised.data = data; + serialised.depth = value->depth; ++ serialised.ordered_offsets_up_to = 0; + + children = (gpointer *) value->contents.tree.children; + n_children = value->contents.tree.n_children; +@@ -439,6 +460,15 @@ g_variant_fill_gvs (GVariantSerialised *serialised, + g_assert (serialised->size == value->size); + serialised->depth = value->depth; + ++ if (value->state & STATE_SERIALISED) ++ { ++ serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to; ++ } ++ else ++ { ++ serialised->ordered_offsets_up_to = 0; ++ } ++ + if (serialised->data) + /* g_variant_store() is a public API, so it + * it will reacquire the lock if it needs to. +@@ -481,6 +511,7 @@ g_variant_ensure_serialised (GVariant *value) + bytes = g_bytes_new_take (data, value->size); + value->contents.serialised.data = g_bytes_get_data (bytes, NULL); + value->contents.serialised.bytes = bytes; ++ value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE; + value->state |= STATE_SERIALISED; + } + } +@@ -561,6 +592,7 @@ g_variant_new_from_bytes (const GVariantType *type, + serialised.type_info = value->type_info; + serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size); + serialised.depth = 0; ++ serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; + + if (!g_variant_serialised_check (serialised)) + { +@@ -610,6 +642,8 @@ g_variant_new_from_bytes (const GVariantType *type, + value->contents.serialised.data = g_bytes_get_data (bytes, &value->size); + } + ++ value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; ++ + g_clear_pointer (&owned_bytes, g_bytes_unref); + + return value; +@@ -1108,6 +1142,7 @@ g_variant_get_child_value (GVariant *value, + child->contents.serialised.bytes = + g_bytes_ref (value->contents.serialised.bytes); + child->contents.serialised.data = s_child.data; ++ child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; + + return child; + } +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index c7c2114..fe0b1a4 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -1,6 +1,7 @@ + /* + * Copyright © 2007, 2008 Ryan Lortie + * Copyright © 2010 Codethink Limited ++ * Copyright © 2020 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -264,6 +265,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, + value.type_info = g_variant_type_info_element (value.type_info); + g_variant_type_info_ref (value.type_info); + value.depth++; ++ value.ordered_offsets_up_to = 0; + + return value; + } +@@ -295,7 +297,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, + { + if (n_children) + { +- GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1 }; ++ GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 }; + + gvs_filler (&child, children[0]); + } +@@ -317,6 +319,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) + /* proper element size: "Just". recurse to the child. */ + value.type_info = g_variant_type_info_element (value.type_info); + value.depth++; ++ value.ordered_offsets_up_to = 0; + + return g_variant_serialised_is_normal (value); + } +@@ -358,6 +361,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, + value.data = NULL; + + value.depth++; ++ value.ordered_offsets_up_to = 0; + + return value; + } +@@ -388,7 +392,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, + { + if (n_children) + { +- GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1 }; ++ GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 }; + + /* write the data for the child. */ + gvs_filler (&child, children[0]); +@@ -408,6 +412,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value) + value.type_info = g_variant_type_info_element (value.type_info); + value.size--; + value.depth++; ++ value.ordered_offsets_up_to = 0; + + return g_variant_serialised_is_normal (value); + } +@@ -691,6 +696,32 @@ gvs_variable_sized_array_n_children (GVariantSerialised value) + return gvs_variable_sized_array_get_frame_offsets (value).length; + } + ++/* Find the index of the first out-of-order element in @data, assuming that ++ * @data is an array of elements of given @type, starting at index @start and ++ * containing a further @len-@start elements. */ ++#define DEFINE_FIND_UNORDERED(type) \ ++ static gsize \ ++ find_unordered_##type (const guint8 *data, gsize start, gsize len) \ ++ { \ ++ gsize off; \ ++ type current, previous; \ ++ \ ++ memcpy (&previous, data + start * sizeof (current), sizeof (current)); \ ++ for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \ ++ { \ ++ memcpy (¤t, data + off, sizeof (current)); \ ++ if (current < previous) \ ++ break; \ ++ previous = current; \ ++ } \ ++ return off / sizeof (current) - 1; \ ++ } ++ ++DEFINE_FIND_UNORDERED (guint8); ++DEFINE_FIND_UNORDERED (guint16); ++DEFINE_FIND_UNORDERED (guint32); ++DEFINE_FIND_UNORDERED (guint64); ++ + static GVariantSerialised + gvs_variable_sized_array_get_child (GVariantSerialised value, + gsize index_) +@@ -706,6 +737,49 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, + g_variant_type_info_ref (child.type_info); + child.depth = value.depth + 1; + ++ /* If the requested @index_ is beyond the set of indices whose framing offsets ++ * have been checked, check the remaining offsets to see whether they’re ++ * normal (in order, no overlapping array elements). */ ++ if (index_ > value.ordered_offsets_up_to) ++ { ++ switch (offsets.offset_size) ++ { ++ case 1: ++ { ++ value.ordered_offsets_up_to = find_unordered_guint8 ( ++ offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ break; ++ } ++ case 2: ++ { ++ value.ordered_offsets_up_to = find_unordered_guint16 ( ++ offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ break; ++ } ++ case 4: ++ { ++ value.ordered_offsets_up_to = find_unordered_guint32 ( ++ offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ break; ++ } ++ case 8: ++ { ++ value.ordered_offsets_up_to = find_unordered_guint64 ( ++ offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ break; ++ } ++ default: ++ /* gvs_get_offset_size() only returns maximum 8 */ ++ g_assert_not_reached (); ++ } ++ } ++ ++ if (index_ > value.ordered_offsets_up_to) ++ { ++ /* Offsets are invalid somewhere, so return an empty child. */ ++ return child; ++ } ++ + if (index_ > 0) + { + guint alignment; +@@ -840,6 +914,9 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) + + g_assert (offset == offsets.data_size); + ++ /* All offsets have now been checked. */ ++ value.ordered_offsets_up_to = G_MAXSIZE; ++ + return TRUE; + } + +@@ -1072,7 +1149,7 @@ gvs_tuple_is_normal (GVariantSerialised value) + for (i = 0; i < length; i++) + { + const GVariantMemberInfo *member_info; +- GVariantSerialised child; ++ GVariantSerialised child = { 0, }; + gsize fixed_size; + guint alignment; + gsize end; +@@ -1132,6 +1209,9 @@ gvs_tuple_is_normal (GVariantSerialised value) + offset = end; + } + ++ /* All element bounds have been checked above. */ ++ value.ordered_offsets_up_to = G_MAXSIZE; ++ + { + gsize fixed_size; + guint alignment; +diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h +index 81343e9..99d18ef 100644 +--- a/glib/gvariant-serialiser.h ++++ b/glib/gvariant-serialiser.h +@@ -29,6 +29,14 @@ typedef struct + guchar *data; + gsize size; + gsize depth; /* same semantics as GVariant.depth */ ++ /* If ordered_offsets_up_to == n this means that all the frame offsets up to and ++ * including the frame offset determining the end of element n are in order. ++ * This guarantees that the bytes of element n don't overlap with any previous ++ * element. ++ * ++ * This is both read and set by g_variant_serialised_get_child for arrays of ++ * non-fixed-width types */ ++ gsize ordered_offsets_up_to; + } GVariantSerialised; + + /* deserialisation */ +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index 0e5ec8e..967e9a1 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -1,5 +1,6 @@ + /* + * Copyright © 2010 Codethink Limited ++ * Copyright © 2020 William Manley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -1283,6 +1284,7 @@ random_instance_filler (GVariantSerialised *serialised, + serialised->size = instance->size; + + serialised->depth = 0; ++ serialised->ordered_offsets_up_to = 0; + + g_assert_true (serialised->type_info == instance->type_info); + g_assert_cmpuint (serialised->size, ==, instance->size); +@@ -5039,6 +5041,47 @@ test_normal_checking_array_offsets (void) + g_variant_unref (variant); + } + ++/* This is a regression test that we can't have non-normal values that take up ++ * significantly more space than the normal equivalent, by specifying the ++ * offset table entries so that array elements overlap. ++ * ++ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_832242 */ ++static void ++test_normal_checking_array_offsets2 (void) ++{ ++ const guint8 data[] = { ++ 'h', 'i', '\0', ++ 0x03, 0x00, 0x03, ++ 0x06, 0x00, 0x06, ++ 0x09, 0x00, 0x09, ++ 0x0c, 0x00, 0x0c, ++ 0x0f, 0x00, 0x0f, ++ 0x12, 0x00, 0x12, ++ 0x15, 0x00, 0x15, ++ }; ++ gsize size = sizeof (data); ++ const GVariantType *aaaaaaas = G_VARIANT_TYPE ("aaaaaaas"); ++ GVariant *variant = NULL; ++ GVariant *normal_variant = NULL; ++ GVariant *expected = NULL; ++ ++ variant = g_variant_new_from_data (aaaaaaas, data, size, FALSE, NULL, NULL); ++ g_assert_nonnull (variant); ++ ++ normal_variant = g_variant_get_normal_form (variant); ++ g_assert_nonnull (normal_variant); ++ g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 2); ++ ++ expected = g_variant_new_parsed ( ++ "[[[[[[['hi', '', ''], [], []], [], []], [], []], [], []], [], []], [], []]"); ++ g_assert_cmpvariant (expected, variant); ++ g_assert_cmpvariant (expected, normal_variant); ++ ++ g_variant_unref (expected); ++ g_variant_unref (normal_variant); ++ g_variant_unref (variant); ++} ++ + /* Test that a tuple with invalidly large values in its offset table is + * normalised successfully without looping infinitely. */ + static void +@@ -5206,6 +5249,8 @@ main (int argc, char **argv) + test_normal_checking_tuples); + g_test_add_func ("/gvariant/normal-checking/array-offsets", + test_normal_checking_array_offsets); ++ g_test_add_func ("/gvariant/normal-checking/array-offsets2", ++ test_normal_checking_array_offsets2); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets", + test_normal_checking_tuple_offsets); + g_test_add_func ("/gvariant/normal-checking/empty-object-path", +-- +2.24.4 + 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 @@ +From 345cae9c1aa7bf6752039225ef4c8d8d69fa8d76 Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Fri, 11 Aug 2023 04:09:12 +0000 +Subject: [PATCH] gvariant-serialiser: Factor out code to get bounds of a tuple + member + +This introduces no functional changes. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/345cae9c1aa7bf6752039225ef4c8d8d69fa8d76] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-serialiser.c | 73 ++++++++++++++++++++++++-------------- + 1 file changed, 46 insertions(+), 27 deletions(-) + +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index fe0b1a4..6f9b366 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -942,6 +942,51 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) + * for the tuple. See the notes in gvarianttypeinfo.h. + */ + ++static void ++gvs_tuple_get_member_bounds (GVariantSerialised value, ++ gsize index_, ++ gsize offset_size, ++ gsize *out_member_start, ++ gsize *out_member_end) ++{ ++ const GVariantMemberInfo *member_info; ++ gsize member_start, member_end; ++ ++ member_info = g_variant_type_info_member_info (value.type_info, index_); ++ ++ if (member_info->i + 1) ++ member_start = gvs_read_unaligned_le (value.data + value.size - ++ offset_size * (member_info->i + 1), ++ offset_size); ++ else ++ member_start = 0; ++ ++ member_start += member_info->a; ++ member_start &= member_info->b; ++ member_start |= member_info->c; ++ ++ if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) ++ member_end = value.size - offset_size * (member_info->i + 1); ++ ++ else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) ++ { ++ gsize fixed_size; ++ ++ g_variant_type_info_query (member_info->type_info, NULL, &fixed_size); ++ member_end = member_start + fixed_size; ++ } ++ ++ else /* G_VARIANT_MEMBER_ENDING_OFFSET */ ++ member_end = gvs_read_unaligned_le (value.data + value.size - ++ offset_size * (member_info->i + 2), ++ offset_size); ++ ++ if (out_member_start != NULL) ++ *out_member_start = member_start; ++ if (out_member_end != NULL) ++ *out_member_end = member_end; ++} ++ + static gsize + gvs_tuple_n_children (GVariantSerialised value) + { +@@ -997,33 +1042,7 @@ gvs_tuple_get_child (GVariantSerialised value, + } + } + +- if (member_info->i + 1) +- start = gvs_read_unaligned_le (value.data + value.size - +- offset_size * (member_info->i + 1), +- offset_size); +- else +- start = 0; +- +- start += member_info->a; +- start &= member_info->b; +- start |= member_info->c; +- +- if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST) +- end = value.size - offset_size * (member_info->i + 1); +- +- else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) +- { +- gsize fixed_size; +- +- g_variant_type_info_query (child.type_info, NULL, &fixed_size); +- end = start + fixed_size; +- child.size = fixed_size; +- } +- +- else /* G_VARIANT_MEMBER_ENDING_OFFSET */ +- end = gvs_read_unaligned_le (value.data + value.size - +- offset_size * (member_info->i + 2), +- offset_size); ++ gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); + + /* The child should not extend into the offset table. */ + if (index_ != g_variant_type_info_n_members (value.type_info) - 1) +-- +2.24.4 + 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 @@ +From 73d0aa81c2575a5c9ae77dcb94da919579014fc0 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Fri, 11 Aug 2023 04:13:02 +0000 +Subject: [PATCH] gvariant-serialiser: Rework child size calculation + +This reduces a few duplicate calls to `g_variant_type_info_query()` and +explains why they’re needed. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/73d0aa81c2575a5c9ae77dcb94da919579014fc0] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-serialiser.c | 31 +++++++++---------------------- + 1 file changed, 9 insertions(+), 22 deletions(-) + +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index 6f9b366..fb75923 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -1007,14 +1007,18 @@ gvs_tuple_get_child (GVariantSerialised value, + child.depth = value.depth + 1; + offset_size = gvs_get_offset_size (value.size); + ++ /* Ensure the size is set for fixed-sized children, or ++ * g_variant_serialised_check() will fail, even if we return ++ * (child.data == NULL) to indicate an error. */ ++ if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED) ++ g_variant_type_info_query (child.type_info, NULL, &child.size); ++ + /* tuples are the only (potentially) fixed-sized containers, so the + * only ones that have to deal with the possibility of having %NULL + * data with a non-zero %size if errors occurred elsewhere. + */ + if G_UNLIKELY (value.data == NULL && value.size != 0) + { +- g_variant_type_info_query (child.type_info, NULL, &child.size); +- + /* this can only happen in fixed-sized tuples, + * so the child must also be fixed sized. + */ +@@ -1032,29 +1036,12 @@ gvs_tuple_get_child (GVariantSerialised value, + else + { + if (offset_size * (member_info->i + 1) > value.size) +- { +- /* if the child is fixed size, return its size. +- * if child is not fixed-sized, return size = 0. +- */ +- g_variant_type_info_query (child.type_info, NULL, &child.size); +- +- return child; +- } ++ return child; + } + +- gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); +- + /* The child should not extend into the offset table. */ +- if (index_ != g_variant_type_info_n_members (value.type_info) - 1) +- { +- GVariantSerialised last_child; +- last_child = gvs_tuple_get_child (value, +- g_variant_type_info_n_members (value.type_info) - 1); +- last_end = last_child.data + last_child.size - value.data; +- g_variant_type_info_unref (last_child.type_info); +- } +- else +- last_end = end; ++ gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end); ++ gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end); + + if (start < end && end <= value.size && end <= last_end) + { +-- +2.24.4 + 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 @@ +From 7cf6f5b69146d20948d42f0c476688fe17fef787 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 16 Aug 2023 12:09:06 +0000 +Subject: [PATCH] gvariant: Don't allow child elements of a tuple to overlap + each other + +This is similar to the earlier commit which prevents child elements of a +variable-sized array from overlapping each other, but this time for +tuples. It is based heavily on ideas by William Manley. + +Tuples are slightly different from variable-sized arrays in that they +contain a mixture of fixed and variable sized elements. All but one of +the variable sized elements have an entry in the frame offsets table. +This means that if we were to just check the ordering of the frame +offsets table, the variable sized elements could still overlap +interleaving fixed sized elements, which would be bad. + +Therefore we have to check the elements rather than the frame offsets. + +The logic of checking the elements up to the index currently being +requested, and caching the result in `ordered_offsets_up_to`, means that +the algorithmic cost implications are the same for this commit as for +variable-sized arrays: an O(N) cost for these checks is amortised out +over N accesses to O(1) per access. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Fixes: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/7cf6f5b69146d20948d42f0c476688fe17fef787] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-core.c | 6 +- + glib/gvariant-serialiser.c | 40 ++++++++ + glib/gvariant-serialiser.h | 7 +- + glib/gvariant.c | 1 + + glib/tests/gvariant.c | 181 +++++++++++++++++++++++++++++++++++++ + 5 files changed, 232 insertions(+), 3 deletions(-) + +diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c +index 9b51e15..b951cd9 100644 +--- a/glib/gvariant-core.c ++++ b/glib/gvariant-core.c +@@ -1,6 +1,7 @@ + /* + * Copyright © 2007, 2008 Ryan Lortie + * Copyright © 2010 Codethink Limited ++ * Copyright © 2022 Endless OS Foundation, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -179,7 +180,7 @@ struct _GVariant + * offsets themselves. + * + * This field is only relevant for arrays of non +- * fixed width types. ++ * fixed width types and for tuples. + * + * .tree: Only valid when the instance is in tree form. + * +@@ -1117,6 +1118,9 @@ g_variant_get_child_value (GVariant *value, + */ + s_child = g_variant_serialised_get_child (serialised, index_); + ++ /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */ ++ value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to); ++ + /* Check whether this would cause nesting too deep. If so, return a fake + * child. The only situation we expect this to happen in is with a variant, + * as all other deeply-nested types have a static type, and hence should +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index fb75923..cd4a3e6 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -942,6 +942,10 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) + * for the tuple. See the notes in gvarianttypeinfo.h. + */ + ++/* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that ++ * condition may not hold true for invalid serialised variants. The caller is ++ * responsible for checking the returned values and handling invalid ones ++ * appropriately. */ + static void + gvs_tuple_get_member_bounds (GVariantSerialised value, + gsize index_, +@@ -1028,6 +1032,42 @@ gvs_tuple_get_child (GVariantSerialised value, + return child; + } + ++ /* If the requested @index_ is beyond the set of indices whose framing offsets ++ * have been checked, check the remaining offsets to see whether they’re ++ * normal (in order, no overlapping tuple elements). ++ * ++ * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check ++ * all the tuple *elements* here, not just all the framing offsets, since ++ * tuples contain a mix of elements which use framing offsets and ones which ++ * don’t. None of them are allowed to overlap. */ ++ if (index_ > value.ordered_offsets_up_to) ++ { ++ gsize i, prev_i_end = 0; ++ ++ if (value.ordered_offsets_up_to > 0) ++ gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end); ++ ++ for (i = value.ordered_offsets_up_to; i <= index_; i++) ++ { ++ gsize i_start, i_end; ++ ++ gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end); ++ ++ if (i_start > i_end || i_start < prev_i_end || i_end > value.size) ++ break; ++ ++ prev_i_end = i_end; ++ } ++ ++ value.ordered_offsets_up_to = i - 1; ++ } ++ ++ if (index_ > value.ordered_offsets_up_to) ++ { ++ /* Offsets are invalid somewhere, so return an empty child. */ ++ return child; ++ } ++ + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET) + { + if (offset_size * (member_info->i + 2) > value.size) +diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h +index 99d18ef..144aec8 100644 +--- a/glib/gvariant-serialiser.h ++++ b/glib/gvariant-serialiser.h +@@ -34,8 +34,11 @@ typedef struct + * This guarantees that the bytes of element n don't overlap with any previous + * element. + * +- * This is both read and set by g_variant_serialised_get_child for arrays of +- * non-fixed-width types */ ++ * This is both read and set by g_variant_serialised_get_child() for arrays of ++ * non-fixed-width types, and for tuples. ++ * ++ * Even when dealing with tuples, @ordered_offsets_up_to is an element index, ++ * rather than an index into the frame offsets. */ + gsize ordered_offsets_up_to; + } GVariantSerialised; + +diff --git a/glib/gvariant.c b/glib/gvariant.c +index d6f68a9..cdb428e 100644 +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -5945,6 +5945,7 @@ g_variant_byteswap (GVariant *value) + serialised.type_info = g_variant_get_type_info (trusted); + serialised.size = g_variant_get_size (trusted); + serialised.data = g_malloc (serialised.size); ++ serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ + g_variant_store (trusted, serialised.data); + g_variant_unref (trusted); + +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index 967e9a1..a84b02e 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -1,6 +1,7 @@ + /* + * Copyright © 2010 Codethink Limited + * Copyright © 2020 William Manley ++ * Copyright © 2022 Endless OS Foundation, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -1451,6 +1452,7 @@ test_maybe (void) + serialised.data = flavoured_malloc (needed_size, flavour); + serialised.size = needed_size; + serialised.depth = 0; ++ serialised.ordered_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, + random_instance_filler, +@@ -1574,6 +1576,7 @@ test_array (void) + serialised.data = flavoured_malloc (needed_size, flavour); + serialised.size = needed_size; + serialised.depth = 0; ++ serialised.ordered_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, random_instance_filler, + (gpointer *) instances, n_children); +@@ -1738,6 +1741,7 @@ test_tuple (void) + serialised.data = flavoured_malloc (needed_size, flavour); + serialised.size = needed_size; + serialised.depth = 0; ++ serialised.ordered_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, random_instance_filler, + (gpointer *) instances, n_children); +@@ -1834,6 +1838,7 @@ test_variant (void) + serialised.data = flavoured_malloc (needed_size, flavour); + serialised.size = needed_size; + serialised.depth = 0; ++ serialised.ordered_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, random_instance_filler, + (gpointer *) &instance, 1); +@@ -5106,6 +5111,176 @@ test_normal_checking_tuple_offsets (void) + g_variant_unref (variant); + } + ++/* This is a regression test that we can't have non-normal values that take up ++ * significantly more space than the normal equivalent, by specifying the ++ * offset table entries so that tuple elements overlap. ++ * ++ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838503 and ++ * https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838513 */ ++static void ++test_normal_checking_tuple_offsets2 (void) ++{ ++ const GVariantType *data_type = G_VARIANT_TYPE ("(yyaiyyaiyy)"); ++ const guint8 data[] = { ++ 0x12, 0x34, 0x56, 0x78, 0x01, ++ /* ++ ^───────────────────┘ ++ ++ ^^^^^^^^^^ 1st yy ++ ^^^^^^^^^^ 2nd yy ++ ^^^^^^^^^^ 3rd yy ++ ^^^^ Framing offsets ++ */ ++ ++ /* If this variant was encoded normally, it would be something like this: ++ * 0x12, 0x34, pad, pad, [array bytes], 0x56, 0x78, pad, pad, [array bytes], 0x9A, 0xBC, 0xXX ++ * ^─────────────────────────────────────────────────────┘ ++ * ++ * ^^^^^^^^^^ 1st yy ++ * ^^^^^^^^^^ 2nd yy ++ * ^^^^^^^^^^ 3rd yy ++ * ^^^^ Framing offsets ++ */ ++ }; ++ gsize size = sizeof (data); ++ GVariant *variant = NULL; ++ GVariant *normal_variant = NULL; ++ GVariant *expected = NULL; ++ ++ variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); ++ g_assert_nonnull (variant); ++ ++ normal_variant = g_variant_get_normal_form (variant); ++ g_assert_nonnull (normal_variant); ++ g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); ++ ++ expected = g_variant_new_parsed ( ++ "@(yyaiyyaiyy) (0x12, 0x34, [], 0x00, 0x00, [], 0x00, 0x00)"); ++ g_assert_cmpvariant (expected, variant); ++ g_assert_cmpvariant (expected, normal_variant); ++ ++ g_variant_unref (expected); ++ g_variant_unref (normal_variant); ++ g_variant_unref (variant); ++} ++ ++/* This is a regression test that overlapping entries in the offset table are ++ * decoded consistently, even though they’re non-normal. ++ * ++ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */ ++static void ++test_normal_checking_tuple_offsets3 (void) ++{ ++ /* The expected decoding of this non-normal byte stream is complex. See ++ * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant ++ * specification. ++ * ++ * The rule “Child Values Overlapping Framing Offsets” from the specification ++ * says that the first `ay` must be decoded as `[0x01]` even though it ++ * overlaps the first byte of the offset table. However, since commit ++ * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow ++ * this as it’s exploitable. So the first `ay` must be given a default value. ++ * ++ * The second and third `ay`s must be given default values because of rule ++ * “End Boundary Precedes Start Boundary”. ++ * ++ * The `i` must be given a default value because of rule “Start or End ++ * Boundary of a Child Falls Outside the Container”. ++ */ ++ const GVariantType *data_type = G_VARIANT_TYPE ("(ayayiay)"); ++ const guint8 data[] = { ++ 0x01, 0x00, 0x02, ++ /* ++ ^──┘ ++ ++ ^^^^^^^^^^ 1st ay, bytes 0-2 (but given a default value anyway, see above) ++ 2nd ay, bytes 2-0 ++ i, bytes 0-4 ++ 3rd ay, bytes 4-1 ++ ^^^^^^^^^^ Framing offsets ++ */ ++ }; ++ gsize size = sizeof (data); ++ GVariant *variant = NULL; ++ GVariant *normal_variant = NULL; ++ GVariant *expected = NULL; ++ ++ variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); ++ g_assert_nonnull (variant); ++ ++ g_assert_false (g_variant_is_normal_form (variant)); ++ ++ normal_variant = g_variant_get_normal_form (variant); ++ g_assert_nonnull (normal_variant); ++ g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); ++ ++ expected = g_variant_new_parsed ("@(ayayiay) ([], [], 0, [])"); ++ g_assert_cmpvariant (expected, variant); ++ g_assert_cmpvariant (expected, normal_variant); ++ ++ g_variant_unref (expected); ++ g_variant_unref (normal_variant); ++ g_variant_unref (variant); ++} ++ ++/* This is a regression test that overlapping entries in the offset table are ++ * decoded consistently, even though they’re non-normal. ++ * ++ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */ ++static void ++test_normal_checking_tuple_offsets4 (void) ++{ ++ /* The expected decoding of this non-normal byte stream is complex. See ++ * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant ++ * specification. ++ * ++ * The rule “Child Values Overlapping Framing Offsets” from the specification ++ * says that the first `ay` must be decoded as `[0x01]` even though it ++ * overlaps the first byte of the offset table. However, since commit ++ * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow ++ * this as it’s exploitable. So the first `ay` must be given a default value. ++ * ++ * The second `ay` must be given a default value because of rule “End Boundary ++ * Precedes Start Boundary”. ++ * ++ * The third `ay` must be given a default value because its framing offsets ++ * overlap that of the first `ay`. ++ */ ++ const GVariantType *data_type = G_VARIANT_TYPE ("(ayayay)"); ++ const guint8 data[] = { ++ 0x01, 0x00, 0x02, ++ /* ++ ^──┘ ++ ++ ^^^^^^^^^^ 1st ay, bytes 0-2 (but given a default value anyway, see above) ++ 2nd ay, bytes 2-0 ++ 3rd ay, bytes 0-1 ++ ^^^^^^^^^^ Framing offsets ++ */ ++ }; ++ gsize size = sizeof (data); ++ GVariant *variant = NULL; ++ GVariant *normal_variant = NULL; ++ GVariant *expected = NULL; ++ ++ variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL); ++ g_assert_nonnull (variant); ++ ++ g_assert_false (g_variant_is_normal_form (variant)); ++ ++ normal_variant = g_variant_get_normal_form (variant); ++ g_assert_nonnull (normal_variant); ++ g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3); ++ ++ expected = g_variant_new_parsed ("@(ayayay) ([], [], [])"); ++ g_assert_cmpvariant (expected, variant); ++ g_assert_cmpvariant (expected, normal_variant); ++ ++ g_variant_unref (expected); ++ g_variant_unref (normal_variant); ++ g_variant_unref (variant); ++} ++ + /* Test that an empty object path is normalised successfully to the base object + * path, ‘/’. */ + static void +@@ -5253,6 +5428,12 @@ main (int argc, char **argv) + test_normal_checking_array_offsets2); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets", + test_normal_checking_tuple_offsets); ++ g_test_add_func ("/gvariant/normal-checking/tuple-offsets2", ++ test_normal_checking_tuple_offsets2); ++ g_test_add_func ("/gvariant/normal-checking/tuple-offsets3", ++ test_normal_checking_tuple_offsets3); ++ g_test_add_func ("/gvariant/normal-checking/tuple-offsets4", ++ test_normal_checking_tuple_offsets4); + g_test_add_func ("/gvariant/normal-checking/empty-object-path", + test_normal_checking_empty_object_path); + +-- +2.24.4 + 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 @@ +From e6490c84e84ba9f182fbd83b51ff4f9f5a0a1793 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Wed, 16 Aug 2023 03:42:47 +0000 +Subject: [PATCH] gvariant: Port g_variant_deep_copy() to count its iterations + directly + +This is equivalent to what `GVariantIter` does, but it means that +`g_variant_deep_copy()` is making its own `g_variant_get_child_value()` +calls. + +This will be useful in an upcoming commit, where those child values will +be inspected a little more deeply. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/e6490c84e84ba9f182fbd83b51ff4f9f5a0a1793] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/glib/gvariant.c b/glib/gvariant.c +index cdb428e..fdd36be 100644 +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -5799,14 +5799,13 @@ g_variant_deep_copy (GVariant *value) + case G_VARIANT_CLASS_VARIANT: + { + GVariantBuilder builder; +- GVariantIter iter; +- GVariant *child; ++ gsize i, n_children; + + g_variant_builder_init (&builder, g_variant_get_type (value)); +- g_variant_iter_init (&iter, value); + +- while ((child = g_variant_iter_next_value (&iter))) ++ for (i = 0, n_children = g_variant_n_children (value); i < n_children; i++) + { ++ GVariant *child = g_variant_get_child_value (value, i); + g_variant_builder_add_value (&builder, g_variant_deep_copy (child)); + g_variant_unref (child); + } +-- +2.24.4 + 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 @@ +From d1a293c4e29880b8d17bb826c9a426a440ca4a91 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 17 Aug 2023 01:30:38 +0000 +Subject: [PATCH] gvariant: Track checked and ordered offsets independently + +The past few commits introduced the concept of known-good offsets in the +offset table (which is used for variable-width arrays and tuples). +Good offsets are ones which are non-overlapping with all the previous +offsets in the table. + +If a bad offset is encountered when indexing into the array or tuple, +the cached known-good offset index will not be increased. In this way, +all child variants at and beyond the first bad offset can be returned as +default values rather than dereferencing potentially invalid data. + +In this case, there was no information about the fact that the indexes +between the highest known-good index and the requested one had been +checked already. That could lead to a pathological case where an offset +table with an invalid first offset is repeatedly checked in full when +trying to access higher-indexed children. + +Avoid that by storing the index of the highest checked offset in the +table, as well as the index of the highest good/ordered offset. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/d1a293c4e29880b8d17bb826c9a426a440ca4a91] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant-core.c | 28 ++++++++++++++++++++++++ + glib/gvariant-serialiser.c | 44 +++++++++++++++++++++++++++----------- + glib/gvariant-serialiser.h | 9 ++++++++ + glib/gvariant.c | 1 + + glib/tests/gvariant.c | 5 +++++ + 5 files changed, 75 insertions(+), 12 deletions(-) + +diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c +index b951cd9..1b9d5cc 100644 +--- a/glib/gvariant-core.c ++++ b/glib/gvariant-core.c +@@ -67,6 +67,7 @@ struct _GVariant + GBytes *bytes; + gconstpointer data; + gsize ordered_offsets_up_to; ++ gsize checked_offsets_up_to; + } serialised; + + struct +@@ -182,6 +183,24 @@ struct _GVariant + * This field is only relevant for arrays of non + * fixed width types and for tuples. + * ++ * .checked_offsets_up_to: Similarly to .ordered_offsets_up_to, this stores ++ * the index of the highest element, n, whose frame ++ * offsets (and all the preceding frame offsets) ++ * have been checked for validity. ++ * ++ * It is always the case that ++ * .checked_offsets_up_to ≥ .ordered_offsets_up_to. ++ * ++ * If .checked_offsets_up_to == .ordered_offsets_up_to, ++ * then a bad offset has not been found so far. ++ * ++ * If .checked_offsets_up_to > .ordered_offsets_up_to, ++ * then a bad offset has been found at ++ * (.ordered_offsets_up_to + 1). ++ * ++ * This field is only relevant for arrays of non ++ * fixed width types and for tuples. ++ * + * .tree: Only valid when the instance is in tree form. + * + * Note that accesses from other threads could result in +@@ -386,6 +405,7 @@ g_variant_to_serialised (GVariant *value) + value->size, + value->depth, + value->contents.serialised.ordered_offsets_up_to, ++ value->contents.serialised.checked_offsets_up_to, + }; + return serialised; + } +@@ -418,6 +438,7 @@ g_variant_serialise (GVariant *value, + serialised.data = data; + serialised.depth = value->depth; + serialised.ordered_offsets_up_to = 0; ++ serialised.checked_offsets_up_to = 0; + + children = (gpointer *) value->contents.tree.children; + n_children = value->contents.tree.n_children; +@@ -464,10 +485,12 @@ g_variant_fill_gvs (GVariantSerialised *serialised, + if (value->state & STATE_SERIALISED) + { + serialised->ordered_offsets_up_to = value->contents.serialised.ordered_offsets_up_to; ++ serialised->checked_offsets_up_to = value->contents.serialised.checked_offsets_up_to; + } + else + { + serialised->ordered_offsets_up_to = 0; ++ serialised->checked_offsets_up_to = 0; + } + + if (serialised->data) +@@ -513,6 +536,7 @@ g_variant_ensure_serialised (GVariant *value) + value->contents.serialised.data = g_bytes_get_data (bytes, NULL); + value->contents.serialised.bytes = bytes; + value->contents.serialised.ordered_offsets_up_to = G_MAXSIZE; ++ value->contents.serialised.checked_offsets_up_to = G_MAXSIZE; + value->state |= STATE_SERIALISED; + } + } +@@ -594,6 +618,7 @@ g_variant_new_from_bytes (const GVariantType *type, + serialised.data = (guchar *) g_bytes_get_data (bytes, &serialised.size); + serialised.depth = 0; + serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; ++ serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0; + + if (!g_variant_serialised_check (serialised)) + { +@@ -644,6 +669,7 @@ g_variant_new_from_bytes (const GVariantType *type, + } + + value->contents.serialised.ordered_offsets_up_to = trusted ? G_MAXSIZE : 0; ++ value->contents.serialised.checked_offsets_up_to = trusted ? G_MAXSIZE : 0; + + g_clear_pointer (&owned_bytes, g_bytes_unref); + +@@ -1120,6 +1146,7 @@ g_variant_get_child_value (GVariant *value, + + /* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */ + value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to); ++ value->contents.serialised.checked_offsets_up_to = MAX (value->contents.serialised.checked_offsets_up_to, serialised.checked_offsets_up_to); + + /* Check whether this would cause nesting too deep. If so, return a fake + * child. The only situation we expect this to happen in is with a variant, +@@ -1147,6 +1174,7 @@ g_variant_get_child_value (GVariant *value, + g_bytes_ref (value->contents.serialised.bytes); + child->contents.serialised.data = s_child.data; + child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to; ++ child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to; + + return child; + } +diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c +index cd4a3e6..0bf7243 100644 +--- a/glib/gvariant-serialiser.c ++++ b/glib/gvariant-serialiser.c +@@ -120,6 +120,8 @@ + * + * @depth has no restrictions; the depth of a top-level serialised #GVariant is + * zero, and it increases for each level of nested child. ++ * ++ * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to + */ + + /* < private > +@@ -147,6 +149,9 @@ g_variant_serialised_check (GVariantSerialised serialised) + !(serialised.size == 0 || serialised.data != NULL)) + return FALSE; + ++ if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to) ++ return FALSE; ++ + /* Depending on the native alignment requirements of the machine, the + * compiler will insert either 3 or 7 padding bytes after the char. + * This will result in the sizeof() the struct being 12 or 16. +@@ -266,6 +271,7 @@ gvs_fixed_sized_maybe_get_child (GVariantSerialised value, + g_variant_type_info_ref (value.type_info); + value.depth++; + value.ordered_offsets_up_to = 0; ++ value.checked_offsets_up_to = 0; + + return value; + } +@@ -297,7 +303,7 @@ gvs_fixed_sized_maybe_serialise (GVariantSerialised value, + { + if (n_children) + { +- GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0 }; ++ GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 }; + + gvs_filler (&child, children[0]); + } +@@ -320,6 +326,7 @@ gvs_fixed_sized_maybe_is_normal (GVariantSerialised value) + value.type_info = g_variant_type_info_element (value.type_info); + value.depth++; + value.ordered_offsets_up_to = 0; ++ value.checked_offsets_up_to = 0; + + return g_variant_serialised_is_normal (value); + } +@@ -362,6 +369,7 @@ gvs_variable_sized_maybe_get_child (GVariantSerialised value, + + value.depth++; + value.ordered_offsets_up_to = 0; ++ value.checked_offsets_up_to = 0; + + return value; + } +@@ -392,7 +400,7 @@ gvs_variable_sized_maybe_serialise (GVariantSerialised value, + { + if (n_children) + { +- GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0 }; ++ GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 }; + + /* write the data for the child. */ + gvs_filler (&child, children[0]); +@@ -413,6 +421,7 @@ gvs_variable_sized_maybe_is_normal (GVariantSerialised value) + value.size--; + value.depth++; + value.ordered_offsets_up_to = 0; ++ value.checked_offsets_up_to = 0; + + return g_variant_serialised_is_normal (value); + } +@@ -739,39 +748,46 @@ gvs_variable_sized_array_get_child (GVariantSerialised value, + + /* If the requested @index_ is beyond the set of indices whose framing offsets + * have been checked, check the remaining offsets to see whether they’re +- * normal (in order, no overlapping array elements). */ +- if (index_ > value.ordered_offsets_up_to) ++ * normal (in order, no overlapping array elements). ++ * ++ * Don’t bother checking if the highest known-good offset is lower than the ++ * highest checked offset, as that means there’s an invalid element at that ++ * index, so there’s no need to check further. */ ++ if (index_ > value.checked_offsets_up_to && ++ value.ordered_offsets_up_to == value.checked_offsets_up_to) + { + switch (offsets.offset_size) + { + case 1: + { + value.ordered_offsets_up_to = find_unordered_guint8 ( +- offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ offsets.array, value.checked_offsets_up_to, index_ + 1); + break; + } + case 2: + { + value.ordered_offsets_up_to = find_unordered_guint16 ( +- offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ offsets.array, value.checked_offsets_up_to, index_ + 1); + break; + } + case 4: + { + value.ordered_offsets_up_to = find_unordered_guint32 ( +- offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ offsets.array, value.checked_offsets_up_to, index_ + 1); + break; + } + case 8: + { + value.ordered_offsets_up_to = find_unordered_guint64 ( +- offsets.array, value.ordered_offsets_up_to, index_ + 1); ++ offsets.array, value.checked_offsets_up_to, index_ + 1); + break; + } + default: + /* gvs_get_offset_size() only returns maximum 8 */ + g_assert_not_reached (); + } ++ ++ value.checked_offsets_up_to = index_; + } + + if (index_ > value.ordered_offsets_up_to) +@@ -916,6 +932,7 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value) + + /* All offsets have now been checked. */ + value.ordered_offsets_up_to = G_MAXSIZE; ++ value.checked_offsets_up_to = G_MAXSIZE; + + return TRUE; + } +@@ -1040,14 +1057,15 @@ gvs_tuple_get_child (GVariantSerialised value, + * all the tuple *elements* here, not just all the framing offsets, since + * tuples contain a mix of elements which use framing offsets and ones which + * don’t. None of them are allowed to overlap. */ +- if (index_ > value.ordered_offsets_up_to) ++ if (index_ > value.checked_offsets_up_to && ++ value.ordered_offsets_up_to == value.checked_offsets_up_to) + { + gsize i, prev_i_end = 0; + +- if (value.ordered_offsets_up_to > 0) +- gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end); ++ if (value.checked_offsets_up_to > 0) ++ gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end); + +- for (i = value.ordered_offsets_up_to; i <= index_; i++) ++ for (i = value.checked_offsets_up_to; i <= index_; i++) + { + gsize i_start, i_end; + +@@ -1060,6 +1078,7 @@ gvs_tuple_get_child (GVariantSerialised value, + } + + value.ordered_offsets_up_to = i - 1; ++ value.checked_offsets_up_to = index_; + } + + if (index_ > value.ordered_offsets_up_to) +@@ -1257,6 +1276,7 @@ gvs_tuple_is_normal (GVariantSerialised value) + + /* All element bounds have been checked above. */ + value.ordered_offsets_up_to = G_MAXSIZE; ++ value.checked_offsets_up_to = G_MAXSIZE; + + { + gsize fixed_size; +diff --git a/glib/gvariant-serialiser.h b/glib/gvariant-serialiser.h +index 144aec8..e132451 100644 +--- a/glib/gvariant-serialiser.h ++++ b/glib/gvariant-serialiser.h +@@ -40,6 +40,15 @@ typedef struct + * Even when dealing with tuples, @ordered_offsets_up_to is an element index, + * rather than an index into the frame offsets. */ + gsize ordered_offsets_up_to; ++ ++ /* Similar to @ordered_offsets_up_to. This gives the index of the child element ++ * whose frame offset is the highest in the offset table which has been ++ * checked so far. ++ * ++ * This is always ≥ @ordered_offsets_up_to. It is always an element index. ++ * ++ * See documentation in gvariant-core.c for `struct GVariant` for details. */ ++ gsize checked_offsets_up_to; + } GVariantSerialised; + + /* deserialisation */ +diff --git a/glib/gvariant.c b/glib/gvariant.c +index fdd36be..f910bd4 100644 +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -5945,6 +5945,7 @@ g_variant_byteswap (GVariant *value) + serialised.size = g_variant_get_size (trusted); + serialised.data = g_malloc (serialised.size); + serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */ ++ serialised.checked_offsets_up_to = G_MAXSIZE; + g_variant_store (trusted, serialised.data); + g_variant_unref (trusted); + +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index a84b02e..640f3c0 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -1286,6 +1286,7 @@ random_instance_filler (GVariantSerialised *serialised, + + serialised->depth = 0; + serialised->ordered_offsets_up_to = 0; ++ serialised->checked_offsets_up_to = 0; + + g_assert_true (serialised->type_info == instance->type_info); + g_assert_cmpuint (serialised->size, ==, instance->size); +@@ -1453,6 +1454,7 @@ test_maybe (void) + serialised.size = needed_size; + serialised.depth = 0; + serialised.ordered_offsets_up_to = 0; ++ serialised.checked_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, + random_instance_filler, +@@ -1577,6 +1579,7 @@ test_array (void) + serialised.size = needed_size; + serialised.depth = 0; + serialised.ordered_offsets_up_to = 0; ++ serialised.checked_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, random_instance_filler, + (gpointer *) instances, n_children); +@@ -1742,6 +1745,7 @@ test_tuple (void) + serialised.size = needed_size; + serialised.depth = 0; + serialised.ordered_offsets_up_to = 0; ++ serialised.checked_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, random_instance_filler, + (gpointer *) instances, n_children); +@@ -1839,6 +1843,7 @@ test_variant (void) + serialised.size = needed_size; + serialised.depth = 0; + serialised.ordered_offsets_up_to = 0; ++ serialised.checked_offsets_up_to = 0; + + g_variant_serialiser_serialise (serialised, random_instance_filler, + (gpointer *) &instance, 1); +-- +2.24.4 + 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 @@ +From 298a537d5f6783e55d87e40011ee3fd3b22b72f9 Mon Sep 17 00:00:00 2001 +From: Philip Withnall <pwithnall@endlessos.org> +Date: Thu, 17 Aug 2023 01:39:01 +0000 +Subject: [PATCH] gvariant: Zero-initialise various GVariantSerialised objects + +The following few commits will add a couple of new fields to +`GVariantSerialised`, and they should be zero-filled by default. + +Try and pre-empt that a bit by zero-filling `GVariantSerialised` by +default in a few places. + +Signed-off-by: Philip Withnall <pwithnall@endlessos.org> + +Helps: #2121 + +CVE: CVE-2023-32665 +Upstream-Status: Backport from [https://gitlab.gnome.org/GNOME/glib/-/commit/298a537d5f6783e55d87e40011ee3fd3b22b72f9] +Signed-off-by: Siddharth Doshi <sdoshi@mvista.com> +--- + glib/gvariant.c | 2 +- + glib/tests/gvariant.c | 12 ++++++------ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/glib/gvariant.c b/glib/gvariant.c +index f910bd4..8ba701e 100644 +--- a/glib/gvariant.c ++++ b/glib/gvariant.c +@@ -5936,7 +5936,7 @@ g_variant_byteswap (GVariant *value) + if (alignment) + /* (potentially) contains multi-byte numeric data */ + { +- GVariantSerialised serialised; ++ GVariantSerialised serialised = { 0, }; + GVariant *trusted; + GBytes *bytes; + +diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c +index 640f3c0..d640c81 100644 +--- a/glib/tests/gvariant.c ++++ b/glib/tests/gvariant.c +@@ -1446,7 +1446,7 @@ test_maybe (void) + + for (flavour = 0; flavour < 8; flavour += alignment) + { +- GVariantSerialised serialised; ++ GVariantSerialised serialised = { 0, }; + GVariantSerialised child; + + serialised.type_info = type_info; +@@ -1572,7 +1572,7 @@ test_array (void) + + for (flavour = 0; flavour < 8; flavour += alignment) + { +- GVariantSerialised serialised; ++ GVariantSerialised serialised = { 0, }; + + serialised.type_info = array_info; + serialised.data = flavoured_malloc (needed_size, flavour); +@@ -1738,7 +1738,7 @@ test_tuple (void) + + for (flavour = 0; flavour < 8; flavour += alignment) + { +- GVariantSerialised serialised; ++ GVariantSerialised serialised = { 0, }; + + serialised.type_info = type_info; + serialised.data = flavoured_malloc (needed_size, flavour); +@@ -1835,7 +1835,7 @@ test_variant (void) + + for (flavour = 0; flavour < 8; flavour += alignment) + { +- GVariantSerialised serialised; ++ GVariantSerialised serialised = { 0, }; + GVariantSerialised child; + + serialised.type_info = type_info; +@@ -2284,7 +2284,7 @@ serialise_tree (TreeInstance *tree, + static void + test_byteswap (void) + { +- GVariantSerialised one, two; ++ GVariantSerialised one = { 0, }, two = { 0, }; + TreeInstance *tree; + + tree = tree_instance_new (NULL, 3); +@@ -2358,7 +2358,7 @@ test_serialiser_children (void) + static void + test_fuzz (gdouble *fuzziness) + { +- GVariantSerialised serialised; ++ GVariantSerialised serialised = { 0, }; + TreeInstance *tree; + + /* make an instance */ +-- +2.24.4 + 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 1a006b9f38..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 @@ -18,6 +18,44 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \ file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \ file://tzdata-update.patch \ file://CVE-2020-35457.patch \ + file://CVE-2021-27218.patch \ + file://CVE-2021-27219-01.patch \ + file://CVE-2021-27219-02.patch \ + file://CVE-2021-27219-03.patch \ + file://CVE-2021-27219-04.patch \ + file://CVE-2021-27219-05.patch \ + file://CVE-2021-27219-06.patch \ + file://CVE-2021-27219-07.patch \ + file://CVE-2021-27219-08.patch \ + file://CVE-2021-27219-09.patch \ + file://CVE-2021-27219-10.patch \ + file://CVE-2021-27219-11.patch \ + file://CVE-2021-27219-reg1-1.patch \ + file://CVE-2021-27219-reg1-2.patch \ + file://CVE-2021-27219-reg1-4.patch \ + file://CVE-2021-27219-reg1-5.patch \ + file://CVE-2021-27219-reg2-1.patch \ + file://CVE-2021-27219-reg2-2.patch \ + file://CVE-2021-27219-reg2-3.patch \ + file://CVE-2021-28153-1.patch \ + file://CVE-2021-28153-2.patch \ + file://CVE-2021-28153-3.patch \ + file://CVE-2021-28153-4.patch \ + file://CVE-2021-28153-5.patch \ + file://CVE-2023-32665-0001.patch \ + file://CVE-2023-32665-0002.patch \ + file://CVE-2023-32665-0003.patch \ + file://CVE-2023-32665-0004.patch \ + file://CVE-2023-32665-0005.patch \ + file://CVE-2023-32665-0006.patch \ + file://CVE-2023-32665-0007.patch \ + file://CVE-2023-32665-0008.patch \ + file://CVE-2023-32665-0009.patch \ + file://CVE-2023-29499.patch \ + file://CVE-2023-32611-0001.patch \ + file://CVE-2023-32611-0002.patch \ + file://CVE-2023-32643.patch \ + file://CVE-2023-32636.patch \ " SRC_URI_append_class-native = " file://relocate-modules.patch" diff --git a/meta/recipes-core/glib-2.0/glib.inc b/meta/recipes-core/glib-2.0/glib.inc index c3ddf18387..1849a6e05c 100644 --- a/meta/recipes-core/glib-2.0/glib.inc +++ b/meta/recipes-core/glib-2.0/glib.inc @@ -4,7 +4,7 @@ HOMEPAGE = "https://developer.gnome.org/glib/" # pcre is under BSD; # docs/reference/COPYING is with a 'public domain'-like license! -LICENSE = "LGPLv2.1+ & BSD & PD" +LICENSE = "LGPLv2.1+ & BSD-3-Clause & PD" LIC_FILES_CHKSUM = "file://COPYING;md5=4fbd65380cdd255951079008b364516c \ file://glib/glib.h;beginline=4;endline=17;md5=b88abb7f3ad09607e71cb9d530155906 \ file://gmodule/COPYING;md5=4fbd65380cdd255951079008b364516c \ |