update libssecomp-golang to v0.9.1

This commit is contained in:
Benjamin Elder 2019-06-20 15:51:57 -07:00
parent ddc4ed0365
commit 23fa8e7b6e
11 changed files with 531 additions and 135 deletions

4
go.mod
View File

@ -123,7 +123,7 @@ require (
github.com/quobyte/api v0.1.2
github.com/robfig/cron v1.1.0
github.com/russross/blackfriday v1.5.2
github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e // indirect
github.com/seccomp/libseccomp-golang v0.9.1 // indirect
github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
github.com/spf13/afero v1.2.2
@ -376,7 +376,7 @@ replace (
github.com/rubiojr/go-vhd => github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c
github.com/russross/blackfriday => github.com/russross/blackfriday v1.5.2
github.com/satori/go.uuid => github.com/satori/go.uuid v1.2.0
github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e
github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.9.1
github.com/sigma/go-inotify => github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d
github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.2.0
github.com/smartystreets/assertions => github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d

4
go.sum
View File

@ -356,8 +356,8 @@ github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNue
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e h1:HJbgNpzYMeTLPpkMwbPNTPlhNd9r4xQtqcZG6qoIGgs=
github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d h1:G1nNtZVTzcCvVKMwcG0Vispo3bhc15EbjO5uamiLikI=
github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d/go.mod h1:stlh9OsqBQSdwxTxX73mu41BBtRbIpZLQ7flcAoxAfo=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=

View File

@ -0,0 +1,4 @@
*~
*.swp
*.orig
tags

View File

@ -7,12 +7,6 @@ go_library(
"seccomp_internal.go",
],
cgo = True,
clinkopts = select({
"@io_bazel_rules_go//go/platform:linux": [
"-lseccomp",
],
"//conditions:default": [],
}),
importmap = "k8s.io/kubernetes/vendor/github.com/seccomp/libseccomp-golang",
importpath = "github.com/seccomp/libseccomp-golang",
visibility = ["//visibility:public"],

17
vendor/github.com/seccomp/libseccomp-golang/CHANGELOG generated vendored Normal file
View File

@ -0,0 +1,17 @@
libseccomp-golang: Releases
===============================================================================
https://github.com/seccomp/libseccomp-golang
* Version 0.9.1 - May 21, 2019
- Minimum supported version of libseccomp bumped to v2.2.0
- Use Libseccomp's `seccomp_version` API to retrieve library version
- Unconditionally set TSync attribute for filters, due to Go's heavily threaded nature
- Fix CVE-2017-18367 - Multiple syscall arguments were incorrectly combined with logical-OR, instead of logical-AND
- Fix a failure to build on Debian-based distributions due to CGo code
- Fix unit test failures on 32-bit architectures
- Improve several errors to be more verbose about their causes
- Add support for SCMP_ACT_LOG (with libseccomp versions 2.4.x and higher), permitting syscalls but logging their execution
- Add support for SCMP_FLTATR_CTL_LOG (with libseccomp versions 2.4.x and higher), logging not-allowed actions when they are denied
* Version 0.9.0 - January 5, 2017
- Initial tagged release

26
vendor/github.com/seccomp/libseccomp-golang/Makefile generated vendored Normal file
View File

@ -0,0 +1,26 @@
# libseccomp-golang
.PHONY: all check check-build check-syntax fix-syntax vet test lint
all: check-build
check: vet test
check-build:
go build
check-syntax:
gofmt -d .
fix-syntax:
gofmt -w .
vet:
go vet -v
test:
go test -v
lint:
@$(if $(shell which golint),true,$(error "install golint and include it in your PATH"))
golint -set_exit_status

View File

@ -24,3 +24,28 @@ please note that a Google account is not required to subscribe to the mailing
list.
-> https://groups.google.com/d/forum/libseccomp
Documentation is also available at:
-> https://godoc.org/github.com/seccomp/libseccomp-golang
* Installing the package
The libseccomp-golang bindings require at least Go v1.2.1 and GCC v4.8.4;
earlier versions may yield unpredictable results. If you meet these
requirements you can install this package using the command below:
$ go get github.com/seccomp/libseccomp-golang
* Testing the Library
A number of tests and lint related recipes are provided in the Makefile, if
you want to run the standard regression tests, you can excute the following:
$ make check
In order to execute the 'make lint' recipe the 'golint' tool is needed, it
can be found at:
-> https://github.com/golang/lint

View File

@ -0,0 +1,112 @@
How to Submit Patches to the libseccomp Project
===============================================================================
https://github.com/seccomp/libseccomp-golang
This document is intended to act as a guide to help you contribute to the
libseccomp project. It is not perfect, and there will always be exceptions
to the rules described here, but by following the instructions below you
should have a much easier time getting your work merged with the upstream
project.
* Test Your Code
There are two possible tests you can run to verify your code. The first test
is used to check the formatting and coding style of your changes, you can run
the test with the following command:
# make check-syntax
... if there are any problems with your changes a diff/patch will be shown
which indicates the problems and how to fix them.
The second possible test is used to ensure the sanity of your code changes
and to test these changes against the included tests. You can run the test
with the following command:
# make check
... if there are any faults or errors they will be displayed.
* Generate the Patch(es)
Depending on how you decided to work with the libseccomp code base and what
tools you are using there are different ways to generate your patch(es).
However, regardless of what tools you use, you should always generate your
patches using the "unified" diff/patch format and the patches should always
apply to the libseccomp source tree using the following command from the top
directory of the libseccomp sources:
# patch -p1 < changes.patch
If you are not using git, stacked git (stgit), or some other tool which can
generate patch files for you automatically, you may find the following command
helpful in generating patches, where "libseccomp.orig/" is the unmodified
source code directory and "libseccomp/" is the source code directory with your
changes:
# diff -purN libseccomp-golang.orig/ libseccomp-golang/
When in doubt please generate your patch and try applying it to an unmodified
copy of the libseccomp sources; if it fails for you, it will fail for the rest
of us.
* Explain Your Work
At the top of every patch you should include a description of the problem you
are trying to solve, how you solved it, and why you chose the solution you
implemented. If you are submitting a bug fix, it is also incredibly helpful
if you can describe/include a reproducer for the problem in the description as
well as instructions on how to test for the bug and verify that it has been
fixed.
* Sign Your Work
The sign-off is a simple line at the end of the patch description, which
certifies that you wrote it or otherwise have the right to pass it on as an
open-source patch. The "Developer's Certificate of Origin" pledge is taken
from the Linux Kernel and the rules are pretty simple:
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
... then you just add a line to the bottom of your patch description, with
your real name, saying:
Signed-off-by: Random J Developer <random@developer.example.org>
* Email Your Patch(es)
Finally, you will need to email your patches to the mailing list so they can
be reviewed and potentially merged into the main libseccomp-golang repository.
When sending patches to the mailing list it is important to send your email in
text form, no HTML mail please, and ensure that your email client does not
mangle your patches. It should be possible to save your raw email to disk and
apply it directly to the libseccomp source code; if that fails then you likely
have a problem with your email client. When in doubt try a test first by
sending yourself an email with your patch and attempting to apply the emailed
patch to the libseccomp-golang repository; if it fails for you, it will fail
for the rest of us trying to test your patch and include it in the main
libseccomp-golang repository.

View File

@ -3,7 +3,7 @@
// Public API specification for libseccomp Go bindings
// Contains public API for the bindings
// Package seccomp rovides bindings for libseccomp, a library wrapping the Linux
// Package seccomp 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
@ -20,13 +20,35 @@ import (
// C wrapping code
// #cgo LDFLAGS: -lseccomp
// #cgo pkg-config: libseccomp
// #include <stdlib.h>
// #include <seccomp.h>
import "C"
// Exported types
// VersionError denotes that the system libseccomp version is incompatible
// with this package.
type VersionError struct {
message string
minimum string
}
func (e VersionError) Error() string {
format := "Libseccomp version too low: "
if e.message != "" {
format += e.message + ": "
}
format += "minimum supported is "
if e.minimum != "" {
format += e.minimum + ": "
} else {
format += "2.2.0: "
}
format += "detected %d.%d.%d"
return fmt.Sprintf(format, verMajor, verMinor, verMicro)
}
// ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a
// per-architecture basis.
type ScmpArch uint
@ -54,8 +76,8 @@ type ScmpSyscall int32
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
// PowerPC and S390(x) architectures are unavailable below library version
// v2.3.0 and will returns errors if used with incompatible libraries
// ArchInvalid is a placeholder to ensure uninitialized ScmpArch
// variables are invalid
@ -85,6 +107,16 @@ const (
// ArchMIPSEL64N32 represents 64-bit MIPS syscalls (little endian,
// 32-bit pointers)
ArchMIPSEL64N32 ScmpArch = iota
// ArchPPC represents 32-bit POWERPC syscalls
ArchPPC ScmpArch = iota
// ArchPPC64 represents 64-bit POWER syscalls (big endian)
ArchPPC64 ScmpArch = iota
// ArchPPC64LE represents 64-bit POWER syscalls (little endian)
ArchPPC64LE ScmpArch = iota
// ArchS390 represents 31-bit System z/390 syscalls
ArchS390 ScmpArch = iota
// ArchS390X represents 64-bit System z/390 syscalls
ArchS390X ScmpArch = iota
)
const (
@ -105,6 +137,10 @@ const (
ActTrace ScmpAction = iota
// ActAllow permits the syscall to continue execution
ActAllow ScmpAction = iota
// ActLog permits the syscall to continue execution after logging it.
// This action is only usable when libseccomp API level 3 or higher is
// supported.
ActLog ScmpAction = iota
)
const (
@ -141,6 +177,10 @@ const (
// GetArchFromString returns an ScmpArch constant from a string representing an
// architecture
func GetArchFromString(arch string) (ScmpArch, error) {
if err := ensureSupportedVersion(); err != nil {
return ArchInvalid, err
}
switch strings.ToLower(arch) {
case "x86":
return ArchX86, nil
@ -164,8 +204,18 @@ func GetArchFromString(arch string) (ScmpArch, error) {
return ArchMIPSEL64, nil
case "mipsel64n32":
return ArchMIPSEL64N32, nil
case "ppc":
return ArchPPC, nil
case "ppc64":
return ArchPPC64, nil
case "ppc64le":
return ArchPPC64LE, nil
case "s390":
return ArchS390, nil
case "s390x":
return ArchS390X, nil
default:
return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %s", arch)
return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %q", arch)
}
}
@ -194,12 +244,22 @@ func (a ScmpArch) String() string {
return "mipsel64"
case ArchMIPSEL64N32:
return "mipsel64n32"
case ArchPPC:
return "ppc"
case ArchPPC64:
return "ppc64"
case ArchPPC64LE:
return "ppc64le"
case ArchS390:
return "s390"
case ArchS390X:
return "s390x"
case ArchNative:
return "native"
case ArchInvalid:
return "Invalid architecture"
default:
return "Unknown architecture"
return fmt.Sprintf("Unknown architecture %#x", uint(a))
}
}
@ -223,7 +283,7 @@ func (a ScmpCompareOp) String() string {
case CompareInvalid:
return "Invalid comparison operator"
default:
return "Unrecognized comparison operator"
return fmt.Sprintf("Unrecognized comparison operator %#x", uint(a))
}
}
@ -239,10 +299,12 @@ func (a ScmpAction) String() string {
case ActTrace:
return fmt.Sprintf("Action: Notify tracing processes with code %d",
(a >> 16))
case ActLog:
return "Action: Log system call"
case ActAllow:
return "Action: Allow system call"
default:
return "Unrecognized Action"
return fmt.Sprintf("Unrecognized Action %#x", uint(a))
}
}
@ -268,10 +330,29 @@ func (a ScmpAction) GetReturnCode() int16 {
// 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) {
func GetLibraryVersion() (major, minor, micro uint) {
return verMajor, verMinor, verMicro
}
// GetApi returns the API level supported by the system.
// Returns a positive int containing the API level, or 0 with an error if the
// API level could not be detected due to the library being older than v2.4.0.
// See the seccomp_api_get(3) man page for details on available API levels:
// https://github.com/seccomp/libseccomp/blob/master/doc/man/man3/seccomp_api_get.3
func GetApi() (uint, error) {
return getApi()
}
// SetApi forcibly sets the API level. General use of this function is strongly
// discouraged.
// Returns an error if the API level could not be set. An error is always
// returned if the library is older than v2.4.0
// See the seccomp_api_get(3) man page for details on available API levels:
// https://github.com/seccomp/libseccomp/blob/master/doc/man/man3/seccomp_api_get.3
func SetApi(api uint) error {
return setApi(api)
}
// Syscall functions
// GetName retrieves the name of a syscall from its number.
@ -294,7 +375,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 for %#x", int32(s))
}
defer C.free(unsafe.Pointer(cString))
@ -308,12 +389,16 @@ func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) {
// Returns the number of the syscall, or an error if no syscall with that name
// was found.
func GetSyscallFromName(name string) (ScmpSyscall, error) {
if err := ensureSupportedVersion(); err != nil {
return 0, err
}
cString := C.CString(name)
defer C.free(unsafe.Pointer(cString))
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: %q", name)
}
return ScmpSyscall(result), nil
@ -325,6 +410,9 @@ func GetSyscallFromName(name string) (ScmpSyscall, error) {
// Returns the number of the syscall, or an error if an invalid architecture is
// passed or a syscall with that name was not found.
func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) {
if err := ensureSupportedVersion(); err != nil {
return 0, err
}
if err := sanitizeArch(arch); err != nil {
return 0, err
}
@ -334,7 +422,7 @@ 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: %q on %v", name, arch)
}
return ScmpSyscall(result), nil
@ -356,12 +444,16 @@ func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) {
func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCondition, error) {
var condStruct ScmpCondition
if err := ensureSupportedVersion(); err != nil {
return condStruct, err
}
if comparison == CompareInvalid {
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 (%d given)", arg)
} 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 (%d given)", len(values))
} else if len(values) == 0 {
return condStruct, fmt.Errorf("must provide at least one value to compare against")
}
@ -383,6 +475,10 @@ func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCo
// GetNativeArch returns architecture token representing the native kernel
// architecture
func GetNativeArch() (ScmpArch, error) {
if err := ensureSupportedVersion(); err != nil {
return ArchInvalid, err
}
arch := C.seccomp_arch_native()
return archFromNative(arch)
@ -405,6 +501,10 @@ type ScmpFilter struct {
// Returns a reference to a valid filter context, or nil and an error if the
// filter context could not be created or an invalid default action was given.
func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) {
if err := ensureSupportedVersion(); err != nil {
return nil, err
}
if err := sanitizeAction(defaultAction); err != nil {
return nil, err
}
@ -419,6 +519,13 @@ func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) {
filter.valid = true
runtime.SetFinalizer(filter, filterFinalizer)
// Enable TSync so all goroutines will receive the same rules
// If the kernel does not support TSYNC, allow us to continue without error
if err := filter.setFilterAttr(filterAttrTsync, 0x1); err != nil && err != syscall.ENOTSUP {
filter.Release()
return nil, fmt.Errorf("could not create filter - error setting tsync bit: %v", err)
}
return filter, nil
}
@ -475,7 +582,7 @@ func (f *ScmpFilter) Release() {
// 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 (Default Action, Bad Arch Action, No New Privs and TSync bools)
// attributes (Default Action, Bad Arch Action, and No New Privs 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
@ -648,24 +755,24 @@ func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) {
return true, nil
}
// 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)
// GetLogBit returns the current state the Log bit will be set to on the filter
// being loaded, or an error if an issue was encountered retrieving the value.
// The Log bit tells the kernel that all actions taken by the filter, with the
// exception of ActAllow, should be logged.
// The Log bit is only usable when libseccomp API level 3 or higher is
// supported.
func (f *ScmpFilter) GetLogBit() (bool, error) {
log, err := f.getFilterAttr(filterAttrLog)
if err != nil {
api, apiErr := getApi()
if (apiErr != nil && api == 0) || (apiErr == nil && api < 3) {
return false, fmt.Errorf("getting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher")
}
return false, err
}
if tSync == 0 {
if log == 0 {
return false, nil
}
@ -698,25 +805,26 @@ func (f *ScmpFilter) SetNoNewPrivsBit(state bool) error {
return f.setFilterAttr(filterAttrNNP, toSet)
}
// 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 {
// SetLogBit sets the state of the Log bit, which will be applied on filter
// load, or an error if an issue was encountered setting the value.
// The Log bit is only usable when libseccomp API level 3 or higher is
// supported.
func (f *ScmpFilter) SetLogBit(state bool) error {
var toSet C.uint32_t = 0x0
if enable {
if state {
toSet = 0x1
}
return f.setFilterAttr(filterAttrTsync, toSet)
err := f.setFilterAttr(filterAttrLog, toSet)
if err != nil {
api, apiErr := getApi()
if (apiErr != nil && api == 0) || (apiErr == nil && api < 3) {
return fmt.Errorf("setting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher")
}
}
return err
}
// SetSyscallPriority sets a syscall's priority.

View File

@ -7,7 +7,6 @@ package seccomp
import (
"fmt"
"os"
"syscall"
)
@ -15,47 +14,40 @@ import (
// Get the seccomp header in scope
// Need stdlib.h for free() on cstrings
// #cgo LDFLAGS: -lseccomp
// #cgo pkg-config: libseccomp
/*
#include <errno.h>
#include <stdlib.h>
#include <seccomp.h>
#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
#error Minimum supported version of Libseccomp is v2.2.0
#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2
#error Minimum supported version of Libseccomp is v2.2.0
#endif
#define ARCH_BAD ~0
const uint32_t C_ARCH_BAD = ARCH_BAD;
#ifndef SCMP_ARCH_AARCH64
#define SCMP_ARCH_AARCH64 ARCH_BAD
#ifndef SCMP_ARCH_PPC
#define SCMP_ARCH_PPC ARCH_BAD
#endif
#ifndef SCMP_ARCH_MIPS
#define SCMP_ARCH_MIPS ARCH_BAD
#ifndef SCMP_ARCH_PPC64
#define SCMP_ARCH_PPC64 ARCH_BAD
#endif
#ifndef SCMP_ARCH_MIPS64
#define SCMP_ARCH_MIPS64 ARCH_BAD
#ifndef SCMP_ARCH_PPC64LE
#define SCMP_ARCH_PPC64LE ARCH_BAD
#endif
#ifndef SCMP_ARCH_MIPS64N32
#define SCMP_ARCH_MIPS64N32 ARCH_BAD
#ifndef SCMP_ARCH_S390
#define SCMP_ARCH_S390 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
#ifndef SCMP_ARCH_S390X
#define SCMP_ARCH_S390X ARCH_BAD
#endif
const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
@ -70,23 +62,35 @@ const uint32_t C_ARCH_MIPS64N32 = SCMP_ARCH_MIPS64N32;
const uint32_t C_ARCH_MIPSEL = SCMP_ARCH_MIPSEL;
const uint32_t C_ARCH_MIPSEL64 = SCMP_ARCH_MIPSEL64;
const uint32_t C_ARCH_MIPSEL64N32 = SCMP_ARCH_MIPSEL64N32;
const uint32_t C_ARCH_PPC = SCMP_ARCH_PPC;
const uint32_t C_ARCH_PPC64 = SCMP_ARCH_PPC64;
const uint32_t C_ARCH_PPC64LE = SCMP_ARCH_PPC64LE;
const uint32_t C_ARCH_S390 = SCMP_ARCH_S390;
const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
#ifndef SCMP_ACT_LOG
#define SCMP_ACT_LOG 0x7ffc0000U
#endif
const uint32_t C_ACT_KILL = SCMP_ACT_KILL;
const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP;
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_LOG = SCMP_ACT_LOG;
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
// The libseccomp SCMP_FLTATR_CTL_LOG member of the scmp_filter_attr enum was
// added in v2.4.0
#if (SCMP_VER_MAJOR < 2) || \
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4)
#define SCMP_FLTATR_CTL_LOG _SCMP_FLTATR_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;
const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
const int C_CMP_NE = (int)SCMP_CMP_NE;
const int C_CMP_LT = (int)SCMP_CMP_LT;
@ -100,25 +104,80 @@ const int C_VERSION_MAJOR = SCMP_VER_MAJOR;
const int C_VERSION_MINOR = SCMP_VER_MINOR;
const int C_VERSION_MICRO = SCMP_VER_MICRO;
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 3
unsigned int get_major_version()
{
return seccomp_version()->major;
}
unsigned int get_minor_version()
{
return seccomp_version()->minor;
}
unsigned int get_micro_version()
{
return seccomp_version()->micro;
}
#else
unsigned int get_major_version()
{
return (unsigned int)C_VERSION_MAJOR;
}
unsigned int get_minor_version()
{
return (unsigned int)C_VERSION_MINOR;
}
unsigned int get_micro_version()
{
return (unsigned int)C_VERSION_MICRO;
}
#endif
// The libseccomp API level functions were added in v2.4.0
#if (SCMP_VER_MAJOR < 2) || \
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4)
const unsigned int seccomp_api_get(void)
{
// libseccomp-golang requires libseccomp v2.2.0, at a minimum, which
// supported API level 2. However, the kernel may not support API level
// 2 constructs which are the seccomp() system call and the TSYNC
// filter flag. Return the "reserved" value of 0 here to indicate that
// proper API level support is not available in libseccomp.
return 0;
}
int seccomp_api_set(unsigned int level)
{
return -EOPNOTSUPP;
}
#endif
typedef struct scmp_arg_cmp* scmp_cast_t;
// Wrapper to create an scmp_arg_cmp struct
void*
make_struct_arg_cmp(
unsigned int arg,
int compare,
uint64_t a,
uint64_t b
)
void* make_arg_cmp_array(unsigned int length)
{
struct scmp_arg_cmp *s = malloc(sizeof(struct scmp_arg_cmp));
return calloc(length, sizeof(struct scmp_arg_cmp));
}
s->arg = arg;
s->op = compare;
s->datum_a = a;
s->datum_b = b;
// Wrapper to add an scmp_arg_cmp struct to an existing arg_cmp array
void add_struct_arg_cmp(
struct scmp_arg_cmp* arr,
unsigned int pos,
unsigned int arg,
int compare,
uint64_t a,
uint64_t b
)
{
arr[pos].arg = arg;
arr[pos].op = compare;
arr[pos].datum_a = a;
arr[pos].datum_b = b;
return s;
return;
}
*/
import "C"
@ -133,6 +192,7 @@ const (
filterAttrActBadArch scmpFilterAttr = iota
filterAttrNNP scmpFilterAttr = iota
filterAttrTsync scmpFilterAttr = iota
filterAttrLog scmpFilterAttr = iota
)
const (
@ -140,10 +200,10 @@ const (
scmpError C.int = -1
// Comparison boundaries to check for architecture validity
archStart ScmpArch = ArchNative
archEnd ScmpArch = ArchMIPSEL64N32
archEnd ScmpArch = ArchS390X
// Comparison boundaries to check for action validity
actionStart ScmpAction = ActKill
actionEnd ScmpAction = ActAllow
actionEnd ScmpAction = ActLog
// Comparison boundaries to check for comparison operator validity
compareOpStart ScmpCompareOp = CompareNotEqual
compareOpEnd ScmpCompareOp = CompareMaskedEqual
@ -153,26 +213,49 @@ 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)
verMajor = uint(C.get_major_version())
verMinor = uint(C.get_minor_version())
verMicro = uint(C.get_micro_version())
)
// Nonexported functions
// Check if library version is greater than or equal to the given one
func checkVersionAbove(major, minor, micro int) bool {
func checkVersionAbove(major, minor, micro uint) bool {
return (verMajor > major) ||
(verMajor == major && verMinor > minor) ||
(verMajor == major && verMinor == minor && verMicro >= micro)
}
// Init function: Verify library version is appropriate
func init() {
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)
// Ensure that the library is supported, i.e. >= 2.2.0.
func ensureSupportedVersion() error {
if !checkVersionAbove(2, 2, 0) {
return VersionError{}
}
return nil
}
// Get the API level
func getApi() (uint, error) {
api := C.seccomp_api_get()
if api == 0 {
return 0, fmt.Errorf("API level operations are not supported")
}
return uint(api), nil
}
// Set the API level
func setApi(api uint) error {
if retCode := C.seccomp_api_set(C.uint(api)); retCode != 0 {
if syscall.Errno(-1*retCode) == syscall.EOPNOTSUPP {
return fmt.Errorf("API level operations are not supported")
}
return fmt.Errorf("could not set API level: %v", retCode)
}
return nil
}
// Filter helpers
@ -191,10 +274,6 @@ func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
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
retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
@ -214,10 +293,6 @@ func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error
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)
if retCode != 0 {
return syscall.Errno(-1 * retCode)
@ -229,12 +304,9 @@ func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error
// DOES NOT LOCK OR CHECK VALIDITY
// Assumes caller has already done this
// Wrapper for seccomp_rule_add_... functions
func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, cond C.scmp_cast_t) error {
var length C.uint
if cond != nil {
length = 1
} else {
length = 0
func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, length C.uint, cond C.scmp_cast_t) error {
if length != 0 && cond == nil {
return fmt.Errorf("null conditions list, but length is nonzero")
}
var retCode C.int
@ -245,9 +317,11 @@ 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 %#x", int32(call))
} else if syscall.Errno(-1*retCode) == syscall.EPERM {
return fmt.Errorf("requested action matches default action of filter")
} else if syscall.Errno(-1*retCode) == syscall.EINVAL {
return fmt.Errorf("two checks on same syscall argument")
} else if retCode != 0 {
return syscall.Errno(-1 * retCode)
}
@ -265,22 +339,32 @@ func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact b
}
if len(conds) == 0 {
if err := f.addRuleWrapper(call, action, exact, nil); err != nil {
if err := f.addRuleWrapper(call, action, exact, 0, nil); err != nil {
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")
return VersionError{
message: "conditional filtering is not supported",
minimum: "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)
argsArr := C.make_arg_cmp_array(C.uint(len(conds)))
if argsArr == nil {
return fmt.Errorf("error allocating memory for conditions")
}
defer C.free(argsArr)
if err := f.addRuleWrapper(call, action, exact, C.scmp_cast_t(cmpStruct)); err != nil {
return err
}
for i, cond := range conds {
C.add_struct_arg_cmp(C.scmp_cast_t(argsArr), C.uint(i),
C.uint(cond.Argument), cond.Op.toNative(),
C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2))
}
if err := f.addRuleWrapper(call, action, exact, C.uint(len(conds)), C.scmp_cast_t(argsArr)); err != nil {
return err
}
}
@ -292,11 +376,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 %#x", uint(in))
}
if in.toNative() == C.C_ARCH_BAD {
return fmt.Errorf("architecture is not supported on this version of the library")
return fmt.Errorf("architecture %v is not supported on this version of the library", in)
}
return nil
@ -305,7 +389,7 @@ 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 %#x", uint(inTmp))
}
if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
@ -317,7 +401,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 %#x", uint(in))
}
return nil
@ -349,8 +433,18 @@ func archFromNative(a C.uint32_t) (ScmpArch, error) {
return ArchMIPSEL64, nil
case C.C_ARCH_MIPSEL64N32:
return ArchMIPSEL64N32, nil
case C.C_ARCH_PPC:
return ArchPPC, nil
case C.C_ARCH_PPC64:
return ArchPPC64, nil
case C.C_ARCH_PPC64LE:
return ArchPPC64LE, nil
case C.C_ARCH_S390:
return ArchS390, nil
case C.C_ARCH_S390X:
return ArchS390X, nil
default:
return 0x0, fmt.Errorf("unrecognized architecture")
return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a))
}
}
@ -379,6 +473,16 @@ func (a ScmpArch) toNative() C.uint32_t {
return C.C_ARCH_MIPSEL64
case ArchMIPSEL64N32:
return C.C_ARCH_MIPSEL64N32
case ArchPPC:
return C.C_ARCH_PPC
case ArchPPC64:
return C.C_ARCH_PPC64
case ArchPPC64LE:
return C.C_ARCH_PPC64LE
case ArchS390:
return C.C_ARCH_S390
case ArchS390X:
return C.C_ARCH_S390X
case ArchNative:
return C.C_ARCH_NATIVE
default:
@ -419,10 +523,12 @@ func actionFromNative(a C.uint32_t) (ScmpAction, error) {
return ActErrno.SetReturnCode(int16(aTmp)), nil
case C.C_ACT_TRACE:
return ActTrace.SetReturnCode(int16(aTmp)), nil
case C.C_ACT_LOG:
return ActLog, nil
case C.C_ACT_ALLOW:
return ActAllow, nil
default:
return 0x0, fmt.Errorf("unrecognized action")
return 0x0, fmt.Errorf("unrecognized action %#x", uint32(a))
}
}
@ -437,6 +543,8 @@ func (a ScmpAction) toNative() C.uint32_t {
return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16)
case ActTrace:
return C.C_ACT_TRACE | (C.uint32_t(a) >> 16)
case ActLog:
return C.C_ACT_LOG
case ActAllow:
return C.C_ACT_ALLOW
default:
@ -455,6 +563,8 @@ func (a scmpFilterAttr) toNative() uint32 {
return uint32(C.C_ATTRIBUTE_NNP)
case filterAttrTsync:
return uint32(C.C_ATTRIBUTE_TSYNC)
case filterAttrLog:
return uint32(C.C_ATTRIBUTE_LOG)
default:
return 0x0
}

2
vendor/modules.txt vendored
View File

@ -727,7 +727,7 @@ github.com/rubiojr/go-vhd/vhd
github.com/russross/blackfriday
# github.com/satori/go.uuid v1.2.0 => github.com/satori/go.uuid v1.2.0
github.com/satori/go.uuid
# github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e => github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e
# github.com/seccomp/libseccomp-golang v0.9.1 => github.com/seccomp/libseccomp-golang v0.9.1
github.com/seccomp/libseccomp-golang
# github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d => github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d
github.com/sigma/go-inotify