]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #17076 from poettering/dissect-cleanup
authorLennart Poettering <lennart@poettering.net>
Wed, 16 Sep 2020 16:42:12 +0000 (18:42 +0200)
committerGitHub <noreply@github.com>
Wed, 16 Sep 2020 16:42:12 +0000 (18:42 +0200)
minor cleanups to the dissector code

23 files changed:
TODO
docs/TRANSIENT-SETTINGS.md
man/org.freedesktop.LogControl1.xml
man/org.freedesktop.systemd1.xml
man/systemd.exec.xml
src/basic/parse-util.c
src/basic/parse-util.h
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/libsystemd/sd-bus/sd-bus.c
src/shared/bus-unit-util.c
src/shared/seccomp-util.c
src/shared/seccomp-util.h
src/socket-proxy/socket-proxyd.c
src/systemctl/systemctl.c
src/test/test-execute.c
src/test/test-parse-util.c
test/test-execute/exec-systemcallfilter-override-error-action.service [new file with mode: 0644]
test/test-execute/exec-systemcallfilter-override-error-action2.service [new file with mode: 0644]

diff --git a/TODO b/TODO
index 69c05d3d38d60c2013cb4f36402079a3eaee8d5d..76cc74f340300afbac37ccfdc5f6f2f47ae3cf98 100644 (file)
--- a/TODO
+++ b/TODO
@@ -561,6 +561,9 @@ Features:
 * sd-bus: add vtable flag, that may be used to request client creds implicitly
   and asynchronously before dispatching the operation
 
+* sd-bus: parse addresses given in sd_bus_set_addresses immediately and not
+  only when used. Add unit tests.
+
 * make use of ethtool veth peer info in machined, for automatically finding out
   host-side interface pointing to the container.
 
index 89f0a7e80d137f927bbe6a85ed1d07e969aa7ced..f8ff413d28f4f8aecae9edde484b7ebafef1e124 100644 (file)
@@ -156,6 +156,7 @@ All execution-related settings are available for transient units.
 ✓ SystemCallFilter=
 ✓ SystemCallArchitectures=
 ✓ SystemCallErrorNumber=
+✓ SystemCallLog=
 ✓ MemoryDenyWriteExecute=
 ✓ RestrictNamespaces=
 ✓ RestrictRealtime=
index a51b7b01e1f25de133972fff5296c93980731279..1fdfb8943a6feaeff77be4711ccbbc4f18e827f2 100644 (file)
@@ -123,7 +123,7 @@ node /org/freedesktop/LogControl1 {
       <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+      <citerefentry project="man-pages"><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     </para>
   </refsect1>
 </refentry>
index 998caccc80ef1ae292181094ce39a50afc5ad3c6..3d833241082a2011d9699745d770c77081c187eb 100644 (file)
@@ -3904,6 +3904,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b Accept = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly b FlushPending = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b Writable = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b KeepAlive = ...;
@@ -3976,8 +3978,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly u NRefused = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
-      readonly u FlushPending = ...;
-      @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly s FileDescriptorName = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly i SocketProtocol = ...;
@@ -4985,6 +4985,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="Accept"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="FlushPending"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Writable"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KeepAlive"/>
@@ -5059,8 +5061,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="NRefused"/>
 
-    <variablelist class="dbus-property" generated="True" extra-ref="FlushPending"/>
-
     <variablelist class="dbus-property" generated="True" extra-ref="FileDescriptorName"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="SocketProtocol"/>
index 8be6a1aadd332f790b032d682efded99224105c6..d0bb5fc9623ed34f92162e81d943575d39f8b340 100644 (file)
@@ -1888,7 +1888,8 @@ RestrictNamespaces=~cgroup net</programlisting>
         <constant>EACCES</constant> or <constant>EUCLEAN</constant> (see <citerefentry
         project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
         full list). This value will be returned when a deny-listed system call is triggered, instead of
-        terminating the processes immediately.  This value takes precedence over the one given in
+        terminating the processes immediately. Special setting <literal>kill</literal> can be used to
+        explicitly specify killing. This value takes precedence over the one given in
         <varname>SystemCallErrorNumber=</varname>, see below.  If running in user mode, or in system mode,
         but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
         <varname>User=nobody</varname>), <varname>NoNewPrivileges=yes</varname> is implied. This feature
