seccomp.go 26 KB

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