github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/profiles/seccomp/seccomp.go (about) 1 // +build linux 2 3 package seccomp // import "github.com/docker/docker/profiles/seccomp" 4 5 import ( 6 "encoding/json" 7 "errors" 8 "fmt" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/pkg/parsers/kernel" 12 specs "github.com/opencontainers/runtime-spec/specs-go" 13 libseccomp "github.com/seccomp/libseccomp-golang" 14 ) 15 16 //go:generate go run -tags 'seccomp' generate.go 17 18 // GetDefaultProfile returns the default seccomp profile. 19 func GetDefaultProfile(rs *specs.Spec) (*specs.LinuxSeccomp, error) { 20 return setupSeccomp(DefaultProfile(), rs) 21 } 22 23 // LoadProfile takes a json string and decodes the seccomp profile. 24 func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) { 25 var config types.Seccomp 26 if err := json.Unmarshal([]byte(body), &config); err != nil { 27 return nil, fmt.Errorf("Decoding seccomp profile failed: %v", err) 28 } 29 return setupSeccomp(&config, rs) 30 } 31 32 var nativeToSeccomp = map[string]types.Arch{ 33 "amd64": types.ArchX86_64, 34 "arm64": types.ArchAARCH64, 35 "mips64": types.ArchMIPS64, 36 "mips64n32": types.ArchMIPS64N32, 37 "mipsel64": types.ArchMIPSEL64, 38 "mipsel64n32": types.ArchMIPSEL64N32, 39 "s390x": types.ArchS390X, 40 } 41 42 // inSlice tests whether a string is contained in a slice of strings or not. 43 // Comparison is case sensitive 44 func inSlice(slice []string, s string) bool { 45 for _, ss := range slice { 46 if s == ss { 47 return true 48 } 49 } 50 return false 51 } 52 53 func setupSeccomp(config *types.Seccomp, rs *specs.Spec) (*specs.LinuxSeccomp, error) { 54 if config == nil { 55 return nil, nil 56 } 57 58 // No default action specified, no syscalls listed, assume seccomp disabled 59 if config.DefaultAction == "" && len(config.Syscalls) == 0 { 60 return nil, nil 61 } 62 63 newConfig := &specs.LinuxSeccomp{} 64 65 var arch string 66 var native, err = libseccomp.GetNativeArch() 67 if err == nil { 68 arch = native.String() 69 } 70 71 if len(config.Architectures) != 0 && len(config.ArchMap) != 0 { 72 return nil, errors.New("'architectures' and 'archMap' were specified in the seccomp profile, use either 'architectures' or 'archMap'") 73 } 74 75 // if config.Architectures == 0 then libseccomp will figure out the architecture to use 76 if len(config.Architectures) != 0 { 77 for _, a := range config.Architectures { 78 newConfig.Architectures = append(newConfig.Architectures, specs.Arch(a)) 79 } 80 } 81 82 if len(config.ArchMap) != 0 { 83 for _, a := range config.ArchMap { 84 seccompArch, ok := nativeToSeccomp[arch] 85 if ok { 86 if a.Arch == seccompArch { 87 newConfig.Architectures = append(newConfig.Architectures, specs.Arch(a.Arch)) 88 for _, sa := range a.SubArches { 89 newConfig.Architectures = append(newConfig.Architectures, specs.Arch(sa)) 90 } 91 break 92 } 93 } 94 } 95 } 96 97 newConfig.DefaultAction = specs.LinuxSeccompAction(config.DefaultAction) 98 99 Loop: 100 // Loop through all syscall blocks and convert them to libcontainer format after filtering them 101 for _, call := range config.Syscalls { 102 if len(call.Excludes.Arches) > 0 { 103 if inSlice(call.Excludes.Arches, arch) { 104 continue Loop 105 } 106 } 107 if len(call.Excludes.Caps) > 0 { 108 for _, c := range call.Excludes.Caps { 109 if inSlice(rs.Process.Capabilities.Bounding, c) { 110 continue Loop 111 } 112 } 113 } 114 if call.Excludes.MinKernel != "" { 115 if ok, err := kernelGreaterEqualThan(call.Excludes.MinKernel); err != nil { 116 return nil, err 117 } else if ok { 118 continue Loop 119 } 120 } 121 if len(call.Includes.Arches) > 0 { 122 if !inSlice(call.Includes.Arches, arch) { 123 continue Loop 124 } 125 } 126 if len(call.Includes.Caps) > 0 { 127 for _, c := range call.Includes.Caps { 128 if !inSlice(rs.Process.Capabilities.Bounding, c) { 129 continue Loop 130 } 131 } 132 } 133 if call.Includes.MinKernel != "" { 134 if ok, err := kernelGreaterEqualThan(call.Includes.MinKernel); err != nil { 135 return nil, err 136 } else if !ok { 137 continue Loop 138 } 139 } 140 141 if call.Name != "" && len(call.Names) != 0 { 142 return nil, errors.New("'name' and 'names' were specified in the seccomp profile, use either 'name' or 'names'") 143 } 144 145 if call.Name != "" { 146 newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall([]string{call.Name}, call.Action, call.Args)) 147 } else { 148 newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(call.Names, call.Action, call.Args)) 149 } 150 } 151 152 return newConfig, nil 153 } 154 155 func createSpecsSyscall(names []string, action types.Action, args []*types.Arg) specs.LinuxSyscall { 156 newCall := specs.LinuxSyscall{ 157 Names: names, 158 Action: specs.LinuxSeccompAction(action), 159 } 160 161 // Loop through all the arguments of the syscall and convert them 162 for _, arg := range args { 163 newArg := specs.LinuxSeccompArg{ 164 Index: arg.Index, 165 Value: arg.Value, 166 ValueTwo: arg.ValueTwo, 167 Op: specs.LinuxSeccompOperator(arg.Op), 168 } 169 170 newCall.Args = append(newCall.Args, newArg) 171 } 172 return newCall 173 } 174 175 var currentKernelVersion *kernel.VersionInfo 176 177 func kernelGreaterEqualThan(v string) (bool, error) { 178 version, err := kernel.ParseRelease(v) 179 if err != nil { 180 return false, err 181 } 182 if currentKernelVersion == nil { 183 currentKernelVersion, err = kernel.GetKernelVersion() 184 if err != nil { 185 return false, err 186 } 187 } 188 return kernel.CompareKernelVersion(*version, *currentKernelVersion) <= 0, nil 189 }