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