diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index b6e60ff77c..e9b78ac76d 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -518,15 +518,12 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. if hostConfig.Privileged { return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces") } - if hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsContainer() { - return warnings, fmt.Errorf("Cannot share the host or a container's network namespace when user namespaces are enabled") + if hostConfig.NetworkMode.IsHost() { + return warnings, fmt.Errorf("Cannot share the host's network namespace when user namespaces are enabled") } if hostConfig.PidMode.IsHost() { return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled") } - if hostConfig.IpcMode.IsContainer() { - return warnings, fmt.Errorf("Cannot share a container's IPC namespace when user namespaces are enabled") - } if hostConfig.ReadonlyRootfs { return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled") } diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go index 0b61f5326b..f00e0416a6 100644 --- a/daemon/oci_linux.go +++ b/daemon/oci_linux.go @@ -230,6 +230,18 @@ func delNamespace(s *specs.Spec, nsType specs.NamespaceType) { } 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"} @@ -240,6 +252,12 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error 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 } @@ -254,6 +272,12 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error } 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() { delNamespace(s, specs.NamespaceType("ipc")) } else { @@ -269,16 +293,6 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error delNamespace(s, specs.NamespaceType("uts")) s.Hostname = "" } - // user - if c.HostConfig.UsernsMode.IsPrivate() { - uidMap, gidMap := daemon.GetUIDGIDMaps() - if uidMap != nil { - ns := specs.Namespace{Type: "user"} - setNamespace(s, ns) - s.Linux.UIDMappings = specMapping(uidMap) - s.Linux.GIDMappings = specMapping(gidMap) - } - } return nil } diff --git a/docs/reference/commandline/daemon.md b/docs/reference/commandline/daemon.md index 20ea3cb20e..61ba1c763d 100644 --- a/docs/reference/commandline/daemon.md +++ b/docs/reference/commandline/daemon.md @@ -792,11 +792,9 @@ The following standard Docker features are currently incompatible when running a Docker daemon with user namespaces enabled: - sharing PID or NET namespaces with the host (`--pid=host` or `--net=host`) - - sharing a network namespace with an existing container (`--net=container:*other*`) - - sharing an IPC namespace with an existing container (`--ipc=container:*other*`) - A `--readonly` container filesystem (this is a Linux kernel restriction against remounting with modified flags of a currently mounted filesystem when inside a user namespace) - external (volume or graph) drivers which are unaware/incapable of using daemon user mappings - - Using `--privileged` mode flag on `docker run` + - Using `--privileged` mode flag on `docker run` (unless also specifying `--userns=host`) In general, user namespaces are an advanced feature and will require coordination with other capabilities. For example, if volumes are mounted from