1// +build linux
2
3// Public API specification for libseccomp Go bindings
4// Contains public API for the bindings
5
6// Package seccomp provides bindings for libseccomp, a library wrapping the Linux
7// seccomp syscall. Seccomp enables an application to restrict system call use
8// for itself and its children.
9package seccomp
10
11import (
12	"fmt"
13	"os"
14	"runtime"
15	"strings"
16	"sync"
17	"syscall"
18	"unsafe"
19)
20
21// C wrapping code
22
23// #cgo pkg-config: libseccomp
24// #include <stdlib.h>
25// #include <seccomp.h>
26import "C"
27
28// Exported types
29
30// ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a
31// per-architecture basis.
32type ScmpArch uint
33
34// ScmpAction represents an action to be taken on a filter rule match in
35// libseccomp
36type ScmpAction uint
37
38// ScmpCompareOp represents a comparison operator which can be used in a filter
39// rule
40type ScmpCompareOp uint
41
42// ScmpCondition represents a rule in a libseccomp filter context
43type ScmpCondition struct {
44	Argument uint          `json:"argument,omitempty"`
45	Op       ScmpCompareOp `json:"operator,omitempty"`
46	Operand1 uint64        `json:"operand_one,omitempty"`
47	Operand2 uint64        `json:"operand_two,omitempty"`
48}
49
50// ScmpSyscall represents a Linux System Call
51type ScmpSyscall int32
52
53// Exported Constants
54
55const (
56	// Valid architectures recognized by libseccomp
57	// ARM64 and all MIPS architectures are unsupported by versions of the
58	// library before v2.2 and will return errors if used
59
60	// ArchInvalid is a placeholder to ensure uninitialized ScmpArch
61	// variables are invalid
62	ArchInvalid ScmpArch = iota
63	// ArchNative is the native architecture of the kernel
64	ArchNative ScmpArch = iota
65	// ArchX86 represents 32-bit x86 syscalls
66	ArchX86 ScmpArch = iota
67	// ArchAMD64 represents 64-bit x86-64 syscalls
68	ArchAMD64 ScmpArch = iota
69	// ArchX32 represents 64-bit x86-64 syscalls (32-bit pointers)
70	ArchX32 ScmpArch = iota
71	// ArchARM represents 32-bit ARM syscalls
72	ArchARM ScmpArch = iota
73	// ArchARM64 represents 64-bit ARM syscalls
74	ArchARM64 ScmpArch = iota
75	// ArchMIPS represents 32-bit MIPS syscalls
76	ArchMIPS ScmpArch = iota
77	// ArchMIPS64 represents 64-bit MIPS syscalls
78	ArchMIPS64 ScmpArch = iota
79	// ArchMIPS64N32 represents 64-bit MIPS syscalls (32-bit pointers)
80	ArchMIPS64N32 ScmpArch = iota
81	// ArchMIPSEL represents 32-bit MIPS syscalls (little endian)
82	ArchMIPSEL ScmpArch = iota
83	// ArchMIPSEL64 represents 64-bit MIPS syscalls (little endian)
84	ArchMIPSEL64 ScmpArch = iota
85	// ArchMIPSEL64N32 represents 64-bit MIPS syscalls (little endian,
86	// 32-bit pointers)
87	ArchMIPSEL64N32 ScmpArch = iota
88	// ArchPPC represents 32-bit POWERPC syscalls
89	ArchPPC ScmpArch = iota
90	// ArchPPC64 represents 64-bit POWER syscalls (big endian)
91	ArchPPC64 ScmpArch = iota
92	// ArchPPC64LE represents 64-bit POWER syscalls (little endian)
93	ArchPPC64LE ScmpArch = iota
94	// ArchS390 represents 31-bit System z/390 syscalls
95	ArchS390 ScmpArch = iota
96	// ArchS390X represents 64-bit System z/390 syscalls
97	ArchS390X ScmpArch = iota
98)
99
100const (
101	// Supported actions on filter match
102
103	// ActInvalid is a placeholder to ensure uninitialized ScmpAction
104	// variables are invalid
105	ActInvalid ScmpAction = iota
106	// ActKill kills the process
107	ActKill ScmpAction = iota
108	// ActTrap throws SIGSYS
109	ActTrap ScmpAction = iota
110	// ActErrno causes the syscall to return a negative error code. This
111	// code can be set with the SetReturnCode method
112	ActErrno ScmpAction = iota
113	// ActTrace causes the syscall to notify tracing processes with the
114	// given error code. This code can be set with the SetReturnCode method
115	ActTrace ScmpAction = iota
116	// ActAllow permits the syscall to continue execution
117	ActAllow ScmpAction = iota
118)
119
120const (
121	// These are comparison operators used in conditional seccomp rules
122	// They are used to compare the value of a single argument of a syscall
123	// against a user-defined constant
124
125	// CompareInvalid is a placeholder to ensure uninitialized ScmpCompareOp
126	// variables are invalid
127	CompareInvalid ScmpCompareOp = iota
128	// CompareNotEqual returns true if the argument is not equal to the
129	// given value
130	CompareNotEqual ScmpCompareOp = iota
131	// CompareLess returns true if the argument is less than the given value
132	CompareLess ScmpCompareOp = iota
133	// CompareLessOrEqual returns true if the argument is less than or equal
134	// to the given value
135	CompareLessOrEqual ScmpCompareOp = iota
136	// CompareEqual returns true if the argument is equal to the given value
137	CompareEqual ScmpCompareOp = iota
138	// CompareGreaterEqual returns true if the argument is greater than or
139	// equal to the given value
140	CompareGreaterEqual ScmpCompareOp = iota
141	// CompareGreater returns true if the argument is greater than the given
142	// value
143	CompareGreater ScmpCompareOp = iota
144	// CompareMaskedEqual returns true if the argument is equal to the given
145	// value, when masked (bitwise &) against the second given value
146	CompareMaskedEqual ScmpCompareOp = iota
147)
148
149// Helpers for types
150
151// GetArchFromString returns an ScmpArch constant from a string representing an
152// architecture
153func GetArchFromString(arch string) (ScmpArch, error) {
154	switch strings.ToLower(arch) {
155	case "x86":
156		return ArchX86, nil
157	case "amd64", "x86-64", "x86_64", "x64":
158		return ArchAMD64, nil
159	case "x32":
160		return ArchX32, nil
161	case "arm":
162		return ArchARM, nil
163	case "arm64", "aarch64":
164		return ArchARM64, nil
165	case "mips":
166		return ArchMIPS, nil
167	case "mips64":
168		return ArchMIPS64, nil
169	case "mips64n32":
170		return ArchMIPS64N32, nil
171	case "mipsel":
172		return ArchMIPSEL, nil
173	case "mipsel64":
174		return ArchMIPSEL64, nil
175	case "mipsel64n32":
176		return ArchMIPSEL64N32, nil
177	case "ppc":
178		return ArchPPC, nil
179	case "ppc64":
180		return ArchPPC64, nil
181	case "ppc64le":
182		return ArchPPC64LE, nil
183	case "s390":
184		return ArchS390, nil
185	case "s390x":
186		return ArchS390X, nil
187	default:
188		return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %s", arch)
189	}
190}
191
192// String returns a string representation of an architecture constant
193func (a ScmpArch) String() string {
194	switch a {
195	case ArchX86:
196		return "x86"
197	case ArchAMD64:
198		return "amd64"
199	case ArchX32:
200		return "x32"
201	case ArchARM:
202		return "arm"
203	case ArchARM64:
204		return "arm64"
205	case ArchMIPS:
206		return "mips"
207	case ArchMIPS64:
208		return "mips64"
209	case ArchMIPS64N32:
210		return "mips64n32"
211	case ArchMIPSEL:
212		return "mipsel"
213	case ArchMIPSEL64:
214		return "mipsel64"
215	case ArchMIPSEL64N32:
216		return "mipsel64n32"
217	case ArchPPC:
218		return "ppc"
219	case ArchPPC64:
220		return "ppc64"
221	case ArchPPC64LE:
222		return "ppc64le"
223	case ArchS390:
224		return "s390"
225	case ArchS390X:
226		return "s390x"
227	case ArchNative:
228		return "native"
229	case ArchInvalid:
230		return "Invalid architecture"
231	default:
232		return "Unknown architecture"
233	}
234}
235
236// String returns a string representation of a comparison operator constant
237func (a ScmpCompareOp) String() string {
238	switch a {
239	case CompareNotEqual:
240		return "Not equal"
241	case CompareLess:
242		return "Less than"
243	case CompareLessOrEqual:
244		return "Less than or equal to"
245	case CompareEqual:
246		return "Equal"
247	case CompareGreaterEqual:
248		return "Greater than or equal to"
249	case CompareGreater:
250		return "Greater than"
251	case CompareMaskedEqual:
252		return "Masked equality"
253	case CompareInvalid:
254		return "Invalid comparison operator"
255	default:
256		return "Unrecognized comparison operator"
257	}
258}
259
260// String returns a string representation of a seccomp match action
261func (a ScmpAction) String() string {
262	switch a & 0xFFFF {
263	case ActKill:
264		return "Action: Kill Process"
265	case ActTrap:
266		return "Action: Send SIGSYS"
267	case ActErrno:
268		return fmt.Sprintf("Action: Return error code %d", (a >> 16))
269	case ActTrace:
270		return fmt.Sprintf("Action: Notify tracing processes with code %d",
271			(a >> 16))
272	case ActAllow:
273		return "Action: Allow system call"
274	default:
275		return "Unrecognized Action"
276	}
277}
278
279// SetReturnCode adds a return code to a supporting ScmpAction, clearing any
280// existing code Only valid on ActErrno and ActTrace. Takes no action otherwise.
281// Accepts 16-bit return code as argument.
282// Returns a valid ScmpAction of the original type with the new error code set.
283func (a ScmpAction) SetReturnCode(code int16) ScmpAction {
284	aTmp := a & 0x0000FFFF
285	if aTmp == ActErrno || aTmp == ActTrace {
286		return (aTmp | (ScmpAction(code)&0xFFFF)<<16)
287	}
288	return a
289}
290
291// GetReturnCode returns the return code of an ScmpAction
292func (a ScmpAction) GetReturnCode() int16 {
293	return int16(a >> 16)
294}
295
296// General utility functions
297
298// GetLibraryVersion returns the version of the library the bindings are built
299// against.
300// The version is formatted as follows: Major.Minor.Micro
301func GetLibraryVersion() (major, minor, micro int) {
302	return verMajor, verMinor, verMicro
303}
304
305// Syscall functions
306
307// GetName retrieves the name of a syscall from its number.
308// Acts on any syscall number.
309// Returns either a string containing the name of the syscall, or an error.
310func (s ScmpSyscall) GetName() (string, error) {
311	return s.GetNameByArch(ArchNative)
312}
313
314// GetNameByArch retrieves the name of a syscall from its number for a given
315// architecture.
316// Acts on any syscall number.
317// Accepts a valid architecture constant.
318// Returns either a string containing the name of the syscall, or an error.
319// if the syscall is unrecognized or an issue occurred.
320func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) {
321	if err := sanitizeArch(arch); err != nil {
322		return "", err
323	}
324
325	cString := C.seccomp_syscall_resolve_num_arch(arch.toNative(), C.int(s))
326	if cString == nil {
327		return "", fmt.Errorf("could not resolve syscall name")
328	}
329	defer C.free(unsafe.Pointer(cString))
330
331	finalStr := C.GoString(cString)
332	return finalStr, nil
333}
334
335// GetSyscallFromName returns the number of a syscall by name on the kernel's
336// native architecture.
337// Accepts a string containing the name of a syscall.
338// Returns the number of the syscall, or an error if no syscall with that name
339// was found.
340func GetSyscallFromName(name string) (ScmpSyscall, error) {
341	cString := C.CString(name)
342	defer C.free(unsafe.Pointer(cString))
343
344	result := C.seccomp_syscall_resolve_name(cString)
345	if result == scmpError {
346		return 0, fmt.Errorf("could not resolve name to syscall")
347	}
348
349	return ScmpSyscall(result), nil
350}
351
352// GetSyscallFromNameByArch returns the number of a syscall by name for a given
353// architecture's ABI.
354// Accepts the name of a syscall and an architecture constant.
355// Returns the number of the syscall, or an error if an invalid architecture is
356// passed or a syscall with that name was not found.
357func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) {
358	if err := sanitizeArch(arch); err != nil {
359		return 0, err
360	}
361
362	cString := C.CString(name)
363	defer C.free(unsafe.Pointer(cString))
364
365	result := C.seccomp_syscall_resolve_name_arch(arch.toNative(), cString)
366	if result == scmpError {
367		return 0, fmt.Errorf("could not resolve name to syscall")
368	}
369
370	return ScmpSyscall(result), nil
371}
372
373// MakeCondition creates and returns a new condition to attach to a filter rule.
374// Associated rules will only match if this condition is true.
375// Accepts the number the argument we are checking, and a comparison operator
376// and value to compare to.
377// The rule will match if argument $arg (zero-indexed) of the syscall is
378// $COMPARE_OP the provided comparison value.
379// Some comparison operators accept two values. Masked equals, for example,
380// will mask $arg of the syscall with the second value provided (via bitwise
381// AND) and then compare against the first value provided.
382// For example, in the less than or equal case, if the syscall argument was
383// 0 and the value provided was 1, the condition would match, as 0 is less
384// than or equal to 1.
385// Return either an error on bad argument or a valid ScmpCondition struct.
386func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCondition, error) {
387	var condStruct ScmpCondition
388
389	if comparison == CompareInvalid {
390		return condStruct, fmt.Errorf("invalid comparison operator")
391	} else if arg > 5 {
392		return condStruct, fmt.Errorf("syscalls only have up to 6 arguments")
393	} else if len(values) > 2 {
394		return condStruct, fmt.Errorf("conditions can have at most 2 arguments")
395	} else if len(values) == 0 {
396		return condStruct, fmt.Errorf("must provide at least one value to compare against")
397	}
398
399	condStruct.Argument = arg
400	condStruct.Op = comparison
401	condStruct.Operand1 = values[0]
402	if len(values) == 2 {
403		condStruct.Operand2 = values[1]
404	} else {
405		condStruct.Operand2 = 0 // Unused
406	}
407
408	return condStruct, nil
409}
410
411// Utility Functions
412
413// GetNativeArch returns architecture token representing the native kernel
414// architecture
415func GetNativeArch() (ScmpArch, error) {
416	arch := C.seccomp_arch_native()
417
418	return archFromNative(arch)
419}
420
421// Public Filter API
422
423// ScmpFilter represents a filter context in libseccomp.
424// A filter context is initially empty. Rules can be added to it, and it can
425// then be loaded into the kernel.
426type ScmpFilter struct {
427	filterCtx C.scmp_filter_ctx
428	valid     bool
429	lock      sync.Mutex
430}
431
432// NewFilter creates and returns a new filter context.
433// Accepts a default action to be taken for syscalls which match no rules in
434// the filter.
435// Returns a reference to a valid filter context, or nil and an error if the
436// filter context could not be created or an invalid default action was given.
437func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) {
438	if err := sanitizeAction(defaultAction); err != nil {
439		return nil, err
440	}
441
442	fPtr := C.seccomp_init(defaultAction.toNative())
443	if fPtr == nil {
444		return nil, fmt.Errorf("could not create filter")
445	}
446
447	filter := new(ScmpFilter)
448	filter.filterCtx = fPtr
449	filter.valid = true
450	runtime.SetFinalizer(filter, filterFinalizer)
451
452	return filter, nil
453}
454
455// IsValid determines whether a filter context is valid to use.
456// Some operations (Release and Merge) render filter contexts invalid and
457// consequently prevent further use.
458func (f *ScmpFilter) IsValid() bool {
459	f.lock.Lock()
460	defer f.lock.Unlock()
461
462	return f.valid
463}
464
465// Reset resets a filter context, removing all its existing state.
466// Accepts a new default action to be taken for syscalls which do not match.
467// Returns an error if the filter or action provided are invalid.
468func (f *ScmpFilter) Reset(defaultAction ScmpAction) error {
469	f.lock.Lock()
470	defer f.lock.Unlock()
471
472	if err := sanitizeAction(defaultAction); err != nil {
473		return err
474	} else if !f.valid {
475		return errBadFilter
476	}
477
478	retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative())
479	if retCode != 0 {
480		return syscall.Errno(-1 * retCode)
481	}
482
483	return nil
484}
485
486// Release releases a filter context, freeing its memory. Should be called after
487// loading into the kernel, when the filter is no longer needed.
488// After calling this function, the given filter is no longer valid and cannot
489// be used.
490// Release() will be invoked automatically when a filter context is garbage
491// collected, but can also be called manually to free memory.
492func (f *ScmpFilter) Release() {
493	f.lock.Lock()
494	defer f.lock.Unlock()
495
496	if !f.valid {
497		return
498	}
499
500	f.valid = false
501	C.seccomp_release(f.filterCtx)
502}
503
504// Merge merges two filter contexts.
505// The source filter src will be released as part of the process, and will no
506// longer be usable or valid after this call.
507// To be merged, filters must NOT share any architectures, and all their
508// attributes (Default Action, Bad Arch Action, No New Privs and TSync bools)
509// must match.
510// The filter src will be merged into the filter this is called on.
511// The architectures of the src filter not present in the destination, and all
512// associated rules, will be added to the destination.
513// Returns an error if merging the filters failed.
514func (f *ScmpFilter) Merge(src *ScmpFilter) error {
515	f.lock.Lock()
516	defer f.lock.Unlock()
517
518	src.lock.Lock()
519	defer src.lock.Unlock()
520
521	if !src.valid || !f.valid {
522		return fmt.Errorf("one or more of the filter contexts is invalid or uninitialized")
523	}
524
525	// Merge the filters
526	retCode := C.seccomp_merge(f.filterCtx, src.filterCtx)
527	if syscall.Errno(-1*retCode) == syscall.EINVAL {
528		return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter")
529	} else if retCode != 0 {
530		return syscall.Errno(-1 * retCode)
531	}
532
533	src.valid = false
534
535	return nil
536}
537
538// IsArchPresent checks if an architecture is present in a filter.
539// If a filter contains an architecture, it uses its default action for
540// syscalls which do not match rules in it, and its rules can match syscalls
541// for that ABI.
542// If a filter does not contain an architecture, all syscalls made to that
543// kernel ABI will fail with the filter's default Bad Architecture Action
544// (by default, killing the process).
545// Accepts an architecture constant.
546// Returns true if the architecture is present in the filter, false otherwise,
547// and an error on an invalid filter context, architecture constant, or an
548// issue with the call to libseccomp.
549func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) {
550	f.lock.Lock()
551	defer f.lock.Unlock()
552
553	if err := sanitizeArch(arch); err != nil {
554		return false, err
555	} else if !f.valid {
556		return false, errBadFilter
557	}
558
559	retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative())
560	if syscall.Errno(-1*retCode) == syscall.EEXIST {
561		// -EEXIST is "arch not present"
562		return false, nil
563	} else if retCode != 0 {
564		return false, syscall.Errno(-1 * retCode)
565	}
566
567	return true, nil
568}
569
570// AddArch adds an architecture to the filter.
571// Accepts an architecture constant.
572// Returns an error on invalid filter context or architecture token, or an
573// issue with the call to libseccomp.
574func (f *ScmpFilter) AddArch(arch ScmpArch) error {
575	f.lock.Lock()
576	defer f.lock.Unlock()
577
578	if err := sanitizeArch(arch); err != nil {
579		return err
580	} else if !f.valid {
581		return errBadFilter
582	}
583
584	// Libseccomp returns -EEXIST if the specified architecture is already
585	// present. Succeed silently in this case, as it's not fatal, and the
586	// architecture is present already.
587	retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative())
588	if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
589		return syscall.Errno(-1 * retCode)
590	}
591
592	return nil
593}
594
595// RemoveArch removes an architecture from the filter.
596// Accepts an architecture constant.
597// Returns an error on invalid filter context or architecture token, or an
598// issue with the call to libseccomp.
599func (f *ScmpFilter) RemoveArch(arch ScmpArch) error {
600	f.lock.Lock()
601	defer f.lock.Unlock()
602
603	if err := sanitizeArch(arch); err != nil {
604		return err
605	} else if !f.valid {
606		return errBadFilter
607	}
608
609	// Similar to AddArch, -EEXIST is returned if the arch is not present
610	// Succeed silently in that case, this is not fatal and the architecture
611	// is not present in the filter after RemoveArch
612	retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative())
613	if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
614		return syscall.Errno(-1 * retCode)
615	}
616
617	return nil
618}
619
620// Load loads a filter context into the kernel.
621// Returns an error if the filter context is invalid or the syscall failed.
622func (f *ScmpFilter) Load() error {
623	f.lock.Lock()
624	defer f.lock.Unlock()
625
626	if !f.valid {
627		return errBadFilter
628	}
629
630	if retCode := C.seccomp_load(f.filterCtx); retCode != 0 {
631		return syscall.Errno(-1 * retCode)
632	}
633
634	return nil
635}
636
637// GetDefaultAction returns the default action taken on a syscall which does not
638// match a rule in the filter, or an error if an issue was encountered
639// retrieving the value.
640func (f *ScmpFilter) GetDefaultAction() (ScmpAction, error) {
641	action, err := f.getFilterAttr(filterAttrActDefault)
642	if err != nil {
643		return 0x0, err
644	}
645
646	return actionFromNative(action)
647}
648
649// GetBadArchAction returns the default action taken on a syscall for an
650// architecture not in the filter, or an error if an issue was encountered
651// retrieving the value.
652func (f *ScmpFilter) GetBadArchAction() (ScmpAction, error) {
653	action, err := f.getFilterAttr(filterAttrActBadArch)
654	if err != nil {
655		return 0x0, err
656	}
657
658	return actionFromNative(action)
659}
660
661// GetNoNewPrivsBit returns the current state the No New Privileges bit will be set
662// to on the filter being loaded, or an error if an issue was encountered
663// retrieving the value.
664// The No New Privileges bit tells the kernel that new processes run with exec()
665// cannot gain more privileges than the process that ran exec().
666// For example, a process with No New Privileges set would be unable to exec
667// setuid/setgid executables.
668func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) {
669	noNewPrivs, err := f.getFilterAttr(filterAttrNNP)
670	if err != nil {
671		return false, err
672	}
673
674	if noNewPrivs == 0 {
675		return false, nil
676	}
677
678	return true, nil
679}
680
681// GetTsyncBit returns whether Thread Synchronization will be enabled on the
682// filter being loaded, or an error if an issue was encountered retrieving the
683// value.
684// Thread Sync ensures that all members of the thread group of the calling
685// process will share the same Seccomp filter set.
686// Tsync is a fairly recent addition to the Linux kernel and older kernels
687// lack support. If the running kernel does not support Tsync and it is
688// requested in a filter, Libseccomp will not enable TSync support and will
689// proceed as normal.
690// This function is unavailable before v2.2 of libseccomp and will return an
691// error.
692func (f *ScmpFilter) GetTsyncBit() (bool, error) {
693	tSync, err := f.getFilterAttr(filterAttrTsync)
694	if err != nil {
695		return false, err
696	}
697
698	if tSync == 0 {
699		return false, nil
700	}
701
702	return true, nil
703}
704
705// SetBadArchAction sets the default action taken on a syscall for an
706// architecture not in the filter, or an error if an issue was encountered
707// setting the value.
708func (f *ScmpFilter) SetBadArchAction(action ScmpAction) error {
709	if err := sanitizeAction(action); err != nil {
710		return err
711	}
712
713	return f.setFilterAttr(filterAttrActBadArch, action.toNative())
714}
715
716// SetNoNewPrivsBit sets the state of the No New Privileges bit, which will be
717// applied on filter load, or an error if an issue was encountered setting the
718// value.
719// Filters with No New Privileges set to 0 can only be loaded if the process
720// has the CAP_SYS_ADMIN capability.
721func (f *ScmpFilter) SetNoNewPrivsBit(state bool) error {
722	var toSet C.uint32_t = 0x0
723
724	if state {
725		toSet = 0x1
726	}
727
728	return f.setFilterAttr(filterAttrNNP, toSet)
729}
730
731// SetTsync sets whether Thread Synchronization will be enabled on the filter
732// being loaded. Returns an error if setting Tsync failed, or the filter is
733// invalid.
734// Thread Sync ensures that all members of the thread group of the calling
735// process will share the same Seccomp filter set.
736// Tsync is a fairly recent addition to the Linux kernel and older kernels
737// lack support. If the running kernel does not support Tsync and it is
738// requested in a filter, Libseccomp will not enable TSync support and will
739// proceed as normal.
740// This function is unavailable before v2.2 of libseccomp and will return an
741// error.
742func (f *ScmpFilter) SetTsync(enable bool) error {
743	var toSet C.uint32_t = 0x0
744
745	if enable {
746		toSet = 0x1
747	}
748
749	return f.setFilterAttr(filterAttrTsync, toSet)
750}
751
752// SetSyscallPriority sets a syscall's priority.
753// This provides a hint to the filter generator in libseccomp about the
754// importance of this syscall. High-priority syscalls are placed
755// first in the filter code, and incur less overhead (at the expense of
756// lower-priority syscalls).
757func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error {
758	f.lock.Lock()
759	defer f.lock.Unlock()
760
761	if !f.valid {
762		return errBadFilter
763	}
764
765	if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call),
766		C.uint8_t(priority)); retCode != 0 {
767		return syscall.Errno(-1 * retCode)
768	}
769
770	return nil
771}
772
773// AddRule adds a single rule for an unconditional action on a syscall.
774// Accepts the number of the syscall and the action to be taken on the call
775// being made.
776// Returns an error if an issue was encountered adding the rule.
777func (f *ScmpFilter) AddRule(call ScmpSyscall, action ScmpAction) error {
778	return f.addRuleGeneric(call, action, false, nil)
779}
780
781// AddRuleExact adds a single rule for an unconditional action on a syscall.
782// Accepts the number of the syscall and the action to be taken on the call
783// being made.
784// No modifications will be made to the rule, and it will fail to add if it
785// cannot be applied to the current architecture without modification.
786// The rule will function exactly as described, but it may not function identically
787// (or be able to be applied to) all architectures.
788// Returns an error if an issue was encountered adding the rule.
789func (f *ScmpFilter) AddRuleExact(call ScmpSyscall, action ScmpAction) error {
790	return f.addRuleGeneric(call, action, true, nil)
791}
792
793// AddRuleConditional adds a single rule for a conditional action on a syscall.
794// Returns an error if an issue was encountered adding the rule.
795// All conditions must match for the rule to match.
796// There is a bug in library versions below v2.2.1 which can, in some cases,
797// cause conditions to be lost when more than one are used. Consequently,
798// AddRuleConditional is disabled on library versions lower than v2.2.1
799func (f *ScmpFilter) AddRuleConditional(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error {
800	return f.addRuleGeneric(call, action, false, conds)
801}
802
803// AddRuleConditionalExact adds a single rule for a conditional action on a
804// syscall.
805// No modifications will be made to the rule, and it will fail to add if it
806// cannot be applied to the current architecture without modification.
807// The rule will function exactly as described, but it may not function identically
808// (or be able to be applied to) all architectures.
809// Returns an error if an issue was encountered adding the rule.
810// There is a bug in library versions below v2.2.1 which can, in some cases,
811// cause conditions to be lost when more than one are used. Consequently,
812// AddRuleConditionalExact is disabled on library versions lower than v2.2.1
813func (f *ScmpFilter) AddRuleConditionalExact(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error {
814	return f.addRuleGeneric(call, action, true, conds)
815}
816
817// ExportPFC output PFC-formatted, human-readable dump of a filter context's
818// rules to a file.
819// Accepts file to write to (must be open for writing).
820// Returns an error if writing to the file fails.
821func (f *ScmpFilter) ExportPFC(file *os.File) error {
822	f.lock.Lock()
823	defer f.lock.Unlock()
824
825	fd := file.Fd()
826
827	if !f.valid {
828		return errBadFilter
829	}
830
831	if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 {
832		return syscall.Errno(-1 * retCode)
833	}
834
835	return nil
836}
837
838// ExportBPF outputs Berkeley Packet Filter-formatted, kernel-readable dump of a
839// filter context's rules to a file.
840// Accepts file to write to (must be open for writing).
841// Returns an error if writing to the file fails.
842func (f *ScmpFilter) ExportBPF(file *os.File) error {
843	f.lock.Lock()
844	defer f.lock.Unlock()
845
846	fd := file.Fd()
847
848	if !f.valid {
849		return errBadFilter
850	}
851
852	if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 {
853		return syscall.Errno(-1 * retCode)
854	}
855
856	return nil
857}
858