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