Allow net and IPC namespaces to be shared when userns=on

Now that the namespace sharing code via runc is vendored with the
containerd changes, we can disable the restrictions on container to
container net and IPC namespace sharing when the daemon has user
namespaces enabled.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
This commit is contained in:
Phil Estes 2016-03-21 21:30:21 -04:00
parent c22d09f563
commit 2b278f4846
3 changed files with 27 additions and 18 deletions

View File

@ -518,15 +518,12 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
if hostConfig.Privileged { if hostConfig.Privileged {
return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces") return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces")
} }
if hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsContainer() { if hostConfig.NetworkMode.IsHost() {
return warnings, fmt.Errorf("Cannot share the host or a container's network namespace when user namespaces are enabled") return warnings, fmt.Errorf("Cannot share the host's network namespace when user namespaces are enabled")
} }
if hostConfig.PidMode.IsHost() { if hostConfig.PidMode.IsHost() {
return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled") 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 { if hostConfig.ReadonlyRootfs {
return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled") return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled")
} }

View File

@ -230,6 +230,18 @@ func delNamespace(s *specs.Spec, nsType specs.NamespaceType) {
} }
func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error { 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 // network
if !c.Config.NetworkDisabled { if !c.Config.NetworkDisabled {
ns := specs.Namespace{Type: "network"} ns := specs.Namespace{Type: "network"}
@ -240,6 +252,12 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
return err return err
} }
ns.Path = fmt.Sprintf("/proc/%d/ns/net", nc.State.GetPID()) 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() { } else if c.HostConfig.NetworkMode.IsHost() {
ns.Path = c.NetworkSettings.SandboxKey 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()) ns.Path = fmt.Sprintf("/proc/%d/ns/ipc", ic.State.GetPID())
setNamespace(s, ns) 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() { } else if c.HostConfig.IpcMode.IsHost() {
delNamespace(s, specs.NamespaceType("ipc")) delNamespace(s, specs.NamespaceType("ipc"))
} else { } else {
@ -269,16 +293,6 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
delNamespace(s, specs.NamespaceType("uts")) delNamespace(s, specs.NamespaceType("uts"))
s.Hostname = "" 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 return nil
} }

View File

@ -792,11 +792,9 @@ The following standard Docker features are currently incompatible when
running a Docker daemon with user namespaces enabled: running a Docker daemon with user namespaces enabled:
- sharing PID or NET namespaces with the host (`--pid=host` or `--net=host`) - 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) - 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 - 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 In general, user namespaces are an advanced feature and will require
coordination with other capabilities. For example, if volumes are mounted from coordination with other capabilities. For example, if volumes are mounted from