github.com/sdibtacm/sandbox@v0.0.0-20200320120712-60470cf803dc/units/seccomp/seccomp.go (about)

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