diff --git a/repos/base-linux/lib/mk/base-linux.mk b/repos/base-linux/lib/mk/base-linux.mk
index e9529685b..abfa2aebd 100644
--- a/repos/base-linux/lib/mk/base-linux.mk
+++ b/repos/base-linux/lib/mk/base-linux.mk
@@ -6,7 +6,7 @@
include $(REP_DIR)/lib/mk/base-linux.inc
-LIBS += startup-linux base-linux-common cxx
+LIBS += startup-linux base-linux-common cxx seccomp
SRC_CC += thread.cc thread_myself.cc thread_linux.cc
SRC_CC += capability_space.cc capability_raw.cc
SRC_CC += attach_stack_area.cc
diff --git a/repos/base-linux/lib/mk/spec/arm/seccomp.mk b/repos/base-linux/lib/mk/spec/arm/seccomp.mk
new file mode 100644
index 000000000..50889af7a
--- /dev/null
+++ b/repos/base-linux/lib/mk/spec/arm/seccomp.mk
@@ -0,0 +1,3 @@
+SRC_BIN += seccomp_bpf_policy.bin
+
+vpath seccomp_bpf_policy.bin $(REP_DIR)/src/lib/seccomp/spec/arm
diff --git a/repos/base-linux/lib/mk/spec/x86_32/seccomp.mk b/repos/base-linux/lib/mk/spec/x86_32/seccomp.mk
new file mode 100644
index 000000000..0886d43ed
--- /dev/null
+++ b/repos/base-linux/lib/mk/spec/x86_32/seccomp.mk
@@ -0,0 +1,3 @@
+SRC_BIN += seccomp_bpf_policy.bin
+
+vpath seccomp_bpf_policy.bin $(REP_DIR)/src/lib/seccomp/spec/x86_32
diff --git a/repos/base-linux/lib/mk/spec/x86_64/seccomp.mk b/repos/base-linux/lib/mk/spec/x86_64/seccomp.mk
new file mode 100644
index 000000000..c0902c8bd
--- /dev/null
+++ b/repos/base-linux/lib/mk/spec/x86_64/seccomp.mk
@@ -0,0 +1,3 @@
+SRC_BIN += seccomp_bpf_policy.bin
+
+vpath seccomp_bpf_policy.bin $(REP_DIR)/src/lib/seccomp/spec/x86_64
diff --git a/repos/base-linux/src/lib/base/platform.cc b/repos/base-linux/src/lib/base/platform.cc
index 82e843931..66fedb793 100644
--- a/repos/base-linux/src/lib/base/platform.cc
+++ b/repos/base-linux/src/lib/base/platform.cc
@@ -12,9 +12,51 @@
* under the terms of the GNU Affero General Public License version 3.
*/
+/* Genode includes */
+#include
/* base-internal includes */
#include
+#include
+#include
+#include /* prctl */
+#include /* seccomp's constants */
-void Genode::binary_ready_hook_for_platform() { }
+using namespace Genode;
+
+extern char _binary_seccomp_bpf_policy_bin_start[];
+extern char _binary_seccomp_bpf_policy_bin_end[];
+
+struct bpf_program {
+ Genode::uint16_t blk_cnt;
+ Genode::uint64_t* blks;
+};
+
+void Genode::binary_ready_hook_for_platform()
+{
+ if (lx_prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
+ error("PR_SET_NO_NEW_PRIVS failed");
+ throw Exception();
+ }
+
+ for (char* i = _binary_seccomp_bpf_policy_bin_start;
+ i < _binary_seccomp_bpf_policy_bin_end - sizeof(Genode::uint32_t); i++) {
+ Genode::uint32_t* v = reinterpret_cast(i);
+ if (*v == 0xCAFEAFFE) {
+ *v = lx_getpid();
+ }
+ }
+
+ bpf_program program;
+ program.blk_cnt = (_binary_seccomp_bpf_policy_bin_end -
+ _binary_seccomp_bpf_policy_bin_start) /
+ sizeof(Genode::uint64_t);
+ program.blks = (Genode::uint64_t*)_binary_seccomp_bpf_policy_bin_start;
+ Genode::uint64_t flags = SECCOMP_FILTER_FLAG_TSYNC;
+ auto ret = lx_seccomp(SECCOMP_SET_MODE_FILTER, flags, &program);
+ if (ret != 0) {
+ error("SECCOMP_SET_MODE_FILTER failed ", ret);
+ throw Exception();
+ }
+}
diff --git a/repos/base-linux/src/lib/base/thread_linux.cc b/repos/base-linux/src/lib/base/thread_linux.cc
index bd70ecb6e..e6f9c4939 100644
--- a/repos/base-linux/src/lib/base/thread_linux.cc
+++ b/repos/base-linux/src/lib/base/thread_linux.cc
@@ -123,7 +123,10 @@ void Thread::_deinit_platform_thread()
for (;;) {
/* destroy thread locally */
- int ret = lx_tgkill(native_thread().pid, native_thread().tid, LX_SIGCANCEL);
+ int pid = native_thread().pid;
+ if (pid == 0) break;
+
+ int ret = lx_tgkill(pid, native_thread().tid, LX_SIGCANCEL);
if (ret < 0) break;
diff --git a/repos/base-linux/src/lib/seccomp/seccomp_bpf_policy.h b/repos/base-linux/src/lib/seccomp/seccomp_bpf_policy.h
new file mode 100644
index 000000000..bdb002f13
--- /dev/null
+++ b/repos/base-linux/src/lib/seccomp/seccomp_bpf_policy.h
@@ -0,0 +1,40 @@
+/*
+ * \brief Including seccomp filter policy binary
+ * \author Stefan Thoeni
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _LIB__SECCOMP_BPF_POLICY_H_
+#define _LIB__SECCOMP_BPF_POLICY_H_
+
+#define STR2(x) #x
+#define STR(x) STR2(x)
+
+#define INCBIN(name, file) \
+ __asm__(".section .rodata\n" \
+ ".global incbin_" STR(name) "_start\n" \
+ ".type incbin_" STR(name) "_start, @object\n" \
+ ".balign 16\n" \
+ "incbin_" STR(name) "_start:\n" \
+ ".incbin \"" file "\"\n" \
+ \
+ ".global incbin_" STR(name) "_end\n" \
+ ".type incbin_" STR(name) "_end, @object\n" \
+ ".balign 1\n" \
+ "incbin_" STR(name) "_end:\n" \
+ ".byte 0\n" \
+ ); \
+ extern const __attribute__((aligned(16))) void* incbin_ ## name ## _start; \
+ extern const void* incbin_ ## name ## _end; \
+
+INCBIN(seccomp_bpf_policy, "seccomp_bpf_policy.bin");
+
+#endif /* _LIB__SECCOMP_BPF_POLICY_H_ */
diff --git a/repos/base-linux/src/lib/seccomp/spec/arm/seccomp_bpf_policy.bin b/repos/base-linux/src/lib/seccomp/spec/arm/seccomp_bpf_policy.bin
new file mode 100644
index 000000000..2303a9af3
Binary files /dev/null and b/repos/base-linux/src/lib/seccomp/spec/arm/seccomp_bpf_policy.bin differ
diff --git a/repos/base-linux/src/lib/seccomp/spec/x86_32/seccomp_bpf_policy.bin b/repos/base-linux/src/lib/seccomp/spec/x86_32/seccomp_bpf_policy.bin
new file mode 100644
index 000000000..38a12d4e0
Binary files /dev/null and b/repos/base-linux/src/lib/seccomp/spec/x86_32/seccomp_bpf_policy.bin differ
diff --git a/repos/base-linux/src/lib/seccomp/spec/x86_64/seccomp_bpf_policy.bin b/repos/base-linux/src/lib/seccomp/spec/x86_64/seccomp_bpf_policy.bin
new file mode 100644
index 000000000..0264978c1
Binary files /dev/null and b/repos/base-linux/src/lib/seccomp/spec/x86_64/seccomp_bpf_policy.bin differ
diff --git a/repos/base-linux/src/lib/seccomp/update.sh b/repos/base-linux/src/lib/seccomp/update.sh
new file mode 100755
index 000000000..b5ebe4e31
--- /dev/null
+++ b/repos/base-linux/src/lib/seccomp/update.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Build and update seccomp Berkeley Packet Filter binary
+# for use in base-linux
+
+SCRIPT_FILE=$(realpath "$0")
+SCRIPT_DIR=$(dirname $SCRIPT_FILE)
+
+make -C $SCRIPT_DIR/../../../../../tool/seccomp \
+&& cp $SCRIPT_DIR/../../../../../tool/seccomp/seccomp_bpf_policy_x86_32.bin $SCRIPT_DIR/spec/x86_32/seccomp_bpf_policy.bin\
+&& cp $SCRIPT_DIR/../../../../../tool/seccomp/seccomp_bpf_policy_x86_64.bin $SCRIPT_DIR/spec/x86_64/seccomp_bpf_policy.bin\
+&& cp $SCRIPT_DIR/../../../../../tool/seccomp/seccomp_bpf_policy_arm.bin $SCRIPT_DIR/spec/arm/seccomp_bpf_policy.bin \
+&& make -C $SCRIPT_DIR/../../../../../tool/seccomp clean \
+|| exit $?
+
diff --git a/repos/base-linux/src/lib/syscall/linux_syscalls.h b/repos/base-linux/src/lib/syscall/linux_syscalls.h
index 6cac5d359..08f9eacfe 100644
--- a/repos/base-linux/src/lib/syscall/linux_syscalls.h
+++ b/repos/base-linux/src/lib/syscall/linux_syscalls.h
@@ -522,4 +522,16 @@ inline bool lx_sigsetmask(int signum, bool state)
}
+inline int lx_prctl(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5)
+{
+ return lx_syscall(SYS_prctl, option, arg2, arg3, arg4, arg5);
+}
+
+
+inline int lx_seccomp(int option, int flag, void* program)
+{
+ return lx_syscall(SYS_seccomp, option, flag, program);
+}
+
#endif /* _LIB__SYSCALL__LINUX_SYSCALLS_H_ */
diff --git a/tool/seccomp/Makefile b/tool/seccomp/Makefile
new file mode 100644
index 000000000..f996bc236
--- /dev/null
+++ b/tool/seccomp/Makefile
@@ -0,0 +1,13 @@
+.DEFAULT_GOAL := seccomp_bpf_filters
+
+seccomp_bpf_filters: seccomp_bpf_policy_x86_32.bin seccomp_bpf_policy_x86_64.bin seccomp_bpf_policy_arm.bin
+
+seccomp_bpf_policy_%.bin: seccomp_bpf_compiler_%.prg
+ ./$< > $@
+
+seccomp_bpf_compiler_%.prg: seccomp_bpf_compiler_%.cc
+ @g++ $< -o $@ -lseccomp
+
+clean:
+ @rm seccomp_bpf_policy_*.bin 2> /dev/null; true
+ @rm seccomp_bpf_compiler_*.prg 2> /dev/null; true
diff --git a/tool/seccomp/seccomp_bpf_compiler.h b/tool/seccomp/seccomp_bpf_compiler.h
new file mode 100644
index 000000000..c666547c1
--- /dev/null
+++ b/tool/seccomp/seccomp_bpf_compiler.h
@@ -0,0 +1,198 @@
+/*
+ * \brief Generate seccomp filter policy for base-linux
+ * \author Stefan Thoeni
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include /* printf */
+#include /* libseccomp */
+#include
+#include
+
+class Filter
+{
+ private:
+ scmp_filter_ctx _ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
+ uint32_t _arch;
+
+
+ void _add_allow_rule(int syscall_number)
+ {
+ int result = seccomp_rule_add(_ctx, SCMP_ACT_ALLOW, syscall_number, 0);
+ if (result != 0) {
+ fprintf(stderr, "Add rule failed for number %i\n", syscall_number);
+ throw -102;
+ }
+ }
+
+
+ void _add_allow_rule(int syscall_number, scmp_arg_cmp c1)
+ {
+ int result = seccomp_rule_add(_ctx, SCMP_ACT_ALLOW, syscall_number, 1, c1);
+ if (result != 0) {
+ fprintf(stderr, "Add rule failed for number %i\n", syscall_number);
+ throw -102;
+ }
+ }
+
+
+ void _add_allow_rule(int syscall_number, scmp_arg_cmp c1, scmp_arg_cmp c2)
+ {
+ int result = seccomp_rule_add(_ctx, SCMP_ACT_ALLOW, syscall_number, 2, c1, c2);
+ if (result != 0) {
+ fprintf(stderr, "Add rule failed for number %i\n", syscall_number);
+ throw -102;
+ }
+ }
+
+ public:
+
+ Filter(uint32_t arch)
+ : _arch(arch)
+ {
+ }
+
+
+ int create()
+ {
+ /* Kill the process if the filter architecture does not fit. */
+ if (seccomp_attr_set(_ctx, SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_KILL_PROCESS) != 0) {
+ fprintf(stderr, "Failed to set bad architecture action\n");
+ throw -103;
+ }
+
+ /* Remove the default architecture (e.g. native architecture) from the filter.*/
+ if (seccomp_arch_remove(_ctx, SCMP_ARCH_NATIVE) != 0) {
+ fprintf(stderr, "Failed to remove default architecture\n");
+ throw -103;
+ }
+
+ /* Add the desired architecture to the filter.*/
+ if (seccomp_arch_add(_ctx, _arch) != 0) {
+ fprintf(stderr, "Failed to add architecture\n");
+ throw -103;
+ }
+
+ /* This syscall is safe as it create a socket pair in the
+ * process */
+ _add_allow_rule(SCMP_SYS(socketpair));
+
+ /* These syscalls should be safe as they only access already open sockets. */
+ _add_allow_rule(SCMP_SYS(sendmsg));
+ _add_allow_rule(SCMP_SYS(recvmsg));
+ _add_allow_rule(SCMP_SYS(write));
+ _add_allow_rule(SCMP_SYS(poll));
+ _add_allow_rule(SCMP_SYS(epoll_create));
+ _add_allow_rule(SCMP_SYS(epoll_ctl));
+ _add_allow_rule(SCMP_SYS(epoll_wait));
+ _add_allow_rule(SCMP_SYS(close));
+ _add_allow_rule(SCMP_SYS(munmap));
+ _add_allow_rule(SCMP_SYS(dup));
+ _add_allow_rule(SCMP_SYS(fstat));
+ _add_allow_rule(SCMP_SYS(fstat64));
+
+ /* This syscall is used to wait for a condition. This should be safe. */
+ _add_allow_rule(SCMP_SYS(futex));
+
+ /* This syscall ends the program. This should be safe */
+ _add_allow_rule(SCMP_SYS(exit));
+
+ /* These syscalls are used to react to signals. They should be safe */
+ _add_allow_rule(SCMP_SYS(sigaltstack));
+ _add_allow_rule(SCMP_SYS(rt_sigaction));
+
+ /* This syscall is used to sleep. This should be safe */
+ _add_allow_rule(SCMP_SYS(nanosleep));
+
+ /* These syscall allow access to global information. We would like
+ * to reduced this. */
+ _add_allow_rule(SCMP_SYS(getpid));
+ _add_allow_rule(SCMP_SYS(gettid));
+ _add_allow_rule(SCMP_SYS(gettimeofday));
+ _add_allow_rule(SCMP_SYS(getpeername));
+
+ int clone_flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
+ | CLONE_THREAD | CLONE_SYSVSEM;
+
+ switch (_arch)
+ {
+ case SCMP_ARCH_X86:
+ {
+ /* The tgkill syscall must be made safe by restricting parameters.
+ * Genode uses LX_SIGCANCEL alias SIGRTMIN to cancel threads
+ * the 0xCAFEAFFE will be replaced with the process ID to restrict
+ * tgkill to the process (= thread group). */
+ _add_allow_rule(SCMP_SYS(tgkill), SCMP_CMP32(0, SCMP_CMP_EQ, 0xCAFEAFFE),
+ SCMP_CMP32(2, SCMP_CMP_EQ, SIGRTMIN));
+
+ /* The clone syscall must be made safe by restricting parameters
+ * The specified flags only allow creation of new threads. */
+ _add_allow_rule(SCMP_SYS(clone), SCMP_CMP32(0, SCMP_CMP_EQ, clone_flags));
+
+ /* The nmap syscall has a different name on different architectures
+ * but it slould be save as it only uses an already open socket. */
+ _add_allow_rule(SCMP_SYS(mmap2));
+ }
+ break;
+ case SCMP_ARCH_X86_64:
+ {
+ /* The tgkill syscall must be made safe by restricting parameters.
+ * Genode uses LX_SIGCANCEL alias SIGRTMIN to cancel threads
+ * the 0xCAFEAFFE will be replaced with the process ID to restrict
+ * tgkill to the process (= thread group). */
+ _add_allow_rule(SCMP_SYS(tgkill), SCMP_CMP64(0, SCMP_CMP_EQ, 0xCAFEAFFE),
+ SCMP_CMP64(2, SCMP_CMP_EQ, SIGRTMIN));
+
+ /* The clone syscall must be made safe by restricting parameters
+ * The specified flags only allow creation of new threads. */
+ _add_allow_rule(SCMP_SYS(clone), SCMP_CMP64(0, SCMP_CMP_EQ, clone_flags));
+
+ /* The nmap syscall has a different name on different architectures
+ * but it slould be save as it only uses an already open socket. */
+ _add_allow_rule(SCMP_SYS(mmap));
+ }
+ break;
+ case SCMP_ARCH_ARM:
+ {
+ /* The tgkill syscall must be made safe by restricting parameters.
+ * Genode uses LX_SIGCANCEL alias SIGRTMIN to cancel threads
+ * the 0xCAFEAFFE will be replaced with the process ID to restrict
+ * tgkill to the process (= thread group). */
+ _add_allow_rule(SCMP_SYS(tgkill), SCMP_CMP32(0, SCMP_CMP_EQ, 0xCAFEAFFE),
+ SCMP_CMP32(2, SCMP_CMP_EQ, SIGRTMIN));
+
+ /* The clone syscall must be made safe by restricting parameters
+ * The specified flags only allow creation of new threads. */
+ _add_allow_rule(SCMP_SYS(clone), SCMP_CMP32(0, SCMP_CMP_EQ, clone_flags));
+
+ /* The nmap2 syscall has a different name on different architectures
+ * but it slould be save as it only uses an already open socket. */
+ _add_allow_rule(SCMP_SYS(mmap2));
+
+ /* This syscall is only used on ARM. */
+ _add_allow_rule(SCMP_SYS(cacheflush));
+
+ /* This syscall is only used on ARM. */
+ _add_allow_rule(SCMP_SYS(sigreturn));
+ }
+ break;
+ default:
+ fprintf(stderr, "Unsupported architecture\n");
+ throw -104;
+ }
+
+ // build and export
+ seccomp_export_bpf(_ctx, 1);
+
+ return 0;
+ }
+};
+
diff --git a/tool/seccomp/seccomp_bpf_compiler_arm.cc b/tool/seccomp/seccomp_bpf_compiler_arm.cc
new file mode 100644
index 000000000..d47f17ae1
--- /dev/null
+++ b/tool/seccomp/seccomp_bpf_compiler_arm.cc
@@ -0,0 +1,23 @@
+/*
+ * \brief Generate seccomp filter policy for base-linux on arm
+ * \author Stefan Thoeni
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include /* printf */
+#include /* libseccomp */
+#include "seccomp_bpf_compiler.h"
+
+int main()
+{
+ Filter filter(SCMP_ARCH_ARM);
+ return filter.create();
+}
diff --git a/tool/seccomp/seccomp_bpf_compiler_x86_32.cc b/tool/seccomp/seccomp_bpf_compiler_x86_32.cc
new file mode 100644
index 000000000..f3e4717f3
--- /dev/null
+++ b/tool/seccomp/seccomp_bpf_compiler_x86_32.cc
@@ -0,0 +1,23 @@
+/*
+ * \brief Generate seccomp filter policy for base-linux on x86_64
+ * \author Stefan Thoeni
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include /* printf */
+#include /* libseccomp */
+#include "seccomp_bpf_compiler.h"
+
+int main()
+{
+ Filter filter(SCMP_ARCH_X86);
+ return filter.create();
+}
diff --git a/tool/seccomp/seccomp_bpf_compiler_x86_64.cc b/tool/seccomp/seccomp_bpf_compiler_x86_64.cc
new file mode 100644
index 000000000..120cb0d2a
--- /dev/null
+++ b/tool/seccomp/seccomp_bpf_compiler_x86_64.cc
@@ -0,0 +1,23 @@
+/*
+ * \brief Generate seccomp filter policy for base-linux on x86_64
+ * \author Stefan Thoeni
+ * \date 2019-12-13
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ * Copyright (C) 2019 gapfruit AG
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include /* printf */
+#include /* libseccomp */
+#include "seccomp_bpf_compiler.h"
+
+int main()
+{
+ Filter filter(SCMP_ARCH_X86_64);
+ return filter.create();
+}