mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-01 00:10:11 +01:00
nm-sudo: reject new request once we have no well-known-name
If we fail to acquire the well-known name or if we already released it, we must not accept anymore new requests. Otherwise, requests directly targeted to the unique name will keep the process alive, and prevent it from restarting (and serving the well-known name). Clients really should not talk to the unique name of a service that exits on idle. If they do, and the service is about to shut down, then the request will be rejected. After we released the name, there is now turning back and we should quit fast (only processing the requests we already have). Also, if we receive a SIGTERM, then we are requested to quit and should do so in a timely manner. That means, we will start with releasing the name. As the service is D-Bus activated, new requests can be served by the next instance (or if the service is about to be disabled altogether, they will start failing).
This commit is contained in:
parent
0aaaab07d1
commit
31c48ec616
1 changed files with 82 additions and 39 deletions
|
|
@ -56,6 +56,8 @@ struct _GlobalData {
|
|||
* of the request, so it is ONLY for testing. */
|
||||
bool no_auth_for_testing;
|
||||
|
||||
bool reject_new_requests;
|
||||
|
||||
bool is_shutting_down_quitting;
|
||||
bool is_shutting_down_timeout;
|
||||
bool is_shutting_down_cleanup;
|
||||
|
|
@ -283,6 +285,23 @@ _bus_method_call(GDBusConnection * connection,
|
|||
return;
|
||||
}
|
||||
|
||||
if (gl->reject_new_requests) {
|
||||
/* after the name was released, we must not accept new requests. This new
|
||||
* request was probably targeted against the unique-name. But we already
|
||||
* gave up the well-known name. If we'd accept new request now, they would
|
||||
* keep the service running indefinitely (and thus preventing the service
|
||||
* to restart and serve the well-known name. */
|
||||
_LOGT("dbus: request sender=%s, %s%s, SERVER SHUTTING DOWN",
|
||||
sender,
|
||||
method_name,
|
||||
g_variant_get_type_string(parameters));
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_NO_SERVER,
|
||||
"Server is exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
_pending_job_register_object(gl, G_OBJECT(invocation));
|
||||
|
||||
_LOGT("dbus: request sender=%s, %s%s",
|
||||
|
|
@ -476,11 +495,59 @@ _pending_job_register_object(GlobalData *gl, GObject *obj)
|
|||
static void
|
||||
_bus_release_name_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
_nm_unused gs_unref_object GObject *keep_alive_object = user_data;
|
||||
_nm_unused gs_unref_object GObject *keep_alive_object = NULL;
|
||||
GlobalData * gl;
|
||||
|
||||
nm_utils_user_data_unpack(user_data, &gl, &keep_alive_object);
|
||||
|
||||
gl->reject_new_requests = TRUE;
|
||||
g_main_context_wakeup(NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_bus_release_name(GlobalData *gl)
|
||||
{
|
||||
gs_unref_object GObject *keep_alive_object = NULL;
|
||||
int r;
|
||||
|
||||
/* We already requested a name. To exit-on-idle without race, we need to dance.
|
||||
* See https://lists.freedesktop.org/archives/dbus/2015-May/016671.html . */
|
||||
|
||||
if (!gl->name_requested)
|
||||
return FALSE;
|
||||
|
||||
gl->name_requested = FALSE;
|
||||
gl->is_shutting_down_quitting = TRUE;
|
||||
|
||||
_LOGT("shutdown: release-name");
|
||||
|
||||
keep_alive_object = g_object_new(G_TYPE_OBJECT, NULL);
|
||||
|
||||
/* we use the _pending_job_register_object() mechanism to make the loop busy during
|
||||
* shutdown. */
|
||||
_pending_job_register_object(gl, keep_alive_object);
|
||||
|
||||
r = nm_sd_notify("STOPPING=1");
|
||||
if (r < 0)
|
||||
_LOGW("shutdown: sd_notifiy(STOPPING=1) failed: %s", nm_strerror_native(-r));
|
||||
else
|
||||
_LOGT("shutdown: sd_notifiy(STOPPING=1) succeeded");
|
||||
|
||||
g_dbus_connection_call(gl->dbus_connection,
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_PATH_DBUS,
|
||||
DBUS_INTERFACE_DBUS,
|
||||
"ReleaseName",
|
||||
g_variant_new("(s)", NM_SUDO_DBUS_BUS_NAME),
|
||||
G_VARIANT_TYPE("(u)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
10000,
|
||||
NULL,
|
||||
_bus_release_name_cb,
|
||||
nm_utils_user_data_pack(gl, g_steal_pointer(&keep_alive_object)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -555,9 +622,21 @@ main(int argc, char **argv)
|
|||
if (!g_cancellable_is_cancelled(gl->quit_cancellable))
|
||||
exit_code = EXIT_FAILURE;
|
||||
gl->is_shutting_down_quitting = TRUE;
|
||||
|
||||
if (gl->name_requested) {
|
||||
/* We requested a name, but something went wrong. Below we will release
|
||||
* the name right away. */
|
||||
} else {
|
||||
/* In case we didn't even went as far to request the name. New requests
|
||||
* can only come via the unique name, and as we are shutting down, they
|
||||
* are rejected. */
|
||||
gl->reject_new_requests = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
if (gl->is_shutting_down_quitting)
|
||||
_bus_release_name(gl);
|
||||
if (!c_list_is_empty(&gl->pending_jobs_lst_head)) {
|
||||
/* we must first reply to all requests. No matter what. */
|
||||
} else if (gl->is_shutting_down_quitting || gl->is_shutting_down_timeout) {
|
||||
|
|
@ -565,44 +644,8 @@ main(int argc, char **argv)
|
|||
* if we received an idle-timeout and the very moment afterwards
|
||||
* a new request, then _bus_method_call() will clear gl->is_shutting_down_timeout
|
||||
* (via _pending_job_register_object()). */
|
||||
|
||||
if (gl->name_requested) {
|
||||
gs_unref_object GObject *keep_alive_object = g_object_new(G_TYPE_OBJECT, NULL);
|
||||
|
||||
/* We already requested a name. To exit-on-idle without race, we need to dance.
|
||||
* See https://lists.freedesktop.org/archives/dbus/2015-May/016671.html . */
|
||||
|
||||
gl->name_requested = FALSE;
|
||||
gl->is_shutting_down_quitting = TRUE;
|
||||
|
||||
_LOGT("shutdown: release-name");
|
||||
|
||||
/* we use the _pending_job_register_object() mechanism to make the loop busy during
|
||||
* shutdown. */
|
||||
_pending_job_register_object(gl, keep_alive_object);
|
||||
|
||||
r = nm_sd_notify("STOPPING=1");
|
||||
if (r < 0)
|
||||
_LOGW("shutdown: sd_notifiy(STOPPING=1) failed: %s", nm_strerror_native(-r));
|
||||
else
|
||||
_LOGT("shutdown: sd_notifiy(STOPPING=1) succeeded");
|
||||
|
||||
g_dbus_connection_call(gl->dbus_connection,
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_PATH_DBUS,
|
||||
DBUS_INTERFACE_DBUS,
|
||||
"ReleaseName",
|
||||
g_variant_new("(s)", NM_SUDO_DBUS_BUS_NAME),
|
||||
G_VARIANT_TYPE("(u)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
10000,
|
||||
NULL,
|
||||
_bus_release_name_cb,
|
||||
g_steal_pointer(&keep_alive_object));
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
if (!_bus_release_name(gl))
|
||||
break;
|
||||
}
|
||||
|
||||
g_main_context_iteration(NULL, TRUE);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue