genode/tool/seccomp/seccomp_bpf_compiler.h
Norman Feske 2f9d430c00 base-linux: 64-bit ARM support
This patch adds support for running Genode/Linux on the AARCH64
architecture.

- The kernel-agnostic startup code (crt0) had to be extended to
  capture the initial stack pointer, which the Linux kernel uses
  to pass the process environment. This is in line with the
  existing startup code for x86_32 and x86_64.

- The link order of the host libraries linked to lx_hybrid
  programs had to be adjusted such that libgcc appears at last
  because the other libraries depend on symbols provided by
  libgcc.

- When using AARCH64 Linux as host, one can execute run scripts
  via 'make run/<script> KERNEL=linux BOARD=linux' now.

Issue #4136
2021-05-10 11:17:20 +02:00

222 lines
7.4 KiB
C++

/*
* \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));
_add_allow_rule(SCMP_SYS(epoll_create1));
_add_allow_rule(SCMP_SYS(epoll_ctl));
_add_allow_rule(SCMP_SYS(epoll_pwait));
_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 by the 'wait_for_continue' debug mechanism. */
_add_allow_rule(SCMP_SYS(read));
/* 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));
unsigned long 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));
/* returning from signal handlers is safe */
_add_allow_rule(SCMP_SYS(sigreturn));
}
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));
/* returning from signal handlers is safe */
_add_allow_rule(SCMP_SYS(rt_sigreturn));
/* restarting syscalls is safe (can occur when debugging with GDB) */
_add_allow_rule(SCMP_SYS(restart_syscall));
}
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));
/* returning from signal handlers is safe */
_add_allow_rule(SCMP_SYS(sigreturn));
}
break;
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;
default:
fprintf(stderr, "Unsupported architecture\n");
throw -104;
}
/* build and export */
seccomp_export_bpf(_ctx, 1);
return 0;
}
};