chiark / gitweb /
syscallfilter: port to libseccomp
authorRonny Chevalier <chevalier.ronny@gmail.com>
Wed, 12 Feb 2014 00:29:54 +0000 (01:29 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 12 Feb 2014 17:30:36 +0000 (18:30 +0100)
16 files changed:
Makefile.am
README
TODO
configure.ac
man/systemd.exec.xml
src/core/build.h
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment.c
src/shared/.gitignore
src/shared/linux/seccomp-bpf.h [deleted file]
src/shared/linux/seccomp.h [deleted file]
src/shared/syscall-list.c [deleted file]
src/shared/syscall-list.h [deleted file]
src/test/test-tables.c

index da25b1dfbd1f53b08b48995dde21089206084420..8c309dabedb4cd4444480f9a85fae1f52597df20 100644 (file)
@@ -654,8 +654,6 @@ noinst_LTLIBRARIES += \
 libsystemd_shared_la_SOURCES = \
        src/shared/linux/auto_dev-ioctl.h \
        src/shared/linux/fanotify.h \
 libsystemd_shared_la_SOURCES = \
        src/shared/linux/auto_dev-ioctl.h \
        src/shared/linux/fanotify.h \
-       src/shared/linux/seccomp.h \
-       src/shared/linux/seccomp-bpf.h \
        src/shared/ioprio.h \
        src/shared/missing.h \
        src/shared/initreq.h \
        src/shared/ioprio.h \
        src/shared/missing.h \
        src/shared/initreq.h \
@@ -763,8 +761,6 @@ libsystemd_shared_la_SOURCES = \
        src/shared/net-util.h \
        src/shared/errno-list.c \
        src/shared/errno-list.h \
        src/shared/net-util.h \
        src/shared/errno-list.c \
        src/shared/errno-list.h \
-       src/shared/syscall-list.c \
-       src/shared/syscall-list.h \
        src/shared/audit.c \
        src/shared/audit.h \
        src/shared/xml.c \
        src/shared/audit.c \
        src/shared/audit.h \
        src/shared/xml.c \
@@ -772,9 +768,7 @@ libsystemd_shared_la_SOURCES = \
 
 nodist_libsystemd_shared_la_SOURCES = \
        src/shared/errno-from-name.h \
 
 nodist_libsystemd_shared_la_SOURCES = \
        src/shared/errno-from-name.h \
-       src/shared/errno-to-name.h \
-       src/shared/syscall-from-name.h \
-       src/shared/syscall-to-name.h
+       src/shared/errno-to-name.h
 
 # ------------------------------------------------------------------------------
 noinst_LTLIBRARIES += \
 
 # ------------------------------------------------------------------------------
 noinst_LTLIBRARIES += \
@@ -999,6 +993,7 @@ libsystemd_core_la_CFLAGS = \
        $(PAM_CFLAGS) \
        $(AUDIT_CFLAGS) \
        $(KMOD_CFLAGS) \
        $(PAM_CFLAGS) \
        $(AUDIT_CFLAGS) \
        $(KMOD_CFLAGS) \
+       $(SECCOMP_CFLAGS) \
        -pthread
 
 libsystemd_core_la_LIBADD = \
        -pthread
 
 libsystemd_core_la_LIBADD = \
@@ -1013,6 +1008,7 @@ libsystemd_core_la_LIBADD = \
        $(PAM_LIBS) \
        $(AUDIT_LIBS) \
        $(CAP_LIBS) \
        $(PAM_LIBS) \
        $(AUDIT_LIBS) \
        $(CAP_LIBS) \
+       $(SECCOMP_LIBS) \
        $(KMOD_LIBS)
 
 src/core/load-fragment-gperf-nulstr.c: src/core/load-fragment-gperf.gperf
        $(KMOD_LIBS)
 
 src/core/load-fragment-gperf-nulstr.c: src/core/load-fragment-gperf.gperf
@@ -1026,33 +1022,13 @@ CLEANFILES += \
        src/core/load-fragment-gperf.gperf \
        src/core/load-fragment-gperf.c \
        src/core/load-fragment-gperf-nulstr.c \
        src/core/load-fragment-gperf.gperf \
        src/core/load-fragment-gperf.c \
        src/core/load-fragment-gperf-nulstr.c \
-       src/shared/syscall-list.txt \
-       src/shared/syscall-from-name.gperf \
        src/shared/errno-list.txt \
        src/shared/errno-from-name.gperf
 
 BUILT_SOURCES += \
        src/shared/errno-list.txt \
        src/shared/errno-from-name.gperf
 
 BUILT_SOURCES += \
-       src/shared/syscall-from-name.h \
-       src/shared/syscall-to-name.h \
        src/shared/errno-from-name.h \
        src/shared/errno-to-name.h
 
        src/shared/errno-from-name.h \
        src/shared/errno-to-name.h
 
-src/shared/syscall-list.txt:
-       $(AM_V_at)$(MKDIR_P) $(dir $@)
-       $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include sys/syscall.h - < /dev/null | $(AWK) '/^#define[ \t]+__NR_[^ ]+[ \t]+[0-9(]/ { sub(/__NR_/, "", $$2); if ($$2 !~ /SYSCALL_BASE/) print $$2; }' > $@
-
-src/shared/syscall-from-name.gperf: src/shared/syscall-list.txt
-       $(AM_V_at)$(MKDIR_P) $(dir $@)
-       $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct syscall_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, __NR_%s\n", $$1, $$1 }' < $< > $@
-
-src/shared/syscall-from-name.h: src/shared/syscall-from-name.gperf
-       $(AM_V_at)$(MKDIR_P) $(dir $@)
-       $(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_syscall -H hash_syscall_name -p -C < $< > $@
-
-src/shared/syscall-to-name.h: src/shared/syscall-list.txt
-       $(AM_V_at)$(MKDIR_P) $(dir $@)
-       $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const syscall_names[] = { "} { printf "[SYSCALL_TO_INDEX(__NR_%s)] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@
-
 src/shared/errno-list.txt:
        $(AM_V_at)$(MKDIR_P) $(dir $@)
        $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - < /dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+[0-9]/ { print $$2; }'  > $@
 src/shared/errno-list.txt:
        $(AM_V_at)$(MKDIR_P) $(dir $@)
        $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - < /dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+[0-9]/ { print $$2; }'  > $@
diff --git a/README b/README
index 9aa63128dd99784897dba8e3dd83851545208821..a04ee3f3e556771cf408594f133eacda0b05cc0b 100644 (file)
--- a/README
+++ b/README
@@ -92,6 +92,7 @@ REQUIREMENTS:
 
         glibc >= 2.14
         libcap
 
         glibc >= 2.14
         libcap
+        libseccomp >= 1.0.0 (optional)
         libblkid >= 2.20 (from util-linux) (optional)
         libkmod >= 15 (optional)
         PAM >= 1.1.2 (optional)
         libblkid >= 2.20 (from util-linux) (optional)
         libkmod >= 15 (optional)
         PAM >= 1.1.2 (optional)
diff --git a/TODO b/TODO
index 7b12f03bf8c1bbf5c572c337b73075c262444932..4abc27d6fdf0d80f8f053702a11a55a5fd7b67e7 100644 (file)
--- a/TODO
+++ b/TODO
@@ -490,7 +490,6 @@ Features:
   - syscall filter: add knowledge about compat syscalls
   - syscall filter: don't enforce no new privs?
   - syscall filter: option to return EPERM rather than SIGSYS?
   - syscall filter: add knowledge about compat syscalls
   - syscall filter: don't enforce no new privs?
   - syscall filter: option to return EPERM rather than SIGSYS?
-  - syscall filter: port to libseccomp
   - system-wide seccomp filter
 
 * load-fragment: when loading a unit file via a chain of symlinks
   - system-wide seccomp filter
 
 * load-fragment: when loading a unit file via a chain of symlinks
index 59650a256d64d479cfa3f677c5bc0cc4ed852502..518f545bd08964096d3a985c8a08ad7677c2753c 100644 (file)
@@ -322,6 +322,19 @@ if test "x$enable_blkid" != "xno"; then
 fi
 AM_CONDITIONAL(HAVE_BLKID, [test "$have_blkid" = "yes"])
 
 fi
 AM_CONDITIONAL(HAVE_BLKID, [test "$have_blkid" = "yes"])
 
+# ------------------------------------------------------------------------------
+have_seccomp=no
+AC_ARG_ENABLE(seccomp, AS_HELP_STRING([--disable-seccomp], [Disable optional SECCOMP support]))
+if test "x$enable_seccomp" != "xno"; then
+        PKG_CHECK_MODULES(SECCOMP, [libseccomp >= 1.0.0],
+               [AC_DEFINE(HAVE_SECCOMP, 1, [Define if seccomp is available]) have_seccomp=yes],
+               [have_seccomp=no])
+        if test "x$have_seccomp" = "xno" -a "x$enable_seccomp" = "xyes"; then
+                AC_MSG_ERROR([*** seccomp support requested but libraries not found])
+        fi
+fi
+AM_CONDITIONAL(HAVE_SECCOMP, [test "$have_seccomp" = "yes"])
+
 # ------------------------------------------------------------------------------
 have_ima=yes
 AC_ARG_ENABLE([ima], AS_HELP_STRING([--disable-ima],[Disable optional IMA support]),
 # ------------------------------------------------------------------------------
 have_ima=yes
 AC_ARG_ENABLE([ima], AS_HELP_STRING([--disable-ima],[Disable optional IMA support]),
@@ -1090,6 +1103,7 @@ AC_MSG_RESULT([
         AUDIT:                   ${have_audit}
         IMA:                     ${have_ima}
         SELinux:                 ${have_selinux}
         AUDIT:                   ${have_audit}
         IMA:                     ${have_ima}
         SELinux:                 ${have_selinux}
+        SECCOMP:                 ${have_seccomp}
         SMACK:                   ${have_smack}
         XZ:                      ${have_xz}
         ACL:                     ${have_acl}
         SMACK:                   ${have_smack}
         XZ:                      ${have_xz}
         ACL:                     ${have_acl}
index f4caccdd23ada352ab2f8c36c50c888a252aa7cc..0c6ca5acfb347212eef790704ab64202f249ec17 100644 (file)
                                 merged. If the empty string is
                                 assigned, the filter is reset, all
                                 prior assignments will have no
                                 merged. If the empty string is
                                 assigned, the filter is reset, all
                                 prior assignments will have no
-                                effect.</para></listitem>
+                                effect.</para>
+
+                                <para>If you specify both types of this option
+                                (i.e. whitelisting and blacklisting) the first
+                                encountered will take precedence and will
+                                dictate the default action (termination
+                                or approval of a system call). Then the
+                                next occurrences of this option will add or
+                                delete the listed system calls from the set
+                                of the filtered system calls, depending of
+                                its type and the default action (e.g. You
+                                have started with a whitelisting of <function>
+                                read</function> and <function>write</function>
+                                and right after it add a blacklisting of
+                                <function>write</function>, then <function>
+                                write</function> will be removed from the set)
+                                </para></listitem>
                         </varlistentry>
 
                 </variablelist>
                         </varlistentry>
 
                 </variablelist>
index 4513a0bad72000d0551a4b513dba68cf03c9f0c6..f04f03f60d7cde0498e211e22bba55ebe8818caf 100644 (file)
 #define _XZ_FEATURE_ "-XZ"
 #endif
 
 #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_
index db169902339a78b747762420292827efc83828e0..2ed7a3c73eb17a1e3874d5ec34315fc636e34031 100644 (file)
@@ -25,7 +25,6 @@
 #include "missing.h"
 #include "ioprio.h"
 #include "strv.h"
 #include "missing.h"
 #include "ioprio.h"
 #include "strv.h"
-#include "syscall-list.h"
 #include "fileio.h"
 #include "execute.h"
 #include "dbus-execute.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);
 
         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[] = {
 }
 
 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("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
 };
 
         SD_BUS_VTABLE_END
 };
 
index b941a024defe378c5766f379ae37909ebf50b0b0..d2e5b740b7f4e282c3331fd1371700edd1a11ddc 100644 (file)
 #include <linux/fs.h>
 #include <linux/oom.h>
 #include <sys/poll.h>
 #include <linux/fs.h>
 #include <linux/oom.h>
 #include <sys/poll.h>
-#include <linux/seccomp-bpf.h>
 #include <glob.h>
 #include <libgen.h>
 #include <glob.h>
 #include <libgen.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+
+#include "set.h"
+#endif
 #undef basename
 
 #ifdef HAVE_PAM
 #undef basename
 
 #ifdef HAVE_PAM
@@ -67,7 +71,6 @@
 #include "utmp-wtmp.h"
 #include "def.h"
 #include "path-util.h"
 #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"
 #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);
 }
 
         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);
 
 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;
                                 }
 
                                         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;
                                 }
                         }
                                 if (err < 0) {
                                         r = EXIT_SECCOMP;
                                         goto fail_child;
                                 }
                         }
