chiark / gitweb /
unit: split off KillContext from ExecContext containing only kill definitions
[elogind.git] / src / core / execute.c
index daba1a384683f766470847bdf7fddebac8f5db76..fc0edc6cfd7387b4c92f66515497c4d9853cb4fa 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/fs.h>
 #include <linux/oom.h>
 #include <sys/poll.h>
+#include <linux/seccomp-bpf.h>
 
 #ifdef HAVE_PAM
 #include <security/pam_appl.h>
@@ -60,6 +61,7 @@
 #include "def.h"
 #include "loopback-setup.h"
 #include "path-util.h"
+#include "syscall-list.h"
 
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 
@@ -924,6 +926,59 @@ 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);
+
+        /* 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, i, 0, 1),
+                                BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+                        };
+
+                        assert_cc(ELEMENTSOF(item) == 2);
+
+                        f[ELEMENTSOF(header) + 2*n]  = item[0];
+                        f[ELEMENTSOF(header) + 2*n+1] = item[1];
+
+                        n++;
+                }
+
+        memcpy(f + (ELEMENTSOF(header) + 2*n), footer, sizeof(footer));
+
+        /* Third: install the filter */
+        zero(prog);
+        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;
+}
+
 int exec_spawn(ExecCommand *command,
                char **argv,
                const ExecContext *context,
@@ -1355,6 +1410,21 @@ int exec_spawn(ExecCommand *command,
                                         r = EXIT_CAPABILITIES;
                                         goto fail_child;
                                 }
+
+                        if (context->no_new_privileges)
+                                if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
+                                        err = -errno;
+                                        r = EXIT_NO_NEW_PRIVILEGES;
+                                        goto fail_child;
+                                }
+
+                        if (context->syscall_filter) {
+                                err = apply_seccomp(context->syscall_filter);
+                                if (err < 0) {
+                                        r = EXIT_SECCOMP;
+                                        goto fail_child;
+                                }
+                        }
                 }
 
                 if (!(our_env = new0(char*, 7))) {
@@ -1471,8 +1541,6 @@ void exec_context_init(ExecContext *c) {
         c->syslog_priority = LOG_DAEMON|LOG_INFO;
         c->syslog_level_prefix = true;
         c->mount_flags = MS_SHARED;
-        c->kill_signal = SIGTERM;
-        c->send_sigkill = true;
         c->control_group_persistent = -1;
         c->ignore_sigpipe = true;
         c->timer_slack_nsec = (nsec_t) -1;
@@ -1539,6 +1607,9 @@ void exec_context_done(ExecContext *c) {
 
         free(c->utmp_id);
         c->utmp_id = NULL;
+
+        free(c->syscall_filter);
+        c->syscall_filter = NULL;
 }
 
 void exec_command_done(ExecCommand *c) {
@@ -1662,7 +1733,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 "%sPrivateTmp: %s\n"
                 "%sControlGroupModify: %s\n"
                 "%sControlGroupPersistent: %s\n"
-                "%sPrivateNetwork: %s\n",
+                "%sPrivateNetwork: %s\n"
+                "%sIgnoreSIGPIPE: %s\n",
                 prefix, c->umask,
                 prefix, c->working_directory ? c->working_directory : "/",
                 prefix, c->root_directory ? c->root_directory : "/",
@@ -1670,7 +1742,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 prefix, yes_no(c->private_tmp),
                 prefix, yes_no(c->control_group_modify),
                 prefix, yes_no(c->control_group_persistent),
-                prefix, yes_no(c->private_network));
+                prefix, yes_no(c->private_network),
+                prefix, yes_no(c->ignore_sigpipe));
 
         STRV_FOREACH(e, c->environment)
                 fprintf(f, "%sEnvironment: %s\n", prefix, *e);
@@ -1821,16 +1894,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 fputs("\n", f);
         }
 
-        fprintf(f,
-                "%sKillMode: %s\n"
-                "%sKillSignal: SIG%s\n"
-                "%sSendSIGKILL: %s\n"
-                "%sIgnoreSIGPIPE: %s\n",
-                prefix, kill_mode_to_string(c->kill_mode),
-                prefix, signal_to_string(c->kill_signal),
-                prefix, yes_no(c->send_sigkill),
-                prefix, yes_no(c->ignore_sigpipe));
-
         if (c->utmp_id)
                 fprintf(f,
                         "%sUtmpIdentifier: %s\n",
@@ -2038,19 +2101,3 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
-
-static const char* const kill_mode_table[_KILL_MODE_MAX] = {
-        [KILL_CONTROL_GROUP] = "control-group",
-        [KILL_PROCESS] = "process",
-        [KILL_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
-
-static const char* const kill_who_table[_KILL_WHO_MAX] = {
-        [KILL_MAIN] = "main",
-        [KILL_CONTROL] = "control",
-        [KILL_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);