diff --git a/src/login/logind-varlink.c b/src/login/logind-varlink.c index ada491c6e2..757b4196fd 100644 --- a/src/login/logind-varlink.c +++ b/src/login/logind-varlink.c @@ -2,8 +2,10 @@ #include "sd-bus.h" #include "sd-event.h" + #include "alloc-util.h" #include "cgroup-util.h" +#include "fd-util.h" #include "format-util.h" #include "hashmap.h" #include "json-util.h" @@ -326,8 +328,9 @@ static int vl_method_release_session(sd_varlink *link, sd_json_variant *paramete return sd_varlink_reply(link, NULL); } -int manager_varlink_init(Manager *m) { +int manager_varlink_init(Manager *m, int fd) { _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL; + _unused_ _cleanup_close_ int fd_close = fd; int r; assert(m); @@ -361,10 +364,15 @@ int manager_varlink_init(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register varlink methods: %m"); - r = sd_varlink_server_listen_address(s, "/run/systemd/io.systemd.Login", 0666); + if (fd < 0) + r = sd_varlink_server_listen_address(s, "/run/systemd/io.systemd.Login", /* mode= */ 0666); + else + r = sd_varlink_server_listen_fd(s, fd); if (r < 0) return log_error_errno(r, "Failed to bind to varlink socket: %m"); + TAKE_FD(fd_close); + r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); diff --git a/src/login/logind-varlink.h b/src/login/logind-varlink.h index d99513d210..b6b74093a5 100644 --- a/src/login/logind-varlink.h +++ b/src/login/logind-varlink.h @@ -3,7 +3,7 @@ #include "logind-forward.h" -int manager_varlink_init(Manager *m); +int manager_varlink_init(Manager *m, int fd); void manager_varlink_done(Manager *m); int session_send_create_reply_varlink(Session *s, const sd_bus_error *error); diff --git a/src/login/logind.c b/src/login/logind.c index adcf306509..c5819101e5 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -525,9 +525,8 @@ fail_close: } static int manager_enumerate_sessions(Manager *m) { - _cleanup_strv_free_ char **fdnames = NULL; _cleanup_closedir_ DIR *d = NULL; - int r = 0, n; + int r = 0; assert(m); @@ -560,6 +559,16 @@ static int manager_enumerate_sessions(Manager *m) { RET_GATHER(r, log_warning_errno(k, "Failed to deserialize session '%s', ignoring: %m", s->id)); } + return r; +} + +static int manager_enumerate_fds(Manager *m, int *ret_varlink_fd) { + _cleanup_strv_free_ char **fdnames = NULL; + int varlink_fd = -EBADF, n, r = 0; + + assert(m); + assert(ret_varlink_fd); + n = sd_listen_fds_with_names(/* unset_environment = */ true, &fdnames); if (n < 0) return log_error_errno(n, "Failed to acquire passed fd list: %m"); @@ -567,9 +576,18 @@ static int manager_enumerate_sessions(Manager *m) { for (int i = 0; i < n; i++) { int fd = SD_LISTEN_FDS_START + i; + if (streq(fdnames[i], "varlink")) { + assert(varlink_fd < 0); + varlink_fd = fd; + continue; + } + RET_GATHER(r, manager_attach_session_fd_one_consume(m, fdnames[i], fd)); } + if (r >= 0) + *ret_varlink_fd = varlink_fd; + return r; } @@ -1171,6 +1189,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa } static int manager_startup(Manager *m) { + _cleanup_close_ int varlink_fd = -EBADF; int r; Seat *seat; Session *session; @@ -1202,10 +1221,6 @@ static int manager_startup(Manager *m) { if (r < 0) return r; - r = manager_varlink_init(m); - if (r < 0) - return r; - /* Instantiate magic seat 0 */ r = manager_add_seat(m, "seat0", &m->seat0); if (r < 0) @@ -1232,6 +1247,10 @@ static int manager_startup(Manager *m) { if (r < 0) log_warning_errno(r, "Session enumeration failed: %m"); + r = manager_enumerate_fds(m, &varlink_fd); + if (r < 0) + log_warning_errno(r, "File descriptor enumeration failed: %m"); + r = manager_enumerate_inhibitors(m); if (r < 0) log_warning_errno(r, "Inhibitor enumeration failed: %m"); @@ -1240,6 +1259,10 @@ static int manager_startup(Manager *m) { if (r < 0) log_warning_errno(r, "Button enumeration failed: %m"); + r = manager_varlink_init(m, TAKE_FD(varlink_fd)); + if (r < 0) + return r; + manager_load_scheduled_shutdown(m); /* Remove stale objects before we start them */ diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index d443188709..1697efd771 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -259,8 +259,9 @@ static int vl_method_set_persistent_storage(sd_varlink *vlink, sd_json_variant * return sd_varlink_reply(vlink, NULL); } -int manager_connect_varlink(Manager *m) { +int manager_connect_varlink(Manager *m, int fd) { _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL; + _unused_ _cleanup_close_ int fd_close = fd; int r; assert(m); @@ -297,10 +298,15 @@ int manager_connect_varlink(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register varlink methods: %m"); - r = sd_varlink_server_listen_address(s, "/run/systemd/netif/io.systemd.Network", 0666); + if (fd < 0) + r = sd_varlink_server_listen_address(s, "/run/systemd/netif/io.systemd.Network", /* mode= */ 0666); + else + r = sd_varlink_server_listen_fd(s, fd); if (r < 0) return log_error_errno(r, "Failed to bind to varlink socket: %m"); + TAKE_FD(fd_close); + r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); @@ -313,5 +319,4 @@ void manager_varlink_done(Manager *m) { assert(m); m->varlink_server = sd_varlink_server_unref(m->varlink_server); - (void) unlink("/run/systemd/netif/io.systemd.Network"); } diff --git a/src/network/networkd-manager-varlink.h b/src/network/networkd-manager-varlink.h index 992e48839e..bd5cede404 100644 --- a/src/network/networkd-manager-varlink.h +++ b/src/network/networkd-manager-varlink.h @@ -3,5 +3,5 @@ #include "networkd-forward.h" -int manager_connect_varlink(Manager *m); +int manager_connect_varlink(Manager *m, int fd); void manager_varlink_done(Manager *m); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a0455544cf..82aa1337fe 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -205,12 +205,13 @@ static int manager_connect_udev(Manager *m) { return 0; } -static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { +static int manager_listen_fds(Manager *m, int *ret_rtnl_fd, int *ret_varlink_fd) { _cleanup_strv_free_ char **names = NULL; - int n, rtnl_fd = -EBADF; + int n, rtnl_fd = -EBADF, varlink_fd = -EBADF; assert(m); assert(ret_rtnl_fd); + assert(ret_varlink_fd); n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); if (n < 0) @@ -221,7 +222,7 @@ static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { if (rtnl_fd >= 0) { - log_debug("Received multiple netlink socket, ignoring."); + log_debug("Received multiple netlink sockets, ignoring."); goto unused; } @@ -229,6 +230,11 @@ static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { continue; } + if (streq(names[i], "varlink")) { + varlink_fd = fd; + continue; + } + if (manager_set_serialization_fd(m, fd, names[i]) >= 0) continue; @@ -243,6 +249,8 @@ static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { } *ret_rtnl_fd = rtnl_fd; + *ret_varlink_fd = varlink_fd; + return 0; } @@ -513,7 +521,7 @@ static int manager_set_keep_configuration(Manager *m) { } int manager_setup(Manager *m) { - _cleanup_close_ int rtnl_fd = -EBADF; + _cleanup_close_ int rtnl_fd = -EBADF, varlink_fd = -EBADF; int r; assert(m); @@ -537,7 +545,7 @@ int manager_setup(Manager *m) { if (r < 0) return r; - r = manager_listen_fds(m, &rtnl_fd); + r = manager_listen_fds(m, &rtnl_fd, &varlink_fd); if (r < 0) return r; @@ -552,7 +560,7 @@ int manager_setup(Manager *m) { if (m->test_mode) return 0; - r = manager_connect_varlink(m); + r = manager_connect_varlink(m, TAKE_FD(varlink_fd)); if (r < 0) return r; diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 280626da9e..34032184c6 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -1405,11 +1405,13 @@ static int manager_setup_event(Manager *manager) { return 0; } -static int manager_listen_fds(Manager *manager) { +static int manager_listen_fds(Manager *manager, int *ret_varlink_fd) { _cleanup_strv_free_ char **names = NULL; + int varlink_fd = -EBADF; int r; assert(manager); + assert(ret_varlink_fd); int n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); if (n < 0) @@ -1418,9 +1420,10 @@ static int manager_listen_fds(Manager *manager) { for (int i = 0; i < n; i++) { int fd = SD_LISTEN_FDS_START + i; - if (streq(names[i], "varlink")) - r = 0; /* The fd will be handled by sd_varlink_server_listen_auto(). */ - else if (streq(names[i], "systemd-udevd-control.socket")) + if (streq(names[i], "varlink")) { + varlink_fd = fd; + r = 0; + } else if (streq(names[i], "systemd-udevd-control.socket")) r = manager_init_ctrl(manager, fd); else if (streq(names[i], "systemd-udevd-kernel.socket")) r = manager_init_device_monitor(manager, fd); @@ -1437,10 +1440,13 @@ static int manager_listen_fds(Manager *manager) { close_and_notify_warn(fd, names[i]); } + *ret_varlink_fd = varlink_fd; + return 0; } int manager_main(Manager *manager) { + _cleanup_close_ int varlink_fd = -EBADF; int r; assert(manager); @@ -1458,7 +1464,7 @@ int manager_main(Manager *manager) { if (r < 0) return r; - r = manager_listen_fds(manager); + r = manager_listen_fds(manager, &varlink_fd); if (r < 0) return r; @@ -1466,7 +1472,7 @@ int manager_main(Manager *manager) { if (r < 0) return r; - r = manager_start_varlink_server(manager); + r = manager_start_varlink_server(manager, TAKE_FD(varlink_fd)); if (r < 0) return r; diff --git a/src/udev/udev-varlink.c b/src/udev/udev-varlink.c index 5228d3512c..9a887d9c7f 100644 --- a/src/udev/udev-varlink.c +++ b/src/udev/udev-varlink.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "fd-util.h" #include "json-util.h" #include "log.h" #include "string-util.h" @@ -165,8 +166,9 @@ static int vl_method_exit(sd_varlink *link, sd_json_variant *parameters, sd_varl return sd_varlink_reply(link, NULL); } -int manager_start_varlink_server(Manager *manager) { +int manager_start_varlink_server(Manager *manager, int fd) { _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *v = NULL; + _cleanup_close_ int fd_close = fd; int r; assert(manager); @@ -183,14 +185,14 @@ int manager_start_varlink_server(Manager *manager) { if (r < 0) return log_error_errno(r, "Failed to attach Varlink connection to event loop: %m"); - r = sd_varlink_server_listen_auto(v); - if (r < 0) - return log_error_errno(r, "Failed to bind to passed Varlink socket: %m"); - if (r == 0) { + if (fd < 0) r = sd_varlink_server_listen_address(v, UDEV_VARLINK_ADDRESS, 0600); - if (r < 0) - return log_error_errno(r, "Failed to bind to Varlink socket: %m"); - } + else + r = sd_varlink_server_listen_fd(v, fd); + if (r < 0) + return log_error_errno(r, "Failed to bind to Varlink socket: %m"); + + TAKE_FD(fd_close); r = sd_varlink_server_add_interface_many( v, diff --git a/src/udev/udev-varlink.h b/src/udev/udev-varlink.h index 080f7c95a7..fb14ac711d 100644 --- a/src/udev/udev-varlink.h +++ b/src/udev/udev-varlink.h @@ -3,5 +3,5 @@ #include "udev-forward.h" -int manager_start_varlink_server(Manager *manager); +int manager_start_varlink_server(Manager *manager, int fd); int udev_varlink_connect(sd_varlink **ret, usec_t timeout); diff --git a/test/units/TEST-74-AUX-UTILS.varlinkctl.sh b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh index 2e0bf5f7d6..481dc85d6f 100755 --- a/test/units/TEST-74-AUX-UTILS.varlinkctl.sh +++ b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh @@ -66,6 +66,20 @@ if [[ -x /usr/lib/systemd/systemd-pcrextend ]]; then varlinkctl introspect /usr/lib/systemd/systemd-pcrextend fi +# Test various varlink socket units to make sure that we can still connect to the varlink sockets even if the +# services are currently stopped (or restarting). +systemctl stop \ + systemd-networkd.service \ + systemd-hostnamed.service \ + systemd-machined.service \ + systemd-udevd.service +varlinkctl introspect /run/systemd/netif/io.systemd.Network +varlinkctl introspect /run/systemd/io.systemd.Hostname +varlinkctl introspect /run/systemd/machine/io.systemd.Machine +if ! systemd-detect-virt -qc; then + varlinkctl introspect /run/udev/io.systemd.Udev +fi + # SSH transport SSHBINDIR="$(mktemp -d)" diff --git a/units/meson.build b/units/meson.build index 8a3ce203a1..3f3b047f3c 100644 --- a/units/meson.build +++ b/units/meson.build @@ -472,6 +472,11 @@ units = [ 'conditions' : ['ENABLE_LOCALED'], 'symlinks' : ['dbus-org.freedesktop.locale1.service'], }, + { + 'file': 'systemd-logind-varlink.socket', + 'conditions': ['ENABLE_LOGIND'], + 'symlinks' : ['sockets.target.wants/'], + }, { 'file' : 'systemd-logind.service.in', 'conditions' : ['ENABLE_LOGIND'], @@ -502,6 +507,10 @@ units = [ 'file' : 'systemd-networkd-persistent-storage.service', 'conditions' : ['ENABLE_NETWORKD'], }, + { + 'file' : 'systemd-networkd-varlink.socket', + 'conditions' : ['ENABLE_NETWORKD'], + }, { 'file' : 'systemd-networkd-wait-online.service.in', 'conditions' : ['ENABLE_NETWORKD'], diff --git a/units/systemd-logind-varlink.socket b/units/systemd-logind-varlink.socket new file mode 100644 index 0000000000..3978e8ab90 --- /dev/null +++ b/units/systemd-logind-varlink.socket @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=User Login Management Varlink Socket +Documentation=man:systemd-logind.service(8) + +[Socket] +ListenStream=/run/systemd/io.systemd.Login +FileDescriptorName=varlink +SocketMode=0666 +Service=systemd-logind.service diff --git a/units/systemd-networkd-varlink.socket b/units/systemd-networkd-varlink.socket new file mode 100644 index 0000000000..0f2304ff49 --- /dev/null +++ b/units/systemd-networkd-varlink.socket @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Network Service Varlink Socket +Documentation=man:systemd-networkd.service(8) +ConditionCapability=CAP_NET_ADMIN +DefaultDependencies=no +Before=sockets.target shutdown.target +Conflicts=shutdown.target + +[Socket] +ListenStream=/run/systemd/netif/io.systemd.Network +FileDescriptorName=varlink +SocketMode=0666 +Service=systemd-networkd.service + +[Install] +WantedBy=sockets.target diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in index 6fb2b7e2db..c7bcf73a27 100644 --- a/units/systemd-networkd.service.in +++ b/units/systemd-networkd.service.in @@ -46,7 +46,7 @@ RestrictRealtime=yes RestrictSUIDSGID=yes RuntimeDirectory=systemd/netif RuntimeDirectoryPreserve=yes -Sockets=systemd-networkd.socket +Sockets=systemd-networkd.socket systemd-networkd-varlink.socket SystemCallArchitectures=native SystemCallErrorNumber=EPERM SystemCallFilter=@system-service bpf @@ -56,7 +56,7 @@ User=systemd-network [Install] WantedBy=multi-user.target -Also=systemd-networkd.socket +Also=systemd-networkd.socket systemd-networkd-varlink.socket Alias=dbus-org.freedesktop.network1.service # The output from this generator is used by udevd and networkd. Enable it by