github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/specgen/generate/security.go (about) 1 package generate 2 3 import ( 4 "strings" 5 6 "github.com/containers/common/pkg/apparmor" 7 "github.com/containers/common/pkg/capabilities" 8 "github.com/containers/common/pkg/config" 9 "github.com/containers/podman/v2/libpod" 10 "github.com/containers/podman/v2/libpod/define" 11 "github.com/containers/podman/v2/libpod/image" 12 "github.com/containers/podman/v2/pkg/specgen" 13 "github.com/containers/podman/v2/pkg/util" 14 "github.com/opencontainers/runtime-tools/generate" 15 "github.com/opencontainers/selinux/go-selinux/label" 16 "github.com/pkg/errors" 17 "github.com/sirupsen/logrus" 18 ) 19 20 // setLabelOpts sets the label options of the SecurityConfig according to the 21 // input. 22 func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error { 23 if !runtime.EnableLabeling() || s.Privileged { 24 s.SelinuxOpts = label.DisableSecOpt() 25 return nil 26 } 27 28 var labelOpts []string 29 if pidConfig.IsHost() { 30 labelOpts = append(labelOpts, label.DisableSecOpt()...) 31 } else if pidConfig.IsContainer() { 32 ctr, err := runtime.LookupContainer(pidConfig.Value) 33 if err != nil { 34 return errors.Wrapf(err, "container %q not found", pidConfig.Value) 35 } 36 secopts, err := label.DupSecOpt(ctr.ProcessLabel()) 37 if err != nil { 38 return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel()) 39 } 40 labelOpts = append(labelOpts, secopts...) 41 } 42 43 if ipcConfig.IsHost() { 44 labelOpts = append(labelOpts, label.DisableSecOpt()...) 45 } else if ipcConfig.IsContainer() { 46 ctr, err := runtime.LookupContainer(ipcConfig.Value) 47 if err != nil { 48 return errors.Wrapf(err, "container %q not found", ipcConfig.Value) 49 } 50 secopts, err := label.DupSecOpt(ctr.ProcessLabel()) 51 if err != nil { 52 return errors.Wrapf(err, "failed to duplicate label %q ", ctr.ProcessLabel()) 53 } 54 labelOpts = append(labelOpts, secopts...) 55 } 56 57 s.SelinuxOpts = append(s.SelinuxOpts, labelOpts...) 58 return nil 59 } 60 61 func setupApparmor(s *specgen.SpecGenerator, rtc *config.Config, g *generate.Generator) error { 62 hasProfile := len(s.ApparmorProfile) > 0 63 if !apparmor.IsEnabled() { 64 if hasProfile && s.ApparmorProfile != "unconfined" { 65 return errors.Errorf("Apparmor profile %q specified, but Apparmor is not enabled on this system", s.ApparmorProfile) 66 } 67 return nil 68 } 69 // If privileged and caller did not specify apparmor profiles return 70 if s.Privileged && !hasProfile { 71 return nil 72 } 73 if !hasProfile { 74 s.ApparmorProfile = rtc.Containers.ApparmorProfile 75 } 76 if len(s.ApparmorProfile) > 0 { 77 g.SetProcessApparmorProfile(s.ApparmorProfile) 78 } 79 80 return nil 81 } 82 83 func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image, rtc *config.Config) error { 84 var ( 85 caplist []string 86 err error 87 ) 88 // HANDLE CAPABILITIES 89 // NOTE: Must happen before SECCOMP 90 if s.Privileged { 91 g.SetupPrivileged(true) 92 caplist = capabilities.AllCapabilities() 93 } else { 94 caplist, err = capabilities.MergeCapabilities(rtc.Containers.DefaultCapabilities, s.CapAdd, s.CapDrop) 95 if err != nil { 96 return err 97 } 98 99 privCapsRequired := []string{} 100 101 // If the container image specifies an label with a 102 // capabilities.ContainerImageLabel then split the comma separated list 103 // of capabilities and record them. This list indicates the only 104 // capabilities, required to run the container. 105 var capsRequiredRequested []string 106 for key, val := range s.Labels { 107 if util.StringInSlice(key, capabilities.ContainerImageLabels) { 108 capsRequiredRequested = strings.Split(val, ",") 109 } 110 } 111 if !s.Privileged && len(capsRequiredRequested) > 0 { 112 113 // Pass capRequiredRequested in CapAdd field to normalize capabilities names 114 capsRequired, err := capabilities.MergeCapabilities(nil, capsRequiredRequested, nil) 115 if err != nil { 116 return errors.Wrapf(err, "capabilities requested by user or image are not valid: %q", strings.Join(capsRequired, ",")) 117 } else { 118 // Verify all capRequiered are in the capList 119 for _, cap := range capsRequired { 120 if !util.StringInSlice(cap, caplist) { 121 privCapsRequired = append(privCapsRequired, cap) 122 } 123 } 124 } 125 if len(privCapsRequired) == 0 { 126 caplist = capsRequired 127 } else { 128 logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ",")) 129 } 130 } 131 } 132 133 configSpec := g.Config 134 configSpec.Process.Capabilities.Ambient = []string{} 135 configSpec.Process.Capabilities.Bounding = caplist 136 configSpec.Process.Capabilities.Inheritable = caplist 137 138 user := strings.Split(s.User, ":")[0] 139 140 if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" { 141 configSpec.Process.Capabilities.Effective = caplist 142 configSpec.Process.Capabilities.Permitted = caplist 143 } else { 144 userCaps, err := capabilities.NormalizeCapabilities(s.CapAdd) 145 if err != nil { 146 return errors.Wrapf(err, "capabilities requested by user are not valid: %q", strings.Join(s.CapAdd, ",")) 147 } 148 configSpec.Process.Capabilities.Effective = userCaps 149 configSpec.Process.Capabilities.Permitted = userCaps 150 151 // Ambient capabilities were added to Linux 4.3. Set ambient 152 // capabilities only when the kernel supports them. 153 if supportAmbientCapabilities() { 154 configSpec.Process.Capabilities.Ambient = userCaps 155 } 156 } 157 158 g.SetProcessNoNewPrivileges(s.NoNewPrivileges) 159 160 if err := setupApparmor(s, rtc, g); err != nil { 161 return err 162 } 163 164 // HANDLE SECCOMP 165 if s.SeccompProfilePath != "unconfined" { 166 seccompConfig, err := getSeccompConfig(s, configSpec, newImage) 167 if err != nil { 168 return err 169 } 170 configSpec.Linux.Seccomp = seccompConfig 171 } 172 173 // Clear default Seccomp profile from Generator for unconfined containers 174 // and privileged containers which do not specify a seccomp profile. 175 if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) { 176 configSpec.Linux.Seccomp = nil 177 } 178 179 g.SetRootReadonly(s.ReadOnlyFilesystem) 180 181 // Add default sysctls 182 defaultSysctls, err := util.ValidateSysctls(rtc.Sysctls()) 183 if err != nil { 184 return err 185 } 186 for sysctlKey, sysctlVal := range defaultSysctls { 187 188 // Ignore mqueue sysctls if --ipc=host 189 if s.IpcNS.IsHost() && strings.HasPrefix(sysctlKey, "fs.mqueue.") { 190 logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to host", sysctlKey, sysctlVal) 191 192 continue 193 } 194 195 // Ignore net sysctls if --net=host 196 if s.NetNS.IsHost() && strings.HasPrefix(sysctlKey, "net.") { 197 logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctlKey, sysctlVal) 198 continue 199 } 200 201 // Ignore uts sysctls if --uts=host 202 if s.UtsNS.IsHost() && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) { 203 logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace set to host", sysctlKey, sysctlVal) 204 continue 205 } 206 207 g.AddLinuxSysctl(sysctlKey, sysctlVal) 208 } 209 210 for sysctlKey, sysctlVal := range s.Sysctl { 211 212 if s.IpcNS.IsHost() && strings.HasPrefix(sysctlKey, "fs.mqueue.") { 213 return errors.Wrapf(define.ErrInvalidArg, "sysctl %s=%s can't be set since IPC Namespace set to host", sysctlKey, sysctlVal) 214 } 215 216 // Ignore net sysctls if --net=host 217 if s.NetNS.IsHost() && strings.HasPrefix(sysctlKey, "net.") { 218 return errors.Wrapf(define.ErrInvalidArg, "sysctl %s=%s can't be set since Host Namespace set to host", sysctlKey, sysctlVal) 219 } 220 221 // Ignore uts sysctls if --uts=host 222 if s.UtsNS.IsHost() && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) { 223 return errors.Wrapf(define.ErrInvalidArg, "sysctl %s=%s can't be set since UTS Namespace set to host", sysctlKey, sysctlVal) 224 } 225 226 g.AddLinuxSysctl(sysctlKey, sysctlVal) 227 } 228 229 return nil 230 }