summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/org.freedesktop.systemd1.xml24
-rw-r--r--man/systemd.exec.xml34
-rw-r--r--src/core/dbus-execute.c85
-rw-r--r--src/core/execute.c46
-rw-r--r--src/core/execute.h6
-rw-r--r--src/core/load-fragment-gperf.gperf.in1
-rw-r--r--src/core/load-fragment.c17
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/service.c3
-rw-r--r--src/shared/bus-unit-util.c89
-rw-r--r--test/fuzz/fuzz-unit-file/directives.mount1
-rw-r--r--test/fuzz/fuzz-unit-file/directives.service1
-rw-r--r--test/fuzz/fuzz-unit-file/directives.socket1
-rw-r--r--test/fuzz/fuzz-unit-file/directives.swap1
14 files changed, 310 insertions, 0 deletions
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 6625a74073..b9b5768bf0 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -2785,6 +2785,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b DynamicUser = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(iss) DynamicUserNFTSet = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b RemoveIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@@ -3332,6 +3334,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property DynamicUser is not documented!-->
+ <!--property DynamicUserNFTSet is not documented!-->
+
<!--property RemoveIPC is not documented!-->
<!--property SetCredential is not documented!-->
@@ -3940,6 +3944,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
@@ -4679,6 +4685,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b DynamicUser = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(iss) DynamicUserNFTSet = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b RemoveIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@@ -5250,6 +5258,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<!--property DynamicUser is not documented!-->
+ <!--property DynamicUserNFTSet is not documented!-->
+
<!--property RemoveIPC is not documented!-->
<!--property SetCredential is not documented!-->
@@ -5852,6 +5862,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
@@ -6480,6 +6492,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b DynamicUser = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(iss) DynamicUserNFTSet = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b RemoveIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@@ -6979,6 +6993,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<!--property DynamicUser is not documented!-->
+ <!--property DynamicUserNFTSet is not documented!-->
+
<!--property RemoveIPC is not documented!-->
<!--property SetCredential is not documented!-->
@@ -7499,6 +7515,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
@@ -8254,6 +8272,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b DynamicUser = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(iss) DynamicUserNFTSet = [...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b RemoveIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(say) SetCredential = [...];
@@ -8739,6 +8759,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<!--property DynamicUser is not documented!-->
+ <!--property DynamicUserNFTSet is not documented!-->
+
<!--property RemoveIPC is not documented!-->
<!--property SetCredential is not documented!-->
@@ -9245,6 +9267,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<variablelist class="dbus-property" generated="True" extra-ref="DynamicUser"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="DynamicUserNFTSet"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="RemoveIPC"/>
<variablelist class="dbus-property" generated="True" extra-ref="SetCredential"/>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 50c5c89703..9798a8d999 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -3164,6 +3164,40 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
</refsect1>
<refsect1>
+ <title>Firewall Integration</title>
+ <variablelist class='unit-directives'>
+
+ <varlistentry>
+ <term><varname>DynamicUserNFTSet=</varname><replaceable>family</replaceable>:<replaceable>table</replaceable>:<replaceable>set</replaceable></term>
+ <listitem><para>This setting provides a method for integrating <varname>DynamicUser=</varname>
+ configuration into firewall rules with NFT sets. This option expects a whitespace separated list of
+ NFT set definitions. Each definition consists of a colon-separated tuple of NFT address family (one
+ of <literal>arp</literal>, <literal>bridge</literal>, <literal>inet</literal>, <literal>ip</literal>,
+ <literal>ip6</literal>, or <literal>netdev</literal>), table name and set name. The names of tables
+ and sets must conform to lexical restrictions of NFT table names. When the unit starts, the user ID
+ will be appended to the NFT sets and it will be removed when the unit is stopped. Failures to manage
+ the sets will be ignored.</para>
+
+ <para>Example:
+ <programlisting>[Service]
+DynamicUserNFTSet=inet:filter:u</programlisting>
+ Corresponding NFT rules:
+ <programlisting>table inet filter {
+ set u {
+ typeof meta skuid
+ }
+ chain service_output {
+ meta skuid != @u drop
+ accept
+ }
+}</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
<title>System V Compatibility</title>
<variablelist class='unit-directives'>
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index a4c37307d2..a3e54e6411 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -22,6 +22,7 @@
#include "execute.h"
#include "fd-util.h"
#include "fileio.h"
+#include "firewall-util.h"
#include "hexdecoct.h"
#include "io-util.h"
#include "ioprio-util.h"
@@ -1138,6 +1139,37 @@ static int bus_property_get_exec_dir_symlink(
return sd_bus_message_close_container(reply);
}
+static int property_get_dynamic_user_nft_set(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "(iss)");
+ if (r < 0)
+ return r;
+
+ for (size_t i = 0; i < c->n_dynamic_user_nft_set_contexts; i++) {
+ NFTSetContext *s = &c->dynamic_user_nft_set_context[i];
+
+ r = sd_bus_message_append(reply, "(iss)", s->nfproto, s->table, s->set);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1232,6 +1264,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DynamicUser", "b", bus_property_get_bool, offsetof(ExecContext, dynamic_user), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DynamicUserNFTSet", "a(iss)", property_get_dynamic_user_nft_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(ExecContext, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SetCredential", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SetCredentialEncrypted", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -3503,6 +3536,58 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "DynamicUserNFTSet")) {
+ int nfproto;
+ const char *table, *set;
+ bool empty = true;
+
+ r = sd_bus_message_enter_container(message, 'a', "(iss)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(iss)", &nfproto, &table, &set)) > 0) {
+ const char *nfproto_name;
+
+ nfproto_name = nfproto_to_string(nfproto);
+ if (!nfproto_name)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid protocol %d.", nfproto);
+
+ if (nft_identifier_bad(table))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT table name %s.", table);
+
+ if (nft_identifier_bad(set))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT set name %s.", set);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ r = nft_set_context_add(&c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts, nfproto, table, set);
+ if (r < 0)
+ return r;
+
+ unit_write_settingf(
+ u, flags|UNIT_ESCAPE_SPECIFIERS, name,
+ "%s=%s:%s:%s",
+ name,
+ nfproto_name,
+ table,
+ set);
+ }
+
+ empty = false;
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (empty) {
+ c->dynamic_user_nft_set_context = nft_set_context_free_many(c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts);
+ unit_write_settingf(u, flags, name, "%s=", name);
+ }
+
+ return 1;
+
} else if ((suffix = startswith(name, "Limit"))) {
const char *soft = NULL;
int ri;
diff --git a/src/core/execute.c b/src/core/execute.c
index 05fc00ca1c..f128a45f54 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -4083,6 +4083,43 @@ static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int fd, int
return 1;
}
+static void exec_op_dynamic_user_nft_set(bool add, const ExecContext *c, uid_t uid) {
+ int r;
+
+ assert(c);
+
+ for (size_t i = 0; i < c->n_dynamic_user_nft_set_contexts; i++) {
+ NFTSetContext *s = &c->dynamic_user_nft_set_context[i];
+ if (add)
+ r = nft_set_element_add_uint32(s, uid);
+ else
+ r = nft_set_element_del_uint32(s, uid);
+ if (r < 0)
+ log_warning_errno(r, "%s NFT family %s table %s set %s UID " UID_FMT " failed, ignoring: %m",
+ add? "Adding" : "Deleting", nfproto_to_string(s->nfproto), s->table, s->set, uid);
+ }
+}
+
+static void exec_add_dynamic_user_nft_set(const ExecContext *c, uid_t uid) {
+ exec_op_dynamic_user_nft_set(true, c, uid);
+}
+
+void exec_delete_dynamic_user_nft_set(const ExecContext *c, DynamicUser *d) {
+ int r;
+ uid_t uid;
+
+ if (!d)
+ return;
+
+ r = dynamic_user_current(d, &uid);
+ if (r < 0) {
+ log_warning_errno(r, "Can't get current dynamic user, ignoring: %m");
+ return;
+ }
+
+ exec_op_dynamic_user_nft_set(false, c, uid);
+}
+
static int exec_child(
Unit *unit,
const ExecCommand *command,
@@ -4284,6 +4321,8 @@ static int exec_child(
if (dcreds->user)
username = dcreds->user->name;
+ exec_add_dynamic_user_nft_set(context, uid);
+
} else {
r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
if (r < 0) {
@@ -5346,6 +5385,8 @@ void exec_context_done(ExecContext *c) {
c->user = mfree(c->user);
c->group = mfree(c->group);
+ c->dynamic_user_nft_set_context = nft_set_context_free_many(c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts);
+
c->supplementary_groups = strv_free(c->supplementary_groups);
c->pam_name = mfree(c->pam_name);
@@ -6020,6 +6061,11 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sGroup: %s\n", prefix, c->group);
fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
+ for (size_t i = 0; i < c->n_dynamic_user_nft_set_contexts; i++)
+ fprintf(f, "%sDynamicUserNFTSet: %s:%s:%s\n", prefix,
+ nfproto_to_string(c->dynamic_user_nft_set_context[i].nfproto),
+ c->dynamic_user_nft_set_context[i].table,
+ c->dynamic_user_nft_set_context[i].set);
strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
diff --git a/src/core/execute.h b/src/core/execute.h
index 904e7943f3..b3516c29fc 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -18,6 +18,7 @@ typedef struct Manager Manager;
#include "cpu-set-util.h"
#include "exec-util.h"
#include "fdset.h"
+#include "firewall-util.h"
#include "list.h"
#include "missing_resource.h"
#include "namespace.h"
@@ -313,6 +314,9 @@ struct ExecContext {
bool mount_apivfs;
bool dynamic_user;
+ size_t n_dynamic_user_nft_set_contexts;
+ NFTSetContext *dynamic_user_nft_set_context;
+
bool remove_ipc;
bool memory_deny_write_execute;
@@ -522,3 +526,5 @@ const char* exec_resource_type_to_string(ExecDirectoryType i) _const_;
ExecDirectoryType exec_resource_type_from_string(const char *s) _pure_;
bool exec_needs_mount_namespace(const ExecContext *context, const ExecParameters *params, const ExecRuntime *runtime);
+
+void exec_delete_dynamic_user_nft_set(const ExecContext *c, DynamicUser *d);
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 0db24268d1..facda69d0d 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -32,6 +32,7 @@
{{type}}.PassEnvironment, config_parse_pass_environ, 0, offsetof({{type}}, exec_context.pass_environment)
{{type}}.UnsetEnvironment, config_parse_unset_environ, 0, offsetof({{type}}, exec_context.unset_environment)
{{type}}.DynamicUser, config_parse_bool, true, offsetof({{type}}, exec_context.dynamic_user)
+{{type}}.DynamicUserNFTSet, config_parse_dynamic_user_nft_set, 0, offsetof({{type}}, exec_context)
{{type}}.RemoveIPC, config_parse_bool, 0, offsetof({{type}}, exec_context.remove_ipc)
{{type}}.StandardInput, config_parse_exec_input, 0, offsetof({{type}}, exec_context)
{{type}}.StandardOutput, config_parse_exec_output, 0, offsetof({{type}}, exec_context)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 12c1af7933..8c136b1402 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -6607,3 +6607,20 @@ int config_parse_cgroup_nft_set(
return config_parse_nft_set(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &c->nft_set_context, &c->n_nft_set_contexts, u);
}
+
+int config_parse_dynamic_user_nft_set(
+ 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) {
+ ExecContext *c = data;
+ Unit *u = userdata;
+
+ return config_parse_nft_set(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &c->dynamic_user_nft_set_context, &c->n_dynamic_user_nft_set_contexts, u);
+}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 3632b5b096..c250e46846 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -151,6 +151,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_restrict_network_interfaces);
CONFIG_PARSER_PROTOTYPE(config_parse_watchdog_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_tty_size);
CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
+CONFIG_PARSER_PROTOTYPE(config_parse_dynamic_user_nft_set);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
diff --git a/src/core/service.c b/src/core/service.c
index 5f1a218bb5..f8d751e32f 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1877,6 +1877,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
/* Get rid of the IPC bits of the user */
unit_unref_uid_gid(UNIT(s), true);
+ /* Delete DynamicUserNFTSet= */
+ exec_delete_dynamic_user_nft_set(&s->exec_context, s->dynamic_creds.user);
+
/* Release the user, and destroy it if we are the only remaining owner */
dynamic_creds_destroy(&s->dynamic_creds);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index e1584c2e8d..1ffdcf384f 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -16,6 +16,7 @@
#include "exec-util.h"
#include "exit-status.h"
#include "fileio.h"
+#include "firewall-util.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
@@ -434,6 +435,91 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni
return sd_bus_message_close_container(m);
}
+static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
+ int r;
+
+ assert(m);
+
+ if (isempty(eq)) {
+ r = sd_bus_message_append(m, "(sv)", field, "a(iss)", 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+ }
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "a(iss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(iss)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ int family;
+
+ r = extract_first_word(&eq, &word, ":", 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %m", field);
+ if (isempty(word)) {
+ log_error("Failed to parse %s", field);
+ return 0;
+ }
+
+ family = nfproto_from_string(word);
+ if (family < 0)
+ return log_error_errno(family, "Failed to parse %s: %m", field);
+
+ r = extract_first_word(&eq, &word, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s: %m", field);
+ if (isempty(word) || isempty(eq)) {
+ log_error("Failed to parse %s", field);
+ return 0;
+ }
+
+ _cleanup_free_ char *unescaped = NULL;
+ ssize_t l;
+
+ l = cunescape(eq, 0, &unescaped);
+ if (l < 0)
+ return log_error_errno(l, "Failed to unescape %s= value: %s", field, eq);
+
+ r = sd_bus_message_append(m, "(iss)", family, word, eq);
+
+ 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);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
int r;
@@ -2051,6 +2137,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return 1;
}
+ if (STR_IN_SET(field, "DynamicUserNFTSet"))
+ return bus_append_nft_set(m, field, eq);
+
return 0;
}
diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount
index 2b3331a411..16d2138a04 100644
--- a/test/fuzz/fuzz-unit-file/directives.mount
+++ b/test/fuzz/fuzz-unit-file/directives.mount
@@ -38,6 +38,7 @@ DevicePolicy=
DirectoryMode=
DisableControllers=
DynamicUser=
+DynamicUserNFTSet=
Environment=
EnvironmentFile=
ExecPaths=
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index 30e6936d12..511c2f6b4f 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -160,6 +160,7 @@ DeviceAllow=
DevicePolicy=
DisableControllers=
DynamicUser=
+DynamicUserNFTSet=
Environment=
EnvironmentFile=
ExecCondition=
diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket
index 1b1ddf8c9c..b9ad5e5f84 100644
--- a/test/fuzz/fuzz-unit-file/directives.socket
+++ b/test/fuzz/fuzz-unit-file/directives.socket
@@ -44,6 +44,7 @@ DevicePolicy=
DirectoryMode=
DisableControllers=
DynamicUser=
+DynamicUserNFTSet=
Environment=
EnvironmentFile=
ExecPaths=
diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap
index 186dedbf3e..4721edce4b 100644
--- a/test/fuzz/fuzz-unit-file/directives.swap
+++ b/test/fuzz/fuzz-unit-file/directives.swap
@@ -37,6 +37,7 @@ DeviceAllow=
DevicePolicy=
DisableControllers=
DynamicUser=
+DynamicUserNFTSet=
Environment=
EnvironmentFile=
ExecPaths=