2019-09-17 12:40:52 +00:00
|
|
|
/*
|
|
|
|
* \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 <stdio.h> /* printf */
|
|
|
|
#include <seccomp.h> /* libseccomp */
|
|
|
|
#include <asm/signal.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
|
|
|
|
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));
|
2021-05-04 10:18:48 +00:00
|
|
|
_add_allow_rule(SCMP_SYS(epoll_create1));
|
2019-09-17 12:40:52 +00:00
|
|
|
_add_allow_rule(SCMP_SYS(epoll_ctl));
|
2021-05-04 10:18:48 +00:00
|
|
|
_add_allow_rule(SCMP_SYS(epoll_pwait));
|
2019-09-17 12:40:52 +00:00
|
|
|
_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));
|
|
|
|
|
2020-07-03 09:56:19 +00:00
|
|
|
/* This syscall is used by the 'wait_for_continue' debug mechanism. */
|
|
|
|
_add_allow_rule(SCMP_SYS(read));
|
|
|
|
|
2019-09-17 12:40:52 +00:00
|
|
|
/* 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));
|
|
|
|
|
2021-05-05 17:20:37 +00:00
|
|
|
unsigned long clone_flags = CLONE_VM | CLONE_FS | CLONE_FILES
|
|
|
|
| CLONE_SIGHAND | CLONE_THREAD
|
|
|
|
| CLONE_SYSVSEM;
|
2019-09-17 12:40:52 +00:00
|
|
|
|
|
|
|
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));
|
2020-07-02 07:03:33 +00:00
|
|
|
|
|
|
|
/* returning from signal handlers is safe */
|
|
|
|
_add_allow_rule(SCMP_SYS(sigreturn));
|
2019-09-17 12:40:52 +00:00
|
|
|
}
|
|
|
|
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));
|
2020-07-02 07:03:33 +00:00
|
|
|
|
|
|
|
/* returning from signal handlers is safe */
|
|
|
|
_add_allow_rule(SCMP_SYS(rt_sigreturn));
|
2020-07-23 14:50:43 +00:00
|
|
|
|
|
|
|
/* restarting syscalls is safe (can occur when debugging with GDB) */
|
|
|
|
_add_allow_rule(SCMP_SYS(restart_syscall));
|
2019-09-17 12:40:52 +00:00
|
|
|
}
|
|
|
|
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));
|
|
|
|
|
2020-07-02 07:03:33 +00:00
|
|
|
/* returning from signal handlers is safe */
|
2019-09-17 12:40:52 +00:00
|
|
|
_add_allow_rule(SCMP_SYS(sigreturn));
|
|
|
|
}
|
|
|
|
break;
|
2021-05-05 17:20:37 +00:00
|
|
|
case SCMP_ARCH_AARCH64:
|
|
|
|
{
|
|
|
|
_add_allow_rule(SCMP_SYS(tgkill), SCMP_CMP32(0, SCMP_CMP_EQ, 0xCAFEAFFE),
|
|
|
|
SCMP_CMP32(2, SCMP_CMP_EQ, SIGRTMIN));
|
|
|
|
_add_allow_rule(SCMP_SYS(clone), SCMP_CMP32(0, SCMP_CMP_EQ, clone_flags));
|
|
|
|
_add_allow_rule(SCMP_SYS(mmap));
|
|
|
|
_add_allow_rule(SCMP_SYS(cacheflush));
|
|
|
|
_add_allow_rule(SCMP_SYS(sigreturn));
|
|
|
|
}
|
|
|
|
break;
|
2019-09-17 12:40:52 +00:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "Unsupported architecture\n");
|
|
|
|
throw -104;
|
|
|
|
}
|
|
|
|
|
2020-07-02 07:03:33 +00:00
|
|
|
/* build and export */
|
2019-09-17 12:40:52 +00:00
|
|
|
seccomp_export_bpf(_ctx, 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|