Compare commits

...

2 Commits

Author SHA1 Message Date
renovate[bot] 99f43c14c4
Merge 82d9bfbcaf into 7c6167725b 2025-04-23 22:02:44 +00:00
renovate[bot] 82d9bfbcaf
fix(deps): update module github.com/seccomp/libseccomp-golang to v0.11.0
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-23 22:02:41 +00:00
7 changed files with 281 additions and 71 deletions

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/containers/storage v1.58.0
github.com/iovisor/gobpf v0.2.1-0.20221005153822-16120a1bf4d4
github.com/opencontainers/runtime-spec v1.2.1
github.com/seccomp/libseccomp-golang v0.10.0
github.com/seccomp/libseccomp-golang v0.11.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0
)

4
go.sum
View File

@ -34,8 +34,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/seccomp/libseccomp-golang v0.11.0 h1:SDkcBRqGLP+sezmMACkxO1EfgbghxIxnRKfd6mHUEis=
github.com/seccomp/libseccomp-golang v0.11.0/go.mod h1:5m1Lk8E9OwgZTTVz4bBOer7JuazaBa+xTkM895tDiWc=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

View File

@ -1,4 +1,12 @@
# For documentation, see https://golangci-lint.run/usage/configuration/
linters:
version: "2"
formatters:
enable:
- gofumpt
linters:
exclusions:
generated: disable
presets:
- std-error-handling

View File

@ -2,6 +2,18 @@ libseccomp-golang: Releases
===============================================================================
https://github.com/seccomp/libseccomp-golang
* Version 0.11.0 - April 23, 2025
- Add new architectures (LOONGARCH64, M68K, SH, SHEB)
- Add support for SCMP_FLTATR_CTL_WAITKILL (GetWaitKill, SetWaitKill)
- Add support for filter precompute (Precompute)
- Add support for transactions (Transaction{Start,Commit,Reject})
- Add ExportBPFMem
- Improve documentation for struct fields
- Fix TestRuleAddAndLoad for ppc architecture
- Fix TestRuleAddAndLoad to not use magic number
- Remove unused get_*_version implementation
- Test against latest libseccomp and Go versions
* Version 0.10.0 - June 9, 2022
- Minimum supported version of libseccomp bumped to v2.3.1
- Add seccomp userspace notification API (ActNotify, filter.*Notif*)

View File

