123
seccomp/seccomp.go
Normal file
123
seccomp/seccomp.go
Normal file
@@ -0,0 +1,123 @@
|
||||
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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user