seccomp.go 26 KB

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