From ad8e763f73d196149c64c3f39a1268200dc56b97 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 14 Mar 2024 20:42:41 +0000 Subject: [PATCH] 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 b8c071cf4..a543df9cf 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)