From 0d670263ce35a938c41d5a70be9e6aad63699dfa Mon Sep 17 00:00:00 2001 From: q66 Date: Tue, 7 May 2024 19:34:37 +0200 Subject: [PATCH] main/glib: update to 2.80.1 --- main/glib/patches/3959.patch | 330 ------ main/glib/patches/3979.patch | 44 - main/glib/patches/CVE-2024-34397.patch | 1272 ------------------------ main/glib/patches/tests.patch | 5 +- main/glib/template.py | 8 +- 5 files changed, 8 insertions(+), 1651 deletions(-) delete mode 100644 main/glib/patches/3959.patch delete mode 100644 main/glib/patches/3979.patch delete mode 100644 main/glib/patches/CVE-2024-34397.patch diff --git a/main/glib/patches/3959.patch b/main/glib/patches/3959.patch deleted file mode 100644 index cf3c0d127f..0000000000 --- a/main/glib/patches/3959.patch +++ /dev/null @@ -1,330 +0,0 @@ -From 1bb5661198cd81d73c60ff0583579edaf7f536a3 Mon Sep 17 00:00:00 2001 -From: Thomas Haller -Date: Mon, 18 Mar 2024 07:49:52 +0100 -Subject: [PATCH 1/3] gobject: fix racy assertion for toggle-refs - -We can only assert for having one toggle reference, after we confirmed -(under lock) that the ref count was in the toggle case. - -Otherwise, if another thread refs/unrefs the object, we can hit a wrong -g_critical() assertion about - - if (tstackptr->n_toggle_refs != 1) - { - g_critical ("Unexpected number of toggle-refs. g_object_add_toggle_ref() must be paired with g_object_remove_toggle_ref()"); - -Fixes: 9ae43169cfe0 ('gobject: fix race in toggle ref during g_object_ref()') ---- - gobject/gobject.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/gobject/gobject.c b/gobject/gobject.c -index 7ec5902b6e..e347400a04 100644 ---- a/gobject/gobject.c -+++ b/gobject/gobject.c -@@ -4152,9 +4152,10 @@ retry: - - /* With ref count 1, check whether we need to emit a toggle notification. */ - object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); - do_retry = !g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, - old_ref, old_ref + 1, &old_ref); -+ if (!do_retry) -+ toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); - object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); - if (do_retry) - goto retry; -@@ -4332,8 +4333,6 @@ retry_beginning: - - object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); - -- toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); -- - if (!g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, - old_ref, old_ref - 1, &old_ref)) - { -@@ -4341,6 +4340,7 @@ retry_beginning: - goto retry_beginning; - } - -+ toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); - object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); - - /* Beware: object might be a dangling pointer. */ -@@ -4426,10 +4426,11 @@ retry_decrement: - * - * In that case, we need a lock to get the toggle notification. */ - object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); - do_retry = !g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, - old_ref, old_ref - 1, - &old_ref); -+ if (!do_retry) -+ toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); - object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); - - if (do_retry) --- -GitLab - - -From f17cfcf930da77ea35bbafe5f7a07e813f329ebf Mon Sep 17 00:00:00 2001 -From: Thomas Haller -Date: Tue, 30 Jan 2024 12:29:05 +0100 -Subject: [PATCH 2/3] gobject: extract duplicate code for toggle reference in - g_object_unref() - -Move comment logic to one place. Add toggle_refs_check_and_ref_or_deref(). ---- - gobject/gobject.c | 89 ++++++++++++++++++++++++----------------------- - 1 file changed, 46 insertions(+), 43 deletions(-) - -diff --git a/gobject/gobject.c b/gobject/gobject.c -index e347400a04..1e8d0a9505 100644 ---- a/gobject/gobject.c -+++ b/gobject/gobject.c -@@ -3949,25 +3949,54 @@ typedef struct { - } toggle_refs[1]; /* flexible array */ - } ToggleRefStack; - --static GToggleNotify --toggle_refs_get_notify_unlocked (GObject *object, -- gpointer *out_data) --{ -- ToggleRefStack *tstackptr; -+G_ALWAYS_INLINE static inline gboolean -+toggle_refs_check_and_ref_or_deref (GObject *object, -+ gboolean is_ref, -+ gint *old_ref, -+ GToggleNotify *toggle_notify, -+ gpointer *toggle_data) -+{ -+ const gint ref_curr = is_ref ? 1 : 2; -+ const gint ref_next = is_ref ? 2 : 1; -+ gboolean success; - -- if (!OBJECT_HAS_TOGGLE_REF (object)) -- return NULL; -+#if G_ENABLE_DEBUG -+ g_assert (ref_curr == *old_ref); -+#endif -+ -+ *toggle_notify = NULL; -+ *toggle_data = NULL; -+ -+ object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -+ -+ /* @old_ref is mainly an (out) parameter. On failure to compare-and-exchange, -+ * we MUST return the new value which the caller will use for retry.*/ - -- tstackptr = g_datalist_id_get_data (&object->qdata, quark_toggle_refs); -+ success = g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, -+ ref_curr, -+ ref_next, -+ old_ref); - -- if (tstackptr->n_toggle_refs != 1) -+ if (success && OBJECT_HAS_TOGGLE_REF (object)) - { -- g_critical ("Unexpected number of toggle-refs. g_object_add_toggle_ref() must be paired with g_object_remove_toggle_ref()"); -- return NULL; -+ ToggleRefStack *tstackptr; -+ -+ tstackptr = g_datalist_id_get_data (&object->qdata, quark_toggle_refs); -+ -+ if (tstackptr->n_toggle_refs != 1) -+ { -+ g_critical ("Unexpected number of toggle-refs. g_object_add_toggle_ref() must be paired with g_object_remove_toggle_ref()"); -+ } -+ else -+ { -+ *toggle_notify = tstackptr->toggle_refs[0].notify; -+ *toggle_data = tstackptr->toggle_refs[0].data; -+ } - } - -- *out_data = tstackptr->toggle_refs[0].data; -- return tstackptr->toggle_refs[0].notify; -+ object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -+ -+ return success; - } - - /** -@@ -4148,16 +4177,8 @@ retry: - } - else if (old_ref == 1) - { -- gboolean do_retry; -- - /* With ref count 1, check whether we need to emit a toggle notification. */ -- object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- do_retry = !g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, -- old_ref, old_ref + 1, &old_ref); -- if (!do_retry) -- toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); -- object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- if (do_retry) -+ if (!toggle_refs_check_and_ref_or_deref (object, TRUE, &old_ref, &toggle_notify, &toggle_data)) - goto retry; - } - else -@@ -4282,7 +4303,6 @@ g_object_unref (gpointer _object) - GToggleNotify toggle_notify; - gpointer toggle_data; - GObjectNotifyQueue *nqueue; -- gboolean do_retry; - GType obj_gtype; - - g_return_if_fail (G_IS_OBJECT (object)); -@@ -4331,17 +4351,8 @@ retry_beginning: - * - * We need to take a lock, to avoid races. */ - -- object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- -- if (!g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, -- old_ref, old_ref - 1, &old_ref)) -- { -- object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- goto retry_beginning; -- } -- -- toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); -- object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -+ if (!toggle_refs_check_and_ref_or_deref (object, FALSE, &old_ref, &toggle_notify, &toggle_data)) -+ goto retry_beginning; - - /* Beware: object might be a dangling pointer. */ - TRACE (GOBJECT_OBJECT_UNREF (object, obj_gtype, old_ref)); -@@ -4425,15 +4436,7 @@ retry_decrement: - * notification. Take a lock and check for that. - * - * In that case, we need a lock to get the toggle notification. */ -- object_bit_lock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- do_retry = !g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count, -- old_ref, old_ref - 1, -- &old_ref); -- if (!do_retry) -- toggle_notify = toggle_refs_get_notify_unlocked (object, &toggle_data); -- object_bit_unlock (object, OPTIONAL_BIT_LOCK_TOGGLE_REFS); -- -- if (do_retry) -+ if (!toggle_refs_check_and_ref_or_deref (object, FALSE, &old_ref, &toggle_notify, &toggle_data)) - goto retry_decrement; - - /* Beware: object might be a dangling pointer. */ --- -GitLab - - -From 1b298d1db11afb125f8ccb17192ef99bb80ab47e Mon Sep 17 00:00:00 2001 -From: Thomas Haller -Date: Tue, 30 Jan 2024 12:29:05 +0100 -Subject: [PATCH 3/3] gobject: add code comment about unlock and - toggle_refs_check_and_ref_or_deref() - -It may not be obvious, but the moment unlock is called, the locker -instance may be destroyed. - -See g_object_unref(), which calls toggle_refs_check_and_ref_or_deref(). -It will check for toggle references while dropping the ref count from 2 -to 1. It must decrement the ref count while holding the lock, but it -also must still unlock afterwards. - -Note that the locker instance is on the object itself. Once we decrement -the ref count we give up our reference and another thread may race -against destroying the object. We thus must not touch object anymore. -How can we then still unlock? - -This works correctly because: - -- unlock operations must not touch the locker instance after unlocking. - -- assume that another thread races g_object_unref() to destroy the - object, while we are about to call object_bit_unlock() in - toggle_refs_check_and_ref_or_deref(). Then that other thread will also - need to acquire the same lock (during g_object_notify_queue_freeze()). - It thus is blocked to destroy the object. - -Add code comments about that. ---- - glib/gbitlock.c | 8 ++++++++ - gobject/gobject.c | 21 +++++++++++++++++++++ - 2 files changed, 29 insertions(+) - -diff --git a/glib/gbitlock.c b/glib/gbitlock.c -index f96cae4766..900897517e 100644 ---- a/glib/gbitlock.c -+++ b/glib/gbitlock.c -@@ -342,6 +342,10 @@ g_bit_unlock (volatile gint *address, - g_atomic_int_and (address_nonvolatile, ~mask); - #endif - -+ /* Warning: unlocking may allow another thread to proceed and destroy the -+ * memory that @address points to. We thus must not dereference it anymore. -+ */ -+ - { - guint class = bit_lock_contended_class (address_nonvolatile); - -@@ -599,6 +603,10 @@ void - g_atomic_pointer_and (pointer_address, ~mask); - #endif - -+ /* Warning: unlocking may allow another thread to proceed and destroy the -+ * memory that @address points to. We thus must not dereference it anymore. -+ */ -+ - { - guint class = bit_lock_contended_class (address_nonvolatile); - -diff --git a/gobject/gobject.c b/gobject/gobject.c -index 1e8d0a9505..9ebe362ce8 100644 ---- a/gobject/gobject.c -+++ b/gobject/gobject.c -@@ -644,6 +644,9 @@ object_bit_unlock (GObject *object, guint lock_bit) - _object_bit_is_locked = 0; - #endif - -+ /* Warning: after unlock, @object may be a dangling pointer (destroyed on -+ * another thread) and must not be touched anymore. */ -+ - g_bit_unlock ((gint *) object_get_optional_flags_p (object), _OPTIONAL_BIT_LOCK); - } - -@@ -3977,6 +3980,20 @@ toggle_refs_check_and_ref_or_deref (GObject *object, - ref_next, - old_ref); - -+ /* Note that if we are called during g_object_unref (@is_ref set to FALSE), -+ * then we drop the ref count from 2 to 1 and give up our reference. We thus -+ * no longer hold a strong reference and another thread may race against -+ * destroying the object. -+ * -+ * After this point with is_ref=FALSE and success=TRUE, @object must no -+ * longer be accessed. -+ * -+ * The exception is here. While we still hold the object lock, we know that -+ * @object could not be destroyed, because g_object_unref() also needs to -+ * acquire the same lock during g_object_notify_queue_freeze(). Thus, we know -+ * object cannot yet be destroyed and we can access it until the unlock -+ * below. */ -+ - if (success && OBJECT_HAS_TOGGLE_REF (object)) - { - ToggleRefStack *tstackptr; -@@ -4385,6 +4402,10 @@ retry_beginning: - * notifications. If the instance gets through to finalize(), the - * notification queue gets automatically drained when g_object_finalize() is - * reached and the qdata is cleared. -+ * -+ * Important: Note that g_object_notify_queue_freeze() takes a object_bit_lock(), -+ * which happens to be the same lock that is also taken by toggle_refs_check_and_ref(), -+ * that is very important. See also the code comment in toggle_refs_check_and_ref(). - */ - nqueue = g_object_notify_queue_freeze (object); - --- -GitLab - diff --git a/main/glib/patches/3979.patch b/main/glib/patches/3979.patch deleted file mode 100644 index 705a8f353d..0000000000 --- a/main/glib/patches/3979.patch +++ /dev/null @@ -1,44 +0,0 @@ -From cc25486b233ada380ac8452f47f5fb35536888f4 Mon Sep 17 00:00:00 2001 -From: q66 -Date: Sat, 23 Mar 2024 20:51:52 +0100 -Subject: [PATCH] Use CPU_COUNT to get the number of set CPUs - -This fixes an issue with the number getting very big due to -CPU_ISSET not returning exactly 0 or 1. - -This also fixes scenarios where there are holes in the CPU -set. E.g. for a simple run like `taskset --cpu-list 1,2,4 ...` -the old code would return 2 instead of 3, due to iterating -until `ncores` (which is 3) and therefore not accounting for -CPUs further in the set. - -Ref https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3784 ---- - glib/gthread.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/glib/gthread.c b/glib/gthread.c -index b39acc475c..a264353ecb 100644 ---- a/glib/gthread.c -+++ b/glib/gthread.c -@@ -1092,7 +1092,6 @@ g_get_num_processors (void) - return count; - #elif defined(_SC_NPROCESSORS_ONLN) && defined(THREADS_POSIX) && defined(HAVE_PTHREAD_GETAFFINITY_NP) - { -- int idx; - int ncores = MIN (sysconf (_SC_NPROCESSORS_ONLN), CPU_SETSIZE); - cpu_set_t cpu_mask; - CPU_ZERO (&cpu_mask); -@@ -1100,8 +1099,7 @@ g_get_num_processors (void) - int af_count = 0; - int err = pthread_getaffinity_np (pthread_self (), sizeof (cpu_mask), &cpu_mask); - if (!err) -- for (idx = 0; idx < ncores && idx < CPU_SETSIZE; ++idx) -- af_count += CPU_ISSET (idx, &cpu_mask); -+ af_count = CPU_COUNT (&cpu_mask); - - int count = (af_count > 0) ? af_count : ncores; - return count; --- -GitLab - diff --git a/main/glib/patches/CVE-2024-34397.patch b/main/glib/patches/CVE-2024-34397.patch deleted file mode 100644 index 0f62e855e5..0000000000 --- a/main/glib/patches/CVE-2024-34397.patch +++ /dev/null @@ -1,1272 +0,0 @@ -Patch-Source: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4039 -tests omitted --- -From bd1bb4f5e094cf3fd329a10471d6616fde0ca92f Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Thu, 14 Mar 2024 19:18:15 +0000 -Subject: [PATCH 05/16] gdbusprivate: Add symbolic constants for the message - bus itself - -Using these is a bit more clearly correct than repeating them everywhere. -To avoid excessive diffstat in a branch for a bug fix, I'm not -immediately replacing all existing occurrences of the same literals with -these names. - -The names of these constants are chosen to be consistent with libdbus, -despite using somewhat outdated terminology (D-Bus now uses the term -"well-known bus name" for what used to be called a service name, -reserving the word "service" to mean specifically the programs that -have .service files and participate in service activation). - -Signed-off-by: Simon McVittie ---- - gio/gdbusprivate.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h -index e7a5bfa4f1..57147e1729 100644 ---- a/gio/gdbusprivate.h -+++ b/gio/gdbusprivate.h -@@ -27,6 +27,11 @@ - - G_BEGIN_DECLS - -+/* Bus name, interface and object path of the message bus itself */ -+#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -+#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS -+#define DBUS_PATH_DBUS "/org/freedesktop/DBus" -+ - /* ---------------------------------------------------------------------------------------------------- */ - - typedef struct GDBusWorker GDBusWorker; --- -GitLab - - -From c5126b330870dbeaa2146e81db9b0ce8dc96c712 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Thu, 14 Mar 2024 19:24:24 +0000 -Subject: [PATCH 06/16] gdbusconnection: Move SignalData, SignalSubscriber - higher up - -Subsequent changes will need to access these data structures from -on_worker_message_received(). No functional change here, only moving -code around. - -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 128 +++++++++++++++++++++--------------------- - 1 file changed, 65 insertions(+), 63 deletions(-) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index 8fcab42a9b..82fde0bce2 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -287,6 +287,71 @@ call_destroy_notify (GMainContext *context, - - /* ---------------------------------------------------------------------------------------------------- */ - -+typedef struct -+{ -+ /* All fields are immutable after construction. */ -+ gatomicrefcount ref_count; -+ GDBusSignalCallback callback; -+ gpointer user_data; -+ GDestroyNotify user_data_free_func; -+ guint id; -+ GMainContext *context; -+} SignalSubscriber; -+ -+static SignalSubscriber * -+signal_subscriber_ref (SignalSubscriber *subscriber) -+{ -+ g_atomic_ref_count_inc (&subscriber->ref_count); -+ return subscriber; -+} -+ -+static void -+signal_subscriber_unref (SignalSubscriber *subscriber) -+{ -+ if (g_atomic_ref_count_dec (&subscriber->ref_count)) -+ { -+ /* Destroy the user data. It doesn’t matter which thread -+ * signal_subscriber_unref() is called in (or whether it’s called with a -+ * lock held), as call_destroy_notify() always defers to the next -+ * #GMainContext iteration. */ -+ call_destroy_notify (subscriber->context, -+ subscriber->user_data_free_func, -+ subscriber->user_data); -+ -+ g_main_context_unref (subscriber->context); -+ g_free (subscriber); -+ } -+} -+ -+typedef struct -+{ -+ gchar *rule; -+ gchar *sender; -+ gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ -+ gchar *interface_name; -+ gchar *member; -+ gchar *object_path; -+ gchar *arg0; -+ GDBusSignalFlags flags; -+ GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ -+} SignalData; -+ -+static void -+signal_data_free (SignalData *signal_data) -+{ -+ g_free (signal_data->rule); -+ g_free (signal_data->sender); -+ g_free (signal_data->sender_unique_name); -+ g_free (signal_data->interface_name); -+ g_free (signal_data->member); -+ g_free (signal_data->object_path); -+ g_free (signal_data->arg0); -+ g_ptr_array_unref (signal_data->subscribers); -+ g_free (signal_data); -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ - #ifdef G_OS_WIN32 - #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE) - #else -@@ -3248,69 +3313,6 @@ g_dbus_connection_remove_filter (GDBusConnection *connection, - - /* ---------------------------------------------------------------------------------------------------- */ - --typedef struct --{ -- gchar *rule; -- gchar *sender; -- gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ -- gchar *interface_name; -- gchar *member; -- gchar *object_path; -- gchar *arg0; -- GDBusSignalFlags flags; -- GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ --} SignalData; -- --static void --signal_data_free (SignalData *signal_data) --{ -- g_free (signal_data->rule); -- g_free (signal_data->sender); -- g_free (signal_data->sender_unique_name); -- g_free (signal_data->interface_name); -- g_free (signal_data->member); -- g_free (signal_data->object_path); -- g_free (signal_data->arg0); -- g_ptr_array_unref (signal_data->subscribers); -- g_free (signal_data); --} -- --typedef struct --{ -- /* All fields are immutable after construction. */ -- gatomicrefcount ref_count; -- GDBusSignalCallback callback; -- gpointer user_data; -- GDestroyNotify user_data_free_func; -- guint id; -- GMainContext *context; --} SignalSubscriber; -- --static SignalSubscriber * --signal_subscriber_ref (SignalSubscriber *subscriber) --{ -- g_atomic_ref_count_inc (&subscriber->ref_count); -- return subscriber; --} -- --static void --signal_subscriber_unref (SignalSubscriber *subscriber) --{ -- if (g_atomic_ref_count_dec (&subscriber->ref_count)) -- { -- /* Destroy the user data. It doesn’t matter which thread -- * signal_subscriber_unref() is called in (or whether it’s called with a -- * lock held), as call_destroy_notify() always defers to the next -- * #GMainContext iteration. */ -- call_destroy_notify (subscriber->context, -- subscriber->user_data_free_func, -- subscriber->user_data); -- -- g_main_context_unref (subscriber->context); -- g_free (subscriber); -- } --} -- - static gchar * - args_to_rule (const gchar *sender, - const gchar *interface_name, --- -GitLab - - -From 91fe59eeefeae6c211528f7f804bc37ae8d29c1d Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Thu, 14 Mar 2024 19:30:12 +0000 -Subject: [PATCH 07/16] gdbusconnection: Factor out signal_data_new_take() - -No functional changes, except that the implicit ownership-transfer -for the rule field becomes explicit (the local variable is set to NULL -afterwards). - -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 42 ++++++++++++++++++++++++++++++++---------- - 1 file changed, 32 insertions(+), 10 deletions(-) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index 82fde0bce2..5000c1f964 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -336,6 +336,30 @@ typedef struct - GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ - } SignalData; - -+static SignalData * -+signal_data_new_take (gchar *rule, -+ gchar *sender, -+ gchar *sender_unique_name, -+ gchar *interface_name, -+ gchar *member, -+ gchar *object_path, -+ gchar *arg0, -+ GDBusSignalFlags flags) -+{ -+ SignalData *signal_data = g_new0 (SignalData, 1); -+ -+ signal_data->rule = rule; -+ signal_data->sender = sender; -+ signal_data->sender_unique_name = sender_unique_name; -+ signal_data->interface_name = interface_name; -+ signal_data->member = member; -+ signal_data->object_path = object_path; -+ signal_data->arg0 = arg0; -+ signal_data->flags = flags; -+ signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref); -+ return g_steal_pointer (&signal_data); -+} -+ - static void - signal_data_free (SignalData *signal_data) - { -@@ -3579,16 +3603,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - goto out; - } - -- signal_data = g_new0 (SignalData, 1); -- signal_data->rule = rule; -- signal_data->sender = g_strdup (sender); -- signal_data->sender_unique_name = g_strdup (sender_unique_name); -- signal_data->interface_name = g_strdup (interface_name); -- signal_data->member = g_strdup (member); -- signal_data->object_path = g_strdup (object_path); -- signal_data->arg0 = g_strdup (arg0); -- signal_data->flags = flags; -- signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref); -+ signal_data = signal_data_new_take (g_steal_pointer (&rule), -+ g_strdup (sender), -+ g_strdup (sender_unique_name), -+ g_strdup (interface_name), -+ g_strdup (member), -+ g_strdup (object_path), -+ g_strdup (arg0), -+ flags); - g_ptr_array_add (signal_data->subscribers, subscriber); - - g_hash_table_insert (connection->map_rule_to_signal_data, --- -GitLab - - -From a8187079dae930fc52409e6ad4e4a7cdf11171e7 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Tue, 23 Apr 2024 20:31:57 +0100 -Subject: [PATCH 08/16] gdbusconnection: Factor out add_signal_data() - -No functional changes. - -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 64 +++++++++++++++++++++++++------------------ - 1 file changed, 37 insertions(+), 27 deletions(-) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index 5000c1f964..c3d6e6d061 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -3457,6 +3457,42 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) - - /* ---------------------------------------------------------------------------------------------------- */ - -+/* called in any thread, connection lock is held */ -+static void -+add_signal_data (GDBusConnection *connection, -+ SignalData *signal_data) -+{ -+ GPtrArray *signal_data_array; -+ -+ g_hash_table_insert (connection->map_rule_to_signal_data, -+ signal_data->rule, -+ signal_data); -+ -+ /* Add the match rule to the bus... -+ * -+ * Avoid adding match rules for NameLost and NameAcquired messages - the bus will -+ * always send such messages to us. -+ */ -+ if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) -+ { -+ if (!is_signal_data_for_name_lost_or_acquired (signal_data)) -+ add_match_rule (connection, signal_data->rule); -+ } -+ -+ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, -+ signal_data->sender_unique_name); -+ if (signal_data_array == NULL) -+ { -+ signal_data_array = g_ptr_array_new (); -+ g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, -+ g_strdup (signal_data->sender_unique_name), -+ signal_data_array); -+ } -+ g_ptr_array_add (signal_data_array, signal_data); -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ - /** - * g_dbus_connection_signal_subscribe: - * @connection: a #GDBusConnection -@@ -3546,7 +3582,6 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - gchar *rule; - SignalData *signal_data; - SignalSubscriber *subscriber; -- GPtrArray *signal_data_array; - const gchar *sender_unique_name; - - /* Right now we abort if AddMatch() fails since it can only fail with the bus being in -@@ -3612,32 +3647,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - g_strdup (arg0), - flags); - g_ptr_array_add (signal_data->subscribers, subscriber); -- -- g_hash_table_insert (connection->map_rule_to_signal_data, -- signal_data->rule, -- signal_data); -- -- /* Add the match rule to the bus... -- * -- * Avoid adding match rules for NameLost and NameAcquired messages - the bus will -- * always send such messages to us. -- */ -- if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) -- { -- if (!is_signal_data_for_name_lost_or_acquired (signal_data)) -- add_match_rule (connection, signal_data->rule); -- } -- -- signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, -- signal_data->sender_unique_name); -- if (signal_data_array == NULL) -- { -- signal_data_array = g_ptr_array_new (); -- g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, -- g_strdup (signal_data->sender_unique_name), -- signal_data_array); -- } -- g_ptr_array_add (signal_data_array, signal_data); -+ add_signal_data (connection, signal_data); - - out: - g_hash_table_insert (connection->map_id_to_signal_data, --- -GitLab - - -From d31f0777d12d22e1d27ba2bb544a9040ce51940f Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Thu, 14 Mar 2024 19:51:59 +0000 -Subject: [PATCH 09/16] gdbusconnection: Factor out - remove_signal_data_if_unused - -No functional change, just removing some nesting. The check for whether -signal_data->subscribers is empty changes from a conditional that tests -whether it is into an early-return if it isn't. - -A subsequent commit will add additional conditions that make us consider -a SignalData to be still in use and therefore not eligible to be removed. - -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 83 +++++++++++++++++++++++++------------------ - 1 file changed, 48 insertions(+), 35 deletions(-) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index c3d6e6d061..0e5cba3ea2 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -3661,6 +3661,52 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - - /* ---------------------------------------------------------------------------------------------------- */ - -+/* -+ * Called in any thread. -+ * Must hold the connection lock when calling this, unless -+ * connection->finalizing is TRUE. -+ * May free signal_data, so do not dereference it after this. -+ */ -+static void -+remove_signal_data_if_unused (GDBusConnection *connection, -+ SignalData *signal_data) -+{ -+ GPtrArray *signal_data_array; -+ -+ if (signal_data->subscribers->len != 0) -+ return; -+ -+ g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); -+ -+ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, -+ signal_data->sender_unique_name); -+ g_warn_if_fail (signal_data_array != NULL); -+ g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); -+ -+ if (signal_data_array->len == 0) -+ { -+ g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, -+ signal_data->sender_unique_name)); -+ } -+ -+ /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ -+ if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) && -+ !is_signal_data_for_name_lost_or_acquired (signal_data) && -+ !g_dbus_connection_is_closed (connection) && -+ !connection->finalizing) -+ { -+ /* The check for g_dbus_connection_is_closed() means that -+ * sending the RemoveMatch message can't fail with -+ * G_IO_ERROR_CLOSED, because we're holding the lock, -+ * so on_worker_closed() can't happen between the check we just -+ * did, and releasing the lock later. -+ */ -+ remove_match_rule (connection, signal_data->rule); -+ } -+ -+ signal_data_free (signal_data); -+} -+ - /* called in any thread */ - /* must hold lock when calling this (except if connection->finalizing is TRUE) - * returns the number of removed subscribers */ -@@ -3669,7 +3715,6 @@ unsubscribe_id_internal (GDBusConnection *connection, - guint subscription_id) - { - SignalData *signal_data; -- GPtrArray *signal_data_array; - guint n; - guint n_removed = 0; - -@@ -3696,40 +3741,8 @@ unsubscribe_id_internal (GDBusConnection *connection, - GUINT_TO_POINTER (subscription_id))); - n_removed++; - g_ptr_array_remove_index_fast (signal_data->subscribers, n); -- -- if (signal_data->subscribers->len == 0) -- { -- g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); -- -- signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, -- signal_data->sender_unique_name); -- g_warn_if_fail (signal_data_array != NULL); -- g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); -- -- if (signal_data_array->len == 0) -- { -- g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, -- signal_data->sender_unique_name)); -- } -- -- /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ -- if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) && -- !is_signal_data_for_name_lost_or_acquired (signal_data) && -- !g_dbus_connection_is_closed (connection) && -- !connection->finalizing) -- { -- /* The check for g_dbus_connection_is_closed() means that -- * sending the RemoveMatch message can't fail with -- * G_IO_ERROR_CLOSED, because we're holding the lock, -- * so on_worker_closed() can't happen between the check we just -- * did, and releasing the lock later. -- */ -- remove_match_rule (connection, signal_data->rule); -- } -- -- signal_data_free (signal_data); -- } -- -+ /* May free signal_data */ -+ remove_signal_data_if_unused (connection, signal_data); - goto out; - } - --- -GitLab - - -From 0bca1891a734de82bd7e0f2c09507ca285c3d1f4 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Tue, 23 Apr 2024 20:39:05 +0100 -Subject: [PATCH 10/16] gdbusconnection: Stop storing sender_unique_name in - SignalData - -This will become confusing when we start tracking the owner of a -well-known-name sender, and it's redundant anyway. Instead, track the -1 bit of data that we actually need: whether it's a well-known name. - -Strictly speaking this too is redundant, because it's syntactically -derivable from the sender, but only via extra string operations. -A subsequent commit will add a data structure to keep track of the -owner of a well-known-name sender, at which point this boolean will -be replaced by the presence or absence of that data structure. - -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 36 ++++++++++++++++++++++++------------ - 1 file changed, 24 insertions(+), 12 deletions(-) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index 0e5cba3ea2..8dcfcbf62b 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -327,19 +327,19 @@ typedef struct - { - gchar *rule; - gchar *sender; -- gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ - gchar *interface_name; - gchar *member; - gchar *object_path; - gchar *arg0; - GDBusSignalFlags flags; - GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ -+ gboolean sender_is_its_own_owner; - } SignalData; - - static SignalData * - signal_data_new_take (gchar *rule, - gchar *sender, -- gchar *sender_unique_name, -+ gboolean sender_is_its_own_owner, - gchar *interface_name, - gchar *member, - gchar *object_path, -@@ -350,7 +350,7 @@ signal_data_new_take (gchar *rule, - - signal_data->rule = rule; - signal_data->sender = sender; -- signal_data->sender_unique_name = sender_unique_name; -+ signal_data->sender_is_its_own_owner = sender_is_its_own_owner; - signal_data->interface_name = interface_name; - signal_data->member = member; - signal_data->object_path = object_path; -@@ -365,7 +365,6 @@ signal_data_free (SignalData *signal_data) - { - g_free (signal_data->rule); - g_free (signal_data->sender); -- g_free (signal_data->sender_unique_name); - g_free (signal_data->interface_name); - g_free (signal_data->member); - g_free (signal_data->object_path); -@@ -3448,7 +3447,7 @@ remove_match_rule (GDBusConnection *connection, - static gboolean - is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) - { -- return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 && -+ return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 && - g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 && - g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 && - (g_strcmp0 (signal_data->member, "NameLost") == 0 || -@@ -3460,7 +3459,8 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) - /* called in any thread, connection lock is held */ - static void - add_signal_data (GDBusConnection *connection, -- SignalData *signal_data) -+ SignalData *signal_data, -+ const char *sender_unique_name) - { - GPtrArray *signal_data_array; - -@@ -3480,12 +3480,12 @@ add_signal_data (GDBusConnection *connection, - } - - signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, -- signal_data->sender_unique_name); -+ sender_unique_name); - if (signal_data_array == NULL) - { - signal_data_array = g_ptr_array_new (); - g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, -- g_strdup (signal_data->sender_unique_name), -+ g_strdup (sender_unique_name), - signal_data_array); - } - g_ptr_array_add (signal_data_array, signal_data); -@@ -3582,6 +3582,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - gchar *rule; - SignalData *signal_data; - SignalSubscriber *subscriber; -+ gboolean sender_is_its_own_owner; - const gchar *sender_unique_name; - - /* Right now we abort if AddMatch() fails since it can only fail with the bus being in -@@ -3617,6 +3618,11 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - rule = args_to_rule (sender, interface_name, member, object_path, arg0, flags); - - if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0)) -+ sender_is_its_own_owner = TRUE; -+ else -+ sender_is_its_own_owner = FALSE; -+ -+ if (sender_is_its_own_owner) - sender_unique_name = sender; - else - sender_unique_name = ""; -@@ -3640,14 +3646,14 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - - signal_data = signal_data_new_take (g_steal_pointer (&rule), - g_strdup (sender), -- g_strdup (sender_unique_name), -+ sender_is_its_own_owner, - g_strdup (interface_name), - g_strdup (member), - g_strdup (object_path), - g_strdup (arg0), - flags); - g_ptr_array_add (signal_data->subscribers, subscriber); -- add_signal_data (connection, signal_data); -+ add_signal_data (connection, signal_data, sender_unique_name); - - out: - g_hash_table_insert (connection->map_id_to_signal_data, -@@ -3671,22 +3677,28 @@ static void - remove_signal_data_if_unused (GDBusConnection *connection, - SignalData *signal_data) - { -+ const gchar *sender_unique_name; - GPtrArray *signal_data_array; - - if (signal_data->subscribers->len != 0) - return; - -+ if (signal_data->sender_is_its_own_owner) -+ sender_unique_name = signal_data->sender; -+ else -+ sender_unique_name = ""; -+ - g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); - - signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, -- signal_data->sender_unique_name); -+ sender_unique_name); - g_warn_if_fail (signal_data_array != NULL); - g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); - - if (signal_data_array->len == 0) - { - g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, -- signal_data->sender_unique_name)); -+ sender_unique_name)); - } - - /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ --- -GitLab - - -From d6c2a2f12e262a4150456a3dac25e9e5628830f2 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Tue, 23 Apr 2024 20:42:17 +0100 -Subject: [PATCH 11/16] gdbus: Track name owners for signal subscriptions - -We will use this in a subsequent commit to prevent signals from an -impostor from being delivered to a subscriber. - -To avoid message reordering leading to misleading situations, this does -not use the existing mechanism for watching bus name ownership, which -delivers the ownership changes to other main-contexts. Instead, it all -happens on the single thread used by the GDBusWorker, so the order in -which messages are received is the order in which they are processed. - -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 350 +++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 343 insertions(+), 7 deletions(-) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index 8dcfcbf62b..b8c071cf45 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -324,6 +324,31 @@ signal_subscriber_unref (SignalSubscriber *subscriber) - } - - typedef struct -+{ -+ /* -+ * 1 reference while waiting for GetNameOwner() to finish -+ * 1 reference for each SignalData that points to this one as its -+ * shared_name_watcher -+ */ -+ grefcount ref_count; -+ -+ gchar *owner; -+ guint32 get_name_owner_serial; -+} WatchedName; -+ -+static WatchedName * -+watched_name_new (void) -+{ -+ WatchedName *watched_name = g_new0 (WatchedName, 1); -+ -+ g_ref_count_init (&watched_name->ref_count); -+ watched_name->owner = NULL; -+ return g_steal_pointer (&watched_name); -+} -+ -+typedef struct SignalData SignalData; -+ -+struct SignalData - { - gchar *rule; - gchar *sender; -@@ -333,13 +358,36 @@ typedef struct - gchar *arg0; - GDBusSignalFlags flags; - GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ -- gboolean sender_is_its_own_owner; --} SignalData; -+ -+ /* -+ * If the sender is a well-known name, this is an unowned SignalData -+ * representing the NameOwnerChanged signal that tracks its owner. -+ * NULL if sender is NULL. -+ * NULL if sender is its own owner (a unique name or DBUS_SERVICE_DBUS). -+ * -+ * Invariants: if not NULL, then -+ * shared_name_watcher->sender == DBUS_SERVICE_DBUS -+ * shared_name_watcher->interface_name == DBUS_INTERFACE_DBUS -+ * shared_name_watcher->member == "NameOwnerChanged" -+ * shared_name_watcher->object_path == DBUS_PATH_DBUS -+ * shared_name_watcher->arg0 == sender -+ * shared_name_watcher->flags == NONE -+ * shared_name_watcher->watched_name == NULL -+ */ -+ SignalData *shared_name_watcher; -+ -+ /* -+ * Non-NULL if this SignalData is another SignalData's shared_name_watcher. -+ * One reference for each SignalData that has this one as its -+ * shared_name_watcher. -+ * Otherwise NULL. -+ */ -+ WatchedName *watched_name; -+}; - - static SignalData * - signal_data_new_take (gchar *rule, - gchar *sender, -- gboolean sender_is_its_own_owner, - gchar *interface_name, - gchar *member, - gchar *object_path, -@@ -350,7 +398,6 @@ signal_data_new_take (gchar *rule, - - signal_data->rule = rule; - signal_data->sender = sender; -- signal_data->sender_is_its_own_owner = sender_is_its_own_owner; - signal_data->interface_name = interface_name; - signal_data->member = member; - signal_data->object_path = object_path; -@@ -363,6 +410,17 @@ signal_data_new_take (gchar *rule, - static void - signal_data_free (SignalData *signal_data) - { -+ /* The SignalData should not be freed while it still has subscribers */ -+ g_assert (signal_data->subscribers->len == 0); -+ -+ /* The SignalData should not be freed while it is watching for -+ * NameOwnerChanged on behalf of another SignalData */ -+ g_assert (signal_data->watched_name == NULL); -+ -+ /* The SignalData should be detached from its name watcher, if any, -+ * before it is freed */ -+ g_assert (signal_data->shared_name_watcher == NULL); -+ - g_free (signal_data->rule); - g_free (signal_data->sender); - g_free (signal_data->interface_name); -@@ -370,6 +428,7 @@ signal_data_free (SignalData *signal_data) - g_free (signal_data->object_path); - g_free (signal_data->arg0); - g_ptr_array_unref (signal_data->subscribers); -+ - g_free (signal_data); - } - -@@ -493,6 +552,7 @@ struct _GDBusConnection - - /* Map used for managing method replies, protected by @lock */ - GHashTable *map_method_serial_to_task; /* guint32 -> owned GTask* */ -+ GHashTable *map_method_serial_to_name_watcher; /* guint32 -> unowned SignalData* */ - - /* Maps used for managing signal subscription, protected by @lock */ - GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */ -@@ -741,6 +801,7 @@ g_dbus_connection_finalize (GObject *object) - g_error_free (connection->initialization_error); - - g_hash_table_unref (connection->map_method_serial_to_task); -+ g_hash_table_unref (connection->map_method_serial_to_name_watcher); - - g_hash_table_unref (connection->map_rule_to_signal_data); - g_hash_table_unref (connection->map_id_to_signal_data); -@@ -1127,6 +1188,7 @@ g_dbus_connection_init (GDBusConnection *connection) - g_mutex_init (&connection->init_lock); - - connection->map_method_serial_to_task = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); -+ connection->map_method_serial_to_name_watcher = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); - - connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash, - g_str_equal); -@@ -2255,6 +2317,191 @@ g_dbus_connection_send_message_with_reply_sync (GDBusConnection *connecti - - /* ---------------------------------------------------------------------------------------------------- */ - -+/* -+ * Called in any thread. -+ * Must hold the connection lock when calling this, unless -+ * connection->finalizing is TRUE. -+ */ -+static void -+name_watcher_unref_watched_name (GDBusConnection *connection, -+ SignalData *name_watcher) -+{ -+ WatchedName *watched_name = name_watcher->watched_name; -+ -+ g_assert (watched_name != NULL); -+ -+ if (!g_ref_count_dec (&watched_name->ref_count)) -+ return; -+ -+ /* Removing watched_name from the name_watcher may result in -+ * name_watcher being freed, so we must make sure name_watcher is no -+ * longer in map_method_serial_to_name_watcher. -+ * -+ * If we stop watching the name while our GetNameOwner call was still -+ * in-flight, then when the reply eventually arrives, we will not find -+ * its serial number in the map and harmlessly ignore it as a result. */ -+ if (watched_name->get_name_owner_serial != 0) -+ g_hash_table_remove (connection->map_method_serial_to_name_watcher, -+ GUINT_TO_POINTER (watched_name->get_name_owner_serial)); -+ -+ name_watcher->watched_name = NULL; -+ g_free (watched_name->owner); -+ g_free (watched_name); -+} -+ -+/* called in GDBusWorker thread with lock held */ -+static void -+name_watcher_set_name_owner_unlocked (SignalData *name_watcher, -+ const char *new_owner) -+{ -+ if (new_owner != NULL && new_owner[0] == '\0') -+ new_owner = NULL; -+ -+ g_assert (name_watcher->watched_name != NULL); -+ g_set_str (&name_watcher->watched_name->owner, new_owner); -+} -+ -+/* called in GDBusWorker thread with lock held */ -+static void -+name_watcher_deliver_name_owner_changed_unlocked (SignalData *name_watcher, -+ GDBusMessage *message) -+{ -+ GVariant *body; -+ -+ body = g_dbus_message_get_body (message); -+ -+ if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(sss)")))) -+ { -+ const char *name; -+ const char *new_owner; -+ -+ g_variant_get (body, "(&s&s&s)", &name, NULL, &new_owner); -+ -+ /* Our caller already checked this */ -+ g_assert (g_strcmp0 (name_watcher->arg0, name) == 0); -+ -+ if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_unique_name (new_owner))) -+ name_watcher_set_name_owner_unlocked (name_watcher, new_owner); -+ else -+ g_warning ("Received NameOwnerChanged signal with invalid owner \"%s\" for \"%s\"", -+ new_owner, name); -+ } -+ else -+ { -+ g_warning ("Received NameOwnerChanged signal with unexpected " -+ "signature %s", -+ body == NULL ? "()" : g_variant_get_type_string (body)); -+ -+ } -+} -+ -+/* called in GDBusWorker thread with lock held */ -+static void -+name_watcher_deliver_get_name_owner_reply_unlocked (SignalData *name_watcher, -+ GDBusConnection *connection, -+ GDBusMessage *message) -+{ -+ GDBusMessageType type; -+ GVariant *body; -+ WatchedName *watched_name; -+ -+ watched_name = name_watcher->watched_name; -+ g_assert (watched_name != NULL); -+ g_assert (watched_name->get_name_owner_serial != 0); -+ -+ type = g_dbus_message_get_message_type (message); -+ body = g_dbus_message_get_body (message); -+ -+ if (type == G_DBUS_MESSAGE_TYPE_ERROR) -+ { -+ if (g_strcmp0 (g_dbus_message_get_error_name (message), -+ "org.freedesktop.DBus.Error.NameHasNoOwner")) -+ name_watcher_set_name_owner_unlocked (name_watcher, NULL); -+ /* else it's something like NoReply or AccessDenied, which tells -+ * us nothing - leave the owner set to whatever we most recently -+ * learned from NameOwnerChanged, or NULL */ -+ } -+ else if (type != G_DBUS_MESSAGE_TYPE_METHOD_RETURN) -+ { -+ g_warning ("Received GetNameOwner reply with unexpected type %d", -+ type); -+ } -+ else if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))) -+ { -+ const char *new_owner; -+ -+ g_variant_get (body, "(&s)", &new_owner); -+ -+ if (G_LIKELY (g_dbus_is_unique_name (new_owner))) -+ name_watcher_set_name_owner_unlocked (name_watcher, new_owner); -+ else -+ g_warning ("Received GetNameOwner reply with invalid owner \"%s\" for \"%s\"", -+ new_owner, name_watcher->arg0); -+ } -+ else -+ { -+ g_warning ("Received GetNameOwner reply with unexpected signature %s", -+ body == NULL ? "()" : g_variant_get_type_string (body)); -+ } -+ -+ g_hash_table_remove (connection->map_method_serial_to_name_watcher, -+ GUINT_TO_POINTER (watched_name->get_name_owner_serial)); -+ watched_name->get_name_owner_serial = 0; -+} -+ -+/* Called in a user thread, lock is held */ -+static void -+name_watcher_call_get_name_owner_unlocked (GDBusConnection *connection, -+ SignalData *name_watcher) -+{ -+ GDBusMessage *message; -+ GError *local_error = NULL; -+ WatchedName *watched_name; -+ -+ g_assert (g_strcmp0 (name_watcher->sender, DBUS_SERVICE_DBUS) == 0); -+ g_assert (g_strcmp0 (name_watcher->interface_name, DBUS_INTERFACE_DBUS) == 0); -+ g_assert (g_strcmp0 (name_watcher->member, "NameOwnerChanged") == 0); -+ g_assert (g_strcmp0 (name_watcher->object_path, DBUS_PATH_DBUS) == 0); -+ /* arg0 of the NameOwnerChanged message is the well-known name whose owner -+ * we are interested in */ -+ g_assert (g_dbus_is_name (name_watcher->arg0)); -+ g_assert (name_watcher->flags == G_DBUS_SIGNAL_FLAGS_NONE); -+ -+ watched_name = name_watcher->watched_name; -+ g_assert (watched_name != NULL); -+ g_assert (watched_name->owner == NULL); -+ g_assert (watched_name->get_name_owner_serial == 0); -+ g_assert (name_watcher->shared_name_watcher == NULL); -+ -+ message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS, -+ DBUS_PATH_DBUS, -+ DBUS_INTERFACE_DBUS, -+ "GetNameOwner"); -+ g_dbus_message_set_body (message, g_variant_new ("(s)", name_watcher->arg0)); -+ -+ if (g_dbus_connection_send_message_unlocked (connection, message, -+ G_DBUS_SEND_MESSAGE_FLAGS_NONE, -+ &watched_name->get_name_owner_serial, -+ &local_error)) -+ { -+ g_assert (watched_name->get_name_owner_serial != 0); -+ g_hash_table_insert (connection->map_method_serial_to_name_watcher, -+ GUINT_TO_POINTER (watched_name->get_name_owner_serial), -+ name_watcher); -+ } -+ else -+ { -+ g_critical ("Error while sending GetNameOwner() message: %s", -+ local_error->message); -+ g_clear_error (&local_error); -+ g_assert (watched_name->get_name_owner_serial == 0); -+ } -+ -+ g_object_unref (message); -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ - typedef struct - { - guint id; -@@ -2378,6 +2625,7 @@ on_worker_message_received (GDBusWorker *worker, - { - guint32 reply_serial; - GTask *task; -+ SignalData *name_watcher; - - reply_serial = g_dbus_message_get_reply_serial (message); - CONNECTION_LOCK (connection); -@@ -2393,6 +2641,19 @@ on_worker_message_received (GDBusWorker *worker, - { - //g_debug ("message reply/error for serial %d but no SendMessageData found for %p", reply_serial, connection); - } -+ -+ name_watcher = g_hash_table_lookup (connection->map_method_serial_to_name_watcher, -+ GUINT_TO_POINTER (reply_serial)); -+ -+ if (name_watcher != NULL) -+ { -+ g_assert (name_watcher->watched_name != NULL); -+ g_assert (name_watcher->watched_name->get_name_owner_serial == reply_serial); -+ name_watcher_deliver_get_name_owner_reply_unlocked (name_watcher, -+ connection, -+ message); -+ } -+ - CONNECTION_UNLOCK (connection); - } - else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL) -@@ -3581,6 +3842,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - { - gchar *rule; - SignalData *signal_data; -+ SignalData *name_watcher = NULL; - SignalSubscriber *subscriber; - gboolean sender_is_its_own_owner; - const gchar *sender_unique_name; -@@ -3646,13 +3908,59 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, - - signal_data = signal_data_new_take (g_steal_pointer (&rule), - g_strdup (sender), -- sender_is_its_own_owner, - g_strdup (interface_name), - g_strdup (member), - g_strdup (object_path), - g_strdup (arg0), - flags); - g_ptr_array_add (signal_data->subscribers, subscriber); -+ -+ /* If subscribing to a signal from a specific sender with a well-known -+ * name, we must first subscribe to NameOwnerChanged signals for that -+ * well-known name, so that we can match the current owner of the name -+ * against the sender of each signal. */ -+ if (sender != NULL && !sender_is_its_own_owner) -+ { -+ gchar *name_owner_rule = NULL; -+ -+ /* We already checked that sender != NULL implies MESSAGE_BUS_CONNECTION */ -+ g_assert (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION); -+ -+ name_owner_rule = args_to_rule (DBUS_SERVICE_DBUS, -+ DBUS_INTERFACE_DBUS, -+ "NameOwnerChanged", -+ DBUS_PATH_DBUS, -+ sender, -+ G_DBUS_SIGNAL_FLAGS_NONE); -+ name_watcher = g_hash_table_lookup (connection->map_rule_to_signal_data, name_owner_rule); -+ -+ if (name_watcher == NULL) -+ { -+ name_watcher = signal_data_new_take (g_steal_pointer (&name_owner_rule), -+ g_strdup (DBUS_SERVICE_DBUS), -+ g_strdup (DBUS_INTERFACE_DBUS), -+ g_strdup ("NameOwnerChanged"), -+ g_strdup (DBUS_PATH_DBUS), -+ g_strdup (sender), -+ G_DBUS_SIGNAL_FLAGS_NONE); -+ add_signal_data (connection, name_watcher, DBUS_SERVICE_DBUS); -+ } -+ -+ if (name_watcher->watched_name == NULL) -+ { -+ name_watcher->watched_name = watched_name_new (); -+ name_watcher_call_get_name_owner_unlocked (connection, name_watcher); -+ } -+ else -+ { -+ g_ref_count_inc (&name_watcher->watched_name->ref_count); -+ } -+ -+ signal_data->shared_name_watcher = name_watcher; -+ -+ g_clear_pointer (&name_owner_rule, g_free); -+ } -+ - add_signal_data (connection, signal_data, sender_unique_name); - - out: -@@ -3680,10 +3988,18 @@ remove_signal_data_if_unused (GDBusConnection *connection, - const gchar *sender_unique_name; - GPtrArray *signal_data_array; - -+ /* Cannot remove while there are still subscribers */ - if (signal_data->subscribers->len != 0) - return; - -- if (signal_data->sender_is_its_own_owner) -+ /* Cannot remove while another SignalData is still using this one -+ * as its shared_name_watcher, which holds watched_name->ref_count > 0 */ -+ if (signal_data->watched_name != NULL) -+ return; -+ -+ /* Point of no return: we have committed to removing it */ -+ -+ if (signal_data->sender != NULL && signal_data->shared_name_watcher == NULL) - sender_unique_name = signal_data->sender; - else - sender_unique_name = ""; -@@ -3716,6 +4032,15 @@ remove_signal_data_if_unused (GDBusConnection *connection, - remove_match_rule (connection, signal_data->rule); - } - -+ if (signal_data->shared_name_watcher != NULL) -+ { -+ SignalData *name_watcher = g_steal_pointer (&signal_data->shared_name_watcher); -+ -+ name_watcher_unref_watched_name (connection, name_watcher); -+ /* May free signal_data */ -+ remove_signal_data_if_unused (connection, name_watcher); -+ } -+ - signal_data_free (signal_data); - } - -@@ -3992,6 +4317,17 @@ schedule_callbacks (GDBusConnection *connection, - continue; - } - -+ if (signal_data->watched_name != NULL) -+ { -+ /* Invariant: SignalData should only have a watched_name if it -+ * represents the NameOwnerChanged signal */ -+ g_assert (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0); -+ g_assert (g_strcmp0 (interface, DBUS_INTERFACE_DBUS) == 0); -+ g_assert (g_strcmp0 (path, DBUS_PATH_DBUS) == 0); -+ g_assert (g_strcmp0 (member, "NameOwnerChanged") == 0); -+ name_watcher_deliver_name_owner_changed_unlocked (signal_data, message); -+ } -+ - for (m = 0; m < signal_data->subscribers->len; m++) - { - SignalSubscriber *subscriber = signal_data->subscribers->pdata[m]; -@@ -4063,7 +4399,7 @@ distribute_signals (GDBusConnection *connection, - schedule_callbacks (connection, signal_data_array, message, sender); - } - -- /* collect subscribers not matching on sender */ -+ /* collect subscribers not matching on sender, or matching a well-known name */ - signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, ""); - if (signal_data_array != NULL) - schedule_callbacks (connection, signal_data_array, message, sender); --- -GitLab - - -From ad8e763f73d196149c64c3f39a1268200dc56b97 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Thu, 14 Mar 2024 20:42:41 +0000 -Subject: [PATCH 12/16] gdbusconnection: Don't deliver signals if the sender - doesn't match - -Otherwise a malicious connection on a shared bus, especially the system -bus, could trick GDBus clients into processing signals sent by the -malicious connection as though they had come from the real owner of a -well-known service name. - -Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/3268 -Signed-off-by: Simon McVittie ---- - gio/gdbusconnection.c | 40 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 40 insertions(+) - -diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c -index b8c071cf45..a543df9cfc 100644 ---- a/gio/gdbusconnection.c -+++ b/gio/gdbusconnection.c -@@ -4300,6 +4300,46 @@ schedule_callbacks (GDBusConnection *connection, - if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0) - continue; - -+ if (signal_data->shared_name_watcher != NULL) -+ { -+ /* We want signals from a specified well-known name, which means -+ * the signal's sender needs to be the unique name that currently -+ * owns that well-known name, and we will have found this -+ * SignalData in -+ * connection->map_sender_unique_name_to_signal_data_array[""]. */ -+ const WatchedName *watched_name; -+ const char *current_owner; -+ -+ g_assert (signal_data->sender != NULL); -+ /* Invariant: We never need to watch for the owner of a unique -+ * name, or for the owner of DBUS_SERVICE_DBUS, either of which -+ * is always its own owner */ -+ g_assert (!g_dbus_is_unique_name (signal_data->sender)); -+ g_assert (g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) != 0); -+ -+ watched_name = signal_data->shared_name_watcher->watched_name; -+ g_assert (watched_name != NULL); -+ current_owner = watched_name->owner; -+ -+ /* Skip the signal if the actual sender is not known to own -+ * the required name */ -+ if (current_owner == NULL || g_strcmp0 (current_owner, sender) != 0) -+ continue; -+ } -+ else if (signal_data->sender != NULL) -+ { -+ /* We want signals from a unique name or o.fd.DBus... */ -+ g_assert (g_dbus_is_unique_name (signal_data->sender) -+ || g_str_equal (signal_data->sender, DBUS_SERVICE_DBUS)); -+ -+ /* ... which means we must have found this SignalData in -+ * connection->map_sender_unique_name_to_signal_data_array[signal_data->sender], -+ * therefore we would only have found it if the signal's -+ * actual sender matches the required signal_data->sender */ -+ g_assert (g_strcmp0 (signal_data->sender, sender) == 0); -+ } -+ /* else the sender is unspecified and we will accept anything */ -+ - if (signal_data->arg0 != NULL) - { - if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE) --- -GitLab diff --git a/main/glib/patches/tests.patch b/main/glib/patches/tests.patch index 81b64f1b88..873274c10a 100644 --- a/main/glib/patches/tests.patch +++ b/main/glib/patches/tests.patch @@ -10,14 +10,17 @@ diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 232ecca..4a799a1 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build -@@ -454,10 +454,6 @@ if host_machine.system() != 'windows' +@@ -439,12 +439,6 @@ if host_machine.system() != 'windows' 'extra_sources' : extra_sources, 'extra_programs': extra_programs, }, - 'gdbus-connection-slow' : { - 'extra_sources' : extra_sources, - 'extra_programs': extra_programs + ['gdbus-connection-flush-helper'], +- # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 +- 'can_fail' : host_system == 'gnu', - }, 'gdbus-error' : {'extra_sources' : extra_sources}, 'gdbus-exit-on-close' : {'extra_sources' : extra_sources}, 'gdbus-export' : { + diff --git a/main/glib/template.py b/main/glib/template.py index 88c9ff79a8..e0f13ced73 100644 --- a/main/glib/template.py +++ b/main/glib/template.py @@ -1,9 +1,9 @@ pkgname = "glib" -pkgver = "2.80.0" -pkgrel = 3 +pkgver = "2.80.1" +pkgrel = 0 build_style = "meson" configure_args = [ - "-Dgtk_doc=false", + "-Ddocumentation=false", "-Dintrospection=enabled", "-Dman-pages=enabled", "-Dselinux=disabled", @@ -39,7 +39,7 @@ license = "LGPL-2.1-or-later" url = "https://wiki.gnome.org/Projects/GLib" source = f"$(GNOME_SITE)/{pkgname}/{pkgver[:-2]}/{pkgname}-{pkgver}.tar.xz" -sha256 = "8228a92f92a412160b139ae68b6345bd28f24434a7b5af150ebe21ff587a561d" +sha256 = "bcfc8c2fab64fc9dcb91011375422159f1440502257fb90219215079d8716705" # FIXME int - strfuncs failure hardening = ["!int"]