func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error { if c.Network.HostNetworking { container.Namespaces["NEWNET"] = false return nil } container.Networks = []*libcontainer.Network{ { Mtu: c.Network.Mtu, Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0), Gateway: "localhost", Type: "loopback", }, } if c.Network.Interface != nil { vethNetwork := libcontainer.Network{ Mtu: c.Network.Mtu, Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen), MacAddress: c.Network.Interface.MacAddress, Gateway: c.Network.Interface.Gateway, Type: "veth", Bridge: c.Network.Interface.Bridge, VethPrefix: "veth", } container.Networks = append(container.Networks, &vethNetwork) } if c.Network.ContainerID != "" { if d.driverType == execdriver.NativeBuiltin { d.Lock() active := d.activeContainers[c.Network.ContainerID] d.Unlock() if active == nil || active.cmd.Process == nil { return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) } cmd := active.cmd nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net") container.Networks = append(container.Networks, &libcontainer.Network{ Type: "netns", NsPath: nspath, }) } else { // external container state, err := libcontainer.GetState(filepath.Join(d.root, c.Network.ContainerID)) if err != nil { return fmt.Errorf("Read container state error: %v", err) } nspath := filepath.Join("/proc", fmt.Sprint(state.InitPid), "ns", "net") container.Networks = append(container.Networks, &libcontainer.Network{ Type: "netns", NsPath: nspath, }) } } return nil }
func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error { if c.Network.HostNetworking { container.Namespaces.Remove(libcontainer.NEWNET) return nil } container.Networks = []*libcontainer.Network{ { Mtu: c.Network.Mtu, Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0), Gateway: "localhost", Type: "loopback", }, } if c.Network.Interface != nil { vethNetwork := libcontainer.Network{ Mtu: c.Network.Mtu, Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen), MacAddress: c.Network.Interface.MacAddress, Gateway: c.Network.Interface.Gateway, Type: "veth", Bridge: c.Network.Interface.Bridge, VethPrefix: "veth", } if c.Network.Interface.GlobalIPv6Address != "" { vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen) vethNetwork.IPv6Gateway = c.Network.Interface.IPv6Gateway } container.Networks = append(container.Networks, &vethNetwork) } if c.Network.ContainerID != "" { d.Lock() active := d.activeContainers[c.Network.ContainerID] d.Unlock() if active == nil || active.cmd.Process == nil { return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) } cmd := active.cmd nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net") container.Namespaces.Add(libcontainer.NEWNET, nspath) } return nil }
func (d *driver) setPrivileged(container *libcontainer.Config) (err error) { container.Capabilities = capabilities.GetAllCapabilities() container.Cgroups.AllowAllDevices = true hostDeviceNodes, err := devices.GetHostDeviceNodes() if err != nil { return err } container.MountConfig.DeviceNodes = hostDeviceNodes container.RestrictSys = false if apparmor.IsEnabled() { container.AppArmorProfile = "unconfined" } return nil }
func (d *driver) setupRlimits(container *libcontainer.Config, c *execdriver.Command) { if c.Resources == nil { return } for _, rlimit := range c.Resources.Rlimits { container.Rlimits = append(container.Rlimits, libcontainer.Rlimit((*rlimit))) } }
func dropCap(container *libcontainer.Config, context interface{}, value string) error { // If the capability is specified multiple times, remove all instances. for i, capability := range container.Capabilities { if capability == value { container.Capabilities = append(container.Capabilities[:i], container.Capabilities[i+1:]...) } } // The capability wasn't found so we will drop it anyways. return nil }
// TODO(vmarmol): Switch to getting this from libcontainer once we have a solid API. func (self *dockerContainerHandler) readLibcontainerConfig() (*libcontainer.Config, error) { out, err := ioutil.ReadFile(self.libcontainerConfigPath) if err != nil { return nil, fmt.Errorf("failed to read libcontainer config from %q: %v", self.libcontainerConfigPath, err) } var config libcontainer.Config err = json.Unmarshal(out, &config) if err != nil { // TODO(vmarmol): Remove this once it becomes the standard. // Try to parse the old config. The main difference is that namespaces used to be a map, now it is a slice of structs. // The JSON marshaler will use the non-nested field before the nested one. type oldLibcontainerConfig struct { libcontainer.Config OldNamespaces map[string]bool `json:"namespaces,omitempty"` } var oldConfig oldLibcontainerConfig err2 := json.Unmarshal(out, &oldConfig) if err2 != nil { // Use original error. return nil, fmt.Errorf("failed to parse libcontainer config at %q: %v", self.libcontainerConfigPath, err) } // Translate the old config into the new config. config = oldConfig.Config for ns := range oldConfig.OldNamespaces { config.Namespaces = append(config.Namespaces, libcontainer.Namespace{ Type: libcontainer.NamespaceType(ns), }) } } // Replace cgroup parent and name with our own since we may be running in a different context. config.Cgroups.Name = self.cgroup.Name config.Cgroups.Parent = self.cgroup.Parent return &config, nil }
func (d *driver) setPrivileged(container *libcontainer.Config) (err error) { container.Capabilities = capabilities.GetAllCapabilities() container.Cgroups.AllowAllDevices = true hostDeviceNodes, err := devices.GetHostDeviceNodes() if err != nil { return err } container.MountConfig.DeviceNodes = hostDeviceNodes delete(container.Context, "restrictions") if apparmor.IsEnabled() { container.Context["apparmor_profile"] = "unconfined" } return nil }
func joinNetNamespace(container *libcontainer.Config, context interface{}, value string) error { var ( running = context.(map[string]*exec.Cmd) cmd = running[value] ) if cmd == nil || cmd.Process == nil { return fmt.Errorf("%s is not a valid running container to join", value) } nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net") container.Networks = append(container.Networks, &libcontainer.Network{ Type: "netns", NsPath: nspath, }) return nil }
func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command) error { if c.Ipc.HostIpc { container.Namespaces["NEWIPC"] = false return nil } if c.Ipc.ContainerID != "" { d.Lock() active := d.activeContainers[c.Ipc.ContainerID] d.Unlock() if active == nil || active.cmd.Process == nil { return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID) } cmd := active.cmd container.IpcNsPath = filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "ipc") } return nil }
func (d *driver) setupLabels(container *libcontainer.Config, c *execdriver.Command) error { container.ProcessLabel = c.Config["process_label"][0] container.MountConfig.MountLabel = c.Config["mount_label"][0] return nil }
func (d *driver) setupLabels(container *libcontainer.Config, c *execdriver.Command) error { container.ProcessLabel = c.ProcessLabel container.MountConfig.MountLabel = c.MountLabel return nil }
func apparmorProfile(container *libcontainer.Config, context interface{}, value string) error { container.AppArmorProfile = value return nil }
func addCap(container *libcontainer.Config, context interface{}, value string) error { container.Capabilities = append(container.Capabilities, value) return nil }
func initUserNs(container *libcontainer.Config, uncleanRootfs, consolePath string, pipe *os.File, args []string) (err error) { // clear the current processes env and replace it with the environment // defined on the container if err := LoadContainerEnvironment(container); err != nil { return err } // We always read this as it is a way to sync with the parent as well var networkState *network.NetworkState if err := json.NewDecoder(pipe).Decode(&networkState); err != nil { return err } // join any namespaces via a path to the namespace fd if provided if err := joinExistingNamespaces(container.Namespaces); err != nil { return err } if consolePath != "" { if err := console.OpenAndDup("/dev/console"); err != nil { return err } } if _, err := syscall.Setsid(); err != nil { return fmt.Errorf("setsid %s", err) } if consolePath != "" { if err := system.Setctty(); err != nil { return fmt.Errorf("setctty %s", err) } } if container.WorkingDir == "" { container.WorkingDir = "/" } if err := setupRlimits(container); err != nil { return fmt.Errorf("setup rlimits %s", err) } cloneFlags := GetNamespaceFlags(container.Namespaces) if container.Hostname != "" { if (cloneFlags & syscall.CLONE_NEWUTS) == 0 { return fmt.Errorf("unable to set the hostname without UTS namespace") } if err := syscall.Sethostname([]byte(container.Hostname)); err != nil { return fmt.Errorf("unable to sethostname %q: %s", container.Hostname, err) } } if err := apparmor.ApplyProfile(container.AppArmorProfile); err != nil { return fmt.Errorf("set apparmor profile %s: %s", container.AppArmorProfile, err) } if err := label.SetProcessLabel(container.ProcessLabel); err != nil { return fmt.Errorf("set process label %s", err) } if container.RestrictSys { if (cloneFlags & syscall.CLONE_NEWNS) == 0 { return fmt.Errorf("unable to restrict access to kernel files without mount namespace") } if err := restrict.Restrict("proc/sys", "proc/sysrq-trigger", "proc/irq", "proc/bus"); err != nil { return err } } pdeathSignal, err := system.GetParentDeathSignal() if err != nil { return fmt.Errorf("get parent death signal %s", err) } if err := FinalizeNamespace(container); err != nil { return fmt.Errorf("finalize namespace %s", err) } // FinalizeNamespace can change user/group which clears the parent death // signal, so we restore it here. if err := RestoreParentDeathSignal(pdeathSignal); err != nil { return fmt.Errorf("restore parent death signal %s", err) } return system.Execv(args[0], args[0:], os.Environ()) }