mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
GDBusConnection: Do not dispatch calls to unregistered objects or subtrees
There was a slight race where we ended up calling into user code if the user managed to unregister an object (or subtree) in the window between - processing the remote call on the worker thread; and - continuing handling it on the user code thread (via an idle handler) This patch fixes the problem. Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
parent
ed7f59770e
commit
db0c55608f
@ -3018,15 +3018,52 @@ exported_interface_free (ExportedInterface *ei)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* Convenience function to check if @registration_id (if not zero) or
|
||||
* @subtree_registration_id (if not zero) has been unregistered. If
|
||||
* so, returns %TRUE.
|
||||
*
|
||||
* Caller must *not* hold lock.
|
||||
*/
|
||||
static gboolean
|
||||
has_object_been_unregistered (GDBusConnection *connection,
|
||||
guint registration_id,
|
||||
guint subtree_registration_id)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
CONNECTION_LOCK (connection);
|
||||
if (registration_id != 0 && g_hash_table_lookup (connection->priv->map_id_to_ei,
|
||||
GUINT_TO_POINTER (registration_id)) == NULL)
|
||||
{
|
||||
ret = TRUE;
|
||||
}
|
||||
else if (subtree_registration_id != 0 && g_hash_table_lookup (connection->priv->map_id_to_es,
|
||||
GUINT_TO_POINTER (subtree_registration_id)) == NULL)
|
||||
{
|
||||
ret = TRUE;
|
||||
}
|
||||
CONNECTION_UNLOCK (connection);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GDBusConnection *connection;
|
||||
GDBusMessage *message;
|
||||
gpointer user_data;
|
||||
const char *property_name;
|
||||
const gchar *property_name;
|
||||
const GDBusInterfaceVTable *vtable;
|
||||
const GDBusInterfaceInfo *interface_info;
|
||||
const GDBusPropertyInfo *property_info;
|
||||
guint registration_id;
|
||||
guint subtree_registration_id;
|
||||
} PropertyData;
|
||||
|
||||
static void
|
||||
@ -3046,6 +3083,19 @@ invoke_get_property_in_idle_cb (gpointer _data)
|
||||
GError *error;
|
||||
GDBusMessage *reply;
|
||||
|
||||
if (has_object_been_unregistered (data->connection,
|
||||
data->registration_id,
|
||||
data->subtree_registration_id))
|
||||
{
|
||||
reply = g_dbus_message_new_method_error (data->message,
|
||||
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||
_("No such interface `org.freedesktop.DBus.Properties' on object at path %s"),
|
||||
g_dbus_message_get_path (data->message));
|
||||
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
||||
g_object_unref (reply);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
value = data->vtable->get_property (data->connection,
|
||||
g_dbus_message_get_sender (data->message),
|
||||
@ -3070,9 +3120,7 @@ invoke_get_property_in_idle_cb (gpointer _data)
|
||||
else
|
||||
{
|
||||
gchar *dbus_error_name;
|
||||
|
||||
g_assert (error != NULL);
|
||||
|
||||
dbus_error_name = g_dbus_error_encode_gerror (error);
|
||||
reply = g_dbus_message_new_method_error_literal (data->message,
|
||||
dbus_error_name,
|
||||
@ -3083,6 +3131,7 @@ invoke_get_property_in_idle_cb (gpointer _data)
|
||||
g_object_unref (reply);
|
||||
}
|
||||
|
||||
out:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -3153,6 +3202,8 @@ invoke_set_property_in_idle_cb (gpointer _data)
|
||||
static gboolean
|
||||
validate_and_maybe_schedule_property_getset (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
guint registration_id,
|
||||
guint subtree_registration_id,
|
||||
gboolean is_get,
|
||||
const GDBusInterfaceInfo *introspection_data,
|
||||
const GDBusInterfaceVTable *vtable,
|
||||
@ -3243,6 +3294,8 @@ validate_and_maybe_schedule_property_getset (GDBusConnection *connect
|
||||
property_data->vtable = vtable;
|
||||
property_data->interface_info = introspection_data;
|
||||
property_data->property_info = property_info;
|
||||
property_data->registration_id = registration_id;
|
||||
property_data->subtree_registration_id = subtree_registration_id;
|
||||
|
||||
idle_source = g_idle_source_new ();
|
||||
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
||||
@ -3304,6 +3357,8 @@ handle_getset_property (GDBusConnection *connection,
|
||||
|
||||
handled = validate_and_maybe_schedule_property_getset (eo->connection,
|
||||
message,
|
||||
ei->id,
|
||||
0,
|
||||
is_get,
|
||||
ei->introspection_data,
|
||||
ei->vtable,
|
||||
@ -3322,6 +3377,8 @@ typedef struct
|
||||
gpointer user_data;
|
||||
const GDBusInterfaceVTable *vtable;
|
||||
const GDBusInterfaceInfo *interface_info;
|
||||
guint registration_id;
|
||||
guint subtree_registration_id;
|
||||
} PropertyGetAllData;
|
||||
|
||||
static void
|
||||
@ -3342,6 +3399,19 @@ invoke_get_all_properties_in_idle_cb (gpointer _data)
|
||||
GDBusMessage *reply;
|
||||
guint n;
|
||||
|
||||
if (has_object_been_unregistered (data->connection,
|
||||
data->registration_id,
|
||||
data->subtree_registration_id))
|
||||
{
|
||||
reply = g_dbus_message_new_method_error (data->message,
|
||||
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||
_("No such interface `org.freedesktop.DBus.Properties' on object at path %s"),
|
||||
g_dbus_message_get_path (data->message));
|
||||
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
||||
g_object_unref (reply);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = NULL;
|
||||
|
||||
/* TODO: Right now we never fail this call - we just omit values if
|
||||
@ -3383,6 +3453,7 @@ invoke_get_all_properties_in_idle_cb (gpointer _data)
|
||||
g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
|
||||
g_object_unref (reply);
|
||||
|
||||
out:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -3390,6 +3461,8 @@ invoke_get_all_properties_in_idle_cb (gpointer _data)
|
||||
static gboolean
|
||||
validate_and_maybe_schedule_property_get_all (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
guint registration_id,
|
||||
guint subtree_registration_id,
|
||||
const GDBusInterfaceInfo *introspection_data,
|
||||
const GDBusInterfaceVTable *vtable,
|
||||
GMainContext *main_context,
|
||||
@ -3416,6 +3489,8 @@ validate_and_maybe_schedule_property_get_all (GDBusConnection *connec
|
||||
property_get_all_data->user_data = user_data;
|
||||
property_get_all_data->vtable = vtable;
|
||||
property_get_all_data->interface_info = introspection_data;
|
||||
property_get_all_data->registration_id = registration_id;
|
||||
property_get_all_data->subtree_registration_id = subtree_registration_id;
|
||||
|
||||
idle_source = g_idle_source_new ();
|
||||
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
||||
@ -3467,6 +3542,8 @@ handle_get_all_properties (GDBusConnection *connection,
|
||||
|
||||
handled = validate_and_maybe_schedule_property_get_all (eo->connection,
|
||||
message,
|
||||
ei->id,
|
||||
0,
|
||||
ei->introspection_data,
|
||||
ei->vtable,
|
||||
ei->context,
|
||||
@ -3656,10 +3733,30 @@ call_in_idle_cb (gpointer user_data)
|
||||
{
|
||||
GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
|
||||
GDBusInterfaceVTable *vtable;
|
||||
guint registration_id;
|
||||
guint subtree_registration_id;
|
||||
|
||||
vtable = g_object_get_data (G_OBJECT (invocation), "g-dbus-interface-vtable");
|
||||
g_assert (vtable != NULL && vtable->method_call != NULL);
|
||||
|
||||
registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-registration-id"));
|
||||
subtree_registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id"));
|
||||
|
||||
if (has_object_been_unregistered (g_dbus_method_invocation_get_connection (invocation),
|
||||
registration_id,
|
||||
subtree_registration_id))
|
||||
{
|
||||
GDBusMessage *reply;
|
||||
reply = g_dbus_message_new_method_error (g_dbus_method_invocation_get_message (invocation),
|
||||
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||
_("No such interface `%s' on object at path %s"),
|
||||
g_dbus_method_invocation_get_interface_name (invocation),
|
||||
g_dbus_method_invocation_get_object_path (invocation));
|
||||
g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, NULL, NULL);
|
||||
g_object_unref (reply);
|
||||
goto out;
|
||||
}
|
||||
|
||||
vtable->method_call (g_dbus_method_invocation_get_connection (invocation),
|
||||
g_dbus_method_invocation_get_sender (invocation),
|
||||
g_dbus_method_invocation_get_object_path (invocation),
|
||||
@ -3669,6 +3766,7 @@ call_in_idle_cb (gpointer user_data)
|
||||
g_object_ref (invocation),
|
||||
g_dbus_method_invocation_get_user_data (invocation));
|
||||
|
||||
out:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -3676,6 +3774,8 @@ call_in_idle_cb (gpointer user_data)
|
||||
static gboolean
|
||||
validate_and_maybe_schedule_method_call (GDBusConnection *connection,
|
||||
GDBusMessage *message,
|
||||
guint registration_id,
|
||||
guint subtree_registration_id,
|
||||
const GDBusInterfaceInfo *introspection_data,
|
||||
const GDBusInterfaceVTable *vtable,
|
||||
GMainContext *main_context,
|
||||
@ -3756,9 +3856,12 @@ validate_and_maybe_schedule_method_call (GDBusConnection *connection,
|
||||
parameters,
|
||||
user_data);
|
||||
g_variant_unref (parameters);
|
||||
g_object_set_data (G_OBJECT (invocation),
|
||||
"g-dbus-interface-vtable",
|
||||
(gpointer) vtable);
|
||||
|
||||
/* TODO: would be nicer with a real MethodData like we already
|
||||
* have PropertyData and PropertyGetAllData... */
|
||||
g_object_set_data (G_OBJECT (invocation), "g-dbus-interface-vtable", (gpointer) vtable);
|
||||
g_object_set_data (G_OBJECT (invocation), "g-dbus-registration-id", GUINT_TO_POINTER (registration_id));
|
||||
g_object_set_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id", GUINT_TO_POINTER (subtree_registration_id));
|
||||
|
||||
idle_source = g_idle_source_new ();
|
||||
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
|
||||
@ -3809,6 +3912,8 @@ obj_message_func (GDBusConnection *connection,
|
||||
|
||||
handled = validate_and_maybe_schedule_method_call (connection,
|
||||
message,
|
||||
ei->id,
|
||||
0,
|
||||
ei->introspection_data,
|
||||
ei->vtable,
|
||||
ei->context,
|
||||
@ -4687,6 +4792,8 @@ handle_subtree_method_invocation (GDBusConnection *connection,
|
||||
CONNECTION_LOCK (connection);
|
||||
handled = validate_and_maybe_schedule_method_call (es->connection,
|
||||
message,
|
||||
0,
|
||||
es->id,
|
||||
introspection_data,
|
||||
interface_vtable,
|
||||
es->context,
|
||||
@ -4746,6 +4853,8 @@ handle_subtree_method_invocation (GDBusConnection *connection,
|
||||
CONNECTION_LOCK (connection);
|
||||
handled = validate_and_maybe_schedule_property_getset (es->connection,
|
||||
message,
|
||||
0,
|
||||
es->id,
|
||||
is_property_get,
|
||||
introspection_data,
|
||||
interface_vtable,
|
||||
@ -4758,6 +4867,8 @@ handle_subtree_method_invocation (GDBusConnection *connection,
|
||||
CONNECTION_LOCK (connection);
|
||||
handled = validate_and_maybe_schedule_property_get_all (es->connection,
|
||||
message,
|
||||
0,
|
||||
es->id,
|
||||
introspection_data,
|
||||
interface_vtable,
|
||||
es->context,
|
||||
|
Loading…
Reference in New Issue
Block a user