+#endif
 #ifdef HAVE_SELINUX
                         if (context->selinux_context && use_selinux()) {
                                 bool ignore;
 #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);
         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) {
 }
 
 void exec_command_done(ExecCommand *c) {
index be811a97c1eed556be9258beb6fd402c83142204..b2d70d7d86bb9c0ab53e3e5de026f9bf2b8a70a3 100644 (file)
@@ -33,6 +33,11 @@ typedef struct ExecRuntime ExecRuntime;
 #include <stdbool.h>
 #include <stdio.h>
 #include <sched.h>
 #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"
 
 #include "list.h"
 #include "util.h"
@@ -162,7 +167,12 @@ struct ExecContext {
          * don't enter a trigger loop. */
         bool same_pgrp;
 
          * 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;
 
         bool oom_score_adjust_set:1;
         bool nice_set:1;
index 7a2d32ddbd6c3a80c2f4acb9bdaceee85354361c..06ff18b5737c1f0db151bfe4c26a26d09ed90b8b 100644 (file)
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #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"
 
 #include "sd-messages.h"
 #include "unit.h"
 #include "unit-printf.h"
 #include "utf8.h"
 #include "path-util.h"
 #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"
 
 #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,
 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;
 }
 
         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,
 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) {
                                 const char *rvalue,
                                 void *data,
                                 void *userdata) {
-
         ExecContext *c = data;
         Unit *u = userdata;
         bool invert = false;
         char *w;
         size_t l;
         char *state;
         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);
 
         assert(filename);
         assert(lvalue);
