* 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.
✓ SystemCallFilter=
✓ SystemCallArchitectures=
✓ SystemCallErrorNumber=
+✓ SystemCallLog=
✓ MemoryDenyWriteExecute=
✓ RestrictNamespaces=
✓ RestrictRealtime=
<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>
@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 = ...;
@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 = ...;
<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"/>
<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"/>
<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
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>
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>
#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"
return e;
}
+#if HAVE_SECCOMP
int parse_syscall_and_errno(const char *in, char **name, int *error) {
_cleanup_free_ char *n = NULL;
char *p;
p = strchr(in, ':');
if (p) {
- e = parse_errno(p + 1);
+ e = seccomp_parse_errno_or_action(p + 1);
if (e < 0)
return e;
return 0;
}
+#endif
static const char *mangle_base(const char *s, unsigned *base) {
const char *k;
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)
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)
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,
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),
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);
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;
!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);
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;
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;
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);
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);
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);
}
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
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++) {
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;
`$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)
`$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
}
}
+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,
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;
}
{ 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
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);
int r;
struct addrinfo *result, hints = {
.ai_socktype = SOCK_STREAM,
- .ai_flags = AI_ADDRCONFIG,
};
assert(b);
#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"
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);
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);
}
if (STR_IN_SET(field, "RestrictAddressFamilies",
- "SystemCallFilter")) {
+ "SystemCallFilter",
+ "SystemCallLog")) {
int allow_list = 1;
const char *p = eq;
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);
#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);
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);
+}
static const struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
- .ai_flags = AI_ADDRCONFIG
};
const char *node, *service;
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;
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
}
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);
#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);
}
static void test_parse_syscall_and_errno(void) {
+#if HAVE_SECCOMP
_cleanup_free_ char *n = NULL;
int e;
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);
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) {
--- /dev/null
+[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
--- /dev/null
+[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