seccomp.go 36 KB

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