aboutsummaryrefslogtreecommitdiffhomepage
path: root/helper
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-03-14 22:42:40 +0900
committerOphestra <cat@gensokyo.uk>2025-03-14 22:42:40 +0900
commit2647a71be1f287e50011a65653b9e9c806627899 (patch)
tree252dd8865632df348b7573ca6f31c04e4cb6c9e5 /helper
parent7c60a4d8e8baa77b42789c041838fa82dd7d36f9 (diff)
seccomp: move out of helper
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'helper')
-rw-r--r--helper/bwrap/config_test.go2
-rw-r--r--helper/bwrap/seccomp.go2
-rw-r--r--helper/seccomp/api.go71
-rw-r--r--helper/seccomp/export.go58
-rw-r--r--helper/seccomp/export_test.go139
-rw-r--r--helper/seccomp/seccomp-build.c302
-rw-r--r--helper/seccomp/seccomp-build.h23
-rw-r--r--helper/seccomp/seccomp.go123
-rw-r--r--helper/seccomp/seccomp_test.go65
9 files changed, 2 insertions, 783 deletions
diff --git a/helper/bwrap/config_test.go b/helper/bwrap/config_test.go
index e0f14511..678f49de 100644
--- a/helper/bwrap/config_test.go
+++ b/helper/bwrap/config_test.go
@@ -8,7 +8,7 @@ import (
"git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/helper/proc"
- "git.gensokyo.uk/security/fortify/helper/seccomp"
+ "git.gensokyo.uk/security/fortify/seccomp"
)
func TestConfig_Args(t *testing.T) {
diff --git a/helper/bwrap/seccomp.go b/helper/bwrap/seccomp.go
index f74015fd..8e55171b 100644
--- a/helper/bwrap/seccomp.go
+++ b/helper/bwrap/seccomp.go
@@ -5,7 +5,7 @@ import (
"strconv"
"git.gensokyo.uk/security/fortify/helper/proc"
- "git.gensokyo.uk/security/fortify/helper/seccomp"
+ "git.gensokyo.uk/security/fortify/seccomp"
)
type SyscallPolicy struct {
diff --git a/helper/seccomp/api.go b/helper/seccomp/api.go
deleted file mode 100644
index 697b09f3..00000000
--- a/helper/seccomp/api.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package seccomp
-
-import (
- "context"
- "errors"
- "syscall"
-
- "git.gensokyo.uk/security/fortify/helper/proc"
-)
-
-// New returns an inactive Encoder instance.
-func New(opts SyscallOpts) *Encoder { return &Encoder{newExporter(opts)} }
-
-// Load loads a filter into the kernel.
-func Load(opts SyscallOpts) error { return buildFilter(-1, opts) }
-
-/*
-An Encoder writes a BPF program to an output stream.
-
-Methods of Encoder are not safe for concurrent use.
-
-An Encoder must not be copied after first use.
-*/
-type Encoder struct {
- *exporter
-}
-
-func (e *Encoder) Read(p []byte) (n int, err error) {
- if err = e.prepare(); err != nil {
- return
- }
- return e.r.Read(p)
-}
-
-func (e *Encoder) Close() error {
- if e.r == nil {
- return syscall.EINVAL
- }
-
- // this hangs if the cgo thread fails to exit
- return errors.Join(e.closeWrite(), <-e.exportErr)
-}
-
-// NewFile returns an instance of exporter implementing [proc.File].
-func NewFile(opts SyscallOpts) proc.File { return &File{opts: opts} }
-
-// File implements [proc.File] and provides access to the read end of exporter pipe.
-type File struct {
- opts SyscallOpts
- proc.BaseFile
-}
-
-func (f *File) ErrCount() int { return 2 }
-func (f *File) Fulfill(ctx context.Context, dispatchErr func(error)) error {
- e := newExporter(f.opts)
- if err := e.prepare(); err != nil {
- return err
- }
- f.Set(e.r)
- go func() {
- select {
- case err := <-e.exportErr:
- dispatchErr(nil)
- dispatchErr(err)
- case <-ctx.Done():
- dispatchErr(e.closeWrite())
- dispatchErr(<-e.exportErr)
- }
- }()
- return nil
-}
diff --git a/helper/seccomp/export.go b/helper/seccomp/export.go
deleted file mode 100644
index 95684235..00000000
--- a/helper/seccomp/export.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package seccomp
-
-import (
- "os"
- "runtime"
- "sync"
-)
-
-type exporter struct {
- opts SyscallOpts
- r, w *os.File
-
- prepareOnce sync.Once
- prepareErr error
- closeOnce sync.Once
- closeErr error
- exportErr <-chan error
-}
-
-func (e *exporter) prepare() error {
- e.prepareOnce.Do(func() {
- if r, w, err := os.Pipe(); err != nil {
- e.prepareErr = err
- return
- } else {
- e.r, e.w = r, w
- }
-
- ec := make(chan error, 1)
- go func(fd uintptr) {
- ec <- buildFilter(int(fd), e.opts)
- close(ec)
- _ = e.closeWrite()
- runtime.KeepAlive(e.w)
- }(e.w.Fd())
- e.exportErr = ec
- runtime.SetFinalizer(e, (*exporter).closeWrite)
- })
- return e.prepareErr
-}
-
-func (e *exporter) closeWrite() error {
- e.closeOnce.Do(func() {
- if e.w == nil {
- panic("closeWrite called on invalid exporter")
- }
- e.closeErr = e.w.Close()
-
- // no need for a finalizer anymore
- runtime.SetFinalizer(e, nil)
- })
-
- return e.closeErr
-}
-
-func newExporter(opts SyscallOpts) *exporter {
- return &exporter{opts: opts}
-}
diff --git a/helper/seccomp/export_test.go b/helper/seccomp/export_test.go
deleted file mode 100644
index ff6f250e..00000000
--- a/helper/seccomp/export_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package seccomp_test
-
-import (
- "crypto/sha512"
- "errors"
- "io"
- "log"
- "slices"
- "syscall"
- "testing"
-
- "git.gensokyo.uk/security/fortify/helper/seccomp"
-)
-
-func TestExport(t *testing.T) {
- testCases := []struct {
- name string
- opts seccomp.SyscallOpts
- want []byte
- wantErr bool
- }{
- {"compat", 0, []byte{
- 0x95, 0xec, 0x69, 0xd0, 0x17, 0x73, 0x3e, 0x07,
- 0x21, 0x60, 0xe0, 0xda, 0x80, 0xfd, 0xeb, 0xec,
- 0xdf, 0x27, 0xae, 0x81, 0x66, 0xf5, 0xe2, 0xa7,
- 0x31, 0x27, 0x0c, 0x98, 0xea, 0x2d, 0x29, 0x46,
- 0xcb, 0x52, 0x31, 0x02, 0x90, 0x63, 0x66, 0x8a,
- 0xf2, 0x15, 0x87, 0x91, 0x55, 0xda, 0x21, 0xac,
- 0xa7, 0x9b, 0x07, 0x0e, 0x04, 0xc0, 0xee, 0x9a,
- 0xcd, 0xf5, 0x8f, 0x55, 0xcf, 0xa8, 0x15, 0xa5,
- }, false},
- {"base", seccomp.FlagExt, []byte{
- 0xdc, 0x7f, 0x2e, 0x1c, 0x5e, 0x82, 0x9b, 0x79,
- 0xeb, 0xb7, 0xef, 0xc7, 0x59, 0x15, 0x0f, 0x54,
- 0xa8, 0x3a, 0x75, 0xc8, 0xdf, 0x6f, 0xee, 0x4d,
- 0xce, 0x5d, 0xad, 0xc4, 0x73, 0x6c, 0x58, 0x5d,
- 0x4d, 0xee, 0xbf, 0xeb, 0x3c, 0x79, 0x69, 0xaf,
- 0x3a, 0x07, 0x7e, 0x90, 0xb7, 0x7b, 0xb4, 0x74,
- 0x1d, 0xb0, 0x5d, 0x90, 0x99, 0x7c, 0x86, 0x59,
- 0xb9, 0x58, 0x91, 0x20, 0x6a, 0xc9, 0x95, 0x2d,
- }, false},
- {"everything", seccomp.FlagExt |
- seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel |
- seccomp.FlagMultiarch | seccomp.FlagLinux32 | seccomp.FlagCan |
- seccomp.FlagBluetooth, []byte{
- 0xe9, 0x9d, 0xd3, 0x45, 0xe1, 0x95, 0x41, 0x34,
- 0x73, 0xd3, 0xcb, 0xee, 0x07, 0xb4, 0xed, 0x57,
- 0xb9, 0x08, 0xbf, 0xa8, 0x9e, 0xa2, 0x07, 0x2f,
- 0xe9, 0x34, 0x82, 0x84, 0x7f, 0x50, 0xb5, 0xb7,
- 0x58, 0xda, 0x17, 0xe7, 0x4c, 0xa2, 0xbb, 0xc0,
- 0x08, 0x13, 0xde, 0x49, 0xa2, 0xb9, 0xbf, 0x83,
- 0x4c, 0x02, 0x4e, 0xd4, 0x88, 0x50, 0xbe, 0x69,
- 0xb6, 0x8a, 0x9a, 0x4c, 0x5f, 0x53, 0xa9, 0xdb,
- }, false},
- {"strict", seccomp.FlagExt |
- seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel, []byte{
- 0xe8, 0x80, 0x29, 0x8d, 0xf2, 0xbd, 0x67, 0x51,
- 0xd0, 0x04, 0x0f, 0xc2, 0x1b, 0xc0, 0xed, 0x4c,
- 0x00, 0xf9, 0x5d, 0xc0, 0xd7, 0xba, 0x50, 0x6c,
- 0x24, 0x4d, 0x8b, 0x8c, 0xf6, 0x86, 0x6d, 0xba,
- 0x8e, 0xf4, 0xa3, 0x32, 0x96, 0xf2, 0x87, 0xb6,
- 0x6c, 0xcc, 0xc1, 0xd7, 0x8e, 0x97, 0x02, 0x65,
- 0x97, 0xf8, 0x4c, 0xc7, 0xde, 0xc1, 0x57, 0x3e,
- 0x14, 0x89, 0x60, 0xfb, 0xd3, 0x5c, 0xd7, 0x35,
- }, false},
- {"strict compat", 0 |
- seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel, []byte{
- 0x39, 0x87, 0x1b, 0x93, 0xff, 0xaf, 0xc8, 0xb9,
- 0x79, 0xfc, 0xed, 0xc0, 0xb0, 0xc3, 0x7b, 0x9e,
- 0x03, 0x92, 0x2f, 0x5b, 0x02, 0x74, 0x8d, 0xc5,
- 0xc3, 0xc1, 0x7c, 0x92, 0x52, 0x7f, 0x6e, 0x02,
- 0x2e, 0xde, 0x1f, 0x48, 0xbf, 0xf5, 0x92, 0x46,
- 0xea, 0x45, 0x2c, 0x0d, 0x1d, 0xe5, 0x48, 0x27,
- 0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd,
- 0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa,
- }, false},
- }
-
- buf := make([]byte, 8)
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- seccomp.CPrintln = log.Println
- t.Cleanup(func() { seccomp.CPrintln = nil })
-
- e := seccomp.New(tc.opts)
- digest := sha512.New()
-
- if _, err := io.CopyBuffer(digest, e, buf); (err != nil) != tc.wantErr {
- t.Errorf("Exporter: error = %v, wantErr %v", err, tc.wantErr)
- return
- }
- if err := e.Close(); err != nil {
- t.Errorf("Close: error = %v", err)
- return
- }
- if got := digest.Sum(nil); slices.Compare(got, tc.want) != 0 {
- t.Fatalf("Export() hash = %x, want %x",
- got, tc.want)
- return
- }
- })
- }
-
- t.Run("close without use", func(t *testing.T) {
- e := seccomp.New(0)
- if err := e.Close(); !errors.Is(err, syscall.EINVAL) {
- t.Errorf("Close: error = %v", err)
- return
- }
- })
-
- t.Run("close partial read", func(t *testing.T) {
- e := seccomp.New(0)
- if _, err := e.Read(make([]byte, 0)); err != nil {
- t.Errorf("Read: error = %v", err)
- return
- }
- if err := e.Close(); err == nil || !errors.Is(err, syscall.ECANCELED) || !errors.Is(err, syscall.EBADF) {
- t.Errorf("Close: error = %v", err)
- return
- }
- })
-}
-
-func BenchmarkExport(b *testing.B) {
- buf := make([]byte, 8)
- for i := 0; i < b.N; i++ {
- e := seccomp.New(seccomp.FlagExt |
- seccomp.FlagDenyNS | seccomp.FlagDenyTTY | seccomp.FlagDenyDevel |
- seccomp.FlagMultiarch | seccomp.FlagLinux32 | seccomp.FlagCan |
- seccomp.FlagBluetooth)
- if _, err := io.CopyBuffer(io.Discard, e, buf); err != nil {
- b.Fatalf("cannot export: %v", err)
- }
- if err := e.Close(); err != nil {
- b.Fatalf("cannot close exporter: %v", err)
- }
- }
-}
diff --git a/helper/seccomp/seccomp-build.c b/helper/seccomp/seccomp-build.c
deleted file mode 100644
index 4b2114f4..00000000
--- a/helper/seccomp/seccomp-build.c
+++ /dev/null
@@ -1,302 +0,0 @@
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE // CLONE_NEWUSER
-#endif
-
-#include "seccomp-build.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/syscall.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/personality.h>
-#include <sched.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 f_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 & F_VERBOSE) F_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 f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts opts) {
- int32_t res = 0; // refer to resErr for meaning
- int allow_multiarch = opts & F_MULTIARCH;
- int allowed_personality = PER_LINUX;
-
- if (opts & F_LINUX32)
- allowed_personality = PER_LINUX32;
-
- // flatpak commit 4c3bf179e2e4a2a298cd1db1d045adaf3f564532
-
- struct f_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},
- };
-
- // fortify: project-specific extensions
- struct f_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 f_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},
- };
-
- // fortify: project-specific extensions
- struct f_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 f_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 f_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 f_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},
- };
-
- // fortify: project-specific extensions
- struct f_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;
- f_syscall_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, F_CAN },
- { AF_BLUETOOTH, F_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 & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns);
- if (opts & F_DENY_TTY) SECCOMP_RULESET_ADD(deny_tty);
- if (opts & F_DENY_DEVEL) SECCOMP_RULESET_ADD(deny_devel);
- if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu);
- if (opts & F_EXT) {
- SECCOMP_RULESET_ADD(deny_common_ext);
- if (opts & F_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;
-}
diff --git a/helper/seccomp/seccomp-build.h b/helper/seccomp/seccomp-build.h
deleted file mode 100644
index 7f1be761..00000000
--- a/helper/seccomp/seccomp-build.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <stdint.h>
-#include <seccomp.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
-
-typedef enum {
- F_VERBOSE = 1 << 0,
- F_EXT = 1 << 1,
- F_DENY_NS = 1 << 2,
- F_DENY_TTY = 1 << 3,
- F_DENY_DEVEL = 1 << 4,
- F_MULTIARCH = 1 << 5,
- F_LINUX32 = 1 << 6,
- F_CAN = 1 << 7,
- F_BLUETOOTH = 1 << 8,
-} f_syscall_opts;
-
-extern void F_println(char *v);
-int32_t f_build_filter(int *ret_p, int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts opts); \ No newline at end of file
diff --git a/helper/seccomp/seccomp.go b/helper/seccomp/seccomp.go
deleted file mode 100644
index 05c314c9..00000000
--- a/helper/seccomp/seccomp.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package seccomp
-
-/*
-#cgo linux pkg-config: --static libseccomp
-
-#include "seccomp-build.h"
-*/
-import "C"
-import (
- "errors"
- "fmt"
- "runtime"
- "syscall"
-)
-
-var CPrintln func(v ...any)
-
-// LibraryError represents a libseccomp error.
-type LibraryError struct {
- Prefix string
- Seccomp syscall.Errno
- Errno error
-}
-
-func (e *LibraryError) Error() string {
- if e.Seccomp == 0 {
- if e.Errno == nil {
- panic("invalid libseccomp error")
- }
- return fmt.Sprintf("%s: %s", e.Prefix, e.Errno)
- }
- if e.Errno == nil {
- return fmt.Sprintf("%s: %s", e.Prefix, e.Seccomp)
- }
- return fmt.Sprintf("%s: %s (%s)", e.Prefix, e.Seccomp, e.Errno)
-}
-
-func (e *LibraryError) Is(err error) bool {
- if e == nil {
- return err == nil
- }
- if ef, ok := err.(*LibraryError); ok {
- return *e == *ef
- }
- return (e.Seccomp != 0 && errors.Is(err, e.Seccomp)) ||
- (e.Errno != nil && errors.Is(err, e.Errno))
-}
-
-var resPrefix = [...]string{
- 0: "",
- 1: "seccomp_init failed",
- 2: "seccomp_arch_add failed",
- 3: "seccomp_arch_add failed (multiarch)",
- 4: "internal libseccomp failure",
- 5: "seccomp_rule_add failed",
- 6: "seccomp_export_bpf failed",
- 7: "seccomp_load failed",
-}
-
-type SyscallOpts = C.f_syscall_opts
-
-const (
- flagVerbose SyscallOpts = C.F_VERBOSE
- // FlagExt are project-specific extensions.
- FlagExt SyscallOpts = C.F_EXT
- // FlagDenyNS denies namespace setup syscalls.
- FlagDenyNS SyscallOpts = C.F_DENY_NS
- // FlagDenyTTY denies faking input.
- FlagDenyTTY SyscallOpts = C.F_DENY_TTY
- // FlagDenyDevel denies development-related syscalls.
- FlagDenyDevel SyscallOpts = C.F_DENY_DEVEL
- // FlagMultiarch allows multiarch/emulation.
- FlagMultiarch SyscallOpts = C.F_MULTIARCH
- // FlagLinux32 sets PER_LINUX32.
- FlagLinux32 SyscallOpts = C.F_LINUX32
- // FlagCan allows AF_CAN.
- FlagCan SyscallOpts = C.F_CAN
- // FlagBluetooth allows AF_BLUETOOTH.
- FlagBluetooth SyscallOpts = C.F_BLUETOOTH
-)
-
-func buildFilter(fd int, opts SyscallOpts) error {
- var (
- arch C.uint32_t = 0
- multiarch C.uint32_t = 0
- )
- switch runtime.GOARCH {
- case "386":
- arch = C.SCMP_ARCH_X86
- case "amd64":
- arch = C.SCMP_ARCH_X86_64
- multiarch = C.SCMP_ARCH_X86
- case "arm":
- arch = C.SCMP_ARCH_ARM
- case "arm64":
- arch = C.SCMP_ARCH_AARCH64
- multiarch = C.SCMP_ARCH_ARM
- }
-
- // this removes repeated transitions between C and Go execution
- // when producing log output via F_println and CPrintln is nil
- if CPrintln != nil {
- opts |= flagVerbose
- }
-
- var ret C.int
- res, err := C.f_build_filter(&ret, C.int(fd), arch, multiarch, opts)
- if prefix := resPrefix[res]; prefix != "" {
- return &LibraryError{
- prefix,
- -syscall.Errno(ret),
- err,
- }
- }
- return err
-}
-
-//export F_println
-func F_println(v *C.char) {
- if CPrintln != nil {
- CPrintln(C.GoString(v))
- }
-}
diff --git a/helper/seccomp/seccomp_test.go b/helper/seccomp/seccomp_test.go
deleted file mode 100644
index c04179c1..00000000
--- a/helper/seccomp/seccomp_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package seccomp_test
-
-import (
- "errors"
- "runtime"
- "syscall"
- "testing"
-
- "git.gensokyo.uk/security/fortify/helper/seccomp"
-)
-
-func TestLibraryError(t *testing.T) {
- testCases := []struct {
- name string
- sample *seccomp.LibraryError
- want string
- wantIs bool
- compare error
- }{
- {
- "full",
- &seccomp.LibraryError{Prefix: "seccomp_export_bpf failed", Seccomp: syscall.ECANCELED, Errno: syscall.EBADF},
- "seccomp_export_bpf failed: operation canceled (bad file descriptor)",
- true,
- &seccomp.LibraryError{Prefix: "seccomp_export_bpf failed", Seccomp: syscall.ECANCELED, Errno: syscall.EBADF},
- },
- {
- "errno only",
- &seccomp.LibraryError{Prefix: "seccomp_init failed", Errno: syscall.ENOMEM},
- "seccomp_init failed: cannot allocate memory",
- false,
- nil,
- },
- {
- "seccomp only",
- &seccomp.LibraryError{Prefix: "internal libseccomp failure", Seccomp: syscall.EFAULT},
- "internal libseccomp failure: bad address",
- true,
- syscall.EFAULT,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- if errors.Is(tc.sample, tc.compare) != tc.wantIs {
- t.Errorf("errors.Is(%#v, %#v) did not return %v",
- tc.sample, tc.compare, tc.wantIs)
- }
-
- if got := tc.sample.Error(); got != tc.want {
- t.Errorf("Error: %q, want %q",
- got, tc.want)
- }
- })
- }
-
- t.Run("invalid", func(t *testing.T) {
- wantPanic := "invalid libseccomp error"
- defer func() {
- if r := recover(); r != wantPanic {
- t.Errorf("panic: %q, want %q", r, wantPanic)
- }
- }()
- runtime.KeepAlive(new(seccomp.LibraryError).Error())
- })
-}