#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>
#include "def.h"
#include "loopback-setup.h"
#include "path-util.h"
+#include "syscall-list.h"
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
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,
if (context->user) {
username = context->user;
- err = get_user_creds(&username, &uid, &gid, &home);
+ err = get_user_creds(&username, &uid, &gid, &home, NULL);
if (err < 0) {
r = EXIT_USER;
goto fail_child;
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))) {
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;
free(c->utmp_id);
c->utmp_id = NULL;
+
+ free(c->syscall_filter);
+ c->syscall_filter = NULL;
}
void exec_command_done(ExecCommand *c) {
"%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 : "/",
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);
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",
};
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);