From 7776abb7175266e8bfd71a4631712b843cb1dd64 Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Wed, 29 May 2013 20:50:21 +0800 Subject: [PATCH v4] When "activating" systemd, handle its special case better When dbus-daemon receives a request to activate a systemd service before systemd has connected to it, it enqueues a fake request to "activate" systemd itself (as a way to get a BusPendingActivationEntry to track the process of waiting for systemd). When systemd later joins the bus, dbus-daemon sends the actual activation message; any future activation messages are sent directly to systemd. In the "pending" code path, the activation messages are currently dispatched as though they had been sent by the same process that sent the original activation request, which is wrong: the bus security policy probably doesn't allow that process to talk to systemd directly. They should be dispatched as though they had been sent by the dbus-daemon itself (connection == NULL), the same as in the non-pending code path. In the worst case, if the attempt to activate systemd timed out, the dbus-daemon would crash with a (fatal) warning, because in this special case, activation_message is a signal with no serial number, whereas the code to send an error reply is expecting a method call with a serial number. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=50199 Signed-off-by: Chengwei Yang Tested-by: Ma Yu --- bus/activation.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/bus/activation.c b/bus/activation.c index 3dfba78..fcb7133 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -80,7 +80,14 @@ typedef struct BusPendingActivationEntry BusPendingActivationEntry; struct BusPendingActivationEntry { + /* Normally a method call, but if connection is NULL, this is a signal + * instead. + */ DBusMessage *activation_message; + /* NULL if this activation entry is for the dbus-daemon itself, + * waiting for systemd to start. In this case, auto_activation is always + * TRUE. + */ DBusConnection *connection; dbus_bool_t auto_activation; @@ -1106,7 +1113,8 @@ bus_activation_service_created (BusActivation *activation, BusPendingActivationEntry *entry = link->data; DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); - if (dbus_connection_get_is_connected (entry->connection)) + /* entry->connection is NULL for activating systemd */ + if (entry->connection && dbus_connection_get_is_connected (entry->connection)) { /* Only send activation replies to regular activation requests. */ if (!entry->auto_activation) @@ -1175,7 +1183,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation BusPendingActivationEntry *entry = link->data; DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); - if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection)) + if (entry->auto_activation && (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection))) { DBusConnection *addressed_recipient; @@ -1233,7 +1241,7 @@ try_send_activation_failure (BusPendingActivation *pending_activation, BusPendingActivationEntry *entry = link->data; DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); - if (dbus_connection_get_is_connected (entry->connection)) + if (entry->connection && dbus_connection_get_is_connected (entry->connection)) { if (!bus_transaction_send_error_reply (transaction, entry->connection, @@ -1759,7 +1767,8 @@ bus_activation_activate_service (BusActivation *activation, pending_activation_entry->activation_message = activation_message; dbus_message_ref (activation_message); pending_activation_entry->connection = connection; - dbus_connection_ref (connection); + if (connection) + dbus_connection_ref (connection); /* Check if the service is being activated */ pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name); @@ -1972,7 +1981,7 @@ bus_activation_activate_service (BusActivation *activation, service_name, entry->systemd_service); /* systemd is not around, let's "activate" it. */ - retval = bus_activation_activate_service (activation, connection, activation_transaction, TRUE, + retval = bus_activation_activate_service (activation, NULL, activation_transaction, TRUE, message, "org.freedesktop.systemd1", error); } -- 1.7.9.5