@@ -1951,34 +1956,37 @@ int config_parse_syscall_filter(const char *unit,
 
         if (isempty(rvalue)) {
                 /* Empty assignment resets the list */
 
         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;
                 return 0;
         }
 
         if (rvalue[0] == '~') {
                 invert = true;
+                action = SCMP_ACT_KILL;
                 rvalue++;
         }
 
                 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) {
         }
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
@@ -1989,23 +1997,39 @@ int config_parse_syscall_filter(const char *unit,
                 if (!t)
                         return log_oom();
 
                 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 (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
                 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;
 }
         c->no_new_privileges = true;
 
         return 0;
 }
+#endif
 
 int config_parse_unit_slice(
                 const char *unit,
 
 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" },
                 { config_parse_set_status,            "STATUS" },
                 { config_parse_service_sockets,       "SOCKETS" },
                 { config_parse_environ,               "ENVIRON" },
+#ifdef HAVE_SECCOMP
                 { config_parse_syscall_filter,        "SYSCALL" },
                 { 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" },
                 { config_parse_cpu_shares,            "SHARES" },
                 { config_parse_memory_limit,          "LIMIT" },
                 { config_parse_device_allow,          "DEVICE" },
index 3820d1956b43749d579db288d2dae9c399a8aa71..c9b5f8171945747b69ba8a36921ef7ded81be313 100644 (file)
@@ -1,7 +1,3 @@
-/syscall-from-name.gperf
-/syscall-from-name.h
-/syscall-list.txt
-/syscall-to-name.h
 /errno-from-name.gperf
 /errno-from-name.h
 /errno-list.txt
 /errno-from-name.gperf
 /errno-from-name.h
 /errno-list.txt
diff --git a/src/shared/linux/seccomp-bpf.h b/src/shared/linux/seccomp-bpf.h
deleted file mode 100644 (file)
index 1e3d136..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * seccomp example for x86 (32-bit and 64-bit) with BPF macros
- *
- * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
- * Authors:
- *  Will Drewry <wad@chromium.org>
- *  Kees Cook <keescook@chromium.org>
- *
- * The code may be used by anyone for any purpose, and can serve as a
- * starting point for developing applications using mode 2 seccomp.
- */
-#ifndef _SECCOMP_BPF_H_
-#define _SECCOMP_BPF_H_
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/prctl.h>
-
-#include <linux/unistd.h>
-#include <linux/audit.h>
-#include <linux/filter.h>
-#include <linux/seccomp.h>
-
-#ifndef SECCOMP_MODE_FILTER
-# define SECCOMP_MODE_FILTER   2 /* uses user-supplied filter. */
-# define SECCOMP_RET_KILL      0x00000000U /* kill the task immediately */
-# define SECCOMP_RET_TRAP      0x00030000U /* disallow and force a SIGSYS */
-# define SECCOMP_RET_ALLOW     0x7fff0000U /* allow */
-struct seccomp_data {
-    int nr;
-    __u32 arch;
-    __u64 instruction_pointer;
-    __u64 args[6];
-};
-#endif
-#ifndef SYS_SECCOMP
-# define SYS_SECCOMP 1
-#endif
-
-#define syscall_nr (offsetof(struct seccomp_data, nr))
-#define arch_nr (offsetof(struct seccomp_data, arch))
-
-#if defined(__i386__)
-# define REG_SYSCALL   REG_EAX
-# define ARCH_NR       AUDIT_ARCH_I386
-#elif defined(__x86_64__)
-# define REG_SYSCALL   REG_RAX
-# define ARCH_NR       AUDIT_ARCH_X86_64
-#else
-# warning "Platform does not support seccomp filter yet"
-# define REG_SYSCALL   0
-# define ARCH_NR       0
-#endif
-
-#define VALIDATE_ARCHITECTURE \
-       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \
-       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
-       BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
-
-#define EXAMINE_SYSCALL \
-       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr)
-
-#define ALLOW_SYSCALL(name) \
-       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \
-       BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
-
-#define _KILL_PROCESS \
-       BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
-
-#endif /* _SECCOMP_BPF_H_ */
diff --git a/src/shared/linux/seccomp.h b/src/shared/linux/seccomp.h
deleted file mode 100644 (file)
index 9c03683..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef _LINUX_SECCOMP_H
-#define _LINUX_SECCOMP_H
-
-
-#include <linux/types.h>
-
-
-/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */
-#define SECCOMP_MODE_DISABLED  0 /* seccomp is not in use. */
-#define SECCOMP_MODE_STRICT    1 /* uses hard-coded filter. */
-#define SECCOMP_MODE_FILTER    2 /* uses user-supplied filter. */
-
-/*
- * All BPF programs must return a 32-bit value.
- * The bottom 16-bits are for optional return data.
- * The upper 16-bits are ordered from least permissive values to most.
- *
- * The ordering ensures that a min_t() over composed return values always
- * selects the least permissive choice.
- */
-#define SECCOMP_RET_KILL       0x00000000U /* kill the task immediately */
-#define SECCOMP_RET_TRAP       0x00030000U /* disallow and force a SIGSYS */
-#define SECCOMP_RET_ERRNO      0x00050000U /* returns an errno */
-#define SECCOMP_RET_TRACE      0x7ff00000U /* pass to a tracer or disallow */
-#define SECCOMP_RET_ALLOW      0x7fff0000U /* allow */
-
-/* Masks for the return value sections. */
-#define SECCOMP_RET_ACTION     0x7fff0000U
-#define SECCOMP_RET_DATA       0x0000ffffU
-
-/**
- * struct seccomp_data - the format the BPF program executes over.
- * @nr: the system call number
- * @arch: indicates system call convention as an AUDIT_ARCH_* value
- *        as defined in <linux/audit.h>.
- * @instruction_pointer: at the time of the system call.
- * @args: up to 6 system call arguments always stored as 64-bit values
- *        regardless of the architecture.
- */
-struct seccomp_data {
-       int nr;
-       __u32 arch;
-       __u64 instruction_pointer;
-       __u64 args[6];
-};
-
-#endif /* _LINUX_SECCOMP_H */
diff --git a/src/shared/syscall-list.c b/src/shared/syscall-list.c
deleted file mode 100644 (file)
index dc84dca..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 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 <sys/syscall.h>
-#include <string.h>
-
-#include "util.h"
-#include "syscall-list.h"
-
-static const struct syscall_name* lookup_syscall(register const char *str,
-                                                 register unsigned int len);
-
-#include "syscall-to-name.h"
-#include "syscall-from-name.h"
-
-const char *syscall_to_name(int id) {
-        id = SYSCALL_TO_INDEX(id);
-        if (id < 0 || id >= (int) ELEMENTSOF(syscall_names))
-                return NULL;
-
-        return syscall_names[id];
-}
-
-int syscall_from_name(const char *name) {
-        const struct syscall_name *sc;
-
-        assert(name);
-
-        sc = lookup_syscall(name, strlen(name));
-        if (!sc)
-                return -1;
-
-        return sc->id;
-}
-
-int syscall_max(void) {
-        return ELEMENTSOF(syscall_names);
-}
diff --git a/src/shared/syscall-list.h b/src/shared/syscall-list.h
deleted file mode 100644 (file)
index 37efc56..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 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/>.
-***/
-
-#if defined __x86_64__ && defined __ILP32__
-/* The x32 ABI defines all of its syscalls with bit 30 set, which causes
-   issues when attempting to use syscalls as simple indices into an array.
-   Instead, use the syscall id & ~SYSCALL_MASK as the index, and | the
-   internal id with the syscall mask as needed.
-*/
-#include <asm/unistd.h>
-#define SYSCALL_TO_INDEX(x) ((x) & ~__X32_SYSCALL_BIT)
-#define INDEX_TO_SYSCALL(x) ((x) | __X32_SYSCALL_BIT)
-#else
-#define SYSCALL_TO_INDEX(x) (x)
-#define INDEX_TO_SYSCALL(x) (x)
-#endif
-
-const char *syscall_to_name(int id);
-int syscall_from_name(const char *name);
-
-int syscall_max(void);
index 3b7800cf37ba99f2fc4c8f37e237ff3886dcb2d2..dff6431b6dc9ae5b9eff297197aafd795e1d3a93 100644 (file)
@@ -43,7 +43,6 @@
 #include "unit-name.h"
 #include "unit.h"
 #include "util.h"
 #include "unit-name.h"
 #include "unit.h"
 #include "util.h"
-#include "syscall-list.h"
 
 #include "test-tables.h"
 
 
 #include "test-tables.h"
 
@@ -99,7 +98,5 @@ int main(int argc, char **argv) {
         test_table(unit_load_state, UNIT_LOAD_STATE);
         test_table(unit_type, UNIT_TYPE);
 
         test_table(unit_load_state, UNIT_LOAD_STATE);
         test_table(unit_type, UNIT_TYPE);
 
-        _test_table("syscall", syscall_to_name, syscall_from_name, syscall_max(), true);
-
         return EXIT_SUCCESS;
 }
         return EXIT_SUCCESS;
 }