diff --git a/README b/README index 695819cd9b..0062563d5c 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 and SO_PASSRIGHTS ✅ systemd utilizes several new kernel APIs, but will fall back gracefully when unavailable. 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 384d0aa330..237394b1fa 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -4907,12 +4907,14 @@ 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 = ...; + readonly b PassPIDFD = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PassSecurity = ...; @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 = ...; @@ -4962,6 +4964,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,12 +5580,14 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - + + + @@ -5624,6 +5630,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -6178,12 +6186,14 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - + + + @@ -6238,6 +6248,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -12092,6 +12104,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ ProtectControlGroupsEx, and 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 b2779e84a2..91552d691f 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 @@ -761,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/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 diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 5781fb59f3..de96f00a15 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -86,9 +86,10 @@ 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("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), @@ -116,6 +117,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,8 +193,8 @@ 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, "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); @@ -200,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); @@ -311,6 +316,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 +356,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..918228fea1 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -510,9 +510,10 @@ 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.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) @@ -522,6 +523,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/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/core/socket.c b/src/core/socket.c index ec75c22c5c..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; @@ -610,13 +611,15 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sTransparent: %s\n" "%sBroadcast: %s\n" "%sPassCredentials: %s\n" - "%sPassFileDescriptorsToExec: %s\n" + "%sPassPIDFD: %s\n" "%sPassSecurity: %s\n" "%sPassPacketInfo: %s\n" + "%sAcceptFileDescriptors: %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 +634,15 @@ 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_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), 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) @@ -1011,6 +1016,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 +1030,82 @@ 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_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) - 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->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) { @@ -1089,50 +1113,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); diff --git a/src/core/socket.h b/src/core/socket.h index 696e0490c1..70291fb0d2 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,9 +131,10 @@ typedef struct Socket { bool transparent; bool broadcast; bool pass_cred; - bool pass_fds_to_exec; + 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/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/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/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index 3255bf8ed3..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; @@ -327,15 +329,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; @@ -853,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 */ @@ -897,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); @@ -3163,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) @@ -3189,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) @@ -3201,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; @@ -3251,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) { @@ -3275,17 +3282,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) { @@ -3306,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) @@ -3502,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) @@ -3519,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) { @@ -3641,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; @@ -3682,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/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, 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/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/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 1e28622668..ce56defeac 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2583,11 +2583,13 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons "Transparent", "Broadcast", "PassCredentials", - "PassFileDescriptorsToExec", + "PassPIDFD", "PassSecurity", "PassPacketInfo", + "AcceptFileDescriptors", "ReusePort", "RemoveOnStop", + "PassFileDescriptorsToExec", "SELinuxContextFromNet")) return bus_append_parse_boolean(m, field, eq); 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/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; 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-ctrl.c b/src/udev/udev-ctrl.c index 5cde769b1f..fbd0834d16 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,15 @@ 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"); + + 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; @@ -240,11 +250,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"); 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"); 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 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