@@ -2098,8 +2099,9 @@ SystemCallErrorNumber=EPERM</programlisting>
         return when the system call filter configured with <varname>SystemCallFilter=</varname> is triggered,
         instead of terminating the process immediately. See <citerefentry
         project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
-        full list of error codes. When this setting is not used, or when the empty string is assigned, the
-        process will be terminated immediately when the filter is triggered.</para></listitem>
+        full list of error codes. When this setting is not used, or when the empty string or the special
+        setting <literal>kill</literal> is assigned, the process will be terminated immediately when the
+        filter is triggered.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -2134,6 +2136,21 @@ SystemCallErrorNumber=EPERM</programlisting>
         details.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>SystemCallLog=</varname></term>
+
+        <listitem><para>Takes a space-separated list of system call names. If this setting is used, all
+        system calls executed by the unit processes for the listed ones will be logged. If the first
+        character of the list is <literal>~</literal>, the effect is inverted: all system calls except the
+        listed system calls will be logged. If running in user mode, or in system mode, but without the
+        <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting <varname>User=nobody</varname>),
+        <varname>NoNewPrivileges=yes</varname> is implied. This feature makes use of the Secure Computing
+        Mode 2 interfaces of the kernel ('seccomp filtering') and is useful for auditing or setting up a
+        minimal sandboxing environment. This option may be specified more than once, in which case the filter
+        masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will
+        have no effect. This does not affect commands prefixed with <literal>+</literal>.</para></listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index 44f0438cf468f7ec12ac427a9f5560048d638da1..818c9054d6e4d6d21b44137b98d3fbc1fd2f7d2e 100644 (file)
@@ -16,6 +16,9 @@
 #include "missing_network.h"
 #include "parse-util.h"
 #include "process-util.h"
+#if HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -314,6 +317,7 @@ int parse_errno(const char *t) {
         return e;
 }
 
