summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/build.h8
-rw-r--r--src/core/dbus-execute.c8
-rw-r--r--src/core/execute.c88
-rw-r--r--src/core/execute.h12
-rw-r--r--src/core/load-fragment.c96
5 files changed, 122 insertions, 90 deletions
diff --git a/src/core/build.h b/src/core/build.h
index 4513a0bad7..f04f03f60d 100644
--- a/src/core/build.h
+++ b/src/core/build.h
@@ -81,4 +81,10 @@
#define _XZ_FEATURE_ "-XZ"
#endif
-#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_
+#ifdef HAVE_SECCOMP
+#define _SECCOMP_FEATURE_ "+SECCOMP"
+#else
+#define _SECCOMP_FEATURE_ "-SECCOMP"
+#endif
+
+#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ _SECCOMP_FEATURE_
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index db16990233..2ed7a3c73e 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -25,7 +25,6 @@
#include "missing.h"
#include "ioprio.h"
#include "strv.h"
-#include "syscall-list.h"
#include "fileio.h"
#include "execute.h"
#include "dbus-execute.h"
@@ -354,10 +353,7 @@ static int property_get_syscall_filter(
assert(reply);
assert(c);
- if (c->syscall_filter)
- return sd_bus_message_append_array(reply, 'u', c->syscall_filter, (syscall_max() + 31) >> 4);
- else
- return sd_bus_message_append_array(reply, 'u', NULL, 0);
+ return sd_bus_message_append(reply, "s", c->syscall_filter_string);
}
const sd_bus_vtable bus_exec_vtable[] = {
@@ -422,7 +418,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SELinuxContext", "s", NULL, offsetof(ExecContext, selinux_context), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SystemCallFilter", "au", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SystemCallFilter", "s", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
diff --git a/src/core/execute.c b/src/core/execute.c
index b941a024de..d2e5b740b7 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -38,9 +38,13 @@
#include <linux/fs.h>
#include <linux/oom.h>
#include <sys/poll.h>
-#include <linux/seccomp-bpf.h>
#include <glob.h>
#include <libgen.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+
+#include "set.h"
+#endif
#undef basename
#ifdef HAVE_PAM
@@ -67,7 +71,6 @@
#include "utmp-wtmp.h"
#include "def.h"
#include "path-util.h"
-#include "syscall-list.h"
#include "env-util.h"
#include "fileio.h"
#include "unit.h"
@@ -933,57 +936,32 @@ static void rename_process_from_path(const char *path) {
rename_process(process_name);
}
-static int apply_seccomp(uint32_t *syscall_filter) {
- static const struct sock_filter header[] = {
- VALIDATE_ARCHITECTURE,
- EXAMINE_SYSCALL
- };
- static const struct sock_filter footer[] = {
- _KILL_PROCESS
- };
-
- int i;
- unsigned n;
- struct sock_filter *f;
- struct sock_fprog prog = {};
-
- assert(syscall_filter);
+#ifdef HAVE_SECCOMP
+static int apply_seccomp(ExecContext *c) {
+ uint32_t action = SCMP_ACT_ALLOW;
+ Iterator i;
+ void *id;
- /* First: count the syscalls to check for */
- for (i = 0, n = 0; i < syscall_max(); i++)
- if (syscall_filter[i >> 4] & (1 << (i & 31)))
- n++;
-
- /* Second: build the filter program from a header the syscall
- * matches and the footer */
- f = alloca(sizeof(struct sock_filter) * (ELEMENTSOF(header) + 2*n + ELEMENTSOF(footer)));
- memcpy(f, header, sizeof(header));
-
- for (i = 0, n = 0; i < syscall_max(); i++)
- if (syscall_filter[i >> 4] & (1 << (i & 31))) {
- struct sock_filter item[] = {
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, INDEX_TO_SYSCALL(i), 0, 1),
- BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
- };
+ assert(c);
- assert_cc(ELEMENTSOF(item) == 2);
+ c->syscall_filter = seccomp_init(c->syscall_filter_default_action);
+ if (!c->syscall_filter)
+ return -1;
- f[ELEMENTSOF(header) + 2*n] = item[0];
- f[ELEMENTSOF(header) + 2*n+1] = item[1];
+ if (c->syscall_filter_default_action == SCMP_ACT_ALLOW)
+ action = SCMP_ACT_KILL;
- n++;
+ SET_FOREACH(id, c->filtered_syscalls, i) {
+ int r = seccomp_rule_add(c->syscall_filter, action, PTR_TO_INT(id) - 1, 0);
+ if (r < 0) {
+ log_error("Failed to add syscall filter");
+ return r;
}
+ }
- memcpy(f + (ELEMENTSOF(header) + 2*n), footer, sizeof(footer));
-
- /* Third: install the filter */
- prog.len = ELEMENTSOF(header) + ELEMENTSOF(footer) + 2*n;
- prog.filter = f;
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0)
- return -errno;
-
- return 0;
+ return seccomp_load(c->syscall_filter);
}
+#endif
static void do_idle_pipe_dance(int idle_pipe[4]) {
assert(idle_pipe);
@@ -1562,13 +1540,15 @@ int exec_spawn(ExecCommand *command,
goto fail_child;
}
- if (context->syscall_filter) {
- err = apply_seccomp(context->syscall_filter);
+#ifdef HAVE_SECCOMP
+ if (context->filtered_syscalls) {
+ err = apply_seccomp(context);
if (err < 0) {
r = EXIT_SECCOMP;
goto fail_child;
}
}
+#endif
#ifdef HAVE_SELINUX
if (context->selinux_context && use_selinux()) {
bool ignore;
@@ -1751,6 +1731,18 @@ void exec_context_done(ExecContext *c) {
free(c->syscall_filter);
c->syscall_filter = NULL;
+
+ free(c->syscall_filter_string);
+ c->syscall_filter_string = NULL;
+
+#ifdef HAVE_SECCOMP
+ if (c->syscall_filter) {
+ seccomp_release(c->syscall_filter);
+ c->syscall_filter = NULL;
+ }
+ set_free(c->filtered_syscalls);
+ c->filtered_syscalls = NULL;
+#endif
}
void exec_command_done(ExecCommand *c) {
diff --git a/src/core/execute.h b/src/core/execute.h
index be811a97c1..b2d70d7d86 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -33,6 +33,11 @@ typedef struct ExecRuntime ExecRuntime;
#include <stdbool.h>
#include <stdio.h>
#include <sched.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+
+#include "set.h"
+#endif
#include "list.h"
#include "util.h"
@@ -162,7 +167,12 @@ struct ExecContext {
* don't enter a trigger loop. */
bool same_pgrp;
- uint32_t *syscall_filter;
+#ifdef HAVE_SECCOMP
+ scmp_filter_ctx syscall_filter;
+ Set *filtered_syscalls;
+ uint32_t syscall_filter_default_action;
+#endif
+ char *syscall_filter_string;
bool oom_score_adjust_set:1;
bool nice_set:1;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 7a2d32ddbd..06ff18b573 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -33,6 +33,11 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+
+#include "set.h"
+#endif
#include "sd-messages.h"
#include "unit.h"
@@ -47,13 +52,12 @@
#include "unit-printf.h"
#include "utf8.h"
#include "path-util.h"
-#include "syscall-list.h"
#include "env-util.h"
#include "cgroup.h"
#include "bus-util.h"
#include "bus-error.h"
-#ifndef HAVE_SYSV_COMPAT
+#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
int config_parse_warn_compat(const char *unit,
const char *filename,
unsigned line,
@@ -1916,16 +1920,7 @@ int config_parse_documentation(const char *unit,
return r;
}
-static void syscall_set(uint32_t *p, int nr) {
- nr = SYSCALL_TO_INDEX(nr);
- p[nr >> 4] |= 1 << (nr & 31);
-}
-
-static void syscall_unset(uint32_t *p, int nr) {
- nr = SYSCALL_TO_INDEX(nr);
- p[nr >> 4] &= ~(1 << (nr & 31));
-}
-
+#ifdef HAVE_SECCOMP
int config_parse_syscall_filter(const char *unit,
const char *filename,
unsigned line,
@@ -1936,13 +1931,23 @@ int config_parse_syscall_filter(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
-
ExecContext *c = data;
Unit *u = userdata;
bool invert = false;
char *w;
size_t l;
char *state;
+ _cleanup_strv_free_ char **syscalls = strv_new(NULL, NULL);
+ _cleanup_free_ char *sorted_syscalls = NULL;
+ uint32_t action = SCMP_ACT_ALLOW;
+ Iterator i;
+ void *e;
+ static char const *default_syscalls[] = {"execve",
+ "exit",
+ "exit_group",
+ "rt_sigreturn",
+ "sigreturn",
+ NULL};
assert(filename);
assert(lvalue);
@@ -1951,34 +1956,37 @@ int config_parse_syscall_filter(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- free(c->syscall_filter);
- c->syscall_filter = NULL;
+ set_free(c->filtered_syscalls);
+ c->filtered_syscalls= NULL;
+ free(c->syscall_filter_string);
+ c->syscall_filter_string = NULL;
return 0;
}
if (rvalue[0] == '~') {
invert = true;
+ action = SCMP_ACT_KILL;
rvalue++;
}
- if (!c->syscall_filter) {
- size_t n;
+ if (!c->filtered_syscalls) {
+ c->filtered_syscalls = set_new(trivial_hash_func, trivial_compare_func);
+ if (invert)
+ c->syscall_filter_default_action = SCMP_ACT_ALLOW;
+ else {
+ char const **syscall;
- n = (syscall_max() + 31) >> 4;
- c->syscall_filter = new(uint32_t, n);
- if (!c->syscall_filter)
- return log_oom();
+ c->syscall_filter_default_action = SCMP_ACT_KILL;
- memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
+ /* accept default syscalls if we are on a whitelist */
+ STRV_FOREACH(syscall, default_syscalls) {
+ int id = seccomp_syscall_resolve_name(*syscall);
+ if (id < 0)
+ continue;
- /* Add these by default */
- syscall_set(c->syscall_filter, __NR_execve);
- syscall_set(c->syscall_filter, __NR_rt_sigreturn);
-#ifdef __NR_sigreturn
- syscall_set(c->syscall_filter, __NR_sigreturn);
-#endif
- syscall_set(c->syscall_filter, __NR_exit_group);
- syscall_set(c->syscall_filter, __NR_exit);
+ set_replace(c->filtered_syscalls, INT_TO_PTR(id + 1));
+ }
+ }
}
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
@@ -1989,23 +1997,39 @@ int config_parse_syscall_filter(const char *unit,
if (!t)
return log_oom();
- id = syscall_from_name(t);
+ id = seccomp_syscall_resolve_name(t);
if (id < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Failed to parse syscall, ignoring: %s", t);
continue;
}
- if (invert)
- syscall_unset(c->syscall_filter, id);
+ /* If we previously wanted to forbid a syscall
+ * and now we want to allow it, then remove it from the list
+ * libseccomp will also return -EPERM if we try to add
+ * a rule with the same action as the default
+ */
+ if (action == c->syscall_filter_default_action)
+ set_remove(c->filtered_syscalls, INT_TO_PTR(id + 1));
else
- syscall_set(c->syscall_filter, id);
+ set_replace(c->filtered_syscalls, INT_TO_PTR(id + 1));
+ }
+
+ SET_FOREACH(e, c->filtered_syscalls, i) {
+ char *name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(e) - 1);
+ strv_push(&syscalls, name);
}
+ sorted_syscalls = strv_join(strv_sort(syscalls), " ");
+ if (invert)
+ c->syscall_filter_string = strv_join(STRV_MAKE("~", sorted_syscalls, NULL), "");
+ else
+ c->syscall_filter_string = strdup(sorted_syscalls);
c->no_new_privileges = true;
return 0;
}
+#endif
int config_parse_unit_slice(
const char *unit,
@@ -2778,7 +2802,11 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_set_status, "STATUS" },
{ config_parse_service_sockets, "SOCKETS" },
{ config_parse_environ, "ENVIRON" },
+#ifdef HAVE_SECCOMP
{ config_parse_syscall_filter, "SYSCALL" },
+#else
+ { config_parse_warn_compat, "NOTSUPPORTED" },
+#endif
{ config_parse_cpu_shares, "SHARES" },
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },