aboutsummaryrefslogtreecommitdiffhomepage
path: root/sandbox/seccomp/seccomp-build.c
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-07-01 20:23:33 +0900
committerOphestra <cat@gensokyo.uk>2025-07-01 22:11:32 +0900
commit1a8840bebc673672235b6e10b1b9386f24751757 (patch)
treed1e6772bfd685e2162d047e3640bd3ee55c1a1f7 /sandbox/seccomp/seccomp-build.c
parent1fb453dffe4c83866fedfa4590be30ec65e815ff (diff)
sandbox/seccomp: resolve rules natively
This enables loading syscall filter policies from external cross-platform config files. This also removes a significant amount of C code. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'sandbox/seccomp/seccomp-build.c')
-rw-r--r--sandbox/seccomp/seccomp-build.c321
1 files changed, 0 insertions, 321 deletions
diff --git a/sandbox/seccomp/seccomp-build.c b/sandbox/seccomp/seccomp-build.c
deleted file mode 100644
index 3fe47df5..00000000
--- a/sandbox/seccomp/seccomp-build.c
+++ /dev/null
@@ -1,321 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* CLONE_NEWUSER */
-#endif
-
-#include "seccomp-build.h"
-#include <assert.h>
-#include <errno.h>
-#include <sched.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/personality.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-
-#if (SCMP_VER_MAJOR < 2) || (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5) || \
- (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 5 && SCMP_VER_MICRO < 1)
-#error This package requires libseccomp >= v2.5.1
-#endif
-
-struct hakurei_syscall_act {
- int syscall;
- int m_errno;
- struct scmp_arg_cmp *arg;
-};
-
-#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-#define SECCOMP_RULESET_ADD(ruleset) \
- do { \
- if (opts & HAKUREI_VERBOSE) \
- hakurei_println("adding seccomp ruleset \"" #ruleset "\""); \
- for (int i = 0; i < LEN(ruleset); i++) { \
- assert(ruleset[i].m_errno == EPERM || ruleset[i].m_errno == ENOSYS); \
- \
- if (ruleset[i].arg) \
- *ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ruleset[i].m_errno), \
- ruleset[i].syscall, 1, *ruleset[i].arg); \
- else \
- *ret_p = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ruleset[i].m_errno), \
- ruleset[i].syscall, 0); \
- \
- if (*ret_p == -EFAULT) { \
- res = 4; \
- goto out; \
- } else if (*ret_p < 0) { \
- res = 5; \
- goto out; \
- } \
- } \
- } while (0)
-
-int32_t hakurei_build_filter(int *ret_p, int fd, uint32_t arch,
- uint32_t multiarch, hakurei_filter_opts opts) {
- int32_t res = 0; /* refer to resPrefix for message */
- int allow_multiarch = opts & HAKUREI_MULTIARCH;
- int allowed_personality = PER_LINUX;
-
- if (opts & HAKUREI_LINUX32)
- allowed_personality = PER_LINUX32;
-
- /* flatpak commit 4c3bf179e2e4a2a298cd1db1d045adaf3f564532 */
-
- struct hakurei_syscall_act deny_common[] = {
- /* Block dmesg */
- {SCMP_SYS(syslog), EPERM},
- /* Useless old syscall */
- {SCMP_SYS(uselib), EPERM},
- /* Don't allow disabling accounting */
- {SCMP_SYS(acct), EPERM},
- /* Don't allow reading current quota use */
- {SCMP_SYS(quotactl), EPERM},
-
- /* Don't allow access to the kernel keyring */
- {SCMP_SYS(add_key), EPERM},
- {SCMP_SYS(keyctl), EPERM},
- {SCMP_SYS(request_key), EPERM},
-
- /* Scary VM/NUMA ops */
- {SCMP_SYS(move_pages), EPERM},
- {SCMP_SYS(mbind), EPERM},
- {SCMP_SYS(get_mempolicy), EPERM},
- {SCMP_SYS(set_mempolicy), EPERM},
- {SCMP_SYS(migrate_pages), EPERM},
- };
-
- /* hakurei: project-specific extensions */
- struct hakurei_syscall_act deny_common_ext[] = {
- /* system calls for changing the system clock */
- {SCMP_SYS(adjtimex), EPERM},
- {SCMP_SYS(clock_adjtime), EPERM},
- {SCMP_SYS(clock_adjtime64), EPERM},
- {SCMP_SYS(clock_settime), EPERM},
- {SCMP_SYS(clock_settime64), EPERM},
- {SCMP_SYS(settimeofday), EPERM},
-
- /* loading and unloading of kernel modules */
- {SCMP_SYS(delete_module), EPERM},
- {SCMP_SYS(finit_module), EPERM},
- {SCMP_SYS(init_module), EPERM},
-
- /* system calls for rebooting and reboot preparation */
- {SCMP_SYS(kexec_file_load), EPERM},
- {SCMP_SYS(kexec_load), EPERM},
- {SCMP_SYS(reboot), EPERM},
-
- /* system calls for enabling/disabling swap devices */
- {SCMP_SYS(swapoff), EPERM},
- {SCMP_SYS(swapon), EPERM},
- };
-
- struct hakurei_syscall_act deny_ns[] = {
- /* Don't allow subnamespace setups: */
- {SCMP_SYS(unshare), EPERM},
- {SCMP_SYS(setns), EPERM},
- {SCMP_SYS(mount), EPERM},
- {SCMP_SYS(umount), EPERM},
- {SCMP_SYS(umount2), EPERM},
- {SCMP_SYS(pivot_root), EPERM},
- {SCMP_SYS(chroot), EPERM},
-#if defined(__s390__) || defined(__s390x__) || defined(__CRIS__)
- /* Architectures with CONFIG_CLONE_BACKWARDS2: the child stack
- * and flags arguments are reversed so the flags come second */
- {SCMP_SYS(clone), EPERM,
- &SCMP_A1(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)},
-#else
- /* Normally the flags come first */
- {SCMP_SYS(clone), EPERM,
- &SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)},
-#endif
-
- /* seccomp can't look into clone3()'s struct clone_args to check whether
- * the flags are OK, so we have no choice but to block clone3().
- * Return ENOSYS so user-space will fall back to clone().
- * (CVE-2021-41133; see also https://github.com/moby/moby/commit/9f6b562d)
- */
- {SCMP_SYS(clone3), ENOSYS},
-
- /* New mount manipulation APIs can also change our VFS. There's no
- * legitimate reason to do these in the sandbox, so block all of them
- * rather than thinking about which ones might be dangerous.
- * (CVE-2021-41133) */
- {SCMP_SYS(open_tree), ENOSYS},
- {SCMP_SYS(move_mount), ENOSYS},
- {SCMP_SYS(fsopen), ENOSYS},
- {SCMP_SYS(fsconfig), ENOSYS},
- {SCMP_SYS(fsmount), ENOSYS},
- {SCMP_SYS(fspick), ENOSYS},
- {SCMP_SYS(mount_setattr), ENOSYS},
- };
-
- /* hakurei: project-specific extensions */
- struct hakurei_syscall_act deny_ns_ext[] = {
- /* changing file ownership */
- {SCMP_SYS(chown), EPERM},
- {SCMP_SYS(chown32), EPERM},
- {SCMP_SYS(fchown), EPERM},
- {SCMP_SYS(fchown32), EPERM},
- {SCMP_SYS(fchownat), EPERM},
- {SCMP_SYS(lchown), EPERM},
- {SCMP_SYS(lchown32), EPERM},
-
- /* system calls for changing user ID and group ID credentials */
- {SCMP_SYS(setgid), EPERM},
- {SCMP_SYS(setgid32), EPERM},
- {SCMP_SYS(setgroups), EPERM},
- {SCMP_SYS(setgroups32), EPERM},
- {SCMP_SYS(setregid), EPERM},
- {SCMP_SYS(setregid32), EPERM},
- {SCMP_SYS(setresgid), EPERM},
- {SCMP_SYS(setresgid32), EPERM},
- {SCMP_SYS(setresuid), EPERM},
- {SCMP_SYS(setresuid32), EPERM},
- {SCMP_SYS(setreuid), EPERM},
- {SCMP_SYS(setreuid32), EPERM},
- {SCMP_SYS(setuid), EPERM},
- {SCMP_SYS(setuid32), EPERM},
- };
-
- struct hakurei_syscall_act deny_tty[] = {
- /* Don't allow faking input to the controlling tty (CVE-2017-5226) */
- {SCMP_SYS(ioctl), EPERM,
- &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCSTI)},
- /* In the unlikely event that the controlling tty is a Linux virtual
- * console (/dev/tty2 or similar), copy/paste operations have an effect
- * similar to TIOCSTI (CVE-2023-28100) */
- {SCMP_SYS(ioctl), EPERM,
- &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCLINUX)},
- };
-
- struct hakurei_syscall_act deny_devel[] = {
- /* Profiling operations; we expect these to be done by tools from outside
- * the sandbox. In particular perf has been the source of many CVEs. */
- {SCMP_SYS(perf_event_open), EPERM},
- /* Don't allow you to switch to bsd emulation or whatnot */
- {SCMP_SYS(personality), EPERM,
- &SCMP_A0(SCMP_CMP_NE, allowed_personality)},
-
- {SCMP_SYS(ptrace), EPERM}};
-
- struct hakurei_syscall_act deny_emu[] = {
- /* modify_ldt is a historic source of interesting information leaks,
- * so it's disabled as a hardening measure.
- * However, it is required to run old 16-bit applications
- * as well as some Wine patches, so it's allowed in multiarch. */
- {SCMP_SYS(modify_ldt), EPERM},
- };
-
- /* hakurei: project-specific extensions */
- struct hakurei_syscall_act deny_emu_ext[] = {
- {SCMP_SYS(subpage_prot), ENOSYS},
- {SCMP_SYS(switch_endian), ENOSYS},
- {SCMP_SYS(vm86), ENOSYS},
- {SCMP_SYS(vm86old), ENOSYS},
- };
-
- /* Blocklist all but unix, inet, inet6 and netlink */
- struct {
- int family;
- hakurei_filter_opts flags_mask;
- } socket_family_allowlist[] = {
- /* NOTE: Keep in numerical order */
- {AF_UNSPEC, 0},
- {AF_LOCAL, 0},
- {AF_INET, 0},
- {AF_INET6, 0},
- {AF_NETLINK, 0},
- {AF_CAN, HAKUREI_CAN},
- {AF_BLUETOOTH, HAKUREI_BLUETOOTH},
- };
-
- scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
- if (ctx == NULL) {
- res = 1;
- goto out;
- } else
- errno = 0;
-
- /* We only really need to handle arches on multiarch systems.
- * If only one arch is supported the default is fine */
- if (arch != 0) {
- /* This *adds* the target arch, instead of replacing the
- * native one. This is not ideal, because we'd like to only
- * allow the target arch, but we can't really disallow the
- * native arch at this point, because then bubblewrap
- * couldn't continue running. */
- *ret_p = seccomp_arch_add(ctx, arch);
- if (*ret_p < 0 && *ret_p != -EEXIST) {
- res = 2;
- goto out;
- }
-
- if (allow_multiarch && multiarch != 0) {
- *ret_p = seccomp_arch_add(ctx, multiarch);
- if (*ret_p < 0 && *ret_p != -EEXIST) {
- res = 3;
- goto out;
- }
- }
- }
-
- SECCOMP_RULESET_ADD(deny_common);
- if (opts & HAKUREI_DENY_NS)
- SECCOMP_RULESET_ADD(deny_ns);
- if (opts & HAKUREI_DENY_TTY)
- SECCOMP_RULESET_ADD(deny_tty);
- if (opts & HAKUREI_DENY_DEVEL)
- SECCOMP_RULESET_ADD(deny_devel);
- if (!allow_multiarch)
- SECCOMP_RULESET_ADD(deny_emu);
- if (opts & HAKUREI_EXT) {
- SECCOMP_RULESET_ADD(deny_common_ext);
- if (opts & HAKUREI_DENY_NS)
- SECCOMP_RULESET_ADD(deny_ns_ext);
- if (!allow_multiarch)
- SECCOMP_RULESET_ADD(deny_emu_ext);
- }
-
- /* Socket filtering doesn't work on e.g. i386, so ignore failures here
- * However, we need to user seccomp_rule_add_exact to avoid libseccomp doing
- * something else: https://github.com/seccomp/libseccomp/issues/8 */
- int last_allowed_family = -1;
- for (int i = 0; i < LEN(socket_family_allowlist); i++) {
- if (socket_family_allowlist[i].flags_mask != 0 &&
- (socket_family_allowlist[i].flags_mask & opts) !=
- socket_family_allowlist[i].flags_mask)
- continue;
-
- for (int disallowed = last_allowed_family + 1;
- disallowed < socket_family_allowlist[i].family; disallowed++) {
- /* Blocklist the in-between valid families */
- seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT),
- SCMP_SYS(socket), 1,
- SCMP_A0(SCMP_CMP_EQ, disallowed));
- }
- last_allowed_family = socket_family_allowlist[i].family;
- }
- /* Blocklist the rest */
- seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1,
- SCMP_A0(SCMP_CMP_GE, last_allowed_family + 1));
-
- if (fd < 0) {
- *ret_p = seccomp_load(ctx);
- if (*ret_p != 0) {
- res = 7;
- goto out;
- }
- } else {
- *ret_p = seccomp_export_bpf(ctx, fd);
- if (*ret_p != 0) {
- res = 6;
- goto out;
- }
- }
-
-out:
- if (ctx)
- seccomp_release(ctx);
-
- return res;
-}