+#if HAVE_SECCOMP
 int parse_syscall_and_errno(const char *in, char **name, int *error) {
         _cleanup_free_ char *n = NULL;
         char *p;
@@ -332,7 +336,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
 
         p = strchr(in, ':');
         if (p) {
-                e = parse_errno(p + 1);
+                e = seccomp_parse_errno_or_action(p + 1);
                 if (e < 0)
                         return e;
 
@@ -351,6 +355,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
 
         return 0;
 }
+#endif
 
 static const char *mangle_base(const char *s, unsigned *base) {
         const char *k;
index 9a516ce5f6d75c96122da6ef39042a3bd986d5fd..2cee65c49ae36b6dafc091b4a57c4253d281c1dd 100644 (file)
@@ -19,7 +19,9 @@ int parse_mtu(int family, const char *s, uint32_t *ret);
 int parse_size(const char *t, uint64_t base, uint64_t *size);
 int parse_range(const char *t, unsigned *lower, unsigned *upper);
 int parse_errno(const char *t);
+#if HAVE_SECCOMP
 int parse_syscall_and_errno(const char *in, char **name, int *error);
+#endif
 
 #define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
 #define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
index 445230d27c2e0a71f02f598efe35270fa3023a71..dfcc2ee6e72930514600b2f298e457dec450ebae 100644 (file)
@@ -387,7 +387,7 @@ static int property_get_syscall_filter(
                         continue;
 
                 if (num >= 0) {
-                        e = errno_to_name(num);
+                        e = seccomp_errno_or_action_to_string(num);
                         if (e) {
                                 s = strjoin(name, ":", e);
                                 if (!s)
@@ -415,6 +415,58 @@ static int property_get_syscall_filter(
         return sd_bus_message_close_container(reply);
 }
 
+static int property_get_syscall_log(
+                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;
+        _cleanup_strv_free_ char **l = NULL;
+        int r;
+
+#if HAVE_SECCOMP
+        void *id, *val;
+#endif
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        r = sd_bus_message_open_container(reply, 'r', "bas");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(reply, "b", c->syscall_log_allow_list);
+        if (r < 0)
+                return r;
+
+#if HAVE_SECCOMP
+        HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
+                char *name = NULL;
+
+                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                if (!name)
+                        continue;
+
+                r = strv_consume(&l, name);
+                if (r < 0)
+                        return r;
+        }
+#endif
+
+        strv_sort(l);
+
+        r = sd_bus_message_append_strv(reply, l);
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_close_container(reply);
+}
+
 static int property_get_syscall_archs(
                 sd_bus *bus,
                 const char *path,
@@ -1068,6 +1120,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SystemCallErrorNumber", "i", bus_property_get_int, offsetof(ExecContext, syscall_errno), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("SystemCallLog", "(bas)", property_get_syscall_log, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Personality", "s", property_get_personality, offsetof(ExecContext, personality), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1424,7 +1477,7 @@ static const char* mount_propagation_flags_to_string_with_check(unsigned long n)
 static BUS_DEFINE_SET_TRANSIENT(nsec, "t", uint64_t, nsec_t, NSEC_FMT);
 static BUS_DEFINE_SET_TRANSIENT_IS_VALID(log_level, "i", int32_t, int, "%" PRIi32, log_level_is_valid);
 #if HAVE_SECCOMP
-static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, errno_is_valid);
+static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, seccomp_errno_or_action_is_valid);
 #endif
 static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
 static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
@@ -2230,6 +2283,76 @@ int bus_exec_context_set_transient_property(
 
                 return 1;
 
+        } else if (streq(name, "SystemCallLog")) {
+                int allow_list;
+                _cleanup_strv_free_ char **l = NULL;
+
+                r = sd_bus_message_enter_container(message, 'r', "bas");
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(message, "b", &allow_list);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read_strv(message, &l);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        _cleanup_free_ char *joined = NULL;
+                        SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
+                        char **s;
+
+                        if (strv_isempty(l)) {
+                                c->syscall_log_allow_list = false;
+                                c->syscall_log = hashmap_free(c->syscall_log);
+
+                                unit_write_settingf(u, flags, name, "SystemCallLog=");
+                                return 1;
+                        }
+
+                        if (!c->syscall_log) {
+                                c->syscall_log = hashmap_new(NULL);
+                                if (!c->syscall_log)
+                                        return log_oom();
+
+                                c->syscall_log_allow_list = allow_list;
+                        }
+
+                        STRV_FOREACH(s, l) {
+                                _cleanup_free_ char *n = NULL;
+                                int e;
+
+                                r = parse_syscall_and_errno(*s, &n, &e);
+                                if (r < 0)
+                                        return r;
+
+                                r = seccomp_parse_syscall_filter(n,
+                                                                 0, /* errno not used */
+                                                                 c->syscall_log,
+                                                                 SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
+                                                                 invert_flag |
+                                                                 (c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
+                                                                 u->id,
+                                                                 NULL, 0);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        joined = strv_join(l, " ");
+                        if (!joined)
+                                return -ENOMEM;
+
+                        unit_write_settingf(u, flags, name, "SystemCallLog=%s%s", allow_list ? "" : "~", joined);
+                }
+
+                return 1;
+
         } else if (streq(name, "SystemCallArchitectures")) {
                 _cleanup_strv_free_ char **l = NULL;
 
index 50294a506f0bb69e635113eb0bf2cd8ffeea70cc..be3509396922648fe4e5d5c81d7cc0ed814870b6 100644 (file)
@@ -1407,6 +1407,13 @@ static bool context_has_syscall_filters(const ExecContext *c) {
                 !hashmap_isempty(c->syscall_filter);
 }
 
+static bool context_has_syscall_logs(const ExecContext *c) {
+        assert(c);
+
+        return c->syscall_log_allow_list ||
+                !hashmap_isempty(c->syscall_log);
+}
+
 static bool context_has_no_new_privileges(const ExecContext *c) {
         assert(c);
 
@@ -1428,6 +1435,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
                 c->protect_kernel_logs ||
                 c->private_devices ||
                 context_has_syscall_filters(c) ||
+                context_has_syscall_logs(c) ||
                 !set_isempty(c->syscall_archs) ||
                 c->lock_personality ||
                 c->protect_hostname;
@@ -1465,7 +1473,7 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
         if (skip_seccomp_unavailable(u, "SystemCallFilter="))
                 return 0;
 
-        negative_action = c->syscall_errno == 0 ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
+        negative_action = c->syscall_errno == SECCOMP_ERROR_NUMBER_KILL ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
 
         if (c->syscall_allow_list) {
                 default_action = negative_action;
@@ -1484,6 +1492,39 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
         return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action, false);
 }
 
+static int apply_syscall_log(const Unit* u, const ExecContext *c) {
+#ifdef SCMP_ACT_LOG
+        uint32_t default_action, action;
+#endif
+
+        assert(u);
+        assert(c);
+
+        if (!context_has_syscall_logs(c))
+                return 0;
+
+#ifdef SCMP_ACT_LOG
+        if (skip_seccomp_unavailable(u, "SystemCallLog="))
+                return 0;
+
+        if (c->syscall_log_allow_list) {
+                /* Log nothing but the ones listed */
+                default_action = SCMP_ACT_ALLOW;
+                action = SCMP_ACT_LOG;
+        } else {
+                /* Log everything but the ones listed */
+                default_action = SCMP_ACT_LOG;
+                action = SCMP_ACT_ALLOW;
+        }
+
+        return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_log, action, false);
+#else
+        /* old libseccomp */
+        log_unit_debug(u, "SECCOMP feature SCMP_ACT_LOG not available, skipping SystemCallLog=");
+        return 0;
+#endif
+}
+
 static int apply_syscall_archs(const Unit *u, const ExecContext *c) {
         assert(u);
         assert(c);
@@ -4438,6 +4479,12 @@ static int exec_child(
                         return log_unit_error_errno(unit, r, "Failed to lock personalities: %m");
                 }
 
+                r = apply_syscall_log(unit, context);
+                if (r < 0) {
+                        *exit_status = EXIT_SECCOMP;
+                        return log_unit_error_errno(unit, r, "Failed to apply system call log filters: %m");
+                }
+
                 /* This really should remain the last step before the execve(), to make sure our own code is unaffected
                  * by the filter as little as possible. */
                 r = apply_syscall_filter(unit, context, needs_ambient_hack);
@@ -4675,6 +4722,9 @@ void exec_context_init(ExecContext *c) {
         assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
         c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
         c->log_level_max = -1;
+#if HAVE_SECCOMP
+        c->syscall_errno = SECCOMP_ERROR_NUMBER_KILL;
+#endif
         numa_policy_reset(&c->numa_policy);
 }
 
@@ -5474,7 +5524,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                         fputs(strna(name), f);
 
                         if (num >= 0) {
-                                errno_name = errno_to_name(num);
+                                errno_name = seccomp_errno_or_action_to_string(num);
                                 if (errno_name)
                                         fprintf(f, ":%s", errno_name);
                                 else
@@ -5517,15 +5567,20 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                         prefix, c->network_namespace_path);
 
         if (c->syscall_errno > 0) {
+#if HAVE_SECCOMP
                 const char *errno_name;
+#endif
 
                 fprintf(f, "%sSystemCallErrorNumber: ", prefix);
 
-                errno_name = errno_to_name(c->syscall_errno);
+#if HAVE_SECCOMP
+                errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
                 if (errno_name)
-                        fprintf(f, "%s\n", errno_name);
+                        fputs(errno_name, f);
                 else
-                        fprintf(f, "%d\n", c->syscall_errno);
+                        fprintf(f, "%d", c->syscall_errno);
+#endif
+                fputc('\n', f);
         }
 
         for (size_t i = 0; i < c->n_mount_images; i++) {
index 810e585fa8147ce30ac0d0df592db5f1cbb7f7da..02a2c8d1e71f3f59ef68de3969e7c096188e9280 100644 (file)
@@ -302,6 +302,9 @@ struct ExecContext {
         int syscall_errno;
         bool syscall_allow_list:1;
 
+        Hashmap *syscall_log;
+        bool syscall_log_allow_list:1; /* Log listed system calls */
+
         bool address_families_allow_list:1;
         Set *address_families;
 
index 4bad8314dcdb68aaccc91f7faab00f8c2910df54..c60d565eb49efb87a9bd8a67f61535c0b3c2dc72 100644 (file)
@@ -79,6 +79,7 @@ m4_ifdef(`HAVE_SECCOMP',
 `$1.SystemCallFilter,            config_parse_syscall_filter,        0,                             offsetof($1, exec_context)
 $1.SystemCallArchitectures,      config_parse_syscall_archs,         0,                             offsetof($1, exec_context.syscall_archs)
 $1.SystemCallErrorNumber,        config_parse_syscall_errno,         0,                             offsetof($1, exec_context)
+$1.SystemCallLog,                config_parse_syscall_log,           0,                             offsetof($1, exec_context)
 $1.MemoryDenyWriteExecute,       config_parse_bool,                  0,                             offsetof($1, exec_context.memory_deny_write_execute)
 $1.RestrictNamespaces,           config_parse_restrict_namespaces,   0,                             offsetof($1, exec_context)
 $1.RestrictRealtime,             config_parse_bool,                  0,                             offsetof($1, exec_context.restrict_realtime)
@@ -88,6 +89,7 @@ $1.LockPersonality,              config_parse_bool,                  0,
 `$1.SystemCallFilter,            config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.SystemCallArchitectures,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.SystemCallErrorNumber,        config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
+$1.SystemCallLog,                config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.MemoryDenyWriteExecute,       config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.RestrictNamespaces,           config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.RestrictRealtime,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
index 3635ed03fe16fc0c7e608db7b4c77915668568da..8630ef0d4dac896254aeb0b4a1364aa894ec4bf2 100644 (file)
@@ -3197,6 +3197,86 @@ int config_parse_syscall_filter(
         }
 }
 
+int config_parse_syscall_log(
+                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;
+        _unused_ const Unit *u = userdata;
+        bool invert = false;
+        const char *p;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+                c->syscall_log = hashmap_free(c->syscall_log);
+                c->syscall_log_allow_list = false;
+                return 0;
+        }
+
+        if (rvalue[0] == '~') {
+                invert = true;
+                rvalue++;
+        }
+
+        if (!c->syscall_log) {
+                c->syscall_log = hashmap_new(NULL);
+                if (!c->syscall_log)
+                        return log_oom();
+
+                if (invert)
+                        /* Log everything but the ones listed */
+                        c->syscall_log_allow_list = false;
+                else
+                        /* Log nothing but the ones listed */
+                        c->syscall_log_allow_list = true;
+        }
+
+        p = rvalue;
+        for (;;) {
+                _cleanup_free_ char *word = NULL, *name = NULL;
+                int num;
+
+                r = extract_first_word(&p, &word, NULL, 0);
+                if (r == 0)
+                        return 0;
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+                        return 0;
+                }
+
+                r = parse_syscall_and_errno(word, &name, &num);
+                if (r < 0 || num >= 0) { /* errno code not allowed */
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall, ignoring: %s", word);
+                        continue;
+                }
+
+                r = seccomp_parse_syscall_filter(
+                                name, 0, c->syscall_log,
+                                SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
+                                (invert ? SECCOMP_PARSE_INVERT : 0)|
+                                (c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
+                                unit, filename, line);
+                if (r < 0)
+                        return r;
+        }
+}
+
 int config_parse_syscall_archs(
                 const char *unit,
                 const char *filename,
@@ -3264,9 +3344,9 @@ int config_parse_syscall_errno(
         assert(lvalue);
         assert(rvalue);
 
-        if (isempty(rvalue)) {
+        if (isempty(rvalue) || streq(rvalue, "kill")) {
                 /* Empty assignment resets to KILL */
-                c->syscall_errno = 0;
+                c->syscall_errno = SECCOMP_ERROR_NUMBER_KILL;
                 return 0;
         }
 
@@ -5444,6 +5524,7 @@ void unit_dump_config_items(FILE *f) {
                 { config_parse_syscall_filter,        "SYSCALLS" },
                 { config_parse_syscall_archs,         "ARCHS" },
                 { config_parse_syscall_errno,         "ERRNO" },
+                { config_parse_syscall_log,           "SYSCALLS" },
                 { config_parse_address_families,      "FAMILIES" },
                 { config_parse_restrict_namespaces,   "NAMESPACES"  },
 #endif
index e90953b80f6e6bb84775418b2fabee79eba99269..3504227cae7be42c7f0bdaa4b7ae1edfc57adeff 100644 (file)
@@ -65,6 +65,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_requires_mounts_for);
 CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter);
 CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs);
 CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno);
+CONFIG_PARSER_PROTOTYPE(config_parse_syscall_log);
 CONFIG_PARSER_PROTOTYPE(config_parse_environ);
 CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
 CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
index 272b97e17a419a33f5a5270479586968eb240aeb..015a215c420ae3f6b790cc11e52330ad7b0a952a 100644 (file)
@@ -782,7 +782,6 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
         int r;
         struct addrinfo *result, hints = {
                 .ai_socktype = SOCK_STREAM,
-                .ai_flags = AI_ADDRCONFIG,
         };
 
         assert(b);
index c72c9791c006ea45e227b6b2f36313a8ada07b52..3ae3c12f92149165644996692cc97630b933ef21 100644 (file)
@@ -30,6 +30,9 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "rlimit-util.h"
+#if HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
 #include "securebits-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
@@ -107,7 +110,10 @@ DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
 DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
 DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
 DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
-DEFINE_BUS_APPEND_PARSE("i", parse_errno);
+#if !HAVE_SECCOMP
+static inline int seccomp_parse_errno_or_action(const char *eq) { return -EINVAL; }
+#endif
+DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
 DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
 DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
 DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
@@ -927,7 +933,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                 return bus_append_parse_nice(m, field, eq);
 
         if (streq(field, "SystemCallErrorNumber"))
-                return bus_append_parse_errno(m, field, eq);
+                return bus_append_seccomp_parse_errno_or_action(m, field, eq);
 
         if (streq(field, "IOSchedulingClass"))
                 return bus_append_ioprio_class_from_string(m, field, eq);
@@ -1293,7 +1299,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
         }
 
         if (STR_IN_SET(field, "RestrictAddressFamilies",
-                              "SystemCallFilter")) {
+                              "SystemCallFilter",
+                              "SystemCallLog")) {
                 int allow_list = 1;
                 const char *p = eq;
 
index 10f78d6c2c6973296eb1ffa50d5865936886a322..358960d5c4b279c481e81a9d7a273dcb06e374b3 100644 (file)
@@ -1071,7 +1071,13 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u
                         int id = PTR_TO_INT(syscall_id) - 1;
                         int error = PTR_TO_INT(val);
 
-                        if (action != SCMP_ACT_ALLOW && error >= 0)
+                        if (error == SECCOMP_ERROR_NUMBER_KILL)
+                                a = scmp_act_kill_process();
+#ifdef SCMP_ACT_LOG
+                        else if (action == SCMP_ACT_LOG)
+                                a = SCMP_ACT_LOG;
+#endif
+                        else if (action != SCMP_ACT_ALLOW && error >= 0)
                                 a = SCMP_ACT_ERRNO(error);
 
                         r = seccomp_rule_add_exact(seccomp, a, id, 0);
index b62ee7c4484d00fe019403005b5a115650edc6f4..ff3b96df4bb4ab4ef08c517a37f22739e2ed1d0f 100644 (file)
@@ -5,7 +5,10 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "errno-list.h"
+#include "parse-util.h"
 #include "set.h"
+#include "string-util.h"
 
 const char* seccomp_arch_to_string(uint32_t c);
 int seccomp_arch_from_string(const char *n, uint32_t *ret);
@@ -115,3 +118,25 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(scmp_filter_ctx, seccomp_release);
 int parse_syscall_archs(char **l, Set **ret_archs);
 
 uint32_t scmp_act_kill_process(void);
+
+/* This is a special value to be used where syscall filters otherwise expect errno numbers, will be
+   replaced with real seccomp action. */
+enum {
+        SECCOMP_ERROR_NUMBER_KILL = INT_MAX - 1,
+};
+
+static inline bool seccomp_errno_or_action_is_valid(int n) {
+        return n == SECCOMP_ERROR_NUMBER_KILL || errno_is_valid(n);
+}
+
+static inline int seccomp_parse_errno_or_action(const char *p) {
+        if (streq_ptr(p, "kill"))
+                return SECCOMP_ERROR_NUMBER_KILL;
+        return parse_errno(p);
+}
+
+static inline const char *seccomp_errno_or_action_to_string(int num) {
+        if (num == SECCOMP_ERROR_NUMBER_KILL)
+                return "kill";
+        return errno_to_name(num);
+}
index 50f5b9c9c536a21ffc83508761e3b633b38401be..60420140696b4cba87be588336e06427eb5c0d61 100644 (file)
@@ -417,7 +417,6 @@ static int resolve_remote(Connection *c) {
         static const struct addrinfo hints = {
                 .ai_family = AF_UNSPEC,
                 .ai_socktype = SOCK_STREAM,
-                .ai_flags = AI_ADDRCONFIG
         };
 
         const char *node, *service;
index aa046c6ada9d5bc2e9d729af871a81a069836d07..115983f98bbdc56045f401dda98860490a85c6f1 100644 (file)
@@ -4822,7 +4822,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
 
                         return 1;
 
-                } else if (STR_IN_SET(name, "SystemCallFilter", "RestrictAddressFamilies")) {
+                } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies")) {
                         _cleanup_strv_free_ char **l = NULL;
                         int allow_list;
 
index e32e0c0b6c4182d002e89112e3386027d1150eeb..f10e32b5b91a921b049ada2200e248f3fe2f5a37 100644 (file)
@@ -434,6 +434,8 @@ static void test_exec_systemcallfilter(Manager *m) {
         test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
         test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
         test(__func__, m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-override-error-action.service", SIGSYS, CLD_KILLED);
+        test(__func__, m, "exec-systemcallfilter-override-error-action2.service", errno_from_name("EILSEQ"), CLD_EXITED);
 #endif
 }
 
@@ -576,10 +578,14 @@ static void test_exec_dynamicuser(Manager *m) {
         test(__func__, m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
         test(__func__, m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 
+        (void) rm_rf("/var/lib/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
+        (void) rm_rf("/var/lib/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
+        (void) rm_rf("/var/lib/private/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
+        (void) rm_rf("/var/lib/private/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
 
         test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
         test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
index 3ca5e1e639cf364a66a801018e809e37ba778221..3806c3f8cf92db7f3490242b86b973e4325a8db5 100644 (file)
@@ -10,6 +10,9 @@
 #include "log.h"
 #include "parse-util.h"
 #include "string-util.h"
+#if HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
 
 static void test_parse_boolean(void) {
         assert_se(parse_boolean("1") == 1);
@@ -852,6 +855,7 @@ static void test_parse_errno(void) {
 }
 
 static void test_parse_syscall_and_errno(void) {
+#if HAVE_SECCOMP
         _cleanup_free_ char *n = NULL;
         int e;
 
@@ -882,11 +886,16 @@ static void test_parse_syscall_and_errno(void) {
         assert_se(e == 255);
         n = mfree(n);
 
+        assert_se(parse_syscall_and_errno("hoge:kill", &n, &e) >= 0);
+        assert_se(streq(n, "hoge"));
+        assert_se(e == SECCOMP_ERROR_NUMBER_KILL);
+        n = mfree(n);
+
         /* The function checks the syscall name is empty or not. */
         assert_se(parse_syscall_and_errno("", &n, &e) == -EINVAL);
         assert_se(parse_syscall_and_errno(":255", &n, &e) == -EINVAL);
 
-        /* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095 */
+        /* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095, or "kill" */
         assert_se(parse_syscall_and_errno("hoge:4096", &n, &e) == -ERANGE);
         assert_se(parse_syscall_and_errno("hoge:-3", &n, &e) == -ERANGE);
         assert_se(parse_syscall_and_errno("hoge:12.3", &n, &e) == -EINVAL);
@@ -896,6 +905,7 @@ static void test_parse_syscall_and_errno(void) {
         assert_se(parse_syscall_and_errno("hoge:-EINVAL", &n, &e) == -EINVAL);
         assert_se(parse_syscall_and_errno("hoge:EINVALaaa", &n, &e) == -EINVAL);
         assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL);
+#endif
 }
 
 static void test_parse_mtu(void) {
diff --git a/test/test-execute/exec-systemcallfilter-override-error-action.service b/test/test-execute/exec-systemcallfilter-override-error-action.service
new file mode 100644 (file)
index 0000000..3569b45
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for SystemCallFilter with specific kill action overriding default errno action
+
+[Service]
+ExecStart=/usr/bin/python3 -c 'import os\ntry: os.uname()\nexcept Exception as e: exit(e.errno)'
+Type=oneshot
+SystemCallFilter=~uname:kill
+SystemCallErrorNumber=EILSEQ
diff --git a/test/test-execute/exec-systemcallfilter-override-error-action2.service b/test/test-execute/exec-systemcallfilter-override-error-action2.service
new file mode 100644 (file)
index 0000000..04bfd6b
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for SystemCallFilter with specific errno action overriding default kill action
+
+[Service]
+ExecStart=/usr/bin/python3 -c 'import os\ntry: os.uname()\nexcept Exception as e: exit(e.errno)'
+Type=oneshot
+SystemCallFilter=~uname:EILSEQ
+SystemCallErrorNumber=kill