diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index df44b927..cd4f1350 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -61,7 +61,7 @@ }, { "ImportPath": "github.com/seccomp/libseccomp-golang", - "Rev": "4ad869ffe4033151a18ef08fc260213051d8388d" + "Rev": "1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1" } ] } diff --git a/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go b/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go index cd4d4e6d..cebafdfa 100644 --- a/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go +++ b/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go @@ -3,9 +3,9 @@ // Public API specification for libseccomp Go bindings // Contains public API for the bindings -// Provides bindings for libseccomp, a library wrapping the Linux seccomp -// syscall. Seccomp enables an application to restrict system call use for -// itself and its children. +// Package seccomp rovides bindings for libseccomp, a library wrapping the Linux +// seccomp syscall. Seccomp enables an application to restrict system call use +// for itself and its children. package seccomp import ( @@ -27,17 +27,19 @@ import "C" // Exported types -// Represents a CPU architecture. -// Seccomp can restrict syscalls on a per-architecture basis. +// ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a +// per-architecture basis. type ScmpArch uint -// Represents an action to be taken on a filter rule match in libseccomp +// ScmpAction represents an action to be taken on a filter rule match in +// libseccomp type ScmpAction uint -// Represents a comparison operator which can be used in a filter rule +// ScmpCompareOp represents a comparison operator which can be used in a filter +// rule type ScmpCompareOp uint -// Represents a rule in a libseccomp filter context +// ScmpCondition represents a rule in a libseccomp filter context type ScmpCondition struct { Argument uint `json:"argument,omitempty"` Op ScmpCompareOp `json:"operator,omitempty"` @@ -45,78 +47,99 @@ type ScmpCondition struct { Operand2 uint64 `json:"operand_two,omitempty"` } -// Represents a Linux System Call +// ScmpSyscall represents a Linux System Call type ScmpSyscall int32 // Exported Constants const ( // Valid architectures recognized by libseccomp + // ARM64 and all MIPS architectures are unsupported by versions of the + // library before v2.2 and will return errors if used - // Ensure uninitialized ScmpArch variables are invalid + // ArchInvalid is a placeholder to ensure uninitialized ScmpArch + // variables are invalid ArchInvalid ScmpArch = iota - // The native architecture of the kernel + // ArchNative is the native architecture of the kernel ArchNative ScmpArch = iota - // 32-bit x86 syscalls + // ArchX86 represents 32-bit x86 syscalls ArchX86 ScmpArch = iota - // 64-bit x86-64 syscalls + // ArchAMD64 represents 64-bit x86-64 syscalls ArchAMD64 ScmpArch = iota - // 64-bit x86-64 syscalls (32-bit pointers) + // ArchX32 represents 64-bit x86-64 syscalls (32-bit pointers) ArchX32 ScmpArch = iota - // 32-bit ARM syscalls + // ArchARM represents 32-bit ARM syscalls ArchARM ScmpArch = iota - // 64-bit ARM syscalls + // ArchARM64 represents 64-bit ARM syscalls ArchARM64 ScmpArch = iota - // 32-bit MIPS syscalls + // ArchMIPS represents 32-bit MIPS syscalls ArchMIPS ScmpArch = iota - // 64-bit MIPS syscalls + // ArchMIPS64 represents 64-bit MIPS syscalls ArchMIPS64 ScmpArch = iota - // 64-bit MIPS syscalls (32-bit pointers) + // ArchMIPS64N32 represents 64-bit MIPS syscalls (32-bit pointers) ArchMIPS64N32 ScmpArch = iota - // 32-bit MIPS syscalls (little endian) + // ArchMIPSEL represents 32-bit MIPS syscalls (little endian) ArchMIPSEL ScmpArch = iota - // 64-bit MIPS syscalls (little endian) + // ArchMIPSEL64 represents 64-bit MIPS syscalls (little endian) ArchMIPSEL64 ScmpArch = iota - // 64-bit MIPS syscalls (little endian, 32-bit pointers) + // ArchMIPSEL64N32 represents 64-bit MIPS syscalls (little endian, + // 32-bit pointers) ArchMIPSEL64N32 ScmpArch = iota ) const ( // Supported actions on filter match - // Ensure uninitialized ScmpAction variables are invalid + // ActInvalid is a placeholder to ensure uninitialized ScmpAction + // variables are invalid ActInvalid ScmpAction = iota - // Kill process + // ActKill kills the process ActKill ScmpAction = iota - // Throw SIGSYS + // ActTrap throws SIGSYS ActTrap ScmpAction = iota - // The syscall will return an negative error code - // This code can be set with the SetReturnCode method + // ActErrno causes the syscall to return a negative error code. This + // code can be set with the SetReturnCode method ActErrno ScmpAction = iota - // Notify tracing processes with given error code - // This code can be set with the SetReturnCode method + // ActTrace causes the syscall to notify tracing processes with the + // given error code. This code can be set with the SetReturnCode method ActTrace ScmpAction = iota - // Permit the syscall to continue execution + // ActAllow permits the syscall to continue execution ActAllow ScmpAction = iota ) const ( // These are comparison operators used in conditional seccomp rules + // They are used to compare the value of a single argument of a syscall + // against a user-defined constant - // Ensure uninitialized ScmpCompareOp variables are invalid - CompareInvalid ScmpCompareOp = iota - CompareNotEqual ScmpCompareOp = iota - CompareLess ScmpCompareOp = iota - CompareLessOrEqual ScmpCompareOp = iota - CompareEqual ScmpCompareOp = iota + // CompareInvalid is a placeholder to ensure uninitialized ScmpCompareOp + // variables are invalid + CompareInvalid ScmpCompareOp = iota + // CompareNotEqual returns true if the argument is not equal to the + // given value + CompareNotEqual ScmpCompareOp = iota + // CompareLess returns true if the argument is less than the given value + CompareLess ScmpCompareOp = iota + // CompareLessOrEqual returns true if the argument is less than or equal + // to the given value + CompareLessOrEqual ScmpCompareOp = iota + // CompareEqual returns true if the argument is equal to the given value + CompareEqual ScmpCompareOp = iota + // CompareGreaterEqual returns true if the argument is greater than or + // equal to the given value CompareGreaterEqual ScmpCompareOp = iota - CompareGreater ScmpCompareOp = iota - CompareMaskedEqual ScmpCompareOp = iota + // CompareGreater returns true if the argument is greater than the given + // value + CompareGreater ScmpCompareOp = iota + // CompareMaskedEqual returns true if the argument is equal to the given + // value, when masked (bitwise &) against the second given value + CompareMaskedEqual ScmpCompareOp = iota ) // Helpers for types -// Return an ScmpArch constant from a string representing an architecture +// GetArchFromString returns an ScmpArch constant from a string representing an +// architecture func GetArchFromString(arch string) (ScmpArch, error) { switch strings.ToLower(arch) { case "x86": @@ -142,11 +165,11 @@ func GetArchFromString(arch string) (ScmpArch, error) { case "mipsel64n32": return ArchMIPSEL64N32, nil default: - return ArchInvalid, fmt.Errorf("Cannot convert unrecognized string %s", arch) + return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %s", arch) } } -// Returns a string representation of an architecture constant +// String returns a string representation of an architecture constant func (a ScmpArch) String() string { switch a { case ArchX86: @@ -180,7 +203,7 @@ func (a ScmpArch) String() string { } } -// Returns a string representation of a comparison operator constant +// String returns a string representation of a comparison operator constant func (a ScmpCompareOp) String() string { switch a { case CompareNotEqual: @@ -204,7 +227,7 @@ func (a ScmpCompareOp) String() string { } } -// Returns a string representation of a seccomp match action +// String returns a string representation of a seccomp match action func (a ScmpAction) String() string { switch a & 0xFFFF { case ActKill: @@ -223,8 +246,8 @@ func (a ScmpAction) String() string { } } -// Add a return code to a supporting ScmpAction, clearing any existing code -// Only valid on ActErrno and ActTrace. Takes no action otherwise. +// SetReturnCode adds a return code to a supporting ScmpAction, clearing any +// existing code Only valid on ActErrno and ActTrace. Takes no action otherwise. // Accepts 16-bit return code as argument. // Returns a valid ScmpAction of the original type with the new error code set. func (a ScmpAction) SetReturnCode(code int16) ScmpAction { @@ -235,21 +258,31 @@ func (a ScmpAction) SetReturnCode(code int16) ScmpAction { return a } -// Get the return code of an ScmpAction +// GetReturnCode returns the return code of an ScmpAction func (a ScmpAction) GetReturnCode() int16 { return int16(a >> 16) } +// General utility functions + +// GetLibraryVersion returns the version of the library the bindings are built +// against. +// The version is formatted as follows: Major.Minor.Micro +func GetLibraryVersion() (major, minor, micro int) { + return verMajor, verMinor, verMicro +} + // Syscall functions -// Get the name of a syscall from its number. +// GetName retrieves the name of a syscall from its number. // Acts on any syscall number. // Returns either a string containing the name of the syscall, or an error. func (s ScmpSyscall) GetName() (string, error) { return s.GetNameByArch(ArchNative) } -// Get the name of a syscall from its number for a given architecture. +// GetNameByArch retrieves the name of a syscall from its number for a given +// architecture. // Acts on any syscall number. // Accepts a valid architecture constant. // Returns either a string containing the name of the syscall, or an error. @@ -261,7 +294,7 @@ func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) { cString := C.seccomp_syscall_resolve_num_arch(arch.toNative(), C.int(s)) if cString == nil { - return "", fmt.Errorf("Could not resolve syscall name") + return "", fmt.Errorf("could not resolve syscall name") } defer C.free(unsafe.Pointer(cString)) @@ -269,7 +302,8 @@ func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) { return finalStr, nil } -// Get the number of a syscall by name on the kernel's native architecture. +// GetSyscallFromName returns the number of a syscall by name on the kernel's +// native architecture. // Accepts a string containing the name of a syscall. // Returns the number of the syscall, or an error if no syscall with that name // was found. @@ -279,13 +313,14 @@ func GetSyscallFromName(name string) (ScmpSyscall, error) { result := C.seccomp_syscall_resolve_name(cString) if result == scmpError { - return 0, fmt.Errorf("Could not resolve name to syscall") + return 0, fmt.Errorf("could not resolve name to syscall") } return ScmpSyscall(result), nil } -// Get the number of a syscall by name for a given architecture's ABI. +// GetSyscallFromNameByArch returns the number of a syscall by name for a given +// architecture's ABI. // Accepts the name of a syscall and an architecture constant. // Returns the number of the syscall, or an error if an invalid architecture is // passed or a syscall with that name was not found. @@ -299,13 +334,13 @@ func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) { result := C.seccomp_syscall_resolve_name_arch(arch.toNative(), cString) if result == scmpError { - return 0, fmt.Errorf("Could not resolve name to syscall") + return 0, fmt.Errorf("could not resolve name to syscall") } return ScmpSyscall(result), nil } -// Make a new condition to attach to a filter rule. +// MakeCondition creates and returns a new condition to attach to a filter rule. // Associated rules will only match if this condition is true. // Accepts the number the argument we are checking, and a comparison operator // and value to compare to. @@ -322,13 +357,13 @@ func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCo var condStruct ScmpCondition if comparison == CompareInvalid { - return condStruct, fmt.Errorf("Invalid comparison operator!") + return condStruct, fmt.Errorf("invalid comparison operator") } else if arg > 5 { - return condStruct, fmt.Errorf("Syscalls only have up to 6 arguments!") + return condStruct, fmt.Errorf("syscalls only have up to 6 arguments") } else if len(values) > 2 { - return condStruct, fmt.Errorf("Conditions can have at most 2 arguments!") + return condStruct, fmt.Errorf("conditions can have at most 2 arguments") } else if len(values) == 0 { - return condStruct, fmt.Errorf("Must provide at least one value to compare against!") + return condStruct, fmt.Errorf("must provide at least one value to compare against") } condStruct.Argument = arg @@ -345,7 +380,8 @@ func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCo // Utility Functions -// Returns architecture token representing the native kernel architecture +// GetNativeArch returns architecture token representing the native kernel +// architecture func GetNativeArch() (ScmpArch, error) { arch := C.seccomp_arch_native() @@ -354,7 +390,7 @@ func GetNativeArch() (ScmpArch, error) { // Public Filter API -// Represents a filter context in libseccomp. +// ScmpFilter represents a filter context in libseccomp. // A filter context is initially empty. Rules can be added to it, and it can // then be loaded into the kernel. type ScmpFilter struct { @@ -363,7 +399,7 @@ type ScmpFilter struct { lock sync.Mutex } -// Create a new filter context. +// NewFilter creates and returns a new filter context. // Accepts a default action to be taken for syscalls which match no rules in // the filter. // Returns a reference to a valid filter context, or nil and an error if the @@ -375,7 +411,7 @@ func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) { fPtr := C.seccomp_init(defaultAction.toNative()) if fPtr == nil { - return nil, fmt.Errorf("Could not create filter") + return nil, fmt.Errorf("could not create filter") } filter := new(ScmpFilter) @@ -386,7 +422,7 @@ func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) { return filter, nil } -// Determine whether a filter context is valid to use. +// IsValid determines whether a filter context is valid to use. // Some operations (Release and Merge) render filter contexts invalid and // consequently prevent further use. func (f *ScmpFilter) IsValid() bool { @@ -396,7 +432,7 @@ func (f *ScmpFilter) IsValid() bool { return f.valid } -// Reset a filter context, removing all its existing state. +// Reset resets a filter context, removing all its existing state. // Accepts a new default action to be taken for syscalls which do not match. // Returns an error if the filter or action provided are invalid. func (f *ScmpFilter) Reset(defaultAction ScmpAction) error { @@ -406,7 +442,7 @@ func (f *ScmpFilter) Reset(defaultAction ScmpAction) error { if err := sanitizeAction(defaultAction); err != nil { return err } else if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative()) @@ -417,7 +453,7 @@ func (f *ScmpFilter) Reset(defaultAction ScmpAction) error { return nil } -// Releases a filter context, freeing its memory. Should be called after +// Release releases a filter context, freeing its memory. Should be called after // loading into the kernel, when the filter is no longer needed. // After calling this function, the given filter is no longer valid and cannot // be used. @@ -435,11 +471,12 @@ func (f *ScmpFilter) Release() { C.seccomp_release(f.filterCtx) } -// Merge two filter contexts. +// Merge merges two filter contexts. // The source filter src will be released as part of the process, and will no // longer be usable or valid after this call. // To be merged, filters must NOT share any architectures, and all their -// attributes must match. +// attributes (Default Action, Bad Arch Action, No New Privs and TSync bools) +// must match. // The filter src will be merged into the filter this is called on. // The architectures of the src filter not present in the destination, and all // associated rules, will be added to the destination. @@ -452,14 +489,13 @@ func (f *ScmpFilter) Merge(src *ScmpFilter) error { defer src.lock.Unlock() if !src.valid || !f.valid { - return fmt.Errorf( - "One or more of the filter contexts is invalid or uninitialized") + return fmt.Errorf("one or more of the filter contexts is invalid or uninitialized") } // Merge the filters retCode := C.seccomp_merge(f.filterCtx, src.filterCtx) if syscall.Errno(-1*retCode) == syscall.EINVAL { - return fmt.Errorf("Filters could not be merged due to a mismatch in attributes or invalid filter!") + return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter") } else if retCode != 0 { return syscall.Errno(-1 * retCode) } @@ -469,7 +505,7 @@ func (f *ScmpFilter) Merge(src *ScmpFilter) error { return nil } -// Check if an architecture is present in a filter. +// IsArchPresent checks if an architecture is present in a filter. // If a filter contains an architecture, it uses its default action for // syscalls which do not match rules in it, and its rules can match syscalls // for that ABI. @@ -487,7 +523,7 @@ func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) { if err := sanitizeArch(arch); err != nil { return false, err } else if !f.valid { - return false, fmt.Errorf("Filter is invalid or uninitialized") + return false, errBadFilter } retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative()) @@ -501,7 +537,7 @@ func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) { return true, nil } -// Add an architecture to the filter. +// AddArch adds an architecture to the filter. // Accepts an architecture constant. // Returns an error on invalid filter context or architecture token, or an // issue with the call to libseccomp. @@ -512,7 +548,7 @@ func (f *ScmpFilter) AddArch(arch ScmpArch) error { if err := sanitizeArch(arch); err != nil { return err } else if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } // Libseccomp returns -EEXIST if the specified architecture is already @@ -526,7 +562,7 @@ func (f *ScmpFilter) AddArch(arch ScmpArch) error { return nil } -// Remove an architecture from the filter. +// RemoveArch removes an architecture from the filter. // Accepts an architecture constant. // Returns an error on invalid filter context or architecture token, or an // issue with the call to libseccomp. @@ -537,7 +573,7 @@ func (f *ScmpFilter) RemoveArch(arch ScmpArch) error { if err := sanitizeArch(arch); err != nil { return err } else if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } // Similar to AddArch, -EEXIST is returned if the arch is not present @@ -551,14 +587,14 @@ func (f *ScmpFilter) RemoveArch(arch ScmpArch) error { return nil } -// Load a filter context into the kernel. +// Load loads a filter context into the kernel. // Returns an error if the filter context is invalid or the syscall failed. func (f *ScmpFilter) Load() error { f.lock.Lock() defer f.lock.Unlock() if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } if retCode := C.seccomp_load(f.filterCtx); retCode != 0 { @@ -568,10 +604,11 @@ func (f *ScmpFilter) Load() error { return nil } -// Returns the default action taken on a syscall which does not match a rule in -// the filter, or an error if an issue was encountered retrieving the value. +// GetDefaultAction returns the default action taken on a syscall which does not +// match a rule in the filter, or an error if an issue was encountered +// retrieving the value. func (f *ScmpFilter) GetDefaultAction() (ScmpAction, error) { - action, err := f.getFilterAttr(filterAttrActDefault, true) + action, err := f.getFilterAttr(filterAttrActDefault) if err != nil { return 0x0, err } @@ -579,10 +616,11 @@ func (f *ScmpFilter) GetDefaultAction() (ScmpAction, error) { return actionFromNative(action) } -// Returns the default action taken on a syscall for an architecture not in the -// filter, or an error if an issue was encountered retrieving the value. +// GetBadArchAction returns the default action taken on a syscall for an +// architecture not in the filter, or an error if an issue was encountered +// retrieving the value. func (f *ScmpFilter) GetBadArchAction() (ScmpAction, error) { - action, err := f.getFilterAttr(filterAttrActBadArch, true) + action, err := f.getFilterAttr(filterAttrActBadArch) if err != nil { return 0x0, err } @@ -590,15 +628,15 @@ func (f *ScmpFilter) GetBadArchAction() (ScmpAction, error) { return actionFromNative(action) } -// Returns the current state the No New Privileges bit will be set to on the -// filter being loaded, or an error if an issue was encountered retrieving the -// value. +// GetNoNewPrivsBit returns the current state the No New Privileges bit will be set +// to on the filter being loaded, or an error if an issue was encountered +// retrieving the value. // The No New Privileges bit tells the kernel that new processes run with exec() // cannot gain more privileges than the process that ran exec(). // For example, a process with No New Privileges set would be unable to exec // setuid/setgid executables. func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) { - noNewPrivs, err := f.getFilterAttr(filterAttrNNP, true) + noNewPrivs, err := f.getFilterAttr(filterAttrNNP) if err != nil { return false, err } @@ -610,16 +648,19 @@ func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) { return true, nil } -// Returns whether Thread Synchronization will be enabled on the filter being -// loaded, or an error if an issue was encountered retrieving the value. +// GetTsyncBit returns whether Thread Synchronization will be enabled on the +// filter being loaded, or an error if an issue was encountered retrieving the +// value. // Thread Sync ensures that all members of the thread group of the calling // process will share the same Seccomp filter set. // Tsync is a fairly recent addition to the Linux kernel and older kernels // lack support. If the running kernel does not support Tsync and it is // requested in a filter, Libseccomp will not enable TSync support and will // proceed as normal. +// This function is unavailable before v2.2 of libseccomp and will return an +// error. func (f *ScmpFilter) GetTsyncBit() (bool, error) { - tSync, err := f.getFilterAttr(filterAttrTsync, true) + tSync, err := f.getFilterAttr(filterAttrTsync) if err != nil { return false, err } @@ -631,8 +672,9 @@ func (f *ScmpFilter) GetTsyncBit() (bool, error) { return true, nil } -// Set the default action taken on a syscall for an architecture not in the -// filter, or an error if an issue was encountered setting the value. +// SetBadArchAction sets the default action taken on a syscall for an +// architecture not in the filter, or an error if an issue was encountered +// setting the value. func (f *ScmpFilter) SetBadArchAction(action ScmpAction) error { if err := sanitizeAction(action); err != nil { return err @@ -641,10 +683,11 @@ func (f *ScmpFilter) SetBadArchAction(action ScmpAction) error { return f.setFilterAttr(filterAttrActBadArch, action.toNative()) } -// Set the state of the No New Privileges bit, which will be applied on filter -// load, or an error if an issue was encountered setting the value. -// Filters with No New Privileges set to 0 can only be loaded with the -// CAP_SYS_ADMIN privilege. +// SetNoNewPrivsBit sets the state of the No New Privileges bit, which will be +// applied on filter load, or an error if an issue was encountered setting the +// value. +// Filters with No New Privileges set to 0 can only be loaded if the process +// has the CAP_SYS_ADMIN capability. func (f *ScmpFilter) SetNoNewPrivsBit(state bool) error { var toSet C.uint32_t = 0x0 @@ -655,14 +698,17 @@ func (f *ScmpFilter) SetNoNewPrivsBit(state bool) error { return f.setFilterAttr(filterAttrNNP, toSet) } -// Sets whether Thread Synchronization will be enabled on the filter being -// loaded. Returns an error if setting Tsync failed, or the filter is invalid. +// SetTsync sets whether Thread Synchronization will be enabled on the filter +// being loaded. Returns an error if setting Tsync failed, or the filter is +// invalid. // Thread Sync ensures that all members of the thread group of the calling // process will share the same Seccomp filter set. // Tsync is a fairly recent addition to the Linux kernel and older kernels // lack support. If the running kernel does not support Tsync and it is // requested in a filter, Libseccomp will not enable TSync support and will // proceed as normal. +// This function is unavailable before v2.2 of libseccomp and will return an +// error. func (f *ScmpFilter) SetTsync(enable bool) error { var toSet C.uint32_t = 0x0 @@ -673,7 +719,7 @@ func (f *ScmpFilter) SetTsync(enable bool) error { return f.setFilterAttr(filterAttrTsync, toSet) } -// Set a syscall's priority. +// SetSyscallPriority sets a syscall's priority. // This provides a hint to the filter generator in libseccomp about the // importance of this syscall. High-priority syscalls are placed // first in the filter code, and incur less overhead (at the expense of @@ -683,7 +729,7 @@ func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error defer f.lock.Unlock() if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call), @@ -694,7 +740,7 @@ func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error return nil } -// Add a single rule for an unconditional action on a syscall. +// AddRule adds a single rule for an unconditional action on a syscall. // Accepts the number of the syscall and the action to be taken on the call // being made. // Returns an error if an issue was encountered adding the rule. @@ -702,7 +748,7 @@ func (f *ScmpFilter) AddRule(call ScmpSyscall, action ScmpAction) error { return f.addRuleGeneric(call, action, false, nil) } -// Add a single rule for an unconditional action on a syscall. +// AddRuleExact adds a single rule for an unconditional action on a syscall. // Accepts the number of the syscall and the action to be taken on the call // being made. // No modifications will be made to the rule, and it will fail to add if it @@ -714,25 +760,32 @@ func (f *ScmpFilter) AddRuleExact(call ScmpSyscall, action ScmpAction) error { return f.addRuleGeneric(call, action, true, nil) } -// Add a single rule for a conditional action on a syscall. +// AddRuleConditional adds a single rule for a conditional action on a syscall. // Returns an error if an issue was encountered adding the rule. // All conditions must match for the rule to match. +// There is a bug in library versions below v2.2.1 which can, in some cases, +// cause conditions to be lost when more than one are used. Consequently, +// AddRuleConditional is disabled on library versions lower than v2.2.1 func (f *ScmpFilter) AddRuleConditional(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error { return f.addRuleGeneric(call, action, false, conds) } -// Add a single rule for a conditional action on a syscall. +// AddRuleConditionalExact adds a single rule for a conditional action on a +// syscall. // No modifications will be made to the rule, and it will fail to add if it // cannot be applied to the current architecture without modification. // The rule will function exactly as described, but it may not function identically // (or be able to be applied to) all architectures. // Returns an error if an issue was encountered adding the rule. +// There is a bug in library versions below v2.2.1 which can, in some cases, +// cause conditions to be lost when more than one are used. Consequently, +// AddRuleConditionalExact is disabled on library versions lower than v2.2.1 func (f *ScmpFilter) AddRuleConditionalExact(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error { return f.addRuleGeneric(call, action, true, conds) } -// Output PFC-formatted, human-readable dump of a filter context's rules to a -// file. +// ExportPFC output PFC-formatted, human-readable dump of a filter context's +// rules to a file. // Accepts file to write to (must be open for writing). // Returns an error if writing to the file fails. func (f *ScmpFilter) ExportPFC(file *os.File) error { @@ -742,7 +795,7 @@ func (f *ScmpFilter) ExportPFC(file *os.File) error { fd := file.Fd() if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 { @@ -752,8 +805,8 @@ func (f *ScmpFilter) ExportPFC(file *os.File) error { return nil } -// Output Berkeley Packet Filter-formatted, kernel-readable dump of a filter -// context's rules to a file. +// ExportBPF outputs Berkeley Packet Filter-formatted, kernel-readable dump of a +// filter context's rules to a file. // Accepts file to write to (must be open for writing). // Returns an error if writing to the file fails. func (f *ScmpFilter) ExportBPF(file *os.File) error { @@ -763,7 +816,7 @@ func (f *ScmpFilter) ExportBPF(file *os.File) error { fd := file.Fd() if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 { diff --git a/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go b/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go index b34cc74e..306ed175 100644 --- a/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go +++ b/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go @@ -20,12 +20,42 @@ import ( #include #include -#if SCMP_VER_MAJOR < 1 -#error Minimum supported version of Libseccomp is v2.2.1 -#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2 -#error Minimum supported version of Libseccomp is v2.2.1 -#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 2 && SCMP_VER_MICRO < 1 -#error Minimum supported version of Libseccomp is v2.2.1 +#if SCMP_VER_MAJOR < 2 +#error Minimum supported version of Libseccomp is v2.1.0 +#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 1 +#error Minimum supported version of Libseccomp is v2.1.0 +#endif + +#define ARCH_BAD ~0 + +const uint32_t C_ARCH_BAD = ARCH_BAD; + +#ifndef SCMP_ARCH_AARCH64 +#define SCMP_ARCH_AARCH64 ARCH_BAD +#endif + +#ifndef SCMP_ARCH_MIPS +#define SCMP_ARCH_MIPS ARCH_BAD +#endif + +#ifndef SCMP_ARCH_MIPS64 +#define SCMP_ARCH_MIPS64 ARCH_BAD +#endif + +#ifndef SCMP_ARCH_MIPS64N32 +#define SCMP_ARCH_MIPS64N32 ARCH_BAD +#endif + +#ifndef SCMP_ARCH_MIPSEL +#define SCMP_ARCH_MIPSEL ARCH_BAD +#endif + +#ifndef SCMP_ARCH_MIPSEL64 +#define SCMP_ARCH_MIPSEL64 ARCH_BAD +#endif + +#ifndef SCMP_ARCH_MIPSEL64N32 +#define SCMP_ARCH_MIPSEL64N32 ARCH_BAD #endif const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE; @@ -47,6 +77,12 @@ const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0); const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0); const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW; +// If TSync is not supported, make sure it doesn't map to a supported filter attribute +// Don't worry about major version < 2, the minimum version checks should catch that case +#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2 +#define SCMP_FLTATR_CTL_TSYNC _SCMP_CMP_MIN +#endif + const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT; const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH; const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP; @@ -73,7 +109,7 @@ make_struct_arg_cmp( int compare, uint64_t a, uint64_t b - ) + ) { struct scmp_arg_cmp *s = malloc(sizeof(struct scmp_arg_cmp)); @@ -113,29 +149,29 @@ const ( compareOpEnd ScmpCompareOp = CompareMaskedEqual ) +var ( + // Error thrown on bad filter context + errBadFilter = fmt.Errorf("filter is invalid or uninitialized") + // Constants representing library major, minor, and micro versions + verMajor = int(C.C_VERSION_MAJOR) + verMinor = int(C.C_VERSION_MINOR) + verMicro = int(C.C_VERSION_MICRO) +) + // Nonexported functions -// Exit with error, as provided version of Libseccomp is too low -func errorOnVersionTooLow() { - fmt.Fprintf(os.Stderr, "Libseccomp version too low: minimum supported is 2.2.1, detected %d.%d.%d", C.C_VERSION_MAJOR, C.C_VERSION_MINOR, C.C_VERSION_MICRO) - os.Exit(-1) +// Check if library version is greater than or equal to the given one +func checkVersionAbove(major, minor, micro int) bool { + return (verMajor > major) || + (verMajor == major && verMinor > minor) || + (verMajor == major && verMinor == minor && verMicro >= micro) } // Init function: Verify library version is appropriate func init() { - // No versions of the 1.x library are supported - if C.C_VERSION_MAJOR < 2 { - errorOnVersionTooLow() - } - - // Versions 2.0 and 2.1 are not supported - if C.C_VERSION_MAJOR == 2 && C.C_VERSION_MINOR < 2 { - errorOnVersionTooLow() - } - - // Version 2.2.0 is not supported - need at least 2.2.1 - if C.C_VERSION_MAJOR == 2 && C.C_VERSION_MINOR == 2 && C.C_VERSION_MICRO < 1 { - errorOnVersionTooLow() + if !checkVersionAbove(2, 1, 0) { + fmt.Fprintf(os.Stderr, "Libseccomp version too low: minimum supported is 2.1.0, detected %d.%d.%d", C.C_VERSION_MAJOR, C.C_VERSION_MINOR, C.C_VERSION_MICRO) + os.Exit(-1) } } @@ -147,14 +183,16 @@ func filterFinalizer(f *ScmpFilter) { } // Get a raw filter attribute -func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr, lock bool) (C.uint32_t, error) { - if lock { - f.lock.Lock() - defer f.lock.Unlock() +func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) { + f.lock.Lock() + defer f.lock.Unlock() - if !f.valid { - return 0x0, fmt.Errorf("Filter is invalid or uninitialized") - } + if !f.valid { + return 0x0, errBadFilter + } + + if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync { + return 0x0, fmt.Errorf("the thread synchronization attribute is not supported in this version of the library") } var attribute C.uint32_t @@ -173,7 +211,11 @@ func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error defer f.lock.Unlock() if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter + } + + if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync { + return fmt.Errorf("the thread synchronization attribute is not supported in this version of the library") } retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value) @@ -203,9 +245,9 @@ func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact b } if syscall.Errno(-1*retCode) == syscall.EFAULT { - return fmt.Errorf("Unrecognized syscall") + return fmt.Errorf("unrecognized syscall") } else if syscall.Errno(-1*retCode) == syscall.EPERM { - return fmt.Errorf("Requested action matches default action of filter") + return fmt.Errorf("requested action matches default action of filter") } else if retCode != 0 { return syscall.Errno(-1 * retCode) } @@ -215,12 +257,11 @@ func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact b // Generic add function for filter rules func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error { - f.lock.Lock() defer f.lock.Unlock() if !f.valid { - return fmt.Errorf("Filter is invalid or uninitialized") + return errBadFilter } if len(conds) == 0 { @@ -228,6 +269,11 @@ func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact b return err } } else { + // We don't support conditional filtering in library version v2.1 + if !checkVersionAbove(2, 2, 1) { + return fmt.Errorf("conditional filtering requires libseccomp version >= 2.2.1") + } + for _, cond := range conds { cmpStruct := C.make_struct_arg_cmp(C.uint(cond.Argument), cond.Op.toNative(), C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2)) defer C.free(cmpStruct) @@ -246,7 +292,11 @@ func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact b // Helper - Sanitize Arch token input func sanitizeArch(in ScmpArch) error { if in < archStart || in > archEnd { - return fmt.Errorf("Unrecognized architecture") + return fmt.Errorf("unrecognized architecture") + } + + if in.toNative() == C.C_ARCH_BAD { + return fmt.Errorf("architecture is not supported on this version of the library") } return nil @@ -255,12 +305,11 @@ func sanitizeArch(in ScmpArch) error { func sanitizeAction(in ScmpAction) error { inTmp := in & 0x0000FFFF if inTmp < actionStart || inTmp > actionEnd { - return fmt.Errorf("Unrecognized action") + return fmt.Errorf("unrecognized action") } if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 { - return fmt.Errorf("Highest 16 bits must be zeroed except for Trace " + - "and Errno") + return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno") } return nil @@ -268,7 +317,7 @@ func sanitizeAction(in ScmpAction) error { func sanitizeCompareOp(in ScmpCompareOp) error { if in < compareOpStart || in > compareOpEnd { - return fmt.Errorf("Unrecognized comparison operator") + return fmt.Errorf("unrecognized comparison operator") } return nil @@ -301,7 +350,7 @@ func archFromNative(a C.uint32_t) (ScmpArch, error) { case C.C_ARCH_MIPSEL64N32: return ArchMIPSEL64N32, nil default: - return 0x0, fmt.Errorf("Unrecognized architecture") + return 0x0, fmt.Errorf("unrecognized architecture") } } @@ -373,7 +422,7 @@ func actionFromNative(a C.uint32_t) (ScmpAction, error) { case C.C_ACT_ALLOW: return ActAllow, nil default: - return 0x0, fmt.Errorf("Unrecognized action") + return 0x0, fmt.Errorf("unrecognized action") } } diff --git a/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_test.go b/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_test.go index f94777cd..b3a49d2d 100644 --- a/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_test.go +++ b/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_test.go @@ -434,6 +434,9 @@ func TestRuleAddAndLoad(t *testing.T) { conditions := []ScmpCondition{cond, cond2} err = filter1.AddRuleConditional(call2, ActErrno.SetReturnCode(0x2), conditions) + if err != nil { + t.Errorf("Error adding conditional rule: %s", err) + } err = filter1.Load() if err != nil {