3 // Internal functions for libseccomp Go bindings
4 // No exported functions
14 // Unexported C wrapping code - provides the C-Golang interface
15 // Get the seccomp header in scope
16 // Need stdlib.h for free() on cstrings
18 // #cgo pkg-config: libseccomp
23 #if SCMP_VER_MAJOR < 2
24 #error Minimum supported version of Libseccomp is v2.1.0
25 #elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 1
26 #error Minimum supported version of Libseccomp is v2.1.0
31 const uint32_t C_ARCH_BAD = ARCH_BAD;
33 #ifndef SCMP_ARCH_AARCH64
34 #define SCMP_ARCH_AARCH64 ARCH_BAD
37 #ifndef SCMP_ARCH_MIPS
38 #define SCMP_ARCH_MIPS ARCH_BAD
41 #ifndef SCMP_ARCH_MIPS64
42 #define SCMP_ARCH_MIPS64 ARCH_BAD
45 #ifndef SCMP_ARCH_MIPS64N32
46 #define SCMP_ARCH_MIPS64N32 ARCH_BAD
49 #ifndef SCMP_ARCH_MIPSEL
50 #define SCMP_ARCH_MIPSEL ARCH_BAD
53 #ifndef SCMP_ARCH_MIPSEL64
54 #define SCMP_ARCH_MIPSEL64 ARCH_BAD
57 #ifndef SCMP_ARCH_MIPSEL64N32
58 #define SCMP_ARCH_MIPSEL64N32 ARCH_BAD
62 #define SCMP_ARCH_PPC ARCH_BAD
65 #ifndef SCMP_ARCH_PPC64
66 #define SCMP_ARCH_PPC64 ARCH_BAD
69 #ifndef SCMP_ARCH_PPC64LE
70 #define SCMP_ARCH_PPC64LE ARCH_BAD
73 #ifndef SCMP_ARCH_S390
74 #define SCMP_ARCH_S390 ARCH_BAD
77 #ifndef SCMP_ARCH_S390X
78 #define SCMP_ARCH_S390X ARCH_BAD
81 const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
82 const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
83 const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
84 const uint32_t C_ARCH_X32 = SCMP_ARCH_X32;
85 const uint32_t C_ARCH_ARM = SCMP_ARCH_ARM;
86 const uint32_t C_ARCH_AARCH64 = SCMP_ARCH_AARCH64;
87 const uint32_t C_ARCH_MIPS = SCMP_ARCH_MIPS;
88 const uint32_t C_ARCH_MIPS64 = SCMP_ARCH_MIPS64;
89 const uint32_t C_ARCH_MIPS64N32 = SCMP_ARCH_MIPS64N32;
90 const uint32_t C_ARCH_MIPSEL = SCMP_ARCH_MIPSEL;
91 const uint32_t C_ARCH_MIPSEL64 = SCMP_ARCH_MIPSEL64;
92 const uint32_t C_ARCH_MIPSEL64N32 = SCMP_ARCH_MIPSEL64N32;
93 const uint32_t C_ARCH_PPC = SCMP_ARCH_PPC;
94 const uint32_t C_ARCH_PPC64 = SCMP_ARCH_PPC64;
95 const uint32_t C_ARCH_PPC64LE = SCMP_ARCH_PPC64LE;
96 const uint32_t C_ARCH_S390 = SCMP_ARCH_S390;
97 const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
99 const uint32_t C_ACT_KILL = SCMP_ACT_KILL;
100 const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP;
101 const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0);
102 const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0);
103 const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW;
105 // If TSync is not supported, make sure it doesn't map to a supported filter attribute
106 // Don't worry about major version < 2, the minimum version checks should catch that case
107 #if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2
108 #define SCMP_FLTATR_CTL_TSYNC _SCMP_CMP_MIN
111 const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
112 const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
113 const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
114 const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
116 const int C_CMP_NE = (int)SCMP_CMP_NE;
117 const int C_CMP_LT = (int)SCMP_CMP_LT;
118 const int C_CMP_LE = (int)SCMP_CMP_LE;
119 const int C_CMP_EQ = (int)SCMP_CMP_EQ;
120 const int C_CMP_GE = (int)SCMP_CMP_GE;
121 const int C_CMP_GT = (int)SCMP_CMP_GT;
122 const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ;
124 const int C_VERSION_MAJOR = SCMP_VER_MAJOR;
125 const int C_VERSION_MINOR = SCMP_VER_MINOR;
126 const int C_VERSION_MICRO = SCMP_VER_MICRO;
128 typedef struct scmp_arg_cmp* scmp_cast_t;
130 // Wrapper to create an scmp_arg_cmp struct
139 struct scmp_arg_cmp *s = malloc(sizeof(struct scmp_arg_cmp));
152 type scmpFilterAttr uint32
154 // Nonexported constants
157 filterAttrActDefault scmpFilterAttr = iota
158 filterAttrActBadArch scmpFilterAttr = iota
159 filterAttrNNP scmpFilterAttr = iota
160 filterAttrTsync scmpFilterAttr = iota
164 // An error return from certain libseccomp functions
166 // Comparison boundaries to check for architecture validity
167 archStart ScmpArch = ArchNative
168 archEnd ScmpArch = ArchS390X
169 // Comparison boundaries to check for action validity
170 actionStart ScmpAction = ActKill
171 actionEnd ScmpAction = ActAllow
172 // Comparison boundaries to check for comparison operator validity
173 compareOpStart ScmpCompareOp = CompareNotEqual
174 compareOpEnd ScmpCompareOp = CompareMaskedEqual
178 // Error thrown on bad filter context
179 errBadFilter = fmt.Errorf("filter is invalid or uninitialized")
180 // Constants representing library major, minor, and micro versions
181 verMajor = int(C.C_VERSION_MAJOR)
182 verMinor = int(C.C_VERSION_MINOR)
183 verMicro = int(C.C_VERSION_MICRO)
186 // Nonexported functions
188 // Check if library version is greater than or equal to the given one
189 func checkVersionAbove(major, minor, micro int) bool {
190 return (verMajor > major) ||
191 (verMajor == major && verMinor > minor) ||
192 (verMajor == major && verMinor == minor && verMicro >= micro)
195 // Init function: Verify library version is appropriate
197 if !checkVersionAbove(2, 1, 0) {
198 fmt.Fprintf(os.Stderr, "Libseccomp version too low: minimum supported is 2.1.0, detected %d.%d.%d", C.C_VERSION_MAJOR, C.C_VERSION_MINOR, C.C_VERSION_MICRO)
205 // Filter finalizer - ensure that kernel context for filters is freed
206 func filterFinalizer(f *ScmpFilter) {
210 // Get a raw filter attribute
211 func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
213 defer f.lock.Unlock()
216 return 0x0, errBadFilter
219 if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync {
220 return 0x0, fmt.Errorf("the thread synchronization attribute is not supported in this version of the library")
223 var attribute C.uint32_t
225 retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
227 return 0x0, syscall.Errno(-1 * retCode)
230 return attribute, nil
233 // Set a raw filter attribute
234 func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error {
236 defer f.lock.Unlock()
242 if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync {
243 return fmt.Errorf("the thread synchronization attribute is not supported in this version of the library")
246 retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
248 return syscall.Errno(-1 * retCode)
254 // DOES NOT LOCK OR CHECK VALIDITY
255 // Assumes caller has already done this
256 // Wrapper for seccomp_rule_add_... functions
257 func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, cond C.scmp_cast_t) error {
267 retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
269 retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
272 if syscall.Errno(-1*retCode) == syscall.EFAULT {
273 return fmt.Errorf("unrecognized syscall")
274 } else if syscall.Errno(-1*retCode) == syscall.EPERM {
275 return fmt.Errorf("requested action matches default action of filter")
276 } else if retCode != 0 {
277 return syscall.Errno(-1 * retCode)
283 // Generic add function for filter rules
284 func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error {
286 defer f.lock.Unlock()
293 if err := f.addRuleWrapper(call, action, exact, nil); err != nil {
297 // We don't support conditional filtering in library version v2.1
298 if !checkVersionAbove(2, 2, 1) {
299 return fmt.Errorf("conditional filtering requires libseccomp version >= 2.2.1")
302 for _, cond := range conds {
303 cmpStruct := C.make_struct_arg_cmp(C.uint(cond.Argument), cond.Op.toNative(), C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2))
304 defer C.free(cmpStruct)
306 if err := f.addRuleWrapper(call, action, exact, C.scmp_cast_t(cmpStruct)); err != nil {
317 // Helper - Sanitize Arch token input
318 func sanitizeArch(in ScmpArch) error {
319 if in < archStart || in > archEnd {
320 return fmt.Errorf("unrecognized architecture")
323 if in.toNative() == C.C_ARCH_BAD {
324 return fmt.Errorf("architecture is not supported on this version of the library")
330 func sanitizeAction(in ScmpAction) error {
331 inTmp := in & 0x0000FFFF
332 if inTmp < actionStart || inTmp > actionEnd {
333 return fmt.Errorf("unrecognized action")
336 if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
337 return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno")
343 func sanitizeCompareOp(in ScmpCompareOp) error {
344 if in < compareOpStart || in > compareOpEnd {
345 return fmt.Errorf("unrecognized comparison operator")
351 func archFromNative(a C.uint32_t) (ScmpArch, error) {
355 case C.C_ARCH_X86_64:
356 return ArchAMD64, nil
361 case C.C_ARCH_NATIVE:
362 return ArchNative, nil
363 case C.C_ARCH_AARCH64:
364 return ArchARM64, nil
367 case C.C_ARCH_MIPS64:
368 return ArchMIPS64, nil
369 case C.C_ARCH_MIPS64N32:
370 return ArchMIPS64N32, nil
371 case C.C_ARCH_MIPSEL:
372 return ArchMIPSEL, nil
373 case C.C_ARCH_MIPSEL64:
374 return ArchMIPSEL64, nil
375 case C.C_ARCH_MIPSEL64N32:
376 return ArchMIPSEL64N32, nil
380 return ArchPPC64, nil
381 case C.C_ARCH_PPC64LE:
382 return ArchPPC64LE, nil
386 return ArchS390X, nil
388 return 0x0, fmt.Errorf("unrecognized architecture")
392 // Only use with sanitized arches, no error handling
393 func (a ScmpArch) toNative() C.uint32_t {
398 return C.C_ARCH_X86_64
404 return C.C_ARCH_AARCH64
408 return C.C_ARCH_MIPS64
410 return C.C_ARCH_MIPS64N32
412 return C.C_ARCH_MIPSEL
414 return C.C_ARCH_MIPSEL64
415 case ArchMIPSEL64N32:
416 return C.C_ARCH_MIPSEL64N32
420 return C.C_ARCH_PPC64
422 return C.C_ARCH_PPC64LE
426 return C.C_ARCH_S390X
428 return C.C_ARCH_NATIVE
434 // Only use with sanitized ops, no error handling
435 func (a ScmpCompareOp) toNative() C.int {
437 case CompareNotEqual:
441 case CompareLessOrEqual:
445 case CompareGreaterEqual:
449 case CompareMaskedEqual:
450 return C.C_CMP_MASKED_EQ
456 func actionFromNative(a C.uint32_t) (ScmpAction, error) {
458 switch a & 0xFFFF0000 {
464 return ActErrno.SetReturnCode(int16(aTmp)), nil
466 return ActTrace.SetReturnCode(int16(aTmp)), nil
470 return 0x0, fmt.Errorf("unrecognized action")
474 // Only use with sanitized actions, no error handling
475 func (a ScmpAction) toNative() C.uint32_t {
482 return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16)
484 return C.C_ACT_TRACE | (C.uint32_t(a) >> 16)
492 // Internal only, assumes safe attribute
493 func (a scmpFilterAttr) toNative() uint32 {
495 case filterAttrActDefault:
496 return uint32(C.C_ATTRIBUTE_DEFAULT)
497 case filterAttrActBadArch:
498 return uint32(C.C_ATTRIBUTE_BADARCH)
500 return uint32(C.C_ATTRIBUTE_NNP)
501 case filterAttrTsync:
502 return uint32(C.C_ATTRIBUTE_TSYNC)