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