@ -17,8 +17,28 @@ import (
"unsafe"
)
// #include <stdlib.h>
// #include <seccomp.h>
/*
#include <errno.h>
#include <stdlib.h>
#include <seccomp.h>
// The following functions were added in libseccomp v2.6.0.
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 6
int seccomp_precompute(scmp_filter_ctx ctx) {
return -EOPNOTSUPP;
}
int seccomp_export_bpf_mem(const scmp_filter_ctx ctx, void *buf, size_t *len) {
return -EOPNOTSUPP;
}
int seccomp_transaction_start(const scmp_filter_ctx ctx) {
return -EOPNOTSUPP;
}
int seccomp_transaction_commit(const scmp_filter_ctx ctx) {
return -EOPNOTSUPP;
}
void seccomp_transaction_reject(const scmp_filter_ctx ctx) {}
#endif
*/
import "C"
// Exported types
@ -33,8 +53,9 @@ type VersionError struct {
func init() {
// This forces the cgo libseccomp to initialize its internal API support state,
// which is necessary on older versions of libseccomp in order to work
// which is necessary on older versions of libseccomp (< 2.5.0) in order to work
// correctly.
// TODO: remove once libseccomp < v2.5.0 is not supported.
_, _ = getAPI()
}
@ -78,49 +99,44 @@ type ScmpSyscall int32
type ScmpFd int32
// ScmpNotifData describes the system call context that triggered a notification.
//
// Syscall: the syscall number
// Arch: the filter architecture
// InstrPointer: address of the instruction that triggered a notification
// Args: arguments (up to 6) for the syscall
//
type ScmpNotifData struct {
Syscall ScmpSyscall `json:"syscall,omitempty"`
Arch ScmpArch `json:"arch,omitempty"`
InstrPointer uint64 `json:"instr_pointer,omitempty"`
Args []uint64 `json:"args,omitempty"`
// Syscall is the syscall number.
Syscall ScmpSyscall `json:"syscall,omitempty"`
// Arch is the filter architecture.
Arch ScmpArch `json:"arch,omitempty"`
// InstrPointer is the address of the instruction that triggered a notification.
InstrPointer uint64 `json:"instr_pointer,omitempty"`
// Args are the arguments (up to 6) for the syscall.
Args []uint64 `json:"args,omitempty"`
}
// ScmpNotifReq represents a seccomp userspace notification. See NotifReceive() for
// info on how to pull such a notification.
//
// ID: notification ID
// Pid: process that triggered the notification event
// Flags: filter flags (see seccomp(2))
// Data: system call context that triggered the notification
//
type ScmpNotifReq struct {
ID uint64 `json:"id,omitempty"`
Pid uint32 `json:"pid,omitempty"`
Flags uint32 `json:"flags,omitempty"`
Data ScmpNotifData `json:"data,omitempty"`
// ID is the notification ID.
ID uint64 `json:"id,omitempty"`
// Pid is the process that triggered the notification event.
Pid uint32 `json:"pid,omitempty"`
// Flags is filter flags (see seccomp(2)).
Flags uint32 `json:"flags,omitempty"`
// Data is system call context that triggered the notification.
Data ScmpNotifData `json:"data,omitempty"`
}
// ScmpNotifResp represents a seccomp userspace notification response. See NotifRespond()
// for info on how to push such a response.
//
// ID: notification ID (must match the corresponding ScmpNotifReq ID)
// Error: must be 0 if no error occurred, or an error constant from package
// syscall (e.g., syscall.EPERM, etc). In the latter case, it's used
// as an error return from the syscall that created the notification.
// Val: return value for the syscall that created the notification. Only
// relevant if Error is 0.
// Flags: userspace notification response flag (e.g., NotifRespFlagContinue)
//
type ScmpNotifResp struct {
ID uint64 `json:"id,omitempty"`
Error int32 `json:"error,omitempty"`
Val uint64 `json:"val,omitempty"`
// ID is the notification ID (must match the corresponding ScmpNotifReq ID).
ID uint64 `json:"id,omitempty"`
// Error must be 0 if no error occurred, or an error constant from
// package syscall (e.g., syscall.EPERM, etc). In the latter case, it
// is used as an error return from the syscall that created the
// notification.
Error int32 `json:"error,omitempty"`
// Val is a return value for the syscall that created the notification.
// Only relevant if Error is 0.
Val uint64 `json:"val,omitempty"`
// Flags is userspace notification response flag (e.g., NotifRespFlagContinue).
Flags uint32 `json:"flags,omitempty"`
}
@ -175,6 +191,14 @@ const (
ArchPARISC64
// ArchRISCV64 represents RISCV64
ArchRISCV64
// ArchLOONGARCH64 represents 64-bit LoongArch.
ArchLOONGARCH64
// ArchM68K represents 32-bit Motorola 68000.
ArchM68K
// ArchSH represents SuperH.
ArchSH
// ArchSHEB represents Big-endian SuperH.
ArchSHEB
)
const (
@ -306,6 +330,14 @@ func GetArchFromString(arch string) (ScmpArch, error) {
return ArchPARISC64, nil
case "riscv64":
return ArchRISCV64, nil
case "loongarch64":
return ArchLOONGARCH64, nil
case "m68k":
return ArchM68K, nil
case "sh":
return ArchSH, nil
case "sheb":
return ArchSHEB, nil
default:
return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %q", arch)
}
@ -352,6 +384,14 @@ func (a ScmpArch) String() string {
return "parisc64"
case ArchRISCV64:
return "riscv64"
case ArchLOONGARCH64:
return "loong64"
case ArchM68K:
return "m68k"
case ArchSH:
return "sh"
case ArchSHEB:
return "sheb"
case ArchNative:
return "native"
case ArchInvalid:
@ -798,6 +838,26 @@ func (f *ScmpFilter) RemoveArch(arch ScmpArch) error {
return nil
}
// Precompute precomputes the seccomp filter for later use by [Load] and
// similar functions. Not only does this improve performance of [Load],
// it also ensures that the seccomp filter can be loaded in an
// async-signal-safe manner if no changes have been made to the filter
// since it was precomputed.
func (f *ScmpFilter) Precompute() error {
f.lock.Lock()
defer f.lock.Unlock()
if !f.valid {
return errBadFilter
}
if retCode := C.seccomp_precompute(f.filterCtx); retCode != 0 {
return errRc(retCode)
}
return nil
}
// Load loads a filter context into the kernel.
// Returns an error if the filter context is invalid or the syscall failed.
func (f *ScmpFilter) Load() error {
@ -941,6 +1001,25 @@ func (f *ScmpFilter) GetRawRC() (bool, error) {
return true, nil
}
// GetWaitKill returns the current state of WaitKill flag,
// or an error if an issue was encountered retrieving the value.
// See SetWaitKill for more details.
func (f *ScmpFilter) GetWaitKill() (bool, error) {
val, err := f.getFilterAttr(filterAttrWaitKill)
if err != nil {
if e := checkAPI("GetWaitKill", 7, 2, 6, 0); e != nil {
err = e
}
return false, err
}
if val == 0 {
return false, nil
}
return true, nil
}
// SetBadArchAction sets the default action taken on a syscall for an
// architecture not in the filter, or an error if an issue was encountered
// setting the value.
@ -1053,6 +1132,25 @@ func (f *ScmpFilter) SetRawRC(state bool) error {
return err
}
// SetWaitKill sets whether libseccomp should request wait killable semantics
// when possible. Defaults to false.
func (f *ScmpFilter) SetWaitKill(state bool) error {
var toSet C.uint32_t = 0x0
if state {
toSet = 0x1
}
err := f.setFilterAttr(filterAttrWaitKill, toSet)
if err != nil {
if e := checkAPI("SetWaitKill", 7, 2, 6, 0); e != nil {
err = e
}
}
return err
}
// SetSyscallPriority sets a syscall's priority.
// This provides a hint to the filter generator in libseccomp about the
// importance of this syscall. High-priority syscalls are placed
@ -1154,6 +1252,30 @@ func (f *ScmpFilter) ExportBPF(file *os.File) error {
return nil
}
// ExportBPFMem is similar to [ExportBPF], except the data is written into
// a memory and returned as []byte.
func (f *ScmpFilter) ExportBPFMem() ([]byte, error) {
f.lock.Lock()
defer f.lock.Unlock()
if !f.valid {
return nil, errBadFilter
}
var len C.size_t
// Get the size required.
if retCode := C.seccomp_export_bpf_mem(f.filterCtx, unsafe.Pointer(nil), &len); retCode < 0 {
return nil, errRc(retCode)
}
// Get the data.
buf := make([]byte, int(len))
if retCode := C.seccomp_export_bpf_mem(f.filterCtx, unsafe.Pointer(&buf[0]), &len); retCode < 0 {
return nil, errRc(retCode)
}
return buf, nil
}
// Userspace Notification API
// GetNotifFd returns the userspace notification file descriptor associated with the given
@ -1186,3 +1308,53 @@ func NotifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error {
func NotifIDValid(fd ScmpFd, id uint64) error {
return notifIDValid(fd, id)
}
// TransactionStart starts a new seccomp filter transaction that the caller can
// use to perform any number of filter modifications which can then be
// committed to the filter using [TransactionCommit] or rejected using
// [TransactionReject]. It is important to note that transactions only affect
// the seccomp filter state while it is being managed by libseccomp; seccomp
// filters which have been loaded into the kernel can not be modified, only new
// seccomp filters can be added on top of the existing loaded filter stack.
func (f *ScmpFilter) TransactionStart() error {
f.lock.Lock()
defer f.lock.Unlock()
if !f.valid {
return errBadFilter
}
if retCode := C.seccomp_transaction_start(f.filterCtx); retCode < 0 {
return errRc(retCode)
}
return nil
}
// TransactionReject rejects a transaction started by [TransactionStart].
func (f *ScmpFilter) TransactionReject() {
f.lock.Lock()
defer f.lock.Unlock()
if !f.valid {
return
}
C.seccomp_transaction_reject(f.filterCtx)
}
// TransactionCommit commits a transaction started by [TransactionStart].
func (f *ScmpFilter) TransactionCommit() error {
f.lock.Lock()
defer f.lock.Unlock()
if !f.valid {
return errBadFilter
}
if retCode := C.seccomp_transaction_commit(f.filterCtx); retCode < 0 {
return errRc(retCode)
}
return nil
}

View File

@ -68,6 +68,22 @@ const uint32_t C_ARCH_BAD = ARCH_BAD;
#define SCMP_ARCH_RISCV64 ARCH_BAD
#endif
#ifndef SCMP_ARCH_LOONGARCH64
#define SCMP_ARCH_LOONGARCH64 ARCH_BAD
#endif
#ifndef SCMP_ARCH_M68K
#define SCMP_ARCH_M68K ARCH_BAD
#endif
#ifndef SCMP_ARCH_SH
#define SCMP_ARCH_SH ARCH_BAD
#endif
#ifndef SCMP_ARCH_SHEB
#define SCMP_ARCH_SHEB ARCH_BAD
#endif
const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
@ -88,6 +104,10 @@ const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
const uint32_t C_ARCH_PARISC = SCMP_ARCH_PARISC;
const uint32_t C_ARCH_PARISC64 = SCMP_ARCH_PARISC64;
const uint32_t C_ARCH_RISCV64 = SCMP_ARCH_RISCV64;
const uint32_t C_ARCH_LOONGARCH64 = SCMP_ARCH_LOONGARCH64;
const uint32_t C_ARCH_M68K = SCMP_ARCH_M68K;
const uint32_t C_ARCH_SH = SCMP_ARCH_SH;
const uint32_t C_ARCH_SHEB = SCMP_ARCH_SHEB;
#ifndef SCMP_ACT_LOG
#define SCMP_ACT_LOG 0x7ffc0000U
@ -128,6 +148,11 @@ const uint32_t C_ACT_NOTIFY = SCMP_ACT_NOTIFY;
#define SCMP_FLTATR_API_SYSRAWRC _SCMP_FLTATR_MIN
#endif
// Added in libseccomp v2.6.0.
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 6
#define SCMP_FLTATR_CTL_WAITKILL _SCMP_FLTATR_MIN
#endif
const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
@ -136,6 +161,7 @@ const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB;
const uint32_t C_ATTRIBUTE_OPTIMIZE = (uint32_t)SCMP_FLTATR_CTL_OPTIMIZE;
const uint32_t C_ATTRIBUTE_SYSRAWRC = (uint32_t)SCMP_FLTATR_API_SYSRAWRC;
const uint32_t C_ATTRIBUTE_WAITKILL = (uint32_t)SCMP_FLTATR_CTL_WAITKILL;
const int C_CMP_NE = (int)SCMP_CMP_NE;
const int C_CMP_LT = (int)SCMP_CMP_LT;
@ -145,11 +171,6 @@ const int C_CMP_GE = (int)SCMP_CMP_GE;
const int C_CMP_GT = (int)SCMP_CMP_GT;
const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ;
const int C_VERSION_MAJOR = SCMP_VER_MAJOR;
const int C_VERSION_MINOR = SCMP_VER_MINOR;
const int C_VERSION_MICRO = SCMP_VER_MICRO;
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 3
unsigned int get_major_version()
{
return seccomp_version()->major;
@ -164,22 +185,6 @@ unsigned int get_micro_version()
{
return seccomp_version()->micro;
}
#else
unsigned int get_major_version()
{
return (unsigned int)C_VERSION_MAJOR;
}
unsigned int get_minor_version()
{
return (unsigned int)C_VERSION_MINOR;
}
unsigned int get_micro_version()
{
return (unsigned int)C_VERSION_MICRO;
}
#endif
// The libseccomp API level functions were added in v2.4.0
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4
@ -284,6 +289,7 @@ const (
filterAttrSSB
filterAttrOptimize
filterAttrRawRC
filterAttrWaitKill
)
const (
@ -291,7 +297,7 @@ const (
scmpError C.int = -1
// Comparison boundaries to check for architecture validity
archStart ScmpArch = ArchNative
archEnd ScmpArch = ArchRISCV64
archEnd ScmpArch = ArchSHEB
// Comparison boundaries to check for action validity
actionStart ScmpAction = ActKillThread
actionEnd ScmpAction = ActKillProcess
@ -552,6 +558,14 @@ func archFromNative(a C.uint32_t) (ScmpArch, error) {
return ArchPARISC64, nil
case C.C_ARCH_RISCV64:
return ArchRISCV64, nil
case C.C_ARCH_LOONGARCH64:
return ArchLOONGARCH64, nil
case C.C_ARCH_M68K:
return ArchM68K, nil
case C.C_ARCH_SH:
return ArchSH, nil
case C.C_ARCH_SHEB:
return ArchSHEB, nil
default:
return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a))
}
@ -598,6 +612,14 @@ func (a ScmpArch) toNative() C.uint32_t {
return C.C_ARCH_PARISC64
case ArchRISCV64:
return C.C_ARCH_RISCV64
case ArchLOONGARCH64:
return C.C_ARCH_LOONGARCH64
case ArchM68K:
return C.C_ARCH_M68K
case ArchSH:
return C.C_ARCH_SH
case ArchSHEB:
return C.C_ARCH_SHEB
case ArchNative:
return C.C_ARCH_NATIVE
default:
@ -694,6 +716,8 @@ func (a scmpFilterAttr) toNative() uint32 {
return uint32(C.C_ATTRIBUTE_OPTIMIZE)
case filterAttrRawRC:
return uint32(C.C_ATTRIBUTE_SYSRAWRC)
case filterAttrWaitKill:
return uint32(C.C_ATTRIBUTE_WAITKILL)
default:
return 0x0
}
@ -794,10 +818,7 @@ func notifReceive(fd ScmpFd) (*ScmpNotifReq, error) {
if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 {
return nil, errRc(retCode)
}
defer func() {
C.seccomp_notify_free(req, resp)
}()
defer C.seccomp_notify_free(req, resp)
for {
retCode, errno := C.seccomp_notify_receive(C.int(fd), req)
@ -831,10 +852,7 @@ func notifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error {
if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 {
return errRc(retCode)
}
defer func() {
C.seccomp_notify_free(req, resp)
}()
defer C.seccomp_notify_free(req, resp)
scmpResp.toNative(resp)

4
vendor/modules.txt vendored
View File

@ -39,8 +39,8 @@ github.com/opencontainers/runtime-spec/specs-go
# github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
## explicit
github.com/pmezard/go-difflib/difflib
# github.com/seccomp/libseccomp-golang v0.10.0
## explicit; go 1.14
# github.com/seccomp/libseccomp-golang v0.11.0
## explicit; go 1.19
github.com/seccomp/libseccomp-golang
# github.com/sirupsen/logrus v1.9.3
## explicit; go 1.13