mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
various: turn off SO_PASSRIGHTS where fds are not expected (#37759)
This commit is contained in:
3
README
3
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.
|
||||
|
||||
3
TODO
3
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?)
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
<!--property PassCredentials is not documented!-->
|
||||
|
||||
<!--property PassFileDescriptorsToExec is not documented!-->
|
||||
<!--property PassPIDFD is not documented!-->
|
||||
|
||||
<!--property PassSecurity is not documented!-->
|
||||
|
||||
<!--property PassPacketInfo is not documented!-->
|
||||
|
||||
<!--property AcceptFileDescriptors is not documented!-->
|
||||
|
||||
<!--property Timestamping is not documented!-->
|
||||
|
||||
<!--property RemoveOnStop is not documented!-->
|
||||
@@ -5624,6 +5630,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<!--property GID is not documented!-->
|
||||
|
||||
<!--property PassFileDescriptorsToExec is not documented!-->
|
||||
|
||||
<!--property ExecStopPre is not documented!-->
|
||||
|
||||
<!--property ExecStopPost is not documented!-->
|
||||
@@ -6178,12 +6186,14 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PassCredentials"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PassFileDescriptorsToExec"/>
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PassPIDFD"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PassSecurity"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PassPacketInfo"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="AcceptFileDescriptors"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Timestamping"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RemoveOnStop"/>
|
||||
@@ -6238,6 +6248,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="GID"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PassFileDescriptorsToExec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecStartPre"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecStartPost"/>
|
||||
@@ -12092,6 +12104,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>ProtectControlGroupsEx</varname>, and
|
||||
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
||||
<para><varname>ProtectHostnameEx</varname>,
|
||||
<varname>PassPIDFD</varname>,
|
||||
<varname>AcceptFileDescriptors</varname>,
|
||||
<varname>DelegateNamespaces</varname>, and
|
||||
<function>RemoveSubgroup()</function> were added in version 258.</para>
|
||||
</refsect2>
|
||||
|
||||
@@ -742,6 +742,16 @@
|
||||
process in an ancillary message. Defaults to <option>false</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PassPIDFD=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean value. This controls the <constant>SO_PASSPIDFD</constant> socket
|
||||
option, which allows <constant>AF_UNIX</constant> sockets to receive the pidfd of the sending
|
||||
process in an ancillary message. Defaults to <option>false</option>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PassSecurity=</varname></term>
|
||||
<listitem><para>Takes a boolean value. This controls the <constant>SO_PASSSEC</constant> socket
|
||||
@@ -761,6 +771,17 @@
|
||||
<xi:include href="version-info.xml" xpointer="v246"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>AcceptFileDescriptors=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean value. This controls the <constant>SO_PASSRIGHTS</constant> socket
|
||||
option, which when disabled prohibits the peer from sending <constant>SCM_RIGHTS</constant>
|
||||
ancillary messages (aka file descriptors) via <constant>AF_UNIX</constant> sockets. Defaults to
|
||||
<option>true</option>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Timestamping=</varname></term>
|
||||
<listitem><para>Takes one of <literal>off</literal>, <literal>us</literal> (alias:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,6 +22,7 @@ PassCredentials=yes
|
||||
PassSecurity=yes
|
||||
ReceiveBuffer=8M
|
||||
SendBuffer=8M
|
||||
Timestamping=us
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
|
||||
Reference in New Issue
Block a user