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