github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/daemon/execdriver/native/create.go (about) 1 // +build linux,cgo 2 3 package native 4 5 import ( 6 "errors" 7 "fmt" 8 "net" 9 "strings" 10 "syscall" 11 12 "github.com/docker/docker/daemon/execdriver" 13 "github.com/opencontainers/runc/libcontainer/apparmor" 14 "github.com/opencontainers/runc/libcontainer/configs" 15 "github.com/opencontainers/runc/libcontainer/devices" 16 "github.com/opencontainers/runc/libcontainer/utils" 17 ) 18 19 // createContainer populates and configures the container type with the 20 // data provided by the execdriver.Command 21 func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) { 22 container := execdriver.InitContainer(c) 23 24 if err := d.createIpc(container, c); err != nil { 25 return nil, err 26 } 27 28 if err := d.createPid(container, c); err != nil { 29 return nil, err 30 } 31 32 if err := d.createUTS(container, c); err != nil { 33 return nil, err 34 } 35 36 if err := d.createNetwork(container, c, hooks); err != nil { 37 return nil, err 38 } 39 40 if c.ProcessConfig.Privileged { 41 if !container.Readonlyfs { 42 // clear readonly for /sys 43 for i := range container.Mounts { 44 if container.Mounts[i].Destination == "/sys" { 45 container.Mounts[i].Flags &= ^syscall.MS_RDONLY 46 } 47 } 48 container.ReadonlyPaths = nil 49 } 50 51 // clear readonly for cgroup 52 for i := range container.Mounts { 53 if container.Mounts[i].Device == "cgroup" { 54 container.Mounts[i].Flags &= ^syscall.MS_RDONLY 55 } 56 } 57 58 container.MaskPaths = nil 59 if err := d.setPrivileged(container); err != nil { 60 return nil, err 61 } 62 } else { 63 if err := d.setCapabilities(container, c); err != nil { 64 return nil, err 65 } 66 } 67 68 container.AdditionalGroups = c.GroupAdd 69 70 if c.AppArmorProfile != "" { 71 container.AppArmorProfile = c.AppArmorProfile 72 } 73 74 if err := execdriver.SetupCgroups(container, c); err != nil { 75 return nil, err 76 } 77 78 if container.Readonlyfs { 79 for i := range container.Mounts { 80 switch container.Mounts[i].Destination { 81 case "/proc", "/dev", "/dev/pts": 82 continue 83 } 84 container.Mounts[i].Flags |= syscall.MS_RDONLY 85 } 86 87 /* These paths must be remounted as r/o */ 88 container.ReadonlyPaths = append(container.ReadonlyPaths, "/dev") 89 } 90 91 if err := d.setupMounts(container, c); err != nil { 92 return nil, err 93 } 94 95 d.setupLabels(container, c) 96 d.setupRlimits(container, c) 97 return container, nil 98 } 99 100 func generateIfaceName() (string, error) { 101 for i := 0; i < 10; i++ { 102 name, err := utils.GenerateRandomName("veth", 7) 103 if err != nil { 104 continue 105 } 106 if _, err := net.InterfaceByName(name); err != nil { 107 if strings.Contains(err.Error(), "no such") { 108 return name, nil 109 } 110 return "", err 111 } 112 } 113 return "", errors.New("Failed to find name for new interface") 114 } 115 116 func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error { 117 if c.Network == nil { 118 return nil 119 } 120 if c.Network.ContainerID != "" { 121 d.Lock() 122 active := d.activeContainers[c.Network.ContainerID] 123 d.Unlock() 124 125 if active == nil { 126 return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) 127 } 128 129 state, err := active.State() 130 if err != nil { 131 return err 132 } 133 134 container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET]) 135 return nil 136 } 137 138 if c.Network.NamespacePath != "" { 139 container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath) 140 return nil 141 } 142 // only set up prestart hook if the namespace path is not set (this should be 143 // all cases *except* for --net=host shared networking) 144 container.Hooks = &configs.Hooks{ 145 Prestart: []configs.Hook{ 146 configs.NewFunctionHook(func(s configs.HookState) error { 147 if len(hooks.PreStart) > 0 { 148 for _, fnHook := range hooks.PreStart { 149 if err := fnHook(&c.ProcessConfig, s.Pid); err != nil { 150 return err 151 } 152 } 153 } 154 return nil 155 }), 156 }, 157 } 158 return nil 159 } 160 161 func (d *Driver) createIpc(container *configs.Config, c *execdriver.Command) error { 162 if c.Ipc.HostIpc { 163 container.Namespaces.Remove(configs.NEWIPC) 164 return nil 165 } 166 167 if c.Ipc.ContainerID != "" { 168 d.Lock() 169 active := d.activeContainers[c.Ipc.ContainerID] 170 d.Unlock() 171 172 if active == nil { 173 return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID) 174 } 175 176 state, err := active.State() 177 if err != nil { 178 return err 179 } 180 container.Namespaces.Add(configs.NEWIPC, state.NamespacePaths[configs.NEWIPC]) 181 } 182 183 return nil 184 } 185 186 func (d *Driver) createPid(container *configs.Config, c *execdriver.Command) error { 187 if c.Pid.HostPid { 188 container.Namespaces.Remove(configs.NEWPID) 189 return nil 190 } 191 192 return nil 193 } 194 195 func (d *Driver) createUTS(container *configs.Config, c *execdriver.Command) error { 196 if c.UTS.HostUTS { 197 container.Namespaces.Remove(configs.NEWUTS) 198 container.Hostname = "" 199 return nil 200 } 201 202 return nil 203 } 204 205 func (d *Driver) setPrivileged(container *configs.Config) (err error) { 206 container.Capabilities = execdriver.GetAllCapabilities() 207 container.Cgroups.AllowAllDevices = true 208 209 hostDevices, err := devices.HostDevices() 210 if err != nil { 211 return err 212 } 213 container.Devices = hostDevices 214 215 if apparmor.IsEnabled() { 216 container.AppArmorProfile = "unconfined" 217 } 218 return nil 219 } 220 221 func (d *Driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) { 222 container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) 223 return err 224 } 225 226 func (d *Driver) setupRlimits(container *configs.Config, c *execdriver.Command) { 227 if c.Resources == nil { 228 return 229 } 230 231 for _, rlimit := range c.Resources.Rlimits { 232 container.Rlimits = append(container.Rlimits, configs.Rlimit{ 233 Type: rlimit.Type, 234 Hard: rlimit.Hard, 235 Soft: rlimit.Soft, 236 }) 237 } 238 } 239 240 func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) error { 241 userMounts := make(map[string]struct{}) 242 for _, m := range c.Mounts { 243 userMounts[m.Destination] = struct{}{} 244 } 245 246 // Filter out mounts that are overriden by user supplied mounts 247 var defaultMounts []*configs.Mount 248 _, mountDev := userMounts["/dev"] 249 for _, m := range container.Mounts { 250 if _, ok := userMounts[m.Destination]; !ok { 251 if mountDev && strings.HasPrefix(m.Destination, "/dev/") { 252 continue 253 } 254 defaultMounts = append(defaultMounts, m) 255 } 256 } 257 container.Mounts = defaultMounts 258 259 for _, m := range c.Mounts { 260 flags := syscall.MS_BIND | syscall.MS_REC 261 if !m.Writable { 262 flags |= syscall.MS_RDONLY 263 } 264 if m.Slave { 265 flags |= syscall.MS_SLAVE 266 } 267 container.Mounts = append(container.Mounts, &configs.Mount{ 268 Source: m.Source, 269 Destination: m.Destination, 270 Device: "bind", 271 Flags: flags, 272 }) 273 } 274 return nil 275 } 276 277 func (d *Driver) setupLabels(container *configs.Config, c *execdriver.Command) { 278 container.ProcessLabel = c.ProcessLabel 279 container.MountLabel = c.MountLabel 280 }