1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
//go:generate go run -tags 'seccomp' generate.go
package seccomp
import (
"encoding/json"
"errors"
"fmt"
"runtime"
"github.com/opencontainers/runtime-spec/specs-go"
)
// GetDefaultProfile returns the default seccomp profile.
func GetDefaultProfile(rs *specs.Spec) (*specs.LinuxSeccomp, error) {
return setupSeccomp(DefaultProfile(), rs)
}
// LoadProfile takes a json string and decodes the seccomp profile.
func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
var config Seccomp
if err := json.Unmarshal([]byte(body), &config); err != nil {
return nil, fmt.Errorf("Decoding seccomp profile failed: %v", err)
}
return setupSeccomp(&config, rs)
}
// libseccomp string => seccomp arch
var nativeToSeccomp = map[string]specs.Arch{
"x86": specs.ArchX86,
"amd64": specs.ArchX86_64,
"arm": specs.ArchARM,
"arm64": specs.ArchAARCH64,
"mips64": specs.ArchMIPS64,
"mips64n32": specs.ArchMIPS64N32,
"mipsel64": specs.ArchMIPSEL64,
"mips3l64n32": specs.ArchMIPSEL64N32,
"mipsle": specs.ArchMIPSEL,
"ppc": specs.ArchPPC,
"ppc64": specs.ArchPPC64,
"ppc64le": specs.ArchPPC64LE,
"riscv64": specs.ArchRISCV64,
"s390": specs.ArchS390,
"s390x": specs.ArchS390X,
}
// GOARCH => libseccomp string
var goToNative = map[string]string{
"386": "x86",
"amd64": "amd64",
"arm": "arm",
"arm64": "arm64",
"mips64": "mips64",
"mips64p32": "mips64n32",
"mips64le": "mipsel64",
"mips64p32le": "mips3l64n32",
"mipsle": "mipsel",
"ppc": "ppc",
"ppc64": "ppc64",
"ppc64le": "ppc64le",
"riscv64": "riscv64",
"s390": "s390",
"s390x": "s390x",
}
// inSlice tests whether a string is contained in a slice of strings or not.
// Comparison is case sensitive
func inSlice(slice []string, s string) bool {
for _, ss := range slice {
if s == ss {
return true
}
}
return false
}
func setupSeccomp(config *Seccomp, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
if config == nil {
return nil, nil
}
// No default action specified, no syscalls listed, assume seccomp disabled
if config.DefaultAction == "" && len(config.Syscalls) == 0 {
return nil, nil
}
if len(config.Architectures) != 0 && len(config.ArchMap) != 0 {
return nil, errors.New("both 'architectures' and 'archMap' are specified in the seccomp profile, use either 'architectures' or 'archMap'")
}
if len(config.LinuxSeccomp.Syscalls) != 0 {
// The Seccomp type overrides the LinuxSeccomp.Syscalls field,
// so 'this should never happen' when loaded from JSON, but could
// happen if someone constructs the Config from source.
return nil, errors.New("the LinuxSeccomp.Syscalls field should be empty")
}
var (
// Copy all common / standard properties to the output profile
newConfig = &config.LinuxSeccomp
arch = goToNative[runtime.GOARCH]
)
if seccompArch, ok := nativeToSeccomp[arch]; ok {
for _, a := range config.ArchMap {
if a.Arch == seccompArch {
newConfig.Architectures = append(newConfig.Architectures, a.Arch)
newConfig.Architectures = append(newConfig.Architectures, a.SubArches...)
break
}
}
}
Loop:
// Convert Syscall to OCI runtimes-spec specs.LinuxSyscall after filtering them.
for _, call := range config.Syscalls {
if call.Name != "" {
if len(call.Names) != 0 {
return nil, errors.New("both 'name' and 'names' are specified in the seccomp profile, use either 'name' or 'names'")
}
call.Names = []string{call.Name}
}
if call.Excludes != nil {
if len(call.Excludes.Arches) > 0 {
if inSlice(call.Excludes.Arches, arch) {
continue Loop
}
}
if len(call.Excludes.Caps) > 0 {
for _, c := range call.Excludes.Caps {
if inSlice(rs.Process.Capabilities.Bounding, c) {
continue Loop
}
}
}
if call.Excludes.MinKernel != nil {
if ok, err := kernelGreaterEqualThan(*call.Excludes.MinKernel); err != nil {
return nil, err
} else if ok {
continue Loop
}
}
}
if call.Includes != nil {
if len(call.Includes.Arches) > 0 {
if !inSlice(call.Includes.Arches, arch) {
continue Loop
}
}
if len(call.Includes.Caps) > 0 {
for _, c := range call.Includes.Caps {
if !inSlice(rs.Process.Capabilities.Bounding, c) {
continue Loop
}
}
}
if call.Includes.MinKernel != nil {
if ok, err := kernelGreaterEqualThan(*call.Includes.MinKernel); err != nil {
return nil, err
} else if !ok {
continue Loop
}
}
}
newConfig.Syscalls = append(newConfig.Syscalls, call.LinuxSyscall)
}
return newConfig, nil
}
|