aboutsummaryrefslogtreecommitdiffhomepage
path: root/sandbox/seccomp/seccomp.go
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/seccomp/seccomp.go')
-rw-r--r--sandbox/seccomp/seccomp.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/sandbox/seccomp/seccomp.go b/sandbox/seccomp/seccomp.go
new file mode 100644
index 00000000..2e730479
--- /dev/null
+++ b/sandbox/seccomp/seccomp.go
@@ -0,0 +1,114 @@
+package seccomp
+
+/*
+#cgo linux pkg-config: --static libseccomp
+
+#include "seccomp-build.h"
+*/
+import "C"
+import (
+ "errors"
+ "fmt"
+ "runtime"
+ "syscall"
+)
+
+// 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 fp := printlnP.Load(); fp != 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
+}