summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am6
-rw-r--r--man/systemd.exec.xml50
-rw-r--r--src/core/dbus-execute.c79
-rw-r--r--src/core/execute.c41
-rw-r--r--src/core/execute.h1
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c55
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/shared/seccomp-util.c63
-rw-r--r--src/shared/seccomp-util.h26
-rw-r--r--src/systemctl/systemctl.c42
11 files changed, 348 insertions, 18 deletions
diff --git a/Makefile.am b/Makefile.am
index 8c309dabed..713a3aad93 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -770,6 +770,12 @@ nodist_libsystemd_shared_la_SOURCES = \
src/shared/errno-from-name.h \
src/shared/errno-to-name.h
+if HAVE_SECCOMP
+libsystemd_shared_la_SOURCES += \
+ src/shared/seccomp-util.h \
+ src/shared/seccomp-util.c
+endif
+
# ------------------------------------------------------------------------------
noinst_LTLIBRARIES += \
libsystemd-units.la
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 86ad7e223d..01356e4c45 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1050,6 +1050,14 @@
<function>write</function> will be
removed from the set).
</para></listitem>
+
+ <para>Note that setting
+ <varname>SystemCallFilter=</varname>
+ implies a
+ <varname>SystemCallArchitectures=</varname>
+ setting of <literal>native</literal>
+ (see below), unless that option is
+ configured otherwise.</para>
</varlistentry>
<varlistentry>
@@ -1072,6 +1080,48 @@
is triggered.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>SystemCallArchitectures=</varname></term>
+
+ <listitem><para>Takes a space
+ separated list of architecture
+ identifiers to include in the system
+ call filter. The known architecture
+ identifiers are
+ <literal>x86</literal>,
+ <literal>x86-64</literal>,
+ <literal>x32</literal>,
+ <literal>arm</literal> as well as the
+ special identifier
+ <literal>native</literal>. Only system
+ calls of the specified architectures
+ will be permitted to processes of this
+ unit. This is an effective way to
+ disable compatibility with non-native
+ architectures for processes, for
+ example to prohibit execution of 32bit
+ x86 binaries on 64bit x86-64
+ systems. The special
+ <literal>native</literal> identifier
+ implicitly maps to the native
+ architecture of the system (or more
+ strictly: to the architecture the
+ system manager is compiled for). Note
+ that setting this option to a
+ non-empty list implies that
+ <literal>native</literal> is included
+ too. By default this option is set to
+ the empty list, i.e. no architecture
+ system call filtering is applied. Note
+ that configuring a system call filter
+ with
+ <varname>SystemCallFilter=</varname>
+ (above) implies a
+ <literal>native</literal> architecture
+ list, unless configured
+ otherwise.</para></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 435c3d505f..a62f517dc6 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -21,6 +21,10 @@
#include <sys/prctl.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+#endif
+
#include "bus-util.h"
#include "missing.h"
#include "ioprio.h"
@@ -31,6 +35,10 @@
#include "capability.h"
#include "env-util.h"
+#ifdef HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
+
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
@@ -349,17 +357,25 @@ static int property_get_syscall_filter(
ExecContext *c = userdata;
_cleanup_strv_free_ char **l = NULL;
- _cleanup_free_ char *t = NULL;
+ int r;
+
#ifdef HAVE_SECCOMP
Iterator i;
void *id;
- int r;
#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_whitelist);
+ if (r < 0)
+ return r;
+
#ifdef HAVE_SECCOMP
SET_FOREACH(id, c->syscall_filter, i) {
char *name;
@@ -378,22 +394,56 @@ static int property_get_syscall_filter(
strv_sort(l);
- t = strv_join(l, " ");
- if (!t)
- return -ENOMEM;
+ r = sd_bus_message_append_strv(reply, l);
+ if (r < 0)
+ return r;
- if (!c->syscall_whitelist) {
- char *d;
+ return sd_bus_message_close_container(reply);
+}
- d = strappend("~", t);
- if (!d)
- return -ENOMEM;
+static int property_get_syscall_archs(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
- free(t);
- t = d;
+ ExecContext *c = userdata;
+ _cleanup_strv_free_ char **l = NULL;
+ int r;
+
+#ifdef HAVE_SECCOMP
+ Iterator i;
+ void *id;
+#endif
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+#ifdef HAVE_SECCOMP
+ SET_FOREACH(id, c->syscall_archs, i) {
+ const char *name;
+
+ name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
+ if (!name)
+ continue;
+
+ r = strv_extend(&l, name);
+ if (r < 0)
+ return -ENOMEM;
}
+#endif
- return sd_bus_message_append(reply, "s", t);
+ strv_sort(l);
+
+ r = sd_bus_message_append_strv(reply, l);
+ if (r < 0)
+ return r;
+
+ return 0;
}
static int property_get_syscall_errno(
@@ -476,7 +526,8 @@ 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", "s", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ 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", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
diff --git a/src/core/execute.c b/src/core/execute.c
index 4033470e5b..06ddd5c91c 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -77,6 +77,10 @@
#include "selinux-util.h"
#include "errno-list.h"
+#ifdef HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
+
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
@@ -953,8 +957,17 @@ static int apply_seccomp(ExecContext *c) {
if (!seccomp)
return -ENOMEM;
- action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
+ SET_FOREACH(id, c->syscall_archs, i) {
+ r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0) {
+ seccomp_release(seccomp);
+ return r;
+ }
+ }
+ action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
SET_FOREACH(id, c->syscall_filter, i) {
r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0);
if (r < 0) {
@@ -1548,7 +1561,7 @@ int exec_spawn(ExecCommand *command,
}
#ifdef HAVE_SECCOMP
- if (context->syscall_filter) {
+ if (context->syscall_filter || context->syscall_archs) {
err = apply_seccomp(context);
if (err < 0) {
r = EXIT_SECCOMP;
@@ -1740,6 +1753,9 @@ void exec_context_done(ExecContext *c) {
#ifdef HAVE_SECCOMP
set_free(c->syscall_filter);
c->syscall_filter = NULL;
+
+ set_free(c->syscall_archs);
+ c->syscall_archs = NULL;
#endif
}
@@ -2122,7 +2138,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
#endif
fprintf(f,
- "%sSystemCallFilter: \n",
+ "%sSystemCallFilter: ",
prefix);
if (!c->syscall_whitelist)
@@ -2137,7 +2153,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
else
fputc(' ', f);
- name = seccomp_syscall_resolve_num_arch(PTR_TO_INT(id)-1, SCMP_ARCH_NATIVE);
+ name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
fputs(strna(name), f);
}
#endif
@@ -2145,6 +2161,23 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fputc('\n', f);
}
+ if (c->syscall_archs) {
+#ifdef HAVE_SECCOMP
+ Iterator j;
+ void *id;
+#endif
+
+ fprintf(f,
+ "%sSystemCallArchitectures:",
+ prefix);
+
+#ifdef HAVE_SECCOMP
+ SET_FOREACH(id, c->syscall_archs, j)
+ fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
+#endif
+ fputc('\n', f);
+ }
+
if (c->syscall_errno != 0)
fprintf(f,
"%sSystemCallErrorNumber: %s\n",
diff --git a/src/core/execute.h b/src/core/execute.h
index baf430a047..06b6b3fb2d 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -168,6 +168,7 @@ struct ExecContext {
bool same_pgrp;
Set *syscall_filter;
+ Set *syscall_archs;
int syscall_errno;
bool syscall_whitelist:1;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 16c9e25785..fa559e58f9 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -51,8 +51,10 @@ $1.TimerSlackNSec, config_parse_nsec, 0,
$1.NoNewPrivileges, config_parse_bool, 0, offsetof($1, exec_context.no_new_privileges)
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)
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)',
`$1.SystemCallFilter, config_parse_warn_compat, 0, 0
+$1.SystemCallArchitectures, config_parse_warn_compat, 0, 0
$1.SystemCallErrorNumber, config_parse_warn_compat, 0, 0')
$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 1b5856e273..ec04ad28ba 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -57,6 +57,10 @@
#include "bus-error.h"
#include "errno-list.h"
+#ifdef HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
+
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
int config_parse_warn_compat(
const char *unit,
@@ -2029,6 +2033,57 @@ int config_parse_syscall_filter(
return 0;
}
+int config_parse_syscall_archs(
+ 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;
+ char *w, *state;
+ size_t l;
+ int r;
+
+ if (isempty(rvalue)) {
+ set_free(c->syscall_archs);
+ c->syscall_archs = NULL;
+ return 0;
+ }
+
+ r = set_ensure_allocated(&c->syscall_archs, trivial_hash_func, trivial_compare_func);
+ if (r < 0)
+ return log_oom();
+
+ FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+ _cleanup_free_ char *t = NULL;
+ uint32_t a;
+
+ t = strndup(w, l);
+ if (!t)
+ return log_oom();
+
+ r = seccomp_arch_from_string(t, &a);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
+ continue;
+ }
+
+ r = set_put(c->syscall_archs, UINT32_TO_PTR(a + 1));
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return log_oom();
+ }
+
+ return 0;
+}
+
int config_parse_syscall_errno(
const char *unit,
const char *filename,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 4cefa76157..23e9d1131b 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -74,6 +74,7 @@ int config_parse_notify_access(const char *unit, const char *filename, unsigned
int config_parse_start_limit_action(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);
int config_parse_unit_requires_mounts_for(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);
int config_parse_syscall_filter(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);
+int config_parse_syscall_archs(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);
int config_parse_syscall_errno(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);
int config_parse_environ(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);
int config_parse_unit_slice(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);
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
new file mode 100644
index 0000000000..ee39cc7c1d
--- /dev/null
+++ b/src/shared/seccomp-util.c
@@ -0,0 +1,63 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <seccomp.h>
+
+#include "util.h"
+#include "seccomp-util.h"
+
+const char* seccomp_arch_to_string(uint32_t c) {
+
+ if (c == SCMP_ARCH_NATIVE)
+ return "native";
+ if (c == SCMP_ARCH_X86)
+ return "x86";
+ if (c == SCMP_ARCH_X86_64)
+ return "x86-64";
+ if (c == SCMP_ARCH_X32)
+ return "x32";
+ if (c == SCMP_ARCH_ARM)
+ return "arm";
+
+ return NULL;
+}
+
+int seccomp_arch_from_string(const char *n, uint32_t *ret) {
+ if (!n)
+ return -EINVAL;
+
+ assert(ret);
+
+ if (streq(n, "native"))
+ *ret = SCMP_ARCH_NATIVE;
+ else if (streq(n, "x86"))
+ *ret = SCMP_ARCH_X86;
+ else if (streq(n, "x86-64"))
+ *ret = SCMP_ARCH_X86_64;
+ else if (streq(n, "x32"))
+ *ret = SCMP_ARCH_X32;
+ else if (streq(n, "arm"))
+ *ret = SCMP_ARCH_ARM;
+ else
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
new file mode 100644
index 0000000000..6b63902f5d
--- /dev/null
+++ b/src/shared/seccomp-util.h
@@ -0,0 +1,26 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+
+const char* seccomp_arch_to_string(uint32_t c);
+int seccomp_arch_from_string(const char *n, uint32_t *ret);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index eb2d3f14fe..edd4daaa24 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3405,6 +3405,48 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
return 0;
+ } else if (streq_ptr(name, "SystemCallFilter")) {
+ _cleanup_strv_free_ char **l = NULL;
+ int whitelist;
+
+ r = sd_bus_message_enter_container(m, 'r', "bas");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_read(m, "b", &whitelist);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_read_strv(m, &l);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (arg_all || whitelist || !strv_isempty(l)) {
+ bool first = true;
+ char **i;
+
+ fputs(name, stdout);
+ fputc('=', stdout);
+
+ if (!whitelist)
+ fputc('~', stdout);
+
+ STRV_FOREACH(i, l) {
+ if (first)
+ first = false;
+ else
+ fputc(' ', stdout);
+
+ fputs(*i, stdout);
+ }
+ fputc('\n', stdout);
+ }
+
+ return 0;
}
break;