Merge pull request #1548 from AkihiroSuda/remove-libseccomp-dependency
remove libseccomp cgo dependency
This commit is contained in:
commit
8871d5cdf8
47
pkg/seccomp/fixtures/proc_self_status
Normal file
47
pkg/seccomp/fixtures/proc_self_status
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
Name: cat
|
||||||
|
State: R (running)
|
||||||
|
Tgid: 19383
|
||||||
|
Ngid: 0
|
||||||
|
Pid: 19383
|
||||||
|
PPid: 19275
|
||||||
|
TracerPid: 0
|
||||||
|
Uid: 1000 1000 1000 1000
|
||||||
|
Gid: 1000 1000 1000 1000
|
||||||
|
FDSize: 256
|
||||||
|
Groups: 24 25 27 29 30 44 46 102 104 108 111 1000 1001
|
||||||
|
NStgid: 19383
|
||||||
|
NSpid: 19383
|
||||||
|
NSpgid: 19383
|
||||||
|
NSsid: 19275
|
||||||
|
VmPeak: 5944 kB
|
||||||
|
VmSize: 5944 kB
|
||||||
|
VmLck: 0 kB
|
||||||
|
VmPin: 0 kB
|
||||||
|
VmHWM: 744 kB
|
||||||
|
VmRSS: 744 kB
|
||||||
|
VmData: 324 kB
|
||||||
|
VmStk: 136 kB
|
||||||
|
VmExe: 48 kB
|
||||||
|
VmLib: 1776 kB
|
||||||
|
VmPTE: 32 kB
|
||||||
|
VmPMD: 12 kB
|
||||||
|
VmSwap: 0 kB
|
||||||
|
Threads: 1
|
||||||
|
SigQ: 0/30067
|
||||||
|
SigPnd: 0000000000000000
|
||||||
|
ShdPnd: 0000000000000000
|
||||||
|
SigBlk: 0000000000000000
|
||||||
|
SigIgn: 0000000000000080
|
||||||
|
SigCgt: 0000000000000000
|
||||||
|
CapInh: 0000000000000000
|
||||||
|
CapPrm: 0000000000000000
|
||||||
|
CapEff: 0000000000000000
|
||||||
|
CapBnd: 0000003fffffffff
|
||||||
|
CapAmb: 0000000000000000
|
||||||
|
Seccomp: 0
|
||||||
|
Cpus_allowed: f
|
||||||
|
Cpus_allowed_list: 0-3
|
||||||
|
Mems_allowed: 00000000,00000001
|
||||||
|
Mems_allowed_list: 0
|
||||||
|
voluntary_ctxt_switches: 0
|
||||||
|
nonvoluntary_ctxt_switches: 1
|
88
pkg/seccomp/seccomp_linux.go
Normal file
88
pkg/seccomp/seccomp_linux.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The runc Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package seccomp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsEnabled returns if the kernel has been configured to support seccomp.
|
||||||
|
// From https://github.com/opencontainers/runc/blob/v1.0.0-rc91/libcontainer/seccomp/seccomp_linux.go#L86-L102
|
||||||
|
func IsEnabled() bool {
|
||||||
|
// Try to read from /proc/self/status for kernels > 3.8
|
||||||
|
s, err := parseStatusFile("/proc/self/status")
|
||||||
|
if err != nil {
|
||||||
|
// Check if Seccomp is supported, via CONFIG_SECCOMP.
|
||||||
|
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
|
||||||
|
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
||||||
|
if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, ok := s["Seccomp"]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseStatusFile is from https://github.com/opencontainers/runc/blob/v1.0.0-rc91/libcontainer/seccomp/seccomp_linux.go#L243-L268
|
||||||
|
func parseStatusFile(path string) (map[string]string, error) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
s := bufio.NewScanner(f)
|
||||||
|
status := make(map[string]string)
|
||||||
|
|
||||||
|
for s.Scan() {
|
||||||
|
text := s.Text()
|
||||||
|
parts := strings.Split(text, ":")
|
||||||
|
|
||||||
|
if len(parts) <= 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
status[parts[0]] = parts[1]
|
||||||
|
}
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
48
pkg/seccomp/seccomp_linux_test.go
Normal file
48
pkg/seccomp/seccomp_linux_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The runc Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package seccomp
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// TestParseStatusFile is from https://github.com/opencontainers/runc/blob/v1.0.0-rc91/libcontainer/seccomp/seccomp_linux_test.go
|
||||||
|
func TestParseStatusFile(t *testing.T) {
|
||||||
|
s, err := parseStatusFile("fixtures/proc_self_status")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := s["Seccomp"]; !ok {
|
||||||
|
|
||||||
|
t.Fatal("expected to find 'Seccomp' in the map but did not.")
|
||||||
|
}
|
||||||
|
}
|
23
pkg/seccomp/seccomp_unsupported.go
Normal file
23
pkg/seccomp/seccomp_unsupported.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package seccomp
|
||||||
|
|
||||||
|
func IsEnabled() bool {
|
||||||
|
return false
|
||||||
|
}
|
@ -32,8 +32,8 @@ import (
|
|||||||
|
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
|
"github.com/containerd/cri/pkg/seccomp"
|
||||||
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
|
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||||
runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp"
|
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@ -146,7 +146,7 @@ func (c *criService) apparmorEnabled() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *criService) seccompEnabled() bool {
|
func (c *criService) seccompEnabled() bool {
|
||||||
return runcseccomp.IsEnabled()
|
return seccomp.IsEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
// openLogFile opens/creates a container log file.
|
// openLogFile opens/creates a container log file.
|
||||||
|
@ -71,7 +71,6 @@ github.com/json-iterator/go v1.1.9
|
|||||||
github.com/modern-go/concurrent 1.0.3
|
github.com/modern-go/concurrent 1.0.3
|
||||||
github.com/modern-go/reflect2 v1.0.1
|
github.com/modern-go/reflect2 v1.0.1
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/pmezard/go-difflib v1.0.0
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1
|
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
golang.org/x/crypto bac4c82f69751a6dd76e702d54b3ceb88adab236
|
golang.org/x/crypto bac4c82f69751a6dd76e702d54b3ceb88adab236
|
||||||
golang.org/x/oauth2 858c2ad4c8b6c5d10852cb89079f6ca1c7309787
|
golang.org/x/oauth2 858c2ad4c8b6c5d10852cb89079f6ca1c7309787
|
||||||
|
77
vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go
generated
vendored
77
vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go
generated
vendored
@ -1,77 +0,0 @@
|
|||||||
package seccomp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
)
|
|
||||||
|
|
||||||
var operators = map[string]configs.Operator{
|
|
||||||
"SCMP_CMP_NE": configs.NotEqualTo,
|
|
||||||
"SCMP_CMP_LT": configs.LessThan,
|
|
||||||
"SCMP_CMP_LE": configs.LessThanOrEqualTo,
|
|
||||||
"SCMP_CMP_EQ": configs.EqualTo,
|
|
||||||
"SCMP_CMP_GE": configs.GreaterThanOrEqualTo,
|
|
||||||
"SCMP_CMP_GT": configs.GreaterThan,
|
|
||||||
"SCMP_CMP_MASKED_EQ": configs.MaskEqualTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
var actions = map[string]configs.Action{
|
|
||||||
"SCMP_ACT_KILL": configs.Kill,
|
|
||||||
"SCMP_ACT_ERRNO": configs.Errno,
|
|
||||||
"SCMP_ACT_TRAP": configs.Trap,
|
|
||||||
"SCMP_ACT_ALLOW": configs.Allow,
|
|
||||||
"SCMP_ACT_TRACE": configs.Trace,
|
|
||||||
"SCMP_ACT_LOG": configs.Log,
|
|
||||||
}
|
|
||||||
|
|
||||||
var archs = map[string]string{
|
|
||||||
"SCMP_ARCH_X86": "x86",
|
|
||||||
"SCMP_ARCH_X86_64": "amd64",
|
|
||||||
"SCMP_ARCH_X32": "x32",
|
|
||||||
"SCMP_ARCH_ARM": "arm",
|
|
||||||
"SCMP_ARCH_AARCH64": "arm64",
|
|
||||||
"SCMP_ARCH_MIPS": "mips",
|
|
||||||
"SCMP_ARCH_MIPS64": "mips64",
|
|
||||||
"SCMP_ARCH_MIPS64N32": "mips64n32",
|
|
||||||
"SCMP_ARCH_MIPSEL": "mipsel",
|
|
||||||
"SCMP_ARCH_MIPSEL64": "mipsel64",
|
|
||||||
"SCMP_ARCH_MIPSEL64N32": "mipsel64n32",
|
|
||||||
"SCMP_ARCH_PPC": "ppc",
|
|
||||||
"SCMP_ARCH_PPC64": "ppc64",
|
|
||||||
"SCMP_ARCH_PPC64LE": "ppc64le",
|
|
||||||
"SCMP_ARCH_S390": "s390",
|
|
||||||
"SCMP_ARCH_S390X": "s390x",
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertStringToOperator converts a string into a Seccomp comparison operator.
|
|
||||||
// Comparison operators use the names they are assigned by Libseccomp's header.
|
|
||||||
// Attempting to convert a string that is not a valid operator results in an
|
|
||||||
// error.
|
|
||||||
func ConvertStringToOperator(in string) (configs.Operator, error) {
|
|
||||||
if op, ok := operators[in]; ok == true {
|
|
||||||
return op, nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("string %s is not a valid operator for seccomp", in)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertStringToAction converts a string into a Seccomp rule match action.
|
|
||||||
// Actions use the names they are assigned in Libseccomp's header, though some
|
|
||||||
// (notable, SCMP_ACT_TRACE) are not available in this implementation and will
|
|
||||||
// return errors.
|
|
||||||
// Attempting to convert a string that is not a valid action results in an
|
|
||||||
// error.
|
|
||||||
func ConvertStringToAction(in string) (configs.Action, error) {
|
|
||||||
if act, ok := actions[in]; ok == true {
|
|
||||||
return act, nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("string %s is not a valid action for seccomp", in)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertStringToArch converts a string into a Seccomp comparison arch.
|
|
||||||
func ConvertStringToArch(in string) (string, error) {
|
|
||||||
if arch, ok := archs[in]; ok == true {
|
|
||||||
return arch, nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("string %s is not a valid arch for seccomp", in)
|
|
||||||
}
|
|
268
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
generated
vendored
268
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
generated
vendored
@ -1,268 +0,0 @@
|
|||||||
// +build linux,cgo,seccomp
|
|
||||||
|
|
||||||
package seccomp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
actAllow = libseccomp.ActAllow
|
|
||||||
actTrap = libseccomp.ActTrap
|
|
||||||
actKill = libseccomp.ActKill
|
|
||||||
actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
|
|
||||||
actLog = libseccomp.ActLog
|
|
||||||
actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Linux system calls can have at most 6 arguments
|
|
||||||
syscallMaxArguments int = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
// Filters given syscalls in a container, preventing them from being used
|
|
||||||
// Started in the container init process, and carried over to all child processes
|
|
||||||
// Setns calls, however, require a separate invocation, as they are not children
|
|
||||||
// of the init until they join the namespace
|
|
||||||
func InitSeccomp(config *configs.Seccomp) error {
|
|
||||||
if config == nil {
|
|
||||||
return errors.New("cannot initialize Seccomp - nil config passed")
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultAction, err := getAction(config.DefaultAction, nil)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("error initializing seccomp - invalid default action")
|
|
||||||
}
|
|
||||||
|
|
||||||
filter, err := libseccomp.NewFilter(defaultAction)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error creating filter: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add extra architectures
|
|
||||||
for _, arch := range config.Architectures {
|
|
||||||
scmpArch, err := libseccomp.GetArchFromString(arch)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error validating Seccomp architecture: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := filter.AddArch(scmpArch); err != nil {
|
|
||||||
return fmt.Errorf("error adding architecture to seccomp filter: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unset no new privs bit
|
|
||||||
if err := filter.SetNoNewPrivsBit(false); err != nil {
|
|
||||||
return fmt.Errorf("error setting no new privileges: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a rule for each syscall
|
|
||||||
for _, call := range config.Syscalls {
|
|
||||||
if call == nil {
|
|
||||||
return errors.New("encountered nil syscall while initializing Seccomp")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = matchCall(filter, call); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = filter.Load(); err != nil {
|
|
||||||
return fmt.Errorf("error loading seccomp filter into kernel: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEnabled returns if the kernel has been configured to support seccomp.
|
|
||||||
func IsEnabled() bool {
|
|
||||||
// Try to read from /proc/self/status for kernels > 3.8
|
|
||||||
s, err := parseStatusFile("/proc/self/status")
|
|
||||||
if err != nil {
|
|
||||||
// Check if Seccomp is supported, via CONFIG_SECCOMP.
|
|
||||||
if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
|
|
||||||
// Make sure the kernel has CONFIG_SECCOMP_FILTER.
|
|
||||||
if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
_, ok := s["Seccomp"]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Libcontainer Action to Libseccomp ScmpAction
|
|
||||||
func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
|
|
||||||
switch act {
|
|
||||||
case configs.Kill:
|
|
||||||
return actKill, nil
|
|
||||||
case configs.Errno:
|
|
||||||
if errnoRet != nil {
|
|
||||||
return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
|
|
||||||
}
|
|
||||||
return actErrno, nil
|
|
||||||
case configs.Trap:
|
|
||||||
return actTrap, nil
|
|
||||||
case configs.Allow:
|
|
||||||
return actAllow, nil
|
|
||||||
case configs.Trace:
|
|
||||||
if errnoRet != nil {
|
|
||||||
return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
|
|
||||||
}
|
|
||||||
return actTrace, nil
|
|
||||||
case configs.Log:
|
|
||||||
return actLog, nil
|
|
||||||
default:
|
|
||||||
return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Libcontainer Operator to Libseccomp ScmpCompareOp
|
|
||||||
func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) {
|
|
||||||
switch op {
|
|
||||||
case configs.EqualTo:
|
|
||||||
return libseccomp.CompareEqual, nil
|
|
||||||
case configs.NotEqualTo:
|
|
||||||
return libseccomp.CompareNotEqual, nil
|
|
||||||
case configs.GreaterThan:
|
|
||||||
return libseccomp.CompareGreater, nil
|
|
||||||
case configs.GreaterThanOrEqualTo:
|
|
||||||
return libseccomp.CompareGreaterEqual, nil
|
|
||||||
case configs.LessThan:
|
|
||||||
return libseccomp.CompareLess, nil
|
|
||||||
case configs.LessThanOrEqualTo:
|
|
||||||
return libseccomp.CompareLessOrEqual, nil
|
|
||||||
case configs.MaskEqualTo:
|
|
||||||
return libseccomp.CompareMaskedEqual, nil
|
|
||||||
default:
|
|
||||||
return libseccomp.CompareInvalid, errors.New("invalid operator, cannot use in rule")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Libcontainer Arg to Libseccomp ScmpCondition
|
|
||||||
func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
|
|
||||||
cond := libseccomp.ScmpCondition{}
|
|
||||||
|
|
||||||
if arg == nil {
|
|
||||||
return cond, errors.New("cannot convert nil to syscall condition")
|
|
||||||
}
|
|
||||||
|
|
||||||
op, err := getOperator(arg.Op)
|
|
||||||
if err != nil {
|
|
||||||
return cond, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return libseccomp.MakeCondition(arg.Index, op, arg.Value, arg.ValueTwo)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a rule to match a single syscall
|
|
||||||
func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error {
|
|
||||||
if call == nil || filter == nil {
|
|
||||||
return errors.New("cannot use nil as syscall to block")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(call.Name) == 0 {
|
|
||||||
return errors.New("empty string is not a valid syscall")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can't resolve the syscall, assume it's not supported on this kernel
|
|
||||||
// Ignore it, don't error out
|
|
||||||
callNum, err := libseccomp.GetSyscallFromName(call.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the call's action to the libseccomp equivalent
|
|
||||||
callAct, err := getAction(call.Action, call.ErrnoRet)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("action in seccomp profile is invalid: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unconditional match - just add the rule
|
|
||||||
if len(call.Args) == 0 {
|
|
||||||
if err = filter.AddRule(callNum, callAct); err != nil {
|
|
||||||
return fmt.Errorf("error adding seccomp filter rule for syscall %s: %s", call.Name, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If two or more arguments have the same condition,
|
|
||||||
// Revert to old behavior, adding each condition as a separate rule
|
|
||||||
argCounts := make([]uint, syscallMaxArguments)
|
|
||||||
conditions := []libseccomp.ScmpCondition{}
|
|
||||||
|
|
||||||
for _, cond := range call.Args {
|
|
||||||
newCond, err := getCondition(cond)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %s", call.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
argCounts[cond.Index] += 1
|
|
||||||
|
|
||||||
conditions = append(conditions, newCond)
|
|
||||||
}
|
|
||||||
|
|
||||||
hasMultipleArgs := false
|
|
||||||
for _, count := range argCounts {
|
|
||||||
if count > 1 {
|
|
||||||
hasMultipleArgs = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasMultipleArgs {
|
|
||||||
// Revert to old behavior
|
|
||||||
// Add each condition attached to a separate rule
|
|
||||||
for _, cond := range conditions {
|
|
||||||
condArr := []libseccomp.ScmpCondition{cond}
|
|
||||||
|
|
||||||
if err = filter.AddRuleConditional(callNum, callAct, condArr); err != nil {
|
|
||||||
return fmt.Errorf("error adding seccomp rule for syscall %s: %s", call.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No conditions share same argument
|
|
||||||
// Use new, proper behavior
|
|
||||||
if err = filter.AddRuleConditional(callNum, callAct, conditions); err != nil {
|
|
||||||
return fmt.Errorf("error adding seccomp rule for syscall %s: %s", call.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseStatusFile(path string) (map[string]string, error) {
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
s := bufio.NewScanner(f)
|
|
||||||
status := make(map[string]string)
|
|
||||||
|
|
||||||
for s.Scan() {
|
|
||||||
text := s.Text()
|
|
||||||
parts := strings.Split(text, ":")
|
|
||||||
|
|
||||||
if len(parts) <= 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
status[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
if err := s.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return status, nil
|
|
||||||
}
|
|
24
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go
generated
vendored
24
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
// +build !linux !cgo !seccomp
|
|
||||||
|
|
||||||
package seccomp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrSeccompNotEnabled = errors.New("seccomp: config provided but seccomp not supported")
|
|
||||||
|
|
||||||
// InitSeccomp does nothing because seccomp is not supported.
|
|
||||||
func InitSeccomp(config *configs.Seccomp) error {
|
|
||||||
if config != nil {
|
|
||||||
return ErrSeccompNotEnabled
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEnabled returns false, because it is not supported.
|
|
||||||
func IsEnabled() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
22
vendor/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
22
vendor/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
Copyright (c) 2015 Matthew Heon <mheon@redhat.com>
|
|
||||||
Copyright (c) 2015 Paul Moore <pmoore@redhat.com>
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
- Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
- Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
51
vendor/github.com/seccomp/libseccomp-golang/README
generated
vendored
51
vendor/github.com/seccomp/libseccomp-golang/README
generated
vendored
@ -1,51 +0,0 @@
|
|||||||
libseccomp-golang: Go Language Bindings for the libseccomp Project
|
|
||||||
===============================================================================
|
|
||||||
https://github.com/seccomp/libseccomp-golang
|
|
||||||
https://github.com/seccomp/libseccomp
|
|
||||||
|
|
||||||
The libseccomp library provides an easy to use, platform independent, interface
|
|
||||||
to the Linux Kernel's syscall filtering mechanism. The libseccomp API is
|
|
||||||
designed to abstract away the underlying BPF based syscall filter language and
|
|
||||||
present a more conventional function-call based filtering interface that should
|
|
||||||
be familiar to, and easily adopted by, application developers.
|
|
||||||
|
|
||||||
The libseccomp-golang library provides a Go based interface to the libseccomp
|
|
||||||
library.
|
|
||||||
|
|
||||||
* Online Resources
|
|
||||||
|
|
||||||
The library source repository currently lives on GitHub at the following URLs:
|
|
||||||
|
|
||||||
-> https://github.com/seccomp/libseccomp-golang
|
|
||||||
-> https://github.com/seccomp/libseccomp
|
|
||||||
|
|
||||||
The project mailing list is currently hosted on Google Groups at the URL below,
|
|
||||||
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
|
|
||||||
|
|
935
vendor/github.com/seccomp/libseccomp-golang/seccomp.go
generated
vendored
935
vendor/github.com/seccomp/libseccomp-golang/seccomp.go
generated
vendored
@ -1,935 +0,0 @@
|
|||||||
// +build linux
|
|
||||||
|
|
||||||
// Public API specification for libseccomp Go bindings
|
|
||||||
// Contains public API for the bindings
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// C wrapping code
|
|
||||||
|
|
||||||
// #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
|
|
||||||
|
|
||||||
// ScmpAction represents an action to be taken on a filter rule match in
|
|
||||||
// libseccomp
|
|
||||||
type ScmpAction uint
|
|
||||||
|
|
||||||
// ScmpCompareOp represents a comparison operator which can be used in a filter
|
|
||||||
// rule
|
|
||||||
type ScmpCompareOp uint
|
|
||||||
|
|
||||||
// ScmpCondition represents a rule in a libseccomp filter context
|
|
||||||
type ScmpCondition struct {
|
|
||||||
Argument uint `json:"argument,omitempty"`
|
|
||||||
Op ScmpCompareOp `json:"operator,omitempty"`
|
|
||||||
Operand1 uint64 `json:"operand_one,omitempty"`
|
|
||||||
Operand2 uint64 `json:"operand_two,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScmpSyscall represents a Linux System Call
|
|
||||||
type ScmpSyscall int32
|
|
||||||
|
|
||||||
// Exported Constants
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Valid architectures recognized by libseccomp
|
|
||||||
// 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
|
|
||||||
ArchInvalid ScmpArch = iota
|
|
||||||
// ArchNative is the native architecture of the kernel
|
|
||||||
ArchNative ScmpArch = iota
|
|
||||||
// ArchX86 represents 32-bit x86 syscalls
|
|
||||||
ArchX86 ScmpArch = iota
|
|
||||||
// ArchAMD64 represents 64-bit x86-64 syscalls
|
|
||||||
ArchAMD64 ScmpArch = iota
|
|
||||||
// ArchX32 represents 64-bit x86-64 syscalls (32-bit pointers)
|
|
||||||
ArchX32 ScmpArch = iota
|
|
||||||
// ArchARM represents 32-bit ARM syscalls
|
|
||||||
ArchARM ScmpArch = iota
|
|
||||||
// ArchARM64 represents 64-bit ARM syscalls
|
|
||||||
ArchARM64 ScmpArch = iota
|
|
||||||
// ArchMIPS represents 32-bit MIPS syscalls
|
|
||||||
ArchMIPS ScmpArch = iota
|
|
||||||
// ArchMIPS64 represents 64-bit MIPS syscalls
|
|
||||||
ArchMIPS64 ScmpArch = iota
|
|
||||||
// ArchMIPS64N32 represents 64-bit MIPS syscalls (32-bit pointers)
|
|
||||||
ArchMIPS64N32 ScmpArch = iota
|
|
||||||
// ArchMIPSEL represents 32-bit MIPS syscalls (little endian)
|
|
||||||
ArchMIPSEL ScmpArch = iota
|
|
||||||
// ArchMIPSEL64 represents 64-bit MIPS syscalls (little endian)
|
|
||||||
ArchMIPSEL64 ScmpArch = iota
|
|
||||||
// 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 (
|
|
||||||
// Supported actions on filter match
|
|
||||||
|
|
||||||
// ActInvalid is a placeholder to ensure uninitialized ScmpAction
|
|
||||||
// variables are invalid
|
|
||||||
ActInvalid ScmpAction = iota
|
|
||||||
// ActKill kills the process
|
|
||||||
ActKill ScmpAction = iota
|
|
||||||
// ActTrap throws SIGSYS
|
|
||||||
ActTrap ScmpAction = iota
|
|
||||||
// ActErrno causes the syscall to return a negative error code. This
|
|
||||||
// code can be set with the SetReturnCode method
|
|
||||||
ActErrno ScmpAction = iota
|
|
||||||
// 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
|
|
||||||
// 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 (
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// 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 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
|
|
||||||
|
|
||||||
// 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
|
|
||||||
case "amd64", "x86-64", "x86_64", "x64":
|
|
||||||
return ArchAMD64, nil
|
|
||||||
case "x32":
|
|
||||||
return ArchX32, nil
|
|
||||||
case "arm":
|
|
||||||
return ArchARM, nil
|
|
||||||
case "arm64", "aarch64":
|
|
||||||
return ArchARM64, nil
|
|
||||||
case "mips":
|
|
||||||
return ArchMIPS, nil
|
|
||||||
case "mips64":
|
|
||||||
return ArchMIPS64, nil
|
|
||||||
case "mips64n32":
|
|
||||||
return ArchMIPS64N32, nil
|
|
||||||
case "mipsel":
|
|
||||||
return ArchMIPSEL, nil
|
|
||||||
case "mipsel64":
|
|
||||||
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 %q", arch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of an architecture constant
|
|
||||||
func (a ScmpArch) String() string {
|
|
||||||
switch a {
|
|
||||||
case ArchX86:
|
|
||||||
return "x86"
|
|
||||||
case ArchAMD64:
|
|
||||||
return "amd64"
|
|
||||||
case ArchX32:
|
|
||||||
return "x32"
|
|
||||||
case ArchARM:
|
|
||||||
return "arm"
|
|
||||||
case ArchARM64:
|
|
||||||
return "arm64"
|
|
||||||
case ArchMIPS:
|
|
||||||
return "mips"
|
|
||||||
case ArchMIPS64:
|
|
||||||
return "mips64"
|
|
||||||
case ArchMIPS64N32:
|
|
||||||
return "mips64n32"
|
|
||||||
case ArchMIPSEL:
|
|
||||||
return "mipsel"
|
|
||||||
case ArchMIPSEL64:
|
|
||||||
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 fmt.Sprintf("Unknown architecture %#x", uint(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of a comparison operator constant
|
|
||||||
func (a ScmpCompareOp) String() string {
|
|
||||||
switch a {
|
|
||||||
case CompareNotEqual:
|
|
||||||
return "Not equal"
|
|
||||||
case CompareLess:
|
|
||||||
return "Less than"
|
|
||||||
case CompareLessOrEqual:
|
|
||||||
return "Less than or equal to"
|
|
||||||
case CompareEqual:
|
|
||||||
return "Equal"
|
|
||||||
case CompareGreaterEqual:
|
|
||||||
return "Greater than or equal to"
|
|
||||||
case CompareGreater:
|
|
||||||
return "Greater than"
|
|
||||||
case CompareMaskedEqual:
|
|
||||||
return "Masked equality"
|
|
||||||
case CompareInvalid:
|
|
||||||
return "Invalid comparison operator"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unrecognized comparison operator %#x", uint(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of a seccomp match action
|
|
||||||
func (a ScmpAction) String() string {
|
|
||||||
switch a & 0xFFFF {
|
|
||||||
case ActKill:
|
|
||||||
return "Action: Kill Process"
|
|
||||||
case ActTrap:
|
|
||||||
return "Action: Send SIGSYS"
|
|
||||||
case ActErrno:
|
|
||||||
return fmt.Sprintf("Action: Return error code %d", (a >> 16))
|
|
||||||
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 fmt.Sprintf("Unrecognized Action %#x", uint(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
aTmp := a & 0x0000FFFF
|
|
||||||
if aTmp == ActErrno || aTmp == ActTrace {
|
|
||||||
return (aTmp | (ScmpAction(code)&0xFFFF)<<16)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 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.
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// if the syscall is unrecognized or an issue occurred.
|
|
||||||
func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) {
|
|
||||||
if err := sanitizeArch(arch); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
cString := C.seccomp_syscall_resolve_num_arch(arch.toNative(), C.int(s))
|
|
||||||
if cString == nil {
|
|
||||||
return "", fmt.Errorf("could not resolve syscall name for %#x", int32(s))
|
|
||||||
}
|
|
||||||
defer C.free(unsafe.Pointer(cString))
|
|
||||||
|
|
||||||
finalStr := C.GoString(cString)
|
|
||||||
return finalStr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
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: %q", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ScmpSyscall(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
cString := C.CString(name)
|
|
||||||
defer C.free(unsafe.Pointer(cString))
|
|
||||||
|
|
||||||
result := C.seccomp_syscall_resolve_name_arch(arch.toNative(), cString)
|
|
||||||
if result == scmpError {
|
|
||||||
return 0, fmt.Errorf("could not resolve name to syscall: %q on %v", name, arch)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ScmpSyscall(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// The rule will match if argument $arg (zero-indexed) of the syscall is
|
|
||||||
// $COMPARE_OP the provided comparison value.
|
|
||||||
// Some comparison operators accept two values. Masked equals, for example,
|
|
||||||
// will mask $arg of the syscall with the second value provided (via bitwise
|
|
||||||
// AND) and then compare against the first value provided.
|
|
||||||
// For example, in the less than or equal case, if the syscall argument was
|
|
||||||
// 0 and the value provided was 1, the condition would match, as 0 is less
|
|
||||||
// than or equal to 1.
|
|
||||||
// Return either an error on bad argument or a valid ScmpCondition struct.
|
|
||||||
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 (%d given)", arg)
|
|
||||||
} else if len(values) > 2 {
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
condStruct.Argument = arg
|
|
||||||
condStruct.Op = comparison
|
|
||||||
condStruct.Operand1 = values[0]
|
|
||||||
if len(values) == 2 {
|
|
||||||
condStruct.Operand2 = values[1]
|
|
||||||
} else {
|
|
||||||
condStruct.Operand2 = 0 // Unused
|
|
||||||
}
|
|
||||||
|
|
||||||
return condStruct, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility Functions
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public Filter API
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
filterCtx C.scmp_filter_ctx
|
|
||||||
valid bool
|
|
||||||
lock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
fPtr := C.seccomp_init(defaultAction.toNative())
|
|
||||||
if fPtr == nil {
|
|
||||||
return nil, fmt.Errorf("could not create filter")
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := new(ScmpFilter)
|
|
||||||
filter.filterCtx = fPtr
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
return f.valid
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if err := sanitizeAction(defaultAction); err != nil {
|
|
||||||
return err
|
|
||||||
} else if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative())
|
|
||||||
if retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// Release() will be invoked automatically when a filter context is garbage
|
|
||||||
// collected, but can also be called manually to free memory.
|
|
||||||
func (f *ScmpFilter) Release() {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if !f.valid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.valid = false
|
|
||||||
C.seccomp_release(f.filterCtx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 (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
|
|
||||||
// associated rules, will be added to the destination.
|
|
||||||
// Returns an error if merging the filters failed.
|
|
||||||
func (f *ScmpFilter) Merge(src *ScmpFilter) error {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
src.lock.Lock()
|
|
||||||
defer src.lock.Unlock()
|
|
||||||
|
|
||||||
if !src.valid || !f.valid {
|
|
||||||
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")
|
|
||||||
} else if retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
src.valid = false
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// If a filter does not contain an architecture, all syscalls made to that
|
|
||||||
// kernel ABI will fail with the filter's default Bad Architecture Action
|
|
||||||
// (by default, killing the process).
|
|
||||||
// Accepts an architecture constant.
|
|
||||||
// Returns true if the architecture is present in the filter, false otherwise,
|
|
||||||
// and an error on an invalid filter context, architecture constant, or an
|
|
||||||
// issue with the call to libseccomp.
|
|
||||||
func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if err := sanitizeArch(arch); err != nil {
|
|
||||||
return false, err
|
|
||||||
} else if !f.valid {
|
|
||||||
return false, errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative())
|
|
||||||
if syscall.Errno(-1*retCode) == syscall.EEXIST {
|
|
||||||
// -EEXIST is "arch not present"
|
|
||||||
return false, nil
|
|
||||||
} else if retCode != 0 {
|
|
||||||
return false, syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
func (f *ScmpFilter) AddArch(arch ScmpArch) error {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if err := sanitizeArch(arch); err != nil {
|
|
||||||
return err
|
|
||||||
} else if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Libseccomp returns -EEXIST if the specified architecture is already
|
|
||||||
// present. Succeed silently in this case, as it's not fatal, and the
|
|
||||||
// architecture is present already.
|
|
||||||
retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative())
|
|
||||||
if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
func (f *ScmpFilter) RemoveArch(arch ScmpArch) error {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if err := sanitizeArch(arch); err != nil {
|
|
||||||
return err
|
|
||||||
} else if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to AddArch, -EEXIST is returned if the arch is not present
|
|
||||||
// Succeed silently in that case, this is not fatal and the architecture
|
|
||||||
// is not present in the filter after RemoveArch
|
|
||||||
retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative())
|
|
||||||
if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
if retCode := C.seccomp_load(f.filterCtx); retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
if err != nil {
|
|
||||||
return 0x0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return actionFromNative(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
if err != nil {
|
|
||||||
return 0x0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return actionFromNative(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if noNewPrivs == 0 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 log == 0 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.setFilterAttr(filterAttrActBadArch, action.toNative())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
if state {
|
|
||||||
toSet = 0x1
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.setFilterAttr(filterAttrNNP, toSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 state {
|
|
||||||
toSet = 0x1
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
// 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
|
|
||||||
// lower-priority syscalls).
|
|
||||||
func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call),
|
|
||||||
C.uint8_t(priority)); retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
func (f *ScmpFilter) AddRule(call ScmpSyscall, action ScmpAction) error {
|
|
||||||
return f.addRuleGeneric(call, action, false, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// 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.
|
|
||||||
func (f *ScmpFilter) AddRuleExact(call ScmpSyscall, action ScmpAction) error {
|
|
||||||
return f.addRuleGeneric(call, action, true, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
fd := file.Fd()
|
|
||||||
|
|
||||||
if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
fd := file.Fd()
|
|
||||||
|
|
||||||
if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
571
vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
generated
vendored
571
vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
generated
vendored
@ -1,571 +0,0 @@
|
|||||||
// +build linux
|
|
||||||
|
|
||||||
// Internal functions for libseccomp Go bindings
|
|
||||||
// No exported functions
|
|
||||||
|
|
||||||
package seccomp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Unexported C wrapping code - provides the C-Golang interface
|
|
||||||
// Get the seccomp header in scope
|
|
||||||
// Need stdlib.h for free() on cstrings
|
|
||||||
|
|
||||||
// #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.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_PPC
|
|
||||||
#define SCMP_ARCH_PPC ARCH_BAD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SCMP_ARCH_PPC64
|
|
||||||
#define SCMP_ARCH_PPC64 ARCH_BAD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SCMP_ARCH_PPC64LE
|
|
||||||
#define SCMP_ARCH_PPC64LE ARCH_BAD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SCMP_ARCH_S390
|
|
||||||
#define SCMP_ARCH_S390 ARCH_BAD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SCMP_ARCH_S390X
|
|
||||||
#define SCMP_ARCH_S390X ARCH_BAD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
|
|
||||||
const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
|
|
||||||
const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
|
|
||||||
const uint32_t C_ARCH_X32 = SCMP_ARCH_X32;
|
|
||||||
const uint32_t C_ARCH_ARM = SCMP_ARCH_ARM;
|
|
||||||
const uint32_t C_ARCH_AARCH64 = SCMP_ARCH_AARCH64;
|
|
||||||
const uint32_t C_ARCH_MIPS = SCMP_ARCH_MIPS;
|
|
||||||
const uint32_t C_ARCH_MIPS64 = SCMP_ARCH_MIPS64;
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
const int C_CMP_LE = (int)SCMP_CMP_LE;
|
|
||||||
const int C_CMP_EQ = (int)SCMP_CMP_EQ;
|
|
||||||
const int C_CMP_GE = (int)SCMP_CMP_GE;
|
|
||||||
const int C_CMP_GT = (int)SCMP_CMP_GT;
|
|
||||||
const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
void* make_arg_cmp_array(unsigned int length)
|
|
||||||
{
|
|
||||||
return calloc(length, sizeof(struct scmp_arg_cmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
// Nonexported types
|
|
||||||
type scmpFilterAttr uint32
|
|
||||||
|
|
||||||
// Nonexported constants
|
|
||||||
|
|
||||||
const (
|
|
||||||
filterAttrActDefault scmpFilterAttr = iota
|
|
||||||
filterAttrActBadArch scmpFilterAttr = iota
|
|
||||||
filterAttrNNP scmpFilterAttr = iota
|
|
||||||
filterAttrTsync scmpFilterAttr = iota
|
|
||||||
filterAttrLog scmpFilterAttr = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// An error return from certain libseccomp functions
|
|
||||||
scmpError C.int = -1
|
|
||||||
// Comparison boundaries to check for architecture validity
|
|
||||||
archStart ScmpArch = ArchNative
|
|
||||||
archEnd ScmpArch = ArchS390X
|
|
||||||
// Comparison boundaries to check for action validity
|
|
||||||
actionStart ScmpAction = ActKill
|
|
||||||
actionEnd ScmpAction = ActLog
|
|
||||||
// Comparison boundaries to check for comparison operator validity
|
|
||||||
compareOpStart ScmpCompareOp = CompareNotEqual
|
|
||||||
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 = 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 uint) bool {
|
|
||||||
return (verMajor > major) ||
|
|
||||||
(verMajor == major && verMinor > minor) ||
|
|
||||||
(verMajor == major && verMinor == minor && verMicro >= micro)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// Filter finalizer - ensure that kernel context for filters is freed
|
|
||||||
func filterFinalizer(f *ScmpFilter) {
|
|
||||||
f.Release()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a raw filter attribute
|
|
||||||
func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if !f.valid {
|
|
||||||
return 0x0, errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
var attribute C.uint32_t
|
|
||||||
|
|
||||||
retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
|
|
||||||
if retCode != 0 {
|
|
||||||
return 0x0, syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return attribute, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a raw filter attribute
|
|
||||||
func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error {
|
|
||||||
f.lock.Lock()
|
|
||||||
defer f.lock.Unlock()
|
|
||||||
|
|
||||||
if !f.valid {
|
|
||||||
return errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
|
|
||||||
if retCode != 0 {
|
|
||||||
return syscall.Errno(-1 * retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, 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
|
|
||||||
if exact {
|
|
||||||
retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
|
||||||
} else {
|
|
||||||
retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if syscall.Errno(-1*retCode) == syscall.EFAULT {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 errBadFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(conds) == 0 {
|
|
||||||
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 VersionError{
|
|
||||||
message: "conditional filtering is not supported",
|
|
||||||
minimum: "2.2.1",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic Helpers
|
|
||||||
|
|
||||||
// Helper - Sanitize Arch token input
|
|
||||||
func sanitizeArch(in ScmpArch) error {
|
|
||||||
if in < archStart || in > archEnd {
|
|
||||||
return fmt.Errorf("unrecognized architecture %#x", uint(in))
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.toNative() == C.C_ARCH_BAD {
|
|
||||||
return fmt.Errorf("architecture %v is not supported on this version of the library", in)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sanitizeAction(in ScmpAction) error {
|
|
||||||
inTmp := in & 0x0000FFFF
|
|
||||||
if inTmp < actionStart || inTmp > actionEnd {
|
|
||||||
return fmt.Errorf("unrecognized action %#x", uint(inTmp))
|
|
||||||
}
|
|
||||||
|
|
||||||
if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
|
|
||||||
return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sanitizeCompareOp(in ScmpCompareOp) error {
|
|
||||||
if in < compareOpStart || in > compareOpEnd {
|
|
||||||
return fmt.Errorf("unrecognized comparison operator %#x", uint(in))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func archFromNative(a C.uint32_t) (ScmpArch, error) {
|
|
||||||
switch a {
|
|
||||||
case C.C_ARCH_X86:
|
|
||||||
return ArchX86, nil
|
|
||||||
case C.C_ARCH_X86_64:
|
|
||||||
return ArchAMD64, nil
|
|
||||||
case C.C_ARCH_X32:
|
|
||||||
return ArchX32, nil
|
|
||||||
case C.C_ARCH_ARM:
|
|
||||||
return ArchARM, nil
|
|
||||||
case C.C_ARCH_NATIVE:
|
|
||||||
return ArchNative, nil
|
|
||||||
case C.C_ARCH_AARCH64:
|
|
||||||
return ArchARM64, nil
|
|
||||||
case C.C_ARCH_MIPS:
|
|
||||||
return ArchMIPS, nil
|
|
||||||
case C.C_ARCH_MIPS64:
|
|
||||||
return ArchMIPS64, nil
|
|
||||||
case C.C_ARCH_MIPS64N32:
|
|
||||||
return ArchMIPS64N32, nil
|
|
||||||
case C.C_ARCH_MIPSEL:
|
|
||||||
return ArchMIPSEL, nil
|
|
||||||
case C.C_ARCH_MIPSEL64:
|
|
||||||
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 %#x", uint32(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only use with sanitized arches, no error handling
|
|
||||||
func (a ScmpArch) toNative() C.uint32_t {
|
|
||||||
switch a {
|
|
||||||
case ArchX86:
|
|
||||||
return C.C_ARCH_X86
|
|
||||||
case ArchAMD64:
|
|
||||||
return C.C_ARCH_X86_64
|
|
||||||
case ArchX32:
|
|
||||||
return C.C_ARCH_X32
|
|
||||||
case ArchARM:
|
|
||||||
return C.C_ARCH_ARM
|
|
||||||
case ArchARM64:
|
|
||||||
return C.C_ARCH_AARCH64
|
|
||||||
case ArchMIPS:
|
|
||||||
return C.C_ARCH_MIPS
|
|
||||||
case ArchMIPS64:
|
|
||||||
return C.C_ARCH_MIPS64
|
|
||||||
case ArchMIPS64N32:
|
|
||||||
return C.C_ARCH_MIPS64N32
|
|
||||||
case ArchMIPSEL:
|
|
||||||
return C.C_ARCH_MIPSEL
|
|
||||||
case ArchMIPSEL64:
|
|
||||||
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:
|
|
||||||
return 0x0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only use with sanitized ops, no error handling
|
|
||||||
func (a ScmpCompareOp) toNative() C.int {
|
|
||||||
switch a {
|
|
||||||
case CompareNotEqual:
|
|
||||||
return C.C_CMP_NE
|
|
||||||
case CompareLess:
|
|
||||||
return C.C_CMP_LT
|
|
||||||
case CompareLessOrEqual:
|
|
||||||
return C.C_CMP_LE
|
|
||||||
case CompareEqual:
|
|
||||||
return C.C_CMP_EQ
|
|
||||||
case CompareGreaterEqual:
|
|
||||||
return C.C_CMP_GE
|
|
||||||
case CompareGreater:
|
|
||||||
return C.C_CMP_GT
|
|
||||||
case CompareMaskedEqual:
|
|
||||||
return C.C_CMP_MASKED_EQ
|
|
||||||
default:
|
|
||||||
return 0x0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func actionFromNative(a C.uint32_t) (ScmpAction, error) {
|
|
||||||
aTmp := a & 0xFFFF
|
|
||||||
switch a & 0xFFFF0000 {
|
|
||||||
case C.C_ACT_KILL:
|
|
||||||
return ActKill, nil
|
|
||||||
case C.C_ACT_TRAP:
|
|
||||||
return ActTrap, nil
|
|
||||||
case C.C_ACT_ERRNO:
|
|
||||||
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 %#x", uint32(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only use with sanitized actions, no error handling
|
|
||||||
func (a ScmpAction) toNative() C.uint32_t {
|
|
||||||
switch a & 0xFFFF {
|
|
||||||
case ActKill:
|
|
||||||
return C.C_ACT_KILL
|
|
||||||
case ActTrap:
|
|
||||||
return C.C_ACT_TRAP
|
|
||||||
case ActErrno:
|
|
||||||
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:
|
|
||||||
return 0x0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal only, assumes safe attribute
|
|
||||||
func (a scmpFilterAttr) toNative() uint32 {
|
|
||||||
switch a {
|
|
||||||
case filterAttrActDefault:
|
|
||||||
return uint32(C.C_ATTRIBUTE_DEFAULT)
|
|
||||||
case filterAttrActBadArch:
|
|
||||||
return uint32(C.C_ATTRIBUTE_BADARCH)
|
|
||||||
case filterAttrNNP:
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user