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