From 5c12797fc3dc2dac37ef2c7873e59cbb6da19daf Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 6 Jun 2025 21:01:33 +0200 Subject: [PATCH] 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",