From ec7885ffb85f68d0fa30a48c7c7c968470867a42 Mon Sep 17 00:00:00 2001 From: Justin Cormack Date: Wed, 28 Sep 2016 13:46:11 +0100 Subject: [PATCH] Add support for ambient capabilities Linux kernel 4.3 and later supports "ambient capabilities" which are the only way to pass capabilities to containers running as a non root uid. Previously there was no way to allow containers not running as root capabilities in a useful way. Fix #8460 Signed-off-by: Justin Cormack Upstream-commit: 199e19548e93262ab00873c1d761b0d05f866042 Component: engine --- components/engine/docs/reference/run.md | 4 ++++ components/engine/docs/security/security.md | 8 ++++++++ .../docker_cli_run_unix_test.go | 18 ++++++++++++++++++ .../integration-cli/requirements_unix.go | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/components/engine/docs/reference/run.md b/components/engine/docs/reference/run.md index 375c0c1538..82bffc1537 100644 --- a/components/engine/docs/reference/run.md +++ b/components/engine/docs/reference/run.md @@ -1220,6 +1220,10 @@ since Docker 1.12. In Docker 1.10 and 1.11 this did not happen and it may be nec to use a custom seccomp profile or use `--security-opt seccomp=unconfined` when adding capabilities. +It is only possible to grant capabilities to a container running as a user other than `root` +on a system with a Linux kernel version of 4.3 or later, as this requires "ambient capabilities" +to be granted. These will be added if the kernel allows it from Docker version 1.13. + ## Logging drivers (--log-driver) The container can have a different logging driver than the Docker daemon. Use diff --git a/components/engine/docs/security/security.md b/components/engine/docs/security/security.md index 7a17f869f8..16c0988aaa 100644 --- a/components/engine/docs/security/security.md +++ b/components/engine/docs/security/security.md @@ -212,6 +212,14 @@ capability removal, or less secure through the addition of capabilities. The best practice for users would be to remove all capabilities except those explicitly required for their processes. +Linux kernel versions since 4.3 allow Docker to grant capabilities to +container processes running as a non root user. This adds an extra +layer of protection as the process can then be denied access to be able +to write files belonging to the root uid, for example. User namespaces +also allow capabilities to be granted to processes that are effectively +non root, but these capabilities are limited to resources created in the +user namespace, so they have limitations. + ## Other kernel security features Capabilities are just one of the many security features provided by diff --git a/components/engine/integration-cli/docker_cli_run_unix_test.go b/components/engine/integration-cli/docker_cli_run_unix_test.go index 165dc54e66..fc690dcbcb 100644 --- a/components/engine/integration-cli/docker_cli_run_unix_test.go +++ b/components/engine/integration-cli/docker_cli_run_unix_test.go @@ -1155,6 +1155,24 @@ func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) { } } +func (s *DockerSuite) TestRunAmbientCapabilities(c *check.C) { + testRequires(c, DaemonIsLinux, ambientCapabilities) + + // test that a non root user can gain capabilities + runCmd := exec.Command(dockerBinary, "run", "--user", "1000", "--cap-add", "chown", "busybox", "chown", "100", "/tmp") + _, _, err := runCommandWithOutput(runCmd) + c.Assert(err, check.IsNil) + // test that non root user has default capabilities + runCmd = exec.Command(dockerBinary, "run", "--user", "1000", "busybox", "chown", "100", "/tmp") + _, _, err = runCommandWithOutput(runCmd) + c.Assert(err, check.IsNil) + // test this fails without cap_chown + runCmd = exec.Command(dockerBinary, "run", "--user", "1000", "--cap-drop", "chown", "busybox", "chown", "100", "/tmp") + out, _, err := runCommandWithOutput(runCmd) + c.Assert(err, checker.NotNil, check.Commentf(out)) + c.Assert(strings.TrimSpace(out), checker.Equals, "chown: /tmp: Operation not permitted") +} + func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) { testRequires(c, SameHostDaemon, Apparmor) diff --git a/components/engine/integration-cli/requirements_unix.go b/components/engine/integration-cli/requirements_unix.go index aa5e0cce06..5d17c49364 100644 --- a/components/engine/integration-cli/requirements_unix.go +++ b/components/engine/integration-cli/requirements_unix.go @@ -112,6 +112,16 @@ var ( }, "Test cannot be run with 'sysctl kernel.unprivileged_userns_clone' = 0", } + ambientCapabilities = testRequirement{ + func() bool { + content, err := ioutil.ReadFile("/proc/self/status") + if err == nil && strings.Contains(string(content), "CapAmb:") { + return true + } + return false + }, + "Test cannot be run without a kernel (4.3+) supporting ambient capabilities", + } ) func init() {