core: add socket xattr settings for socket unit
This commit is contained in:
@@ -5245,6 +5245,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as Symlinks = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(ss) XAttrEntryPoint = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(ss) XAttrListen = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly a(ss) XAttrAccept = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly i Mark = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly u MaxConnections = ...;
|
||||
@@ -6616,6 +6622,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Symlinks"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="XAttrEntryPoint"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="XAttrListen"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="XAttrAccept"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Mark"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="MaxConnections"/>
|
||||
@@ -7299,6 +7311,17 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
<para><varname>FlushPending</varname> specifies whether to flush the socket
|
||||
just before entering the listening state. This setting only applies to sockets with
|
||||
<varname>Accept=</varname> set to <literal>no</literal>.</para>
|
||||
|
||||
<para><varname>XAttrEntryPoint</varname>, <varname>XAttrListen</varname> and
|
||||
<varname>XAttrAccept</varname> each contain a list of extended attributes (as
|
||||
<literal><replaceable>NAME</replaceable></literal>/<literal><replaceable>VALUE</replaceable></literal>
|
||||
pairs) to set on socket inodes. <varname>XAttrEntryPoint</varname> applies to the file-system inode an
|
||||
<constant>AF_UNIX</constant> socket is bound to, <varname>XAttrListen</varname> applies to the listening
|
||||
socket, and <varname>XAttrAccept</varname> applies to connection sockets accepted off the listening
|
||||
socket. See the <varname>XAttrEntryPoint=</varname>, <varname>XAttrListen=</varname> and
|
||||
<varname>XAttrAccept=</varname> settings in
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
@@ -12977,6 +13000,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>IOPressureWatch</varname>,
|
||||
<varname>CPUSetPartition</varname>, and
|
||||
<varname>OOMRules</varname> were added in version 261.</para>
|
||||
<para><varname>XAttrEntryPoint</varname>,
|
||||
<varname>XAttrListen</varname>, and
|
||||
<varname>XAttrAccept</varname> were added in version 262.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Mount Unit Objects</title>
|
||||
|
||||
@@ -675,6 +675,40 @@
|
||||
<xi:include href="version-info.xml" xpointer="v196"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>XAttrEntryPoint=</varname></term>
|
||||
<term><varname>XAttrListen=</varname></term>
|
||||
<term><varname>XAttrAccept=</varname></term>
|
||||
<listitem><para>Set an extended attribute on the socket, in the form
|
||||
<literal><replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></literal>. The extended
|
||||
attribute's name must be in the <literal>user.</literal> namespace, i.e. begin with the four
|
||||
characters <literal>user.</literal>. Specifiers are expanded in both the name and the value, see
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details on the available specifiers. These settings may be used more than once to set multiple
|
||||
extended attributes; assigning the empty string resets the list.</para>
|
||||
|
||||
<para>The three variables control where the extended attributes are applied:
|
||||
<varname>XAttrEntryPoint=</varname> sets them on the file-system inode an
|
||||
<constant>AF_UNIX</constant> socket is bound to (i.e. the socket node visible in the file system at
|
||||
the specified listening path; this only applies to <constant>AF_UNIX</constant> sockets),
|
||||
<varname>XAttrListen=</varname> sets them on the listening socket, and
|
||||
<varname>XAttrAccept=</varname> sets them on the connection sockets accepted off the listening socket
|
||||
(and is thus only relevant in combination with
|
||||
<varname>Accept=</varname><literal>yes</literal>).</para>
|
||||
|
||||
<para>This is primarily useful to tag sockets so that they can be discovered and classified by other
|
||||
tools. For example, Varlink entrypoint sockets are supposed to be tagged with
|
||||
<literal>user.varlink=entrypoint</literal> via <varname>XAttrEntryPoint=</varname>, which makes them
|
||||
discoverable via <command>varlinkctl list-sockets</command>, see
|
||||
<citerefentry><refentrytitle>varlinkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>These settings require kernel support for extended attributes on socket inodes (available since
|
||||
Linux 7.0). Extended attributes that cannot be applied are logged at debug level and otherwise
|
||||
ignored.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v262"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>SELinuxContextFromNet=</varname></term>
|
||||
<listitem><para>Takes a boolean argument. When true, systemd
|
||||
|
||||
@@ -58,6 +58,33 @@ static int property_get_listen(
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int property_get_xattr(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *reterr_error) {
|
||||
|
||||
char ***xattr = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(ss)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH_PAIR(name, value, *xattr) {
|
||||
r = sd_bus_message_append(reply, "(ss)", *name, *value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
const sd_bus_vtable bus_socket_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -95,6 +122,9 @@ const sd_bus_vtable bus_socket_vtable[] = {
|
||||
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),
|
||||
SD_BUS_PROPERTY("Symlinks", "as", NULL, offsetof(Socket, symlinks), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("XAttrEntryPoint", "a(ss)", property_get_xattr, offsetof(Socket, xattr_entrypoint), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("XAttrListen", "a(ss)", property_get_xattr, offsetof(Socket, xattr_listen), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("XAttrAccept", "a(ss)", property_get_xattr, offsetof(Socket, xattr_accept), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("MaxConnectionsPerSource", "u", bus_property_get_unsigned, offsetof(Socket, max_connections_per_source), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -153,6 +183,63 @@ static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(socket_timestamping, SocketTimestamping, socket_timestamping_from_string_harder);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(socket_defer_trigger, SocketDeferTrigger, socket_defer_trigger_from_string);
|
||||
|
||||
static int bus_socket_set_transient_xattr(
|
||||
Unit *u,
|
||||
const char *name,
|
||||
char ***p,
|
||||
sd_bus_message *message,
|
||||
UnitWriteFlags flags,
|
||||
sd_bus_error *reterr_error) {
|
||||
|
||||
_cleanup_strv_free_ char **pairs = NULL;
|
||||
const char *xname, *xvalue;
|
||||
bool empty = true;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(name);
|
||||
assert(p);
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_enter_container(message, 'a', "(ss)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_read(message, "(ss)", &xname, &xvalue)) > 0) {
|
||||
if (!startswith(xname, "user."))
|
||||
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Extended attribute name does not begin with 'user.': %s", xname);
|
||||
|
||||
r = strv_extend_many(&pairs, xname, xvalue);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
empty = false;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
if (empty) {
|
||||
*p = strv_free(*p);
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=", name);
|
||||
} else {
|
||||
r = strv_extend_strv(p, pairs, /* filter_duplicates= */ false);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH_PAIR(n, v, pairs)
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s=%s", name, *n, *v);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bus_socket_set_transient_property(
|
||||
Socket *s,
|
||||
const char *name,
|
||||
@@ -335,6 +422,15 @@ static int bus_socket_set_transient_property(
|
||||
&s->exec_command[ci],
|
||||
message, flags, reterr_error);
|
||||
|
||||
if (streq(name, "XAttrEntryPoint"))
|
||||
return bus_socket_set_transient_xattr(u, name, &s->xattr_entrypoint, message, flags, reterr_error);
|
||||
|
||||
if (streq(name, "XAttrListen"))
|
||||
return bus_socket_set_transient_xattr(u, name, &s->xattr_listen, message, flags, reterr_error);
|
||||
|
||||
if (streq(name, "XAttrAccept"))
|
||||
return bus_socket_set_transient_xattr(u, name, &s->xattr_accept, message, flags, reterr_error);
|
||||
|
||||
if (streq(name, "Symlinks")) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
|
||||
|
||||
@@ -561,6 +561,9 @@ Socket.PollLimitIntervalSec, config_parse_sec,
|
||||
Socket.PollLimitBurst, config_parse_unsigned, 0, offsetof(Socket, poll_limit.burst)
|
||||
Socket.DeferTrigger, config_parse_socket_defer_trigger, 0, offsetof(Socket, defer_trigger)
|
||||
Socket.DeferTriggerMaxSec, config_parse_sec_fix_0, 0, offsetof(Socket, defer_trigger_max_usec)
|
||||
Socket.XAttrEntryPoint, config_parse_xattr, 0, offsetof(Socket, xattr_entrypoint)
|
||||
Socket.XAttrListen, config_parse_xattr, 0, offsetof(Socket, xattr_listen)
|
||||
Socket.XAttrAccept, config_parse_xattr, 0, offsetof(Socket, xattr_accept)
|
||||
{% if ENABLE_SMACK %}
|
||||
Socket.SmackLabel, config_parse_unit_string_printf, 0, offsetof(Socket, smack)
|
||||
Socket.SmackLabelIPIn, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_in)
|
||||
|
||||
@@ -2247,6 +2247,66 @@ int config_parse_socket_service(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_xattr(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
char ***lp = ASSERT_PTR(data);
|
||||
Unit *u = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*lp = strv_free(*lp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *name = NULL, *value = NULL;
|
||||
r = split_pair(rvalue, "=", &name, &value);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse extended attribute expression, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *expanded_name = NULL;
|
||||
r = unit_full_printf(u, name, &expanded_name);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in extended attribute expression, ignoring: %s", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!startswith(expanded_name, "user.")) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Extended attribute name does not begin with 'user.', ignoring: %s", expanded_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *expanded_value = NULL;
|
||||
r = unit_full_printf(u, value, &expanded_value);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in extended attribute expression, ignoring: %s", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strv_push_pair(lp, expanded_name, expanded_value) < 0)
|
||||
return log_oom();
|
||||
|
||||
TAKE_PTR(expanded_name);
|
||||
TAKE_PTR(expanded_value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_fdname(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
||||
@@ -173,6 +173,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bind_network_interface);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_memory_thp);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_partition);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_luo_sessions);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_xattr);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
||||
+8
-1
@@ -210,6 +210,10 @@ static void socket_done(Unit *u) {
|
||||
|
||||
strv_free(s->symlinks);
|
||||
|
||||
strv_free(s->xattr_entrypoint);
|
||||
strv_free(s->xattr_listen);
|
||||
strv_free(s->xattr_accept);
|
||||
|
||||
s->user = mfree(s->user);
|
||||
s->group = mfree(s->group);
|
||||
|
||||
@@ -1510,7 +1514,9 @@ static int socket_address_listen_do(
|
||||
s->directory_mode,
|
||||
s->socket_mode,
|
||||
selinux_label,
|
||||
s->smack);
|
||||
s->smack,
|
||||
s->xattr_entrypoint,
|
||||
s->xattr_listen);
|
||||
}
|
||||
|
||||
#define log_address_error_errno(u, address, error, fmt) \
|
||||
@@ -3208,6 +3214,7 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
|
||||
if (cfd < 0)
|
||||
goto fail;
|
||||
|
||||
(void) socket_set_xattrs(cfd, /* path= */ NULL, p->socket->xattr_accept);
|
||||
socket_apply_socket_options(p->socket, p, cfd);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ typedef struct Socket {
|
||||
|
||||
char **symlinks;
|
||||
|
||||
char **xattr_entrypoint;
|
||||
char **xattr_listen;
|
||||
char **xattr_accept;
|
||||
|
||||
bool accept;
|
||||
bool remove_on_stop;
|
||||
bool writable;
|
||||
|
||||
@@ -224,6 +224,58 @@ static int bus_append_strv_colon(sd_bus_message *m, const char *field, const cha
|
||||
return bus_append_strv_full(m, field, eq, ":" WHITESPACE, EXTRACT_UNQUOTE);
|
||||
}
|
||||
|
||||
static int bus_append_xattr(sd_bus_message *m, const char *field, const char *eq) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(field);
|
||||
|
||||
/* Sends an extended attribute assignment of the form "name=value" as an a(ss) array of one
|
||||
* name/value pair (or as an empty array if the value is empty, which resets the list). */
|
||||
|
||||
r = sd_bus_message_open_container(m, 'r', "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_basic(m, 's', field);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "a(ss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(ss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (!isempty(eq)) {
|
||||
_cleanup_free_ char *name = NULL, *value = NULL;
|
||||
|
||||
r = split_pair(eq, "=", &name, &value);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse extended attribute expression '%s': %m", eq);
|
||||
|
||||
r = sd_bus_message_append(m, "(ss)", name, value);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
|
||||
int r;
|
||||
|
||||
@@ -2786,6 +2838,9 @@ static const BusProperty socket_properties[] = {
|
||||
{ "Timestamping", bus_append_string },
|
||||
{ "DeferTrigger", bus_append_string },
|
||||
{ "Symlinks", bus_append_strv },
|
||||
{ "XAttrEntryPoint", bus_append_xattr },
|
||||
{ "XAttrListen", bus_append_xattr },
|
||||
{ "XAttrAccept", bus_append_xattr },
|
||||
{ "SocketProtocol", bus_append_parse_ip_protocol },
|
||||
{ "ListenStream", bus_append_listen },
|
||||
{ "ListenDatagram", bus_append_listen },
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#include "socket-label.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "umask-util.h"
|
||||
#include "xattr-util.h"
|
||||
|
||||
static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
|
||||
[SOCKET_ADDRESS_DEFAULT] = "default",
|
||||
@@ -36,6 +38,32 @@ SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(cons
|
||||
return socket_address_bind_ipv6_only_from_string(s);
|
||||
}
|
||||
|
||||
int socket_set_xattrs(int fd, const char *path, char **xattrs) {
|
||||
int r;
|
||||
|
||||
assert(wildcard_fd_is_valid(fd));
|
||||
|
||||
if (strv_isempty(xattrs))
|
||||
return 0;
|
||||
|
||||
r = socket_xattr_supported();
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
int c = 0;
|
||||
STRV_FOREACH_PAIR(name, value, xattrs) {
|
||||
r = xsetxattr(fd, path, AT_EMPTY_PATH, *name, *value);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to set extended attribute '%s' on socket, ignoring: %m", *name);
|
||||
continue;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int socket_address_listen(
|
||||
const SocketAddress *a,
|
||||
int flags,
|
||||
@@ -48,7 +76,9 @@ int socket_address_listen(
|
||||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *selinux_label,
|
||||
const char *smack_label) {
|
||||
const char *smack_label,
|
||||
char **xattr_entrypoint,
|
||||
char **xattr_listen) {
|
||||
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
const char *p;
|
||||
@@ -119,6 +149,8 @@ int socket_address_listen(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) socket_set_xattrs(fd, /* path= */ NULL, xattr_listen);
|
||||
|
||||
p = socket_address_get_path(a);
|
||||
if (p) {
|
||||
/* Create parents */
|
||||
@@ -138,11 +170,14 @@ int socket_address_listen(
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (smack_label) {
|
||||
r = mac_smack_apply(p, SMACK_ATTR_ACCESS, smack_label);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to apply SMACK label for socket path, ignoring: %m");
|
||||
}
|
||||
|
||||
(void) socket_set_xattrs(AT_FDCWD, p, xattr_entrypoint);
|
||||
} else {
|
||||
if (bind(fd, &a->sockaddr.sa, a->size) < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -26,4 +26,8 @@ int socket_address_listen(
|
||||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *selinux_label,
|
||||
const char *smack_label);
|
||||
const char *smack_label,
|
||||
char **xattr_entrypoint,
|
||||
char **xattr_listen);
|
||||
|
||||
int socket_set_xattrs(int fd, const char *path, char **xattrs);
|
||||
|
||||
@@ -198,7 +198,9 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) {
|
||||
0755,
|
||||
0644,
|
||||
/* selinux_label= */ NULL,
|
||||
/* smack_label= */ NULL);
|
||||
/* smack_label= */ NULL,
|
||||
/* xattr_entrypoint= */ NULL,
|
||||
/* xattr_listen= */ NULL);
|
||||
if (fd < 0 || log_get_max_level() >= log_level) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
|
||||
@@ -1467,6 +1467,25 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
|
||||
STR_IN_SET(name, "XAttrEntryPoint", "XAttrListen", "XAttrAccept")) {
|
||||
const char *xname, *xvalue;
|
||||
|
||||
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_read(m, "(ss)", &xname, &xvalue)) > 0)
|
||||
bus_print_property_valuef(name, expected_value, flags, "%s=%s", xname, xvalue);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
|
||||
const char *base;
|
||||
uint64_t v, next_elapse;
|
||||
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/util.sh
|
||||
. "$(dirname "$0")"/util.sh
|
||||
|
||||
# Extended attributes on socket inodes (and hence the XAttr*= socket settings and
|
||||
# "varlinkctl list-sockets") require a sufficiently new kernel. Probe for actual
|
||||
# support and skip if unavailable, since the kernel version alone is not a reliable
|
||||
# indicator.
|
||||
if ! socket_inode_supports_user_xattrs; then
|
||||
echo "Socket inode extended attributes unsupported on this kernel, skipping." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
UNIT_SOCKET_PATH="/run/test-socket-xattr.sock"
|
||||
RUN_SOCKET_PATH="/run/test-socket-xattr-run.sock"
|
||||
|
||||
at_exit() {
|
||||
set +e
|
||||
systemctl stop test-socket-xattr.socket test-socket-xattr-run.socket
|
||||
systemctl reset-failed test-socket-xattr-run.socket test-socket-xattr-run.service
|
||||
rm -f /run/systemd/system/test-socket-xattr.socket
|
||||
rm -f /run/systemd/system/test-socket-xattr.service
|
||||
systemctl daemon-reload
|
||||
}
|
||||
trap at_exit EXIT
|
||||
|
||||
# Read the single user.varlink extended attribute value off the given path.
|
||||
read_role() {
|
||||
getfattr --absolute-names --only-values --name=user.varlink "$1"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 1) XAttr*= configured in a unit file on disk
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# A matching .service unit is required to be able to start the .socket unit. It is
|
||||
# never actually triggered here (we only check the listening socket), so a trivial
|
||||
# service is sufficient.
|
||||
cat >/run/systemd/system/test-socket-xattr.service <<EOF
|
||||
[Service]
|
||||
ExecStart=/bin/true
|
||||
EOF
|
||||
|
||||
cat >/run/systemd/system/test-socket-xattr.socket <<EOF
|
||||
[Unit]
|
||||
Description=Socket xattr test (on-disk unit)
|
||||
|
||||
[Socket]
|
||||
ListenStream=$UNIT_SOCKET_PATH
|
||||
SocketMode=0666
|
||||
XAttrEntryPoint=user.varlink=entrypoint
|
||||
XAttrListen=user.varlink=listen
|
||||
XAttrAccept=user.varlink=server
|
||||
RemoveOnStop=true
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl start test-socket-xattr.socket
|
||||
|
||||
# The socket node bound into the file system must carry the entrypoint xattr.
|
||||
test -S "$UNIT_SOCKET_PATH"
|
||||
[[ "$(read_role "$UNIT_SOCKET_PATH")" == "entrypoint" ]]
|
||||
|
||||
# The configured settings must be exposed again via the manager's D-Bus properties.
|
||||
systemctl show -P XAttrEntryPoint test-socket-xattr.socket | grep "user.varlink=entrypoint" >/dev/null
|
||||
systemctl show -P XAttrListen test-socket-xattr.socket | grep "user.varlink=listen" >/dev/null
|
||||
systemctl show -P XAttrAccept test-socket-xattr.socket | grep "user.varlink=server" >/dev/null
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 2) XAttr*= set via "systemd-run --socket-property="
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
rm -f "$RUN_SOCKET_PATH"
|
||||
|
||||
# systemd-run synthesizes the matching test-socket-xattr-run.service for us.
|
||||
systemd-run \
|
||||
--unit=test-socket-xattr-run \
|
||||
--service-type=oneshot \
|
||||
--remain-after-exit \
|
||||
--socket-property=ListenStream="$RUN_SOCKET_PATH" \
|
||||
--socket-property=SocketMode=0666 \
|
||||
--socket-property=XAttrEntryPoint=user.varlink=entrypoint \
|
||||
--socket-property=XAttrListen=user.varlink=listen \
|
||||
--socket-property=XAttrAccept=user.varlink=server \
|
||||
--socket-property=RemoveOnStop=true \
|
||||
true
|
||||
|
||||
systemctl cat test-socket-xattr-run.socket
|
||||
|
||||
# The XAttr*= settings must have been serialized into the transient socket unit.
|
||||
grep "^XAttrEntryPoint=user.varlink=entrypoint$" /run/systemd/transient/test-socket-xattr-run.socket >/dev/null
|
||||
grep "^XAttrListen=user.varlink=listen$" /run/systemd/transient/test-socket-xattr-run.socket >/dev/null
|
||||
grep "^XAttrAccept=user.varlink=server$" /run/systemd/transient/test-socket-xattr-run.socket >/dev/null
|
||||
|
||||
# And the transient socket must validate cleanly.
|
||||
systemd-analyze verify --recursive-errors=no "/run/systemd/transient/test-socket-xattr-run.socket"
|
||||
|
||||
# Wait for the transient socket to be bound, then check the entrypoint xattr.
|
||||
test -S "$RUN_SOCKET_PATH"
|
||||
[[ "$(read_role "$RUN_SOCKET_PATH")" == "entrypoint" ]]
|
||||
|
||||
systemctl show -P XAttrEntryPoint test-socket-xattr-run.socket | grep "user.varlink=entrypoint" >/dev/null
|
||||
systemctl show -P XAttrListen test-socket-xattr-run.socket | grep "user.varlink=listen" >/dev/null
|
||||
systemctl show -P XAttrAccept test-socket-xattr-run.socket | grep "user.varlink=server" >/dev/null
|
||||
@@ -251,6 +251,24 @@ cgroupfs_supports_user_xattrs() {
|
||||
[[ "$(getfattr --name="$xattr" --absolute-names --only-values /sys/fs/cgroup)" -eq 254 ]]
|
||||
}
|
||||
|
||||
socket_inode_supports_user_xattrs() {
|
||||
local socket xattr
|
||||
|
||||
# The XAttr*= socket settings and "varlinkctl list-sockets" rely on extended
|
||||
# attributes on socket inodes. This needs a sufficiently new kernel, but the
|
||||
# kernel version alone is not a reliable indicator: some kernels that report
|
||||
# >= 7.0 still reject user.* xattrs on socket inodes (with EPERM/EOPNOTSUPP).
|
||||
# Hence probe for actual support, mirroring socket_xattr_supported() in the
|
||||
# C code, by binding a throwaway socket and trying to tag it.
|
||||
socket="$(mktemp -u /run/socket-xattr-probe.XXXXXX.sock)"
|
||||
xattr="user.probe_$RANDOM"
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -f '$socket'" RETURN
|
||||
|
||||
python3 -c 'import socket, sys; socket.socket(socket.AF_UNIX).bind(sys.argv[1])' "$socket" || return 1
|
||||
setfattr --name="$xattr" --value=1 "$socket" 2>/dev/null
|
||||
}
|
||||
|
||||
tpm_has_pcr() {
|
||||
local algorithm="${1:?}"
|
||||
local pcr="${2:?}"
|
||||
|
||||
Reference in New Issue
Block a user