seccomp.go 29 KB

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