seccomp_internal.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. // +build linux
  2. // Internal functions for libseccomp Go bindings
  3. // No exported functions
  4. package seccomp
  5. import (
  6. "fmt"
  7. "syscall"
  8. )
  9. // Unexported C wrapping code - provides the C-Golang interface
  10. // Get the seccomp header in scope
  11. // Need stdlib.h for free() on cstrings
  12. // #cgo pkg-config: libseccomp
  13. /*
  14. #include <errno.h>
  15. #include <stdlib.h>
  16. #include <seccomp.h>
  17. #if SCMP_VER_MAJOR < 2
  18. #error Minimum supported version of Libseccomp is v2.2.0
  19. #elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2
  20. #error Minimum supported version of Libseccomp is v2.2.0
  21. #endif
  22. #define ARCH_BAD ~0
  23. const uint32_t C_ARCH_BAD = ARCH_BAD;
  24. #ifndef SCMP_ARCH_PPC
  25. #define SCMP_ARCH_PPC ARCH_BAD
  26. #endif
  27. #ifndef SCMP_ARCH_PPC64
  28. #define SCMP_ARCH_PPC64 ARCH_BAD
  29. #endif
  30. #ifndef SCMP_ARCH_PPC64LE
  31. #define SCMP_ARCH_PPC64LE ARCH_BAD
  32. #endif
  33. #ifndef SCMP_ARCH_S390
  34. #define SCMP_ARCH_S390 ARCH_BAD
  35. #endif
  36. #ifndef SCMP_ARCH_S390X
  37. #define SCMP_ARCH_S390X ARCH_BAD
  38. #endif
  39. const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
  40. const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
  41. const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
  42. const uint32_t C_ARCH_X32 = SCMP_ARCH_X32;
  43. const uint32_t C_ARCH_ARM = SCMP_ARCH_ARM;
  44. const uint32_t C_ARCH_AARCH64 = SCMP_ARCH_AARCH64;
  45. const uint32_t C_ARCH_MIPS = SCMP_ARCH_MIPS;
  46. const uint32_t C_ARCH_MIPS64 = SCMP_ARCH_MIPS64;
  47. const uint32_t C_ARCH_MIPS64N32 = SCMP_ARCH_MIPS64N32;
  48. const uint32_t C_ARCH_MIPSEL = SCMP_ARCH_MIPSEL;
  49. const uint32_t C_ARCH_MIPSEL64 = SCMP_ARCH_MIPSEL64;
  50. const uint32_t C_ARCH_MIPSEL64N32 = SCMP_ARCH_MIPSEL64N32;
  51. const uint32_t C_ARCH_PPC = SCMP_ARCH_PPC;
  52. const uint32_t C_ARCH_PPC64 = SCMP_ARCH_PPC64;
  53. const uint32_t C_ARCH_PPC64LE = SCMP_ARCH_PPC64LE;
  54. const uint32_t C_ARCH_S390 = SCMP_ARCH_S390;
  55. const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
  56. #ifndef SCMP_ACT_LOG
  57. #define SCMP_ACT_LOG 0x7ffc0000U
  58. #endif
  59. const uint32_t C_ACT_KILL = SCMP_ACT_KILL;
  60. const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP;
  61. const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0);
  62. const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0);
  63. const uint32_t C_ACT_LOG = SCMP_ACT_LOG;
  64. const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW;
  65. // The libseccomp SCMP_FLTATR_CTL_LOG member of the scmp_filter_attr enum was
  66. // added in v2.4.0
  67. #if (SCMP_VER_MAJOR < 2) || \
  68. (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4)
  69. #define SCMP_FLTATR_CTL_LOG _SCMP_FLTATR_MIN
  70. #endif
  71. const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
  72. const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
  73. const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
  74. const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
  75. const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
  76. const int C_CMP_NE = (int)SCMP_CMP_NE;
  77. const int C_CMP_LT = (int)SCMP_CMP_LT;
  78. const int C_CMP_LE = (int)SCMP_CMP_LE;
  79. const int C_CMP_EQ = (int)SCMP_CMP_EQ;
  80. const int C_CMP_GE = (int)SCMP_CMP_GE;
  81. const int C_CMP_GT = (int)SCMP_CMP_GT;
  82. const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ;
  83. const int C_VERSION_MAJOR = SCMP_VER_MAJOR;
  84. const int C_VERSION_MINOR = SCMP_VER_MINOR;
  85. const int C_VERSION_MICRO = SCMP_VER_MICRO;
  86. #if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 3
  87. unsigned int get_major_version()
  88. {
  89. return seccomp_version()->major;
  90. }
  91. unsigned int get_minor_version()
  92. {
  93. return seccomp_version()->minor;
  94. }
  95. unsigned int get_micro_version()
  96. {
  97. return seccomp_version()->micro;
  98. }
  99. #else
  100. unsigned int get_major_version()
  101. {
  102. return (unsigned int)C_VERSION_MAJOR;
  103. }
  104. unsigned int get_minor_version()
  105. {
  106. return (unsigned int)C_VERSION_MINOR;
  107. }
  108. unsigned int get_micro_version()
  109. {
  110. return (unsigned int)C_VERSION_MICRO;
  111. }
  112. #endif
  113. // The libseccomp API level functions were added in v2.4.0
  114. #if (SCMP_VER_MAJOR < 2) || \
  115. (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4)
  116. const unsigned int seccomp_api_get(void)
  117. {
  118. // libseccomp-golang requires libseccomp v2.2.0, at a minimum, which
  119. // supported API level 2. However, the kernel may not support API level
  120. // 2 constructs which are the seccomp() system call and the TSYNC
  121. // filter flag. Return the "reserved" value of 0 here to indicate that
  122. // proper API level support is not available in libseccomp.
  123. return 0;
  124. }
  125. int seccomp_api_set(unsigned int level)
  126. {
  127. return -EOPNOTSUPP;
  128. }
  129. #endif
  130. typedef struct scmp_arg_cmp* scmp_cast_t;
  131. void* make_arg_cmp_array(unsigned int length)
  132. {
  133. return calloc(length, sizeof(struct scmp_arg_cmp));
  134. }
  135. // Wrapper to add an scmp_arg_cmp struct to an existing arg_cmp array
  136. void add_struct_arg_cmp(
  137. struct scmp_arg_cmp* arr,
  138. unsigned int pos,
  139. unsigned int arg,
  140. int compare,
  141. uint64_t a,
  142. uint64_t b
  143. )
  144. {
  145. arr[pos].arg = arg;
  146. arr[pos].op = compare;
  147. arr[pos].datum_a = a;
  148. arr[pos].datum_b = b;
  149. return;
  150. }
  151. */
  152. import "C"
  153. // Nonexported types
  154. type scmpFilterAttr uint32
  155. // Nonexported constants
  156. const (
  157. filterAttrActDefault scmpFilterAttr = iota
  158. filterAttrActBadArch scmpFilterAttr = iota
  159. filterAttrNNP scmpFilterAttr = iota
  160. filterAttrTsync scmpFilterAttr = iota
  161. filterAttrLog scmpFilterAttr = iota
  162. )
  163. const (
  164. // An error return from certain libseccomp functions
  165. scmpError C.int = -1
  166. // Comparison boundaries to check for architecture validity
  167. archStart ScmpArch = ArchNative
  168. archEnd ScmpArch = ArchS390X
  169. // Comparison boundaries to check for action validity
  170. actionStart ScmpAction = ActKill
  171. actionEnd ScmpAction = ActLog
  172. // Comparison boundaries to check for comparison operator validity
  173. compareOpStart ScmpCompareOp = CompareNotEqual
  174. compareOpEnd ScmpCompareOp = CompareMaskedEqual
  175. )
  176. var (
  177. // Error thrown on bad filter context
  178. errBadFilter = fmt.Errorf("filter is invalid or uninitialized")
  179. // Constants representing library major, minor, and micro versions
  180. verMajor = uint(C.get_major_version())
  181. verMinor = uint(C.get_minor_version())
  182. verMicro = uint(C.get_micro_version())
  183. )
  184. // Nonexported functions
  185. // Check if library version is greater than or equal to the given one
  186. func checkVersionAbove(major, minor, micro uint) bool {
  187. return (verMajor > major) ||
  188. (verMajor == major && verMinor > minor) ||
  189. (verMajor == major && verMinor == minor && verMicro >= micro)
  190. }
  191. // Ensure that the library is supported, i.e. >= 2.2.0.
  192. func ensureSupportedVersion() error {
  193. if !checkVersionAbove(2, 2, 0) {
  194. return VersionError{}
  195. }
  196. return nil
  197. }
  198. // Get the API level
  199. func getApi() (uint, error) {
  200. api := C.seccomp_api_get()
  201. if api == 0 {
  202. return 0, fmt.Errorf("API level operations are not supported")
  203. }
  204. return uint(api), nil
  205. }
  206. // Set the API level
  207. func setApi(api uint) error {
  208. if retCode := C.seccomp_api_set(C.uint(api)); retCode != 0 {
  209. if syscall.Errno(-1*retCode) == syscall.EOPNOTSUPP {
  210. return fmt.Errorf("API level operations are not supported")
  211. }
  212. return fmt.Errorf("could not set API level: %v", retCode)
  213. }
  214. return nil
  215. }
  216. // Filter helpers
  217. // Filter finalizer - ensure that kernel context for filters is freed
  218. func filterFinalizer(f *ScmpFilter) {
  219. f.Release()
  220. }
  221. // Get a raw filter attribute
  222. func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
  223. f.lock.Lock()
  224. defer f.lock.Unlock()
  225. if !f.valid {
  226. return 0x0, errBadFilter
  227. }
  228. var attribute C.uint32_t
  229. retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
  230. if retCode != 0 {
  231. return 0x0, syscall.Errno(-1 * retCode)
  232. }
  233. return attribute, nil
  234. }
  235. // Set a raw filter attribute
  236. func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error {
  237. f.lock.Lock()
  238. defer f.lock.Unlock()
  239. if !f.valid {
  240. return errBadFilter
  241. }
  242. retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
  243. if retCode != 0 {
  244. return syscall.Errno(-1 * retCode)
  245. }
  246. return nil
  247. }
  248. // DOES NOT LOCK OR CHECK VALIDITY
  249. // Assumes caller has already done this
  250. // Wrapper for seccomp_rule_add_... functions
  251. func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, length C.uint, cond C.scmp_cast_t) error {
  252. if length != 0 && cond == nil {
  253. return fmt.Errorf("null conditions list, but length is nonzero")
  254. }
  255. var retCode C.int
  256. if exact {
  257. retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
  258. } else {
  259. retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
  260. }
  261. if syscall.Errno(-1*retCode) == syscall.EFAULT {
  262. return fmt.Errorf("unrecognized syscall %#x", int32(call))
  263. } else if syscall.Errno(-1*retCode) == syscall.EPERM {
  264. return fmt.Errorf("requested action matches default action of filter")
  265. } else if syscall.Errno(-1*retCode) == syscall.EINVAL {
  266. return fmt.Errorf("two checks on same syscall argument")
  267. } else if retCode != 0 {
  268. return syscall.Errno(-1 * retCode)
  269. }
  270. return nil
  271. }
  272. // Generic add function for filter rules
  273. func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error {
  274. f.lock.Lock()
  275. defer f.lock.Unlock()
  276. if !f.valid {
  277. return errBadFilter
  278. }
  279. if len(conds) == 0 {
  280. if err := f.addRuleWrapper(call, action, exact, 0, nil); err != nil {
  281. return err
  282. }
  283. } else {
  284. // We don't support conditional filtering in library version v2.1
  285. if !checkVersionAbove(2, 2, 1) {
  286. return VersionError{
  287. message: "conditional filtering is not supported",
  288. minimum: "2.2.1",
  289. }
  290. }
  291. argsArr := C.make_arg_cmp_array(C.uint(len(conds)))
  292. if argsArr == nil {
  293. return fmt.Errorf("error allocating memory for conditions")
  294. }
  295. defer C.free(argsArr)
  296. for i, cond := range conds {
  297. C.add_struct_arg_cmp(C.scmp_cast_t(argsArr), C.uint(i),
  298. C.uint(cond.Argument), cond.Op.toNative(),
  299. C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2))
  300. }
  301. if err := f.addRuleWrapper(call, action, exact, C.uint(len(conds)), C.scmp_cast_t(argsArr)); err != nil {
  302. return err
  303. }
  304. }
  305. return nil
  306. }
  307. // Generic Helpers
  308. // Helper - Sanitize Arch token input
  309. func sanitizeArch(in ScmpArch) error {
  310. if in < archStart || in > archEnd {
  311. return fmt.Errorf("unrecognized architecture %#x", uint(in))
  312. }
  313. if in.toNative() == C.C_ARCH_BAD {
  314. return fmt.Errorf("architecture %v is not supported on this version of the library", in)
  315. }
  316. return nil
  317. }
  318. func sanitizeAction(in ScmpAction) error {
  319. inTmp := in & 0x0000FFFF
  320. if inTmp < actionStart || inTmp > actionEnd {
  321. return fmt.Errorf("unrecognized action %#x", uint(inTmp))
  322. }
  323. if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
  324. return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno")
  325. }
  326. return nil
  327. }
  328. func sanitizeCompareOp(in ScmpCompareOp) error {
  329. if in < compareOpStart || in > compareOpEnd {
  330. return fmt.Errorf("unrecognized comparison operator %#x", uint(in))
  331. }
  332. return nil
  333. }
  334. func archFromNative(a C.uint32_t) (ScmpArch, error) {
  335. switch a {
  336. case C.C_ARCH_X86:
  337. return ArchX86, nil
  338. case C.C_ARCH_X86_64:
  339. return ArchAMD64, nil
  340. case C.C_ARCH_X32:
  341. return ArchX32, nil
  342. case C.C_ARCH_ARM:
  343. return ArchARM, nil
  344. case C.C_ARCH_NATIVE:
  345. return ArchNative, nil
  346. case C.C_ARCH_AARCH64:
  347. return ArchARM64, nil
  348. case C.C_ARCH_MIPS:
  349. return ArchMIPS, nil
  350. case C.C_ARCH_MIPS64:
  351. return ArchMIPS64, nil
  352. case C.C_ARCH_MIPS64N32:
  353. return ArchMIPS64N32, nil
  354. case C.C_ARCH_MIPSEL:
  355. return ArchMIPSEL, nil
  356. case C.C_ARCH_MIPSEL64:
  357. return ArchMIPSEL64, nil
  358. case C.C_ARCH_MIPSEL64N32:
  359. return ArchMIPSEL64N32, nil
  360. case C.C_ARCH_PPC:
  361. return ArchPPC, nil
  362. case C.C_ARCH_PPC64:
  363. return ArchPPC64, nil
  364. case C.C_ARCH_PPC64LE:
  365. return ArchPPC64LE, nil
  366. case C.C_ARCH_S390:
  367. return ArchS390, nil
  368. case C.C_ARCH_S390X:
  369. return ArchS390X, nil
  370. default:
  371. return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a))
  372. }
  373. }
  374. // Only use with sanitized arches, no error handling
  375. func (a ScmpArch) toNative() C.uint32_t {
  376. switch a {
  377. case ArchX86:
  378. return C.C_ARCH_X86
  379. case ArchAMD64:
  380. return C.C_ARCH_X86_64
  381. case ArchX32:
  382. return C.C_ARCH_X32
  383. case ArchARM:
  384. return C.C_ARCH_ARM
  385. case ArchARM64:
  386. return C.C_ARCH_AARCH64
  387. case ArchMIPS:
  388. return C.C_ARCH_MIPS
  389. case ArchMIPS64:
  390. return C.C_ARCH_MIPS64
  391. case ArchMIPS64N32:
  392. return C.C_ARCH_MIPS64N32
  393. case ArchMIPSEL:
  394. return C.C_ARCH_MIPSEL
  395. case ArchMIPSEL64:
  396. return C.C_ARCH_MIPSEL64
  397. case ArchMIPSEL64N32:
  398. return C.C_ARCH_MIPSEL64N32
  399. case ArchPPC:
  400. return C.C_ARCH_PPC
  401. case ArchPPC64:
  402. return C.C_ARCH_PPC64
  403. case ArchPPC64LE:
  404. return C.C_ARCH_PPC64LE
  405. case ArchS390:
  406. return C.C_ARCH_S390
  407. case ArchS390X:
  408. return C.C_ARCH_S390X
  409. case ArchNative:
  410. return C.C_ARCH_NATIVE
  411. default:
  412. return 0x0
  413. }
  414. }
  415. // Only use with sanitized ops, no error handling
  416. func (a ScmpCompareOp) toNative() C.int {
  417. switch a {
  418. case CompareNotEqual:
  419. return C.C_CMP_NE
  420. case CompareLess:
  421. return C.C_CMP_LT
  422. case CompareLessOrEqual:
  423. return C.C_CMP_LE
  424. case CompareEqual:
  425. return C.C_CMP_EQ
  426. case CompareGreaterEqual:
  427. return C.C_CMP_GE
  428. case CompareGreater:
  429. return C.C_CMP_GT
  430. case CompareMaskedEqual:
  431. return C.C_CMP_MASKED_EQ
  432. default:
  433. return 0x0
  434. }
  435. }
  436. func actionFromNative(a C.uint32_t) (ScmpAction, error) {
  437. aTmp := a & 0xFFFF
  438. switch a & 0xFFFF0000 {
  439. case C.C_ACT_KILL:
  440. return ActKill, nil
  441. case C.C_ACT_TRAP:
  442. return ActTrap, nil
  443. case C.C_ACT_ERRNO:
  444. return ActErrno.SetReturnCode(int16(aTmp)), nil
  445. case C.C_ACT_TRACE:
  446. return ActTrace.SetReturnCode(int16(aTmp)), nil
  447. case C.C_ACT_LOG:
  448. return ActLog, nil
  449. case C.C_ACT_ALLOW:
  450. return ActAllow, nil
  451. default:
  452. return 0x0, fmt.Errorf("unrecognized action %#x", uint32(a))
  453. }
  454. }
  455. // Only use with sanitized actions, no error handling
  456. func (a ScmpAction) toNative() C.uint32_t {
  457. switch a & 0xFFFF {
  458. case ActKill:
  459. return C.C_ACT_KILL
  460. case ActTrap:
  461. return C.C_ACT_TRAP
  462. case ActErrno:
  463. return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16)
  464. case ActTrace:
  465. return C.C_ACT_TRACE | (C.uint32_t(a) >> 16)
  466. case ActLog:
  467. return C.C_ACT_LOG
  468. case ActAllow:
  469. return C.C_ACT_ALLOW
  470. default:
  471. return 0x0
  472. }
  473. }
  474. // Internal only, assumes safe attribute
  475. func (a scmpFilterAttr) toNative() uint32 {
  476. switch a {
  477. case filterAttrActDefault:
  478. return uint32(C.C_ATTRIBUTE_DEFAULT)
  479. case filterAttrActBadArch:
  480. return uint32(C.C_ATTRIBUTE_BADARCH)
  481. case filterAttrNNP:
  482. return uint32(C.C_ATTRIBUTE_NNP)
  483. case filterAttrTsync:
  484. return uint32(C.C_ATTRIBUTE_TSYNC)
  485. case filterAttrLog:
  486. return uint32(C.C_ATTRIBUTE_LOG)
  487. default:
  488. return 0x0
  489. }
  490. }