func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) error { linkedEnv, err := daemon.setupLinkedContainers(c) if err != nil { return err } s.Root = specs.Root{ Path: c.BaseFS, Readonly: c.HostConfig.ReadonlyRootfs, } rootUID, rootGID := daemon.GetRemappedUIDGID() if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil { return err } cwd := c.Config.WorkingDir if len(cwd) == 0 { cwd = "/" } s.Process.Args = append([]string{c.Path}, c.Args...) // only add the custom init if it is specified and the container is running in its // own private pid namespace. It does not make sense to add if it is running in the // host namespace or another container's pid namespace where we already have an init if c.HostConfig.PidMode.IsPrivate() { if (c.HostConfig.Init != nil && *c.HostConfig.Init) || (c.HostConfig.Init == nil && daemon.configStore.Init) { s.Process.Args = append([]string{"/dev/init", c.Path}, c.Args...) var path string if daemon.configStore.InitPath == "" && c.HostConfig.InitPath == "" { path, err = exec.LookPath(DefaultInitBinary) if err != nil { return err } } if daemon.configStore.InitPath != "" { path = daemon.configStore.InitPath } if c.HostConfig.InitPath != "" { path = c.HostConfig.InitPath } s.Mounts = append(s.Mounts, specs.Mount{ Destination: "/dev/init", Type: "bind", Source: path, Options: []string{"bind", "ro"}, }) } } s.Process.Cwd = cwd s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv) s.Process.Terminal = c.Config.Tty s.Hostname = c.FullHostname() return nil }
func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error { userNS := false // user if c.HostConfig.UsernsMode.IsPrivate() { uidMap, gidMap := daemon.GetUIDGIDMaps() if uidMap != nil { userNS = true ns := specs.Namespace{Type: "user"} setNamespace(s, ns) s.Linux.UIDMappings = specMapping(uidMap) s.Linux.GIDMappings = specMapping(gidMap) } } // network if !c.Config.NetworkDisabled { ns := specs.Namespace{Type: "network"} parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2) if parts[0] == "container" { nc, err := daemon.getNetworkedContainer(c.ID, c.HostConfig.NetworkMode.ConnectedContainer()) if err != nil { return err } ns.Path = fmt.Sprintf("/proc/%d/ns/net", nc.State.GetPID()) if userNS { // to share a net namespace, they must also share a user namespace nsUser := specs.Namespace{Type: "user"} nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", nc.State.GetPID()) setNamespace(s, nsUser) } } else if c.HostConfig.NetworkMode.IsHost() { ns.Path = c.NetworkSettings.SandboxKey } setNamespace(s, ns) } // ipc if c.HostConfig.IpcMode.IsContainer() { ns := specs.Namespace{Type: "ipc"} ic, err := daemon.getIpcContainer(c) if err != nil { return err } ns.Path = fmt.Sprintf("/proc/%d/ns/ipc", ic.State.GetPID()) setNamespace(s, ns) if userNS { // to share an IPC namespace, they must also share a user namespace nsUser := specs.Namespace{Type: "user"} nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", ic.State.GetPID()) setNamespace(s, nsUser) } } else if c.HostConfig.IpcMode.IsHost() { oci.RemoveNamespace(s, specs.NamespaceType("ipc")) } else { ns := specs.Namespace{Type: "ipc"} setNamespace(s, ns) } // pid if c.HostConfig.PidMode.IsContainer() { ns := specs.Namespace{Type: "pid"} pc, err := daemon.getPidContainer(c) if err != nil { return err } ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID()) setNamespace(s, ns) if userNS { // to share a PID namespace, they must also share a user namespace nsUser := specs.Namespace{Type: "user"} nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", pc.State.GetPID()) setNamespace(s, nsUser) } } else if c.HostConfig.PidMode.IsHost() { oci.RemoveNamespace(s, specs.NamespaceType("pid")) } else { ns := specs.Namespace{Type: "pid"} setNamespace(s, ns) } // uts if c.HostConfig.UTSMode.IsHost() { oci.RemoveNamespace(s, specs.NamespaceType("uts")) s.Hostname = "" } return nil }