diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-10-13 18:49:58 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-10-13 18:51:35 +0900 |
| commit | 123d7fbfd5a2955dc5042c0a85211e376d5a8e65 (patch) | |
| tree | 7e03e35309083b81873f3cf1939d2f4d27d41659 /container/seccomp/libseccomp.go | |
| parent | 7638a44fa613f23434318bdf136723aa010e8638 (diff) | |
container/seccomp: remove export pipe
This was only useful when wrapping bwrap.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container/seccomp/libseccomp.go')
| -rw-r--r-- | container/seccomp/libseccomp.go | 96 |
1 files changed, 69 insertions, 27 deletions
diff --git a/container/seccomp/libseccomp.go b/container/seccomp/libseccomp.go index 21236a06..2044a668 100644 --- a/container/seccomp/libseccomp.go +++ b/container/seccomp/libseccomp.go @@ -3,7 +3,7 @@ package seccomp /* #cgo linux pkg-config: --static libseccomp -#include <libseccomp-helper.h> +#include "libseccomp-helper.h" #include <sys/personality.h> */ import "C" @@ -11,24 +11,22 @@ import ( "errors" "fmt" "runtime" + "runtime/cgo" "syscall" "unsafe" ) -const ( - PER_LINUX = C.PER_LINUX - PER_LINUX32 = C.PER_LINUX32 -) - -var ( - ErrInvalidRules = errors.New("invalid native rules slice") -) +// ErrInvalidRules is returned for a zero-length rules slice. +var ErrInvalidRules = errors.New("invalid native rules slice") // LibraryError represents a libseccomp error. type LibraryError struct { - Prefix string + // User facing description of the libseccomp function returning the error. + Prefix string + // Negated errno value returned by libseccomp. Seccomp syscall.Errno - Errno error + // Global errno value on return. + Errno error } func (e *LibraryError) Error() string { @@ -56,8 +54,10 @@ func (e *LibraryError) Is(err error) bool { } type ( + // ScmpSyscall represents a syscall number passed to libseccomp via [NativeRule.Syscall]. ScmpSyscall = C.int - ScmpErrno = C.int + // ScmpErrno represents an errno value passed to libseccomp via [NativeRule.Errno]. + ScmpErrno = C.int ) // A NativeRule specifies an arch-specific action taken by seccomp under certain conditions. @@ -88,12 +88,23 @@ var resPrefix = [...]string{ 3: "seccomp_arch_add failed (multiarch)", 4: "internal libseccomp failure", 5: "seccomp_rule_add failed", - 6: "seccomp_export_bpf failed", + 6: "seccomp_export_bpf_mem failed", 7: "seccomp_load failed", } -// Export streams filter contents to fd, or installs it to the current process if fd < 0. -func Export(fd int, rules []NativeRule, flags ExportFlag) error { +// cbAllocateBuffer is the function signature for the function handle passed to hakurei_export_filter +// which allocates the buffer that the resulting bpf program is copied into, and writes its slice header +// to a value held by the caller. +type cbAllocateBuffer = func(len C.size_t) (buf unsafe.Pointer) + +//export hakurei_scmp_allocate +func hakurei_scmp_allocate(f C.uintptr_t, len C.size_t) (buf unsafe.Pointer) { + return cgo.Handle(f).Value().(cbAllocateBuffer)(len) +} + +// makeFilter generates a bpf program from a slice of [NativeRule] and writes the resulting byte slice to p. +// The filter is installed to the current process if p is nil. +func makeFilter(rules []NativeRule, flags ExportFlag, p *[]byte) error { if len(rules) == 0 { return ErrInvalidRules } @@ -117,33 +128,56 @@ func Export(fd int, rules []NativeRule, flags ExportFlag) error { var ret C.int - var rulesPinner runtime.Pinner + var scmpPinner runtime.Pinner for i := range rules { rule := &rules[i] - rulesPinner.Pin(rule) + scmpPinner.Pin(rule) if rule.Arg != nil { - rulesPinner.Pin(rule.Arg) + scmpPinner.Pin(rule.Arg) } } - res, err := C.hakurei_export_filter( - &ret, C.int(fd), + + var allocateP cgo.Handle + if p != nil { + allocateP = cgo.NewHandle(func(len C.size_t) (buf unsafe.Pointer) { + // this is so the slice header gets a Go pointer + *p = make([]byte, len) + + buf = unsafe.Pointer(unsafe.SliceData(*p)) + scmpPinner.Pin(buf) + return + }) + } + + res, err := C.hakurei_scmp_make_filter( + &ret, C.uintptr_t(allocateP), arch, multiarch, (*C.struct_hakurei_syscall_rule)(unsafe.Pointer(&rules[0])), C.size_t(len(rules)), flags, ) - rulesPinner.Unpin() + scmpPinner.Unpin() + if p != nil { + allocateP.Delete() + } if prefix := resPrefix[res]; prefix != "" { - return &LibraryError{ - prefix, - -syscall.Errno(ret), - err, - } + return &LibraryError{prefix, syscall.Errno(-ret), err} } return err } +// Export generates a bpf program from a slice of [NativeRule]. +// Errors returned by libseccomp is wrapped in [LibraryError]. +func Export(rules []NativeRule, flags ExportFlag) (data []byte, err error) { + err = makeFilter(rules, flags, &data) + return +} + +// Load generates a bpf program from a slice of [NativeRule] and enforces it on the current process. +// Errors returned by libseccomp is wrapped in [LibraryError]. +func Load(rules []NativeRule, flags ExportFlag) error { return makeFilter(rules, flags, nil) } + // ScmpCompare is the equivalent of scmp_compare; // Comparison operators type ScmpCompare = C.enum_scmp_compare @@ -184,7 +218,15 @@ type ScmpArgCmp struct { DatumA, DatumB ScmpDatum } -// only used for testing +const ( + // PersonaLinux is passed in a [ScmpDatum] for filtering calls to syscall.SYS_PERSONALITY. + PersonaLinux = C.PER_LINUX + // PersonaLinux32 is passed in a [ScmpDatum] for filtering calls to syscall.SYS_PERSONALITY. + PersonaLinux32 = C.PER_LINUX32 +) + +// syscallResolveName resolves a syscall number by name via seccomp_syscall_resolve_name. +// This function is only for testing the lookup tables and included here for convenience. func syscallResolveName(s string) (trap int) { v := C.CString(s) trap = int(C.seccomp_syscall_resolve_name(v)) |
