From d53444085f00087754ff755d953b6226e07e363b Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 5 Jun 2025 23:04:16 +0200 Subject: [PATCH 01/14] README: add more kernel APIs we now utilize --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index 695819cd9b..7199166669 100644 --- a/README +++ b/README @@ -71,7 +71,10 @@ REQUIREMENTS: and MOVE_MOUNT_BENEATH ≥ 6.6 for quota support on tmpfs ≥ 6.9 for pidfs + ≥ 6.10 for fcntl(F_DUPFD_QUERY), unprivileged linkat(AT_EMPTY_PATH), + and block device 'partscan' sysfs attribute ≥ 6.13 for PIDFD_GET_INFO and {set,remove}xattrat() + ≥ 6.16 for coredump pattern '%F' (pidfd) specifier ✅ systemd utilizes several new kernel APIs, but will fall back gracefully when unavailable. From 9453a92ad78e2b2469862b43bd13cd34c9dbbbe5 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 16 May 2025 19:08:34 +0200 Subject: [PATCH 02/14] units/systemd-journald@.socket: enable SO_TIMESTAMP Follow-up for 02229dff2b371f3a6235fe18ea72e972ddbc90a9 This applies the change to journal namespace instances too. --- units/systemd-journald@.socket | 1 + 1 file changed, 1 insertion(+) diff --git a/units/systemd-journald@.socket b/units/systemd-journald@.socket index 65813a5f6d..b5bee28a6d 100644 --- a/units/systemd-journald@.socket +++ b/units/systemd-journald@.socket @@ -22,6 +22,7 @@ PassCredentials=yes PassSecurity=yes ReceiveBuffer=8M SendBuffer=8M +Timestamping=us [Install] WantedBy=sockets.target From 58f3be82cef1d6e03f6c14515c70a39ac072ae4e Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 20:06:45 +0200 Subject: [PATCH 03/14] udev-ctrl: enable SO_PASSCREDS on listening socket already rather than on accept() This matches what systemd-udevd-control.socket does. --- src/udev/udev-ctrl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 5cde769b1f..eeaa0c01f3 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -44,6 +44,7 @@ struct UdevCtrl { int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) { _cleanup_close_ int sock = -EBADF; UdevCtrl *uctrl; + int r; assert(ret); @@ -53,6 +54,11 @@ int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) { return log_error_errno(errno, "Failed to create socket: %m"); } + /* enable receiving of the sender credentials in the messages */ + r = setsockopt_int(fd >= 0 ? fd : sock, SOL_SOCKET, SO_PASSCRED, true); + if (r < 0) + log_warning_errno(r, "Failed to set SO_PASSCRED, ignoring: %m"); + uctrl = new(UdevCtrl, 1); if (!uctrl) return -ENOMEM; @@ -240,11 +246,6 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, return 0; } - /* enable receiving of the sender credentials in the messages */ - r = setsockopt_int(sock, SOL_SOCKET, SO_PASSCRED, true); - if (r < 0) - log_warning_errno(r, "Failed to set SO_PASSCRED, ignoring: %m"); - r = sd_event_add_io(uctrl->event, &uctrl->event_source_connect, sock, EPOLLIN, udev_ctrl_connection_event_handler, uctrl); if (r < 0) { log_error_errno(r, "Failed to create event source for udev control connection: %m"); From b36ab0d4ce2c75628b2bda2d17b71852e3d24eba Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 20:31:19 +0200 Subject: [PATCH 04/14] core/socket: don't suggest PassFileDescriptorsToExec= is a socket option by not interleaving it among socket options. --- man/org.freedesktop.systemd1.xml | 12 ++++++------ src/core/dbus-socket.c | 11 ++++++----- src/core/load-fragment-gperf.gperf.in | 2 +- src/core/socket.c | 4 ++-- src/core/socket.h | 7 ++++--- src/shared/bus-unit-util.c | 2 +- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 384d0aa330..fd7bbab513 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -4907,8 +4907,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassCredentials = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") - readonly b PassFileDescriptorsToExec = ...; - @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassSecurity = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassPacketInfo = ...; @@ -4962,6 +4960,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { readonly u PollLimitBurst = ...; readonly u UID = ...; readonly u GID = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b PassFileDescriptorsToExec = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates") readonly a(sasbttttuii) ExecStartPre = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates") @@ -5576,8 +5576,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - - @@ -5624,6 +5622,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -6178,8 +6178,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - - @@ -6238,6 +6236,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 5781fb59f3..aeb6ae5fe1 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -86,7 +86,6 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Transparent", "b", bus_property_get_bool, offsetof(Socket, transparent), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("PassFileDescriptorsToExec", "b", bus_property_get_bool, offsetof(Socket, pass_fds_to_exec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassPacketInfo", "b", bus_property_get_bool, offsetof(Socket, pass_pktinfo), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Timestamping", "s", property_get_timestamping, offsetof(Socket, timestamping), SD_BUS_VTABLE_PROPERTY_CONST), @@ -116,6 +115,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("PollLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, poll_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("PassFileDescriptorsToExec", "b", bus_property_get_bool, offsetof(Socket, pass_fds_to_exec), SD_BUS_VTABLE_PROPERTY_CONST), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), @@ -191,9 +191,6 @@ static int bus_socket_set_transient_property( if (streq(name, "PassCredentials")) return bus_set_transient_bool(u, name, &s->pass_cred, message, flags, error); - if (streq(name, "PassFileDescriptorsToExec")) - return bus_set_transient_bool(u, name, &s->pass_fds_to_exec, message, flags, error); - if (streq(name, "PassSecurity")) return bus_set_transient_bool(u, name, &s->pass_sec, message, flags, error); @@ -311,6 +308,9 @@ static int bus_socket_set_transient_property( if (streq(name, "SocketProtocol")) return bus_set_transient_socket_protocol(u, name, &s->socket_protocol, message, flags, error); + if (streq(name, "PassFileDescriptorsToExec")) + return bus_set_transient_bool(u, name, &s->pass_fds_to_exec, message, flags, error); + ci = socket_exec_command_from_string(name); if (ci >= 0) return bus_set_transient_exec_command(u, name, @@ -348,8 +348,9 @@ static int bus_socket_set_transient_property( } return 1; + } - } else if (streq(name, "Listen")) { + if (streq(name, "Listen")) { const char *t, *a; bool empty = true; diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 1bd7c950fc..2330bc0f4c 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -510,7 +510,6 @@ Socket.FreeBind, config_parse_bool, Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent) Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred) -Socket.PassFileDescriptorsToExec, config_parse_bool, 0, offsetof(Socket, pass_fds_to_exec) Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) Socket.PassPacketInfo, config_parse_bool, 0, offsetof(Socket, pass_pktinfo) Socket.Timestamping, config_parse_socket_timestamping, 0, offsetof(Socket, timestamping) @@ -522,6 +521,7 @@ Socket.RemoveOnStop, config_parse_bool, Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks) Socket.FileDescriptorName, config_parse_fdname, 0, 0 Socket.Service, config_parse_socket_service, 0, 0 +Socket.PassFileDescriptorsToExec, config_parse_bool, 0, offsetof(Socket, pass_fds_to_exec) Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval) Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst) Socket.PollLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, poll_limit.interval) diff --git a/src/core/socket.c b/src/core/socket.c index ec75c22c5c..5517c0ce07 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -610,13 +610,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sTransparent: %s\n" "%sBroadcast: %s\n" "%sPassCredentials: %s\n" - "%sPassFileDescriptorsToExec: %s\n" "%sPassSecurity: %s\n" "%sPassPacketInfo: %s\n" "%sTCPCongestion: %s\n" "%sRemoveOnStop: %s\n" "%sWritable: %s\n" "%sFileDescriptorName: %s\n" + "%sPassFileDescriptorsToExec: %s\n" "%sSELinuxContextFromNet: %s\n", prefix, socket_state_to_string(s->state), prefix, socket_result_to_string(s->result), @@ -631,13 +631,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->transparent), prefix, yes_no(s->broadcast), prefix, yes_no(s->pass_cred), - prefix, yes_no(s->pass_fds_to_exec), prefix, yes_no(s->pass_sec), prefix, yes_no(s->pass_pktinfo), prefix, strna(s->tcp_congestion), prefix, yes_no(s->remove_on_stop), prefix, yes_no(s->writable), prefix, socket_fdname(s), + prefix, yes_no(s->pass_fds_to_exec), prefix, yes_no(s->selinux_context_from_net)); if (s->timestamping != SOCKET_TIMESTAMPING_OFF) diff --git a/src/core/socket.h b/src/core/socket.h index 696e0490c1..f85448c484 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -86,7 +86,7 @@ typedef struct Socket { usec_t keep_alive_interval; usec_t defer_accept; - ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX]; + ExecCommand *exec_command[_SOCKET_EXEC_COMMAND_MAX]; ExecContext exec_context; KillContext kill_context; CGroupContext cgroup_context; @@ -103,10 +103,12 @@ typedef struct Socket { sd_event_source *timer_event_source; - ExecCommand* control_command; + ExecCommand *control_command; SocketExecCommand control_command_id; PidRef control_pid; + bool pass_fds_to_exec; + mode_t directory_mode; mode_t socket_mode; @@ -129,7 +131,6 @@ typedef struct Socket { bool transparent; bool broadcast; bool pass_cred; - bool pass_fds_to_exec; bool pass_sec; bool pass_pktinfo; SocketTimestamping timestamping; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1e28622668..d18a9088d4 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2583,11 +2583,11 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons "Transparent", "Broadcast", "PassCredentials", - "PassFileDescriptorsToExec", "PassSecurity", "PassPacketInfo", "ReusePort", "RemoveOnStop", + "PassFileDescriptorsToExec", "SELinuxContextFromNet")) return bus_append_parse_boolean(m, field, eq); From b81a14b91efea17631d634f5dbd69314780815ab Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 10 Jun 2025 11:26:04 +0200 Subject: [PATCH 05/14] core/socket: use universal format string for socket option warnings --- src/core/socket.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/core/socket.c b/src/core/socket.c index 5517c0ce07..0b7228a86c 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1011,6 +1011,10 @@ static void socket_close_fds(Socket *s) { DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(Socket*, socket_close_fds, NULL); +#define SOCKET_OPTION_WARNING_FORMAT_STR "Failed to set %s socket option, ignoring: %m" +#define log_socket_option_warning_errno(s, error, option) \ + log_unit_warning_errno(UNIT(s), (error), SOCKET_OPTION_WARNING_FORMAT_STR, STRINGIFY(option)) + static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) { int r; @@ -1021,67 +1025,68 @@ static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) { if (s->keep_alive) { r = setsockopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "SO_KEEPALIVE failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, SO_KEEPALIVE); } if (timestamp_is_set(s->keep_alive_time)) { r = setsockopt_int(fd, SOL_TCP, TCP_KEEPIDLE, s->keep_alive_time / USEC_PER_SEC); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "TCP_KEEPIDLE failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, TCP_KEEPIDLE); } if (s->keep_alive_interval > 0) { r = setsockopt_int(fd, SOL_TCP, TCP_KEEPINTVL, s->keep_alive_interval / USEC_PER_SEC); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "TCP_KEEPINTVL failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, TCP_KEEPINTVL); } if (s->keep_alive_cnt > 0) { r = setsockopt_int(fd, SOL_TCP, TCP_KEEPCNT, s->keep_alive_cnt); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "TCP_KEEPCNT failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, TCP_KEEPCNT); } if (s->defer_accept > 0) { r = setsockopt_int(fd, SOL_TCP, TCP_DEFER_ACCEPT, s->defer_accept / USEC_PER_SEC); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "TCP_DEFER_ACCEPT failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, TCP_DEFER_ACCEPT); } if (s->no_delay) { if (s->socket_protocol == IPPROTO_SCTP) { r = setsockopt_int(fd, SOL_SCTP, SCTP_NODELAY, true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "SCTP_NODELAY failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, SCTP_NODELAY); } else { r = setsockopt_int(fd, SOL_TCP, TCP_NODELAY, true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "TCP_NODELAY failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, TCP_NODELAY); } } if (s->broadcast) { r = setsockopt_int(fd, SOL_SOCKET, SO_BROADCAST, true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "SO_BROADCAST failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, SO_BROADCAST); } if (s->pass_cred) { r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "SO_PASSCRED failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, SO_PASSCRED); } if (s->pass_sec) { r = setsockopt_int(fd, SOL_SOCKET, SO_PASSSEC, true); if (r < 0) - log_unit_full_errno(UNIT(s), ERRNO_IS_NEG_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, "SO_PASSSEC failed, ignoring: %m"); + log_unit_full_errno(UNIT(s), ERRNO_IS_NEG_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, + SOCKET_OPTION_WARNING_FORMAT_STR, "SO_PASSSEC"); } if (s->pass_pktinfo) { r = socket_set_recvpktinfo(fd, socket_address_family(&p->address), true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "Failed to enable packet info socket option, ignoring: %m"); + log_unit_warning_errno(UNIT(s), r, SOCKET_OPTION_WARNING_FORMAT_STR, "packet info"); } if (s->timestamping != SOCKET_TIMESTAMPING_OFF) { @@ -1089,50 +1094,50 @@ static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) { s->timestamping == SOCKET_TIMESTAMPING_NS ? SO_TIMESTAMPNS : SO_TIMESTAMP, true); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "Failed to enable timestamping socket option, ignoring: %m"); + log_unit_warning_errno(UNIT(s), r, SOCKET_OPTION_WARNING_FORMAT_STR, "timestamping"); } if (s->priority >= 0) { r = setsockopt_int(fd, SOL_SOCKET, SO_PRIORITY, s->priority); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "SO_PRIORITY failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, SO_PRIORITY); } if (s->receive_buffer > 0) { r = fd_set_rcvbuf(fd, s->receive_buffer, false); if (r < 0) - log_unit_full_errno(UNIT(s), ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r, - "SO_RCVBUF/SO_RCVBUFFORCE failed, ignoring: %m"); + log_unit_full_errno(UNIT(s), ERRNO_IS_NEG_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r, + SOCKET_OPTION_WARNING_FORMAT_STR, "SO_RCVBUF/SO_RCVBUFFORCE"); } if (s->send_buffer > 0) { r = fd_set_sndbuf(fd, s->send_buffer, false); if (r < 0) - log_unit_full_errno(UNIT(s), ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r, - "SO_SNDBUF/SO_SNDBUFFORCE failed, ignoring: %m"); + log_unit_full_errno(UNIT(s), ERRNO_IS_NEG_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r, + SOCKET_OPTION_WARNING_FORMAT_STR, "SO_SNDBUF/SO_SNDBUFFORCE"); } if (s->mark >= 0) { r = setsockopt_int(fd, SOL_SOCKET, SO_MARK, s->mark); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "SO_MARK failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, SO_MARK); } if (s->ip_tos >= 0) { r = setsockopt_int(fd, IPPROTO_IP, IP_TOS, s->ip_tos); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "IP_TOS failed, ignoring: %m"); + log_socket_option_warning_errno(s, r, IP_TOS); } if (s->ip_ttl >= 0) { r = socket_set_ttl(fd, socket_address_family(&p->address), s->ip_ttl); if (r < 0) - log_unit_warning_errno(UNIT(s), r, "IP_TTL/IPV6_UNICAST_HOPS failed, ignoring: %m"); + log_unit_warning_errno(UNIT(s), r, SOCKET_OPTION_WARNING_FORMAT_STR, "IP_TTL/IPV6_UNICAST_HOPS"); } if (s->tcp_congestion) if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0) - log_unit_warning_errno(UNIT(s), errno, "TCP_CONGESTION failed, ignoring: %m"); + log_socket_option_warning_errno(s, errno, TCP_CONGESTION); if (s->smack_ip_in) { r = mac_smack_apply_fd(fd, SMACK_ATTR_IPIN, s->smack_ip_in); From 35462aa14a425e12a839b24abb1db2d27835b4c6 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 10 Jun 2025 11:27:44 +0200 Subject: [PATCH 06/14] core/socket: add PassPIDFD= --- TODO | 3 --- man/org.freedesktop.systemd1.xml | 7 +++++++ man/systemd.socket.xml | 10 ++++++++++ src/core/dbus-socket.c | 4 ++++ src/core/load-fragment-gperf.gperf.in | 1 + src/core/socket.c | 9 +++++++++ src/core/socket.h | 1 + src/shared/bus-unit-util.c | 1 + 8 files changed, 33 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index 252d25afd6..4f77391f62 100644 --- a/TODO +++ b/TODO @@ -128,9 +128,6 @@ Features: also raises the question whether such sessions shall be considered active or not -* Add PassPidFileDescriptor= similar in style to PassCredentials= to .socket - units - * automatically reset specific EFI vars on factory reset (make this generic enough so that infrac can be used to erase shim's mok vars?) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index fd7bbab513..814400ad43 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -4907,6 +4907,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassCredentials = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b PassPIDFD = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassSecurity = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassPacketInfo = ...; @@ -5576,6 +5578,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -6178,6 +6182,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -12092,6 +12098,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ ProtectControlGroupsEx, and PrivatePIDs were added in version 257. ProtectHostnameEx, + PassPIDFD, DelegateNamespaces, and RemoveSubgroup() were added in version 258. diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index b2779e84a2..b43f8e685b 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -742,6 +742,16 @@ process in an ancillary message. Defaults to . + + PassPIDFD= + + Takes a boolean value. This controls the SO_PASSPIDFD socket + option, which allows AF_UNIX sockets to receive the pidfd of the sending + process in an ancillary message. Defaults to . + + + + PassSecurity= Takes a boolean value. This controls the SO_PASSSEC socket diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index aeb6ae5fe1..b07b3c93c5 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -86,6 +86,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Transparent", "b", bus_property_get_bool, offsetof(Socket, transparent), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PassPIDFD", "b", bus_property_get_bool, offsetof(Socket, pass_pidfd), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassPacketInfo", "b", bus_property_get_bool, offsetof(Socket, pass_pktinfo), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Timestamping", "s", property_get_timestamping, offsetof(Socket, timestamping), SD_BUS_VTABLE_PROPERTY_CONST), @@ -191,6 +192,9 @@ static int bus_socket_set_transient_property( if (streq(name, "PassCredentials")) return bus_set_transient_bool(u, name, &s->pass_cred, message, flags, error); + if (streq(name, "PassPIDFD")) + return bus_set_transient_bool(u, name, &s->pass_pidfd, message, flags, error); + if (streq(name, "PassSecurity")) return bus_set_transient_bool(u, name, &s->pass_sec, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 2330bc0f4c..e3c2333731 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -510,6 +510,7 @@ Socket.FreeBind, config_parse_bool, Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent) Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred) +Socket.PassPIDFD, config_parse_bool, 0, offsetof(Socket, pass_pidfd) Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) Socket.PassPacketInfo, config_parse_bool, 0, offsetof(Socket, pass_pktinfo) Socket.Timestamping, config_parse_socket_timestamping, 0, offsetof(Socket, timestamping) diff --git a/src/core/socket.c b/src/core/socket.c index 0b7228a86c..6d69d6cb42 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -610,6 +610,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sTransparent: %s\n" "%sBroadcast: %s\n" "%sPassCredentials: %s\n" + "%sPassPIDFD: %s\n" "%sPassSecurity: %s\n" "%sPassPacketInfo: %s\n" "%sTCPCongestion: %s\n" @@ -631,6 +632,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->transparent), prefix, yes_no(s->broadcast), prefix, yes_no(s->pass_cred), + prefix, yes_no(s->pass_pidfd), prefix, yes_no(s->pass_sec), prefix, yes_no(s->pass_pktinfo), prefix, strna(s->tcp_congestion), @@ -1076,6 +1078,13 @@ static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) { log_socket_option_warning_errno(s, r, SO_PASSCRED); } + if (s->pass_pidfd) { + r = setsockopt_int(fd, SOL_SOCKET, SO_PASSPIDFD, true); + if (r < 0) + log_unit_full_errno(UNIT(s), ERRNO_IS_NEG_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, + SOCKET_OPTION_WARNING_FORMAT_STR, "SO_PASSPIDFD"); + } + if (s->pass_sec) { r = setsockopt_int(fd, SOL_SOCKET, SO_PASSSEC, true); if (r < 0) diff --git a/src/core/socket.h b/src/core/socket.h index f85448c484..99fcc0cbe6 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -131,6 +131,7 @@ typedef struct Socket { bool transparent; bool broadcast; bool pass_cred; + bool pass_pidfd; bool pass_sec; bool pass_pktinfo; SocketTimestamping timestamping; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index d18a9088d4..aebeaa15ce 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2583,6 +2583,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons "Transparent", "Broadcast", "PassCredentials", + "PassPIDFD", "PassSecurity", "PassPacketInfo", "ReusePort", From f66eeedf6fee3f8f96f3e6547819de3bb10515ed Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 5 Jun 2025 23:00:40 +0200 Subject: [PATCH 07/14] missing_socket: add SO_PASSRIGHTS --- README | 2 +- src/basic/missing_socket.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README b/README index 7199166669..0062563d5c 100644 --- a/README +++ b/README @@ -74,7 +74,7 @@ REQUIREMENTS: ≥ 6.10 for fcntl(F_DUPFD_QUERY), unprivileged linkat(AT_EMPTY_PATH), and block device 'partscan' sysfs attribute ≥ 6.13 for PIDFD_GET_INFO and {set,remove}xattrat() - ≥ 6.16 for coredump pattern '%F' (pidfd) specifier + ≥ 6.16 for coredump pattern '%F' (pidfd) specifier and SO_PASSRIGHTS ✅ systemd utilizes several new kernel APIs, but will fall back gracefully when unavailable. diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 3a81dfff8a..cc453d2396 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -13,6 +13,11 @@ #define SO_PEERPIDFD 77 #endif +/* Supported since kernel v6.16 (77cbe1a6d8730a07f99f9263c2d5f2304cf5e830) */ +#ifndef SO_PASSRIGHTS +#define SO_PASSRIGHTS 83 +#endif + /* Not exposed yet. Defined in include/linux/socket.h. */ #ifndef SOL_SCTP #define SOL_SCTP 132 From 5c12797fc3dc2dac37ef2c7873e59cbb6da19daf Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 21:01:33 +0200 Subject: [PATCH 08/14] core/socket: introduce AcceptFileDescriptors= This controls the new SO_PASSRIGHTS socket option in kernel v6.16. Note that I intentionally choose a different naming scheme than Pass*=, since all other Pass*= options controls whether some extra bits are attached to the message, while this one's about denying file descriptor transfer and it feels more explicit this way. And diverging from underlying socket option name is precedented by Timestamping=. But happy to change it to just say PassRights= if people disagree. --- man/org.freedesktop.systemd1.xml | 7 +++++++ man/systemd.socket.xml | 11 +++++++++++ src/core/dbus-socket.c | 4 ++++ src/core/load-fragment-gperf.gperf.in | 1 + src/core/socket.c | 10 ++++++++++ src/core/socket.h | 1 + src/shared/bus-unit-util.c | 1 + 7 files changed, 35 insertions(+) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 814400ad43..237394b1fa 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -4913,6 +4913,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassPacketInfo = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b AcceptFileDescriptors = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s Timestamping = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b RemoveOnStop = ...; @@ -5584,6 +5586,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -6188,6 +6192,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -12099,6 +12105,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ PrivatePIDs were added in version 257. ProtectHostnameEx, PassPIDFD, + AcceptFileDescriptors, DelegateNamespaces, and RemoveSubgroup() were added in version 258. diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index b43f8e685b..91552d691f 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -771,6 +771,17 @@ + + AcceptFileDescriptors= + + Takes a boolean value. This controls the SO_PASSRIGHTS socket + option, which when disabled prohibits the peer from sending SCM_RIGHTS + ancillary messages (aka file descriptors) via AF_UNIX sockets. Defaults to + . + + + + Timestamping= Takes one of off, us (alias: diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index b07b3c93c5..de96f00a15 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -89,6 +89,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("PassPIDFD", "b", bus_property_get_bool, offsetof(Socket, pass_pidfd), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassPacketInfo", "b", bus_property_get_bool, offsetof(Socket, pass_pktinfo), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("AcceptFileDescriptors", "b", bus_property_get_bool, offsetof(Socket, pass_rights), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Timestamping", "s", property_get_timestamping, offsetof(Socket, timestamping), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RemoveOnStop", "b", bus_property_get_bool, offsetof(Socket, remove_on_stop), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -201,6 +202,9 @@ static int bus_socket_set_transient_property( if (streq(name, "PassPacketInfo")) return bus_set_transient_bool(u, name, &s->pass_pktinfo, message, flags, error); + if (streq(name, "AcceptFileDescriptors")) + return bus_set_transient_bool(u, name, &s->pass_rights, message, flags, error); + if (streq(name, "Timestamping")) return bus_set_transient_socket_timestamping(u, name, &s->timestamping, message, flags, error); diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index e3c2333731..918228fea1 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -513,6 +513,7 @@ Socket.PassCredentials, config_parse_bool, Socket.PassPIDFD, config_parse_bool, 0, offsetof(Socket, pass_pidfd) Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) Socket.PassPacketInfo, config_parse_bool, 0, offsetof(Socket, pass_pktinfo) +Socket.AcceptFileDescriptors, config_parse_bool, 0, offsetof(Socket, pass_rights) Socket.Timestamping, config_parse_socket_timestamping, 0, offsetof(Socket, timestamping) Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port) diff --git a/src/core/socket.c b/src/core/socket.c index 6d69d6cb42..e5cff0de76 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -129,6 +129,7 @@ static void socket_init(Unit *u) { s->max_connections = 64; + s->pass_rights = true; /* defaults to enabled in kernel */ s->priority = -1; s->ip_tos = -1; s->ip_ttl = -1; @@ -613,6 +614,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sPassPIDFD: %s\n" "%sPassSecurity: %s\n" "%sPassPacketInfo: %s\n" + "%sAcceptFileDescriptors: %s\n" "%sTCPCongestion: %s\n" "%sRemoveOnStop: %s\n" "%sWritable: %s\n" @@ -635,6 +637,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->pass_pidfd), prefix, yes_no(s->pass_sec), prefix, yes_no(s->pass_pktinfo), + prefix, yes_no(s->pass_rights), prefix, strna(s->tcp_congestion), prefix, yes_no(s->remove_on_stop), prefix, yes_no(s->writable), @@ -1098,6 +1101,13 @@ static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) { log_unit_warning_errno(UNIT(s), r, SOCKET_OPTION_WARNING_FORMAT_STR, "packet info"); } + if (!s->pass_rights) { + r = setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0) + log_unit_full_errno(UNIT(s), ERRNO_IS_NEG_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, + SOCKET_OPTION_WARNING_FORMAT_STR, "SO_PASSRIGHTS"); + } + if (s->timestamping != SOCKET_TIMESTAMPING_OFF) { r = setsockopt_int(fd, SOL_SOCKET, s->timestamping == SOCKET_TIMESTAMPING_NS ? SO_TIMESTAMPNS : SO_TIMESTAMP, diff --git a/src/core/socket.h b/src/core/socket.h index 99fcc0cbe6..70291fb0d2 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -134,6 +134,7 @@ typedef struct Socket { bool pass_pidfd; bool pass_sec; bool pass_pktinfo; + bool pass_rights; SocketTimestamping timestamping; /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */ diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index aebeaa15ce..ce56defeac 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2586,6 +2586,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons "PassPIDFD", "PassSecurity", "PassPacketInfo", + "AcceptFileDescriptors", "ReusePort", "RemoveOnStop", "PassFileDescriptorsToExec", From 718e7eb1849d6acafaf77738df808403c0e81953 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 5 Jun 2025 23:01:09 +0200 Subject: [PATCH 09/14] notify-recv: disable SO_PASSRIGHTS by default in notify_socket_prepare() --- src/home/homed-manager.c | 5 +++-- src/import/importd.c | 3 +-- src/notify/notify.c | 3 +-- src/shared/fork-journal.c | 3 ++- src/shared/notify-recv.c | 10 +++++++++- src/shared/notify-recv.h | 13 ++++++++++++- src/sysupdate/sysupdate-transfer.c | 3 +-- src/sysupdate/sysupdated.c | 3 +-- src/test/test-notify-recv.c | 2 +- src/udev/udev-manager.c | 3 +-- 10 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 5c0ad7625f..072cb12360 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -1154,15 +1154,16 @@ static int manager_listen_notify(Manager *m) { assert(m); assert(!m->notify_socket_path); - r = notify_socket_prepare( + r = notify_socket_prepare_full( m->event, SD_EVENT_PRIORITY_NORMAL - 5, /* Make sure we process sd_notify() before SIGCHLD for * any worker, so that we always know the error number * of a client before it exits. */ on_notify_socket, m, + /* accept_fds = */ true, &m->notify_socket_path, - /* ret_event_source= */ NULL); + /* ret_event_source = */ NULL); if (r < 0) return log_error_errno(r, "Failed to prepare notify socket: %m"); diff --git a/src/import/importd.c b/src/import/importd.c index 2b59c965f7..b28e644534 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -723,8 +723,7 @@ static int manager_new(Manager **ret) { SD_EVENT_PRIORITY_NORMAL, manager_on_notify, m, - &m->notify_socket_path, - /* ret_event_source= */ NULL); + &m->notify_socket_path); if (r < 0) return r; diff --git a/src/notify/notify.c b/src/notify/notify.c index facd1eb9ee..3035c9f6cf 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -511,8 +511,7 @@ static int action_fork(char *const *_command) { * more interesting, "positive" information. */ on_notify_socket, &child, - &addr_string, - /* ret_event_source= */ NULL); + &addr_string); if (r < 0) return log_error_errno(r, "Failed to prepare notify socket: %m"); diff --git a/src/shared/fork-journal.c b/src/shared/fork-journal.c index 6e4a0300ff..4fac8dead1 100644 --- a/src/shared/fork-journal.c +++ b/src/shared/fork-journal.c @@ -108,11 +108,12 @@ int journal_fork(RuntimeScope scope, char * const *units, PidRef *ret_pidref) { _cleanup_(sd_event_source_disable_unrefp) sd_event_source *notify_event_source = NULL; _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL; _cleanup_free_ char *addr_string = NULL; - r = notify_socket_prepare( + r = notify_socket_prepare_full( event, SD_EVENT_PRIORITY_NORMAL-10, /* We want the notification message from the child before the SIGCHLD */ on_child_notify, &child, + /* accept_fds = */ false, &addr_string, ¬ify_event_source); if (r < 0) diff --git a/src/shared/notify-recv.c b/src/shared/notify-recv.c index 1bc320af41..ceee6587fa 100644 --- a/src/shared/notify-recv.c +++ b/src/shared/notify-recv.c @@ -15,11 +15,12 @@ #include "socket-util.h" #include "strv.h" -int notify_socket_prepare( +int notify_socket_prepare_full( sd_event *event, int64_t priority, sd_event_io_handler_t handler, void *userdata, + bool accept_fds, char **ret_path, sd_event_source **ret_event_source) { @@ -48,6 +49,13 @@ int notify_socket_prepare( if (r < 0) log_debug_errno(r, "Failed to enable SO_PASSPIDFD on notification socket, ignoring: %m"); + if (!accept_fds) { + /* since kernel v6.16 */ + r = setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0) + log_debug_errno(r, "Failed to disable SO_PASSRIGHTS on notification socket, ignoring: %m"); + } + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; r = sd_event_add_io(event, &s, fd, EPOLLIN, handler, userdata); if (r < 0) diff --git a/src/shared/notify-recv.h b/src/shared/notify-recv.h index 4306439b6f..e260e7ef5e 100644 --- a/src/shared/notify-recv.h +++ b/src/shared/notify-recv.h @@ -3,14 +3,25 @@ #include "forward.h" -int notify_socket_prepare( +int notify_socket_prepare_full( sd_event *event, int64_t priority, sd_event_io_handler_t handler, void *userdata, + bool accept_fds, char **ret_path, sd_event_source **ret_event_source); +static inline int notify_socket_prepare( + sd_event *event, + int64_t priority, + sd_event_io_handler_t handler, + void *userdata, + char **ret_path) { + + return notify_socket_prepare_full(event, priority, handler, userdata, false, ret_path, NULL); +} + int notify_recv_with_fds( int fd, char **ret_text, diff --git a/src/sysupdate/sysupdate-transfer.c b/src/sysupdate/sysupdate-transfer.c index f9c87ffad7..0916aacab2 100644 --- a/src/sysupdate/sysupdate-transfer.c +++ b/src/sysupdate/sysupdate-transfer.c @@ -1066,8 +1066,7 @@ static int run_callout( SD_EVENT_PRIORITY_NORMAL - 5, helper_on_notify, ctx, - &bind_name, - /* ret_event_source= */ NULL); + &bind_name); if (r < 0) return log_error_errno(r, "Failed to prepare notify socket: %m"); diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 3d65d99389..c46b2804b5 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -1748,8 +1748,7 @@ static int manager_new(Manager **ret) { SD_EVENT_PRIORITY_NORMAL, manager_on_notify, m, - &m->notify_socket_path, - /* ret_event_source= */ NULL); + &m->notify_socket_path); if (r < 0) return r; diff --git a/src/test/test-notify-recv.c b/src/test/test-notify-recv.c index 5820048c92..bca56df13b 100644 --- a/src/test/test-notify-recv.c +++ b/src/test/test-notify-recv.c @@ -88,7 +88,7 @@ TEST(notify_socket_prepare) { .pidref = PIDREF_NULL, }; _cleanup_free_ char *path = NULL; - ASSERT_OK(notify_socket_prepare(e, SD_EVENT_PRIORITY_NORMAL - 10, on_recv, &c, &path, /* ret_event_source= */ NULL)); + ASSERT_OK(notify_socket_prepare_full(e, SD_EVENT_PRIORITY_NORMAL - 10, on_recv, &c, true, &path, NULL)); ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD)); diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index aaaabe0d31..09ab8997e1 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -1232,8 +1232,7 @@ static int manager_start_worker_notify(Manager *manager) { EVENT_PRIORITY_WORKER_NOTIFY, on_worker_notify, manager, - &manager->worker_notify_socket_path, - /* ret_event_source= */ NULL); + &manager->worker_notify_socket_path); if (r < 0) return log_error_errno(r, "Failed to prepare worker notification socket: %m"); From 9b255107c21ebe5e3504ae8611374ee92c3b1c2c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 23:07:02 +0200 Subject: [PATCH 10/14] logind: port one remaining varlink server allocation to varlink_server_new() --- src/login/logind-varlink.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/login/logind-varlink.c b/src/login/logind-varlink.c index 79b53092a3..ada491c6e2 100644 --- a/src/login/logind-varlink.c +++ b/src/login/logind-varlink.c @@ -335,16 +335,15 @@ int manager_varlink_init(Manager *m) { if (m->varlink_server) return 0; - r = sd_varlink_server_new( + r = varlink_server_new( &s, SD_VARLINK_SERVER_ACCOUNT_UID| SD_VARLINK_SERVER_INHERIT_USERDATA| - SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT); + SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT, + m); if (r < 0) return log_error_errno(r, "Failed to allocate varlink server object: %m"); - sd_varlink_server_set_userdata(s, m); - r = sd_varlink_server_add_interface_many( s, &vl_interface_io_systemd_Login, From 60483ea14c585b8f463cf104ac60112acbfb9d45 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Mon, 9 Jun 2025 20:06:59 +0200 Subject: [PATCH 11/14] sd-varlink: remove unneeded strdup() --- src/libsystemd/sd-varlink/sd-varlink.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 3255bf8ed3..545311a118 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -327,15 +327,11 @@ static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) { if (!h) return log_oom_debug(); - _cleanup_free_ char *c = strdup(e + 1); - if (!c) - return log_oom_debug(); - - if (!path_is_absolute(c)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Remote AF_UNIX socket path is not absolute, refusing: %s", c); + if (!path_is_absolute(e + 1)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Remote AF_UNIX socket path is not absolute, refusing: %s", e + 1); _cleanup_free_ char *p = NULL; - r = path_simplify_alloc(c, &p); + r = path_simplify_alloc(e + 1, &p); if (r < 0) return r; From 72098df8439411b65ddeeddc1e50c8fb3f06be47 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 10 Jun 2025 00:01:53 +0200 Subject: [PATCH 12/14] sd-varlink: unify AF_UNIX check in sd_varlink_set_allow_fd_passing_output() Currently, the socket type is only checked if the fd passing is being enabled. The special handling seems unnecessary though, as in the disable case, either fd passing is already false and would be caught by the (... == !!b) shortcut at the beginning, or the AF_UNIX check wouldn't have succeeded in the first place, for the initial toggle to true. Hence, just uniformly check AF_UNIX. While at it, sd_varlink_set_allow_fd_passing_*() oddly return 1 iff changed and !b, which doesn't fit into our coding style and I can't come up with any use case for such behavior. Let's return 1 on changed and 0 otherwise. sd_varlink_set_allow_fd_passing_input() will be fixed in the later commits with other enhancements. --- src/libsystemd/sd-varlink/sd-varlink.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 545311a118..bf764bb97f 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -3271,17 +3271,12 @@ _public_ int sd_varlink_set_allow_fd_passing_output(sd_varlink *v, int b) { if (v->allow_fd_passing_output == !!b) return 0; - if (!b) { - v->allow_fd_passing_output = false; - return 1; - } - r = verify_unix_socket(v); if (r < 0) return r; - v->allow_fd_passing_output = true; - return 0; + v->allow_fd_passing_output = !!b; + return 1; } _public_ int sd_varlink_set_input_sensitive(sd_varlink *v) { From ed6b7b6acea44b2e0233aa0d6d2c0b147ecac968 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 21:47:39 +0200 Subject: [PATCH 13/14] sd-varlink: hook up fd passing control with SO_PASSRIGHTS This is a tricky one, because we effectively turn fd passing input toggle into a tristate: unset, disabled, and enabled; whereas unset and disabled were identical previously. *Unset* state silently ignores SCM_RIGHTS passed by invoking recv() instead of recvmsg(), and for disabled we now disable SO_PASSRIGHTS completely. The plot thickens when it comes to the server, since we want to turn off the SO_PASSRIGHTS already on the listening socket so that there's no race between accept() and recvmsg() wrt SO_PASSRIGHTS state. However, if we do this unconditionally, the existing use case of creating a custom connection callback and enabling fd passing there would be broken. Hence, let's introduce a new flag, SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT, which when set ties the enablement of fd passing to SO_PASSRIGHTS in server, and set it for all our varlink servers. Refer to the previous commit for the rationale behind return value change in sd_varlink_set_allow_fd_passing_input(). --- src/libsystemd/sd-varlink/sd-varlink.c | 71 +++++++++++++------- src/libsystemd/sd-varlink/varlink-internal.h | 6 +- src/libsystemd/sd-varlink/varlink-util.c | 2 +- src/systemd/sd-varlink.h | 1 + 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index bf764bb97f..1e70ce41a7 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -139,12 +139,14 @@ static int varlink_new(sd_varlink **ret) { .ucred = UCRED_INVALID, + .peer_pidfd = -EBADF, + .timestamp = USEC_INFINITY, .timeout = VARLINK_DEFAULT_TIMEOUT_USEC, - .af = -1, + .allow_fd_passing_input = -1, - .peer_pidfd = -EBADF, + .af = -1, }; *ret = v; @@ -849,7 +851,7 @@ static int varlink_read(sd_varlink *v) { p = v->input_buffer + v->input_buffer_index + v->input_buffer_size; rs = MALLOC_SIZEOF_SAFE(v->input_buffer) - (v->input_buffer_index + v->input_buffer_size); - if (v->allow_fd_passing_input) { + if (v->allow_fd_passing_input > 0) { iov = IOVEC_MAKE(p, rs); /* Allocate the fd buffer on the heap, since we need a lot of space potentially */ @@ -893,14 +895,14 @@ static int varlink_read(sd_varlink *v) { return n; if (n == 0) { /* EOF */ - if (v->allow_fd_passing_input) + if (v->allow_fd_passing_input > 0) cmsg_close_all(&mh); v->read_disconnected = true; return 1; } - if (v->allow_fd_passing_input) { + if (v->allow_fd_passing_input > 0) { struct cmsghdr *cmsg; cmsg = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, (socklen_t) -1); @@ -3159,7 +3161,7 @@ _public_ int sd_varlink_peek_fd(sd_varlink *v, size_t i) { /* Returns one of the file descriptors that were received along with the current message. This does * not duplicate the fd nor invalidate it, it hence remains in our possession. */ - if (!v->allow_fd_passing_input) + if (v->allow_fd_passing_input <= 0) return -EPERM; if (i >= v->n_input_fds) @@ -3185,7 +3187,7 @@ _public_ int sd_varlink_take_fd(sd_varlink *v, size_t i) { * we'll invalidate the reference to it under our possession. If called twice in a row will return * -EBADF */ - if (!v->allow_fd_passing_input) + if (v->allow_fd_passing_input <= 0) return -EPERM; if (i >= v->n_input_fds) @@ -3197,7 +3199,7 @@ _public_ int sd_varlink_take_fd(sd_varlink *v, size_t i) { _public_ int sd_varlink_get_n_fds(sd_varlink *v) { assert_return(v, -EINVAL); - if (!v->allow_fd_passing_input) + if (v->allow_fd_passing_input <= 0) return -EPERM; return (int) v->n_input_fds; @@ -3247,20 +3249,29 @@ _public_ int sd_varlink_set_allow_fd_passing_input(sd_varlink *v, int b) { assert_return(v, -EINVAL); - if (v->allow_fd_passing_input == !!b) + if (v->allow_fd_passing_input >= 0 && (v->allow_fd_passing_input > 0) == !!b) return 0; - if (!b) { - v->allow_fd_passing_input = false; - return 1; + r = verify_unix_socket(v); + if (r < 0) { + assert(v->allow_fd_passing_input <= 0); + + if (!b) { + v->allow_fd_passing_input = false; + return 0; + } + + return r; } - r = verify_unix_socket(v); - if (r < 0) - return r; + if (!v->server || FLAGS_SET(v->server->flags, SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT)) { + r = setsockopt_int(v->input_fd, SOL_SOCKET, SO_PASSRIGHTS, !!b); + if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r)) + log_debug_errno(r, "Failed to set SO_PASSRIGHTS socket option: %m"); + } - v->allow_fd_passing_input = true; - return 0; + v->allow_fd_passing_input = !!b; + return 1; } _public_ int sd_varlink_set_allow_fd_passing_output(sd_varlink *v, int b) { @@ -3297,7 +3308,8 @@ _public_ int sd_varlink_server_new(sd_varlink_server **ret, sd_varlink_server_fl SD_VARLINK_SERVER_INHERIT_USERDATA| SD_VARLINK_SERVER_INPUT_SENSITIVE| SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT| - SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT)) == 0, -EINVAL); + SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT| + SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT)) == 0, -EINVAL); s = new(sd_varlink_server, 1); if (!s) @@ -3493,6 +3505,12 @@ _public_ int sd_varlink_server_add_connection_pair( if (r < 0) return r; + /* Link up the server and the connection, and take reference in both directions. Note that the + * reference on the connection is left dangling. It will be dropped when the connection is closed, + * which happens in varlink_close(), including in the event loop quit callback. */ + v->server = sd_varlink_server_ref(server); + sd_varlink_ref(v); + v->input_fd = input_fd; v->output_fd = output_fd; if (server->flags & SD_VARLINK_SERVER_INHERIT_USERDATA) @@ -3510,12 +3528,6 @@ _public_ int sd_varlink_server_add_connection_pair( (void) sd_varlink_set_allow_fd_passing_input(v, FLAGS_SET(server->flags, SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT)); (void) sd_varlink_set_allow_fd_passing_output(v, FLAGS_SET(server->flags, SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT)); - /* Link up the server and the connection, and take reference in both directions. Note that the - * reference on the connection is left dangling. It will be dropped when the connection is closed, - * which happens in varlink_close(), including in the event loop quit callback. */ - v->server = sd_varlink_server_ref(server); - sd_varlink_ref(v); - varlink_set_state(v, VARLINK_IDLE_SERVER); if (server->event) { @@ -3632,6 +3644,13 @@ _public_ int sd_varlink_server_listen_fd(sd_varlink_server *s, int fd) { if (r < 0) return r; + /* If fd passing is disabled on server, and SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT flag is set, + * turn off SO_PASSRIGHTS immediately on listening socket. The conditionalization behind a flag + * is needed to retain backwards compat, where implementations would register a connection callback + * to enable fd passing after accept(), which might race with clients wrt SO_PASSRIGHTS state. */ + if (FLAGS_SET(s->flags, SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT)) + (void) setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, FLAGS_SET(s->flags, SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT)); + r = varlink_server_create_listen_fd_socket(s, fd, &ss); if (r < 0) return r; @@ -3673,6 +3692,10 @@ _public_ int sd_varlink_server_listen_address(sd_varlink_server *s, const char * fd = fd_move_above_stdio(fd); + /* See the comment in sd_varlink_server_listen_fd() */ + if (FLAGS_SET(s->flags, SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT)) + (void) setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, FLAGS_SET(s->flags, SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT)); + (void) sockaddr_un_unlink(&sockaddr.un); WITH_UMASK(~m & 0777) diff --git a/src/libsystemd/sd-varlink/varlink-internal.h b/src/libsystemd/sd-varlink/varlink-internal.h index a163f81061..ef84824373 100644 --- a/src/libsystemd/sd-varlink/varlink-internal.h +++ b/src/libsystemd/sd-varlink/varlink-internal.h @@ -166,12 +166,12 @@ struct sd_varlink { bool prefer_write:1; bool got_pollhup:1; - bool allow_fd_passing_input:1; - bool allow_fd_passing_output:1; - bool output_buffer_sensitive:1; /* whether to erase the output buffer after writing it to the socket */ bool input_sensitive:1; /* Whether incoming messages might be sensitive */ + bool allow_fd_passing_output; + int allow_fd_passing_input; + int af; /* address family if socket; AF_UNSPEC if not socket; negative if not known */ usec_t timestamp; diff --git a/src/libsystemd/sd-varlink/varlink-util.c b/src/libsystemd/sd-varlink/varlink-util.c index cc18656d13..be7df73143 100644 --- a/src/libsystemd/sd-varlink/varlink-util.c +++ b/src/libsystemd/sd-varlink/varlink-util.c @@ -174,7 +174,7 @@ int varlink_server_new( _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL; int r; - r = sd_varlink_server_new(&s, flags); + r = sd_varlink_server_new(&s, flags|SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT); if (r < 0) return log_debug_errno(r, "Failed to allocate varlink server object: %m"); diff --git a/src/systemd/sd-varlink.h b/src/systemd/sd-varlink.h index 67d9cc3d94..9d3dc48a44 100644 --- a/src/systemd/sd-varlink.h +++ b/src/systemd/sd-varlink.h @@ -68,6 +68,7 @@ __extension__ typedef enum _SD_ENUM_TYPE_S64(sd_varlink_server_flags_t) { SD_VARLINK_SERVER_INPUT_SENSITIVE = 1 << 4, /* Automatically mark all connection input as sensitive */ SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT = 1 << 5, /* Allow receiving fds over all connections */ SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT = 1 << 6, /* Allow sending fds over all connections */ + SD_VARLINK_SERVER_FD_PASSING_INPUT_STRICT = 1 << 7, /* Reject input messages with fds if fd passing is disabled (needs kernel v6.16+) */ _SD_ENUM_FORCE_S64(SD_VARLINK_SERVER) } sd_varlink_server_flags_t; From 85352c095ec172528cd8e01daf9306936bb95c14 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 22:00:52 +0200 Subject: [PATCH 14/14] various: turn off SO_PASSRIGHTS where fds are not expected --- src/core/manager.c | 12 ++++++++++-- src/journal/journald-stream.c | 12 ++++++++---- src/journal/journald-syslog.c | 11 ++++++++--- src/nspawn/nspawn.c | 4 ++++ src/shared/ask-password-api.c | 2 ++ src/udev/udev-ctrl.c | 4 ++++ units/syslog.socket | 1 + 7 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index d794a2518f..53c62afaae 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1136,6 +1136,10 @@ static int manager_setup_user_lookup_fd(Manager *m) { if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, m->user_lookup_fds) < 0) return log_error_errno(errno, "Failed to allocate user lookup socket: %m"); + r = setsockopt_int(m->user_lookup_fds[0], SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r)) + log_warning_errno(r, "Failed to turn off SO_PASSRIGHTS on user lookup socket, ignoring: %m"); + (void) fd_increase_rxbuf(m->user_lookup_fds[0], MANAGER_SOCKET_RCVBUF_SIZE); } @@ -1176,7 +1180,11 @@ static int manager_setup_handoff_timestamp_fd(Manager *m) { r = setsockopt_int(m->handoff_timestamp_fds[0], SOL_SOCKET, SO_PASSCRED, true); if (r < 0) - return log_error_errno(r, "SO_PASSCRED failed: %m"); + return log_error_errno(r, "Failed to enable SO_PASSCRED on handoff timestamp socket: %m"); + + r = setsockopt_int(m->handoff_timestamp_fds[0], SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r)) + log_warning_errno(r, "Failed to turn off SO_PASSRIGHTS on handoff timestamp socket, ignoring: %m"); /* Mark the receiving socket as O_NONBLOCK (but leave sending side as-is) */ r = fd_nonblock(m->handoff_timestamp_fds[0], true); @@ -1223,7 +1231,7 @@ static int manager_setup_pidref_transport_fd(Manager *m) { r = setsockopt_int(m->pidref_transport_fds[0], SOL_SOCKET, SO_PASSPIDFD, true); if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) - log_debug("SO_PASSPIDFD is not supported for pidref socket, ignoring."); + log_debug_errno(r, "SO_PASSPIDFD is not supported for pidref socket, ignoring."); else if (r < 0) log_warning_errno(r, "Failed to enable SO_PASSPIDFD for pidref socket, ignoring: %m"); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index c7da314118..45fc3257ff 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -647,10 +647,6 @@ int stdout_stream_install(Manager *m, int fd, StdoutStream **ret) { if (r < 0) return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to determine peer credentials: %m"); - r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true); - if (r < 0) - return log_error_errno(r, "SO_PASSCRED failed: %m"); - if (mac_selinux_use()) { r = getpeersec(fd, &stream->label); if (r < 0 && r != -EOPNOTSUPP) @@ -918,6 +914,14 @@ int manager_open_stdout_socket(Manager *m, const char *stdout_socket) { } else (void) fd_nonblock(m->stdout_fd, true); + r = setsockopt_int(m->stdout_fd, SOL_SOCKET, SO_PASSCRED, true); + if (r < 0) + return log_error_errno(r, "Failed to enable SO_PASSCRED: %m"); + + r = setsockopt_int(m->stdout_fd, SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0) + log_debug_errno(r, "Failed to turn off SO_PASSRIGHTS, ignoring: %m"); + r = sd_event_add_io(m->event, &m->stdout_event_source, m->stdout_fd, EPOLLIN, stdout_stream_new, m); if (r < 0) return log_error_errno(r, "Failed to add stdout server fd to event source: %m"); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index f441476f1d..ca204f25f5 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -504,17 +504,22 @@ int manager_open_syslog_socket(Manager *m, const char *syslog_socket) { r = setsockopt_int(m->syslog_fd, SOL_SOCKET, SO_PASSCRED, true); if (r < 0) - return log_error_errno(r, "SO_PASSCRED failed: %m"); + return log_error_errno(r, "Failed to enable SO_PASSCRED: %m"); + + r = setsockopt_int(m->syslog_fd, SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0) + log_debug_errno(r, "Failed to turn off SO_PASSRIGHTS, ignoring: %m"); if (mac_selinux_use()) { r = setsockopt_int(m->syslog_fd, SOL_SOCKET, SO_PASSSEC, true); if (r < 0) - log_full_errno(ERRNO_IS_NEG_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, "SO_PASSSEC failed, ignoring: %m"); + log_full_errno(ERRNO_IS_NEG_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to enable SO_PASSSEC, ignoring: %m"); } r = setsockopt_int(m->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, true); if (r < 0) - return log_error_errno(r, "SO_TIMESTAMP failed: %m"); + return log_error_errno(r, "Failed to enable SO_TIMESTAMP: %m"); r = sd_event_add_io(m->event, &m->syslog_event_source, m->syslog_fd, EPOLLIN, manager_process_datagram, m); if (r < 0) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 36b7495482..4edd092d3d 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3716,6 +3716,10 @@ static int setup_notify_child(const void *directory) { if (r < 0) log_debug_errno(r, "Failed to enable SO_PASSPIDFD, ignoring: %m"); + r = setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0) + log_debug_errno(r, "Failed to turn off SO_PASSRIGHTS, ignoring: %m"); + return TAKE_FD(fd); } diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 33ed81fbb5..5b0cc14be8 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -819,6 +819,8 @@ static int create_socket(const char *askpwdir, char **ret) { if (r < 0) return r; + (void) setsockopt_int(fd, SOL_SOCKET, SO_PASSRIGHTS, false); + *ret = TAKE_PTR(path); return TAKE_FD(fd); } diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index eeaa0c01f3..fbd0834d16 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -59,6 +59,10 @@ int udev_ctrl_new_from_fd(UdevCtrl **ret, int fd) { if (r < 0) log_warning_errno(r, "Failed to set SO_PASSCRED, ignoring: %m"); + r = setsockopt_int(fd >= 0 ? fd : sock, SOL_SOCKET, SO_PASSRIGHTS, false); + if (r < 0) + log_debug_errno(r, "Failed to turn off SO_PASSRIGHTS, ignoring: %m"); + uctrl = new(UdevCtrl, 1); if (!uctrl) return -ENOMEM; diff --git a/units/syslog.socket b/units/syslog.socket index 26b691c105..383bc7a067 100644 --- a/units/syslog.socket +++ b/units/syslog.socket @@ -27,6 +27,7 @@ ListenDatagram=/run/systemd/journal/syslog SocketMode=0666 PassCredentials=yes PassSecurity=yes +AcceptFileDescriptors=no ReceiveBuffer=8M # The default syslog implementation should make syslog.service a