From 03f65b3d0d66ccdc8b69a447b75508d594007600 Mon Sep 17 00:00:00 2001 From: Tim Dettrick Date: Fri, 19 Jun 2015 16:01:50 +1000 Subject: [PATCH 1/2] Revert "Revert "Add docker exec run a command in privileged mode"" This reverts commit 40b71adee390e9c06471b89ed845132b4ec80177. Original commit (for which this is effectively a rebased version) is 72a500e9e5929b038816d8bd18d462a19e571c99 and was provided by Lei Jitang . Signed-off-by: Tim Dettrick --- contrib/completion/bash/docker | 2 +- daemon/exec.go | 1 + daemon/execdriver/native/exec.go | 5 ++++- docs/reference/commandline/exec.md | 1 + integration-cli/docker_cli_exec_test.go | 25 ++++++++++++++++++++++++ man/docker-exec.1.md | 8 ++++++++ runconfig/exec.go | 26 ++++++++++++------------- 7 files changed, 53 insertions(+), 15 deletions(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index d056c2c46..a9008aea2 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -620,7 +620,7 @@ _docker_exec() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i --privileged -t --tty -u --user" -- "$cur" ) ) ;; *) __docker_containers_running diff --git a/daemon/exec.go b/daemon/exec.go index 73f0f5640..265420c61 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -152,6 +152,7 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro Entrypoint: entrypoint, Arguments: args, User: user, + Privileged: config.Privileged, } execConfig := &execConfig{ diff --git a/daemon/execdriver/native/exec.go b/daemon/execdriver/native/exec.go index a52bd8f1b..f50630d8e 100644 --- a/daemon/execdriver/native/exec.go +++ b/daemon/execdriver/native/exec.go @@ -19,7 +19,6 @@ import ( // Exec implements the exec driver Driver interface, // it calls libcontainer APIs to execute a container. -// TODO(vishh): Add support for running in privileged mode. func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) { active := d.activeContainers[c.ID] if active == nil { @@ -33,6 +32,10 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo User: processConfig.User, } + if processConfig.Privileged { + p.Capabilities = execdriver.GetAllCapabilities() + } + config := active.Config() if err := setupPipes(&config, processConfig, p, pipes); err != nil { return -1, err diff --git a/docs/reference/commandline/exec.md b/docs/reference/commandline/exec.md index 6ad6883ad..b5ddc64dc 100644 --- a/docs/reference/commandline/exec.md +++ b/docs/reference/commandline/exec.md @@ -17,6 +17,7 @@ weight=1 -d, --detach=false Detached mode: run command in the background -i, --interactive=false Keep STDIN open even if not attached + --privileged=false Give extended privileges to the command -t, --tty=false Allocate a pseudo-TTY -u, --user= Username or UID (format: [:]) diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go index 91c633e1e..bce007b15 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -532,6 +532,31 @@ func (s *DockerSuite) TestExecWithUser(c *check.C) { } } +func (s *DockerSuite) TestExecWithPrivileged(c *check.C) { + + runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "top") + if out, _, err := runCommandWithOutput(runCmd); err != nil { + c.Fatal(out, err) + } + + cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sda b 8 0") + out, _, err := runCommandWithOutput(cmd) + if err == nil || !strings.Contains(out, "Operation not permitted") { + c.Fatalf("exec mknod in --cap-drop=ALL container without --privileged should failed") + } + + cmd = exec.Command(dockerBinary, "exec", "--privileged", "parent", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") + out, _, err = runCommandWithOutput(cmd) + if err != nil { + c.Fatal(err, out) + } + + if actual := strings.TrimSpace(out); actual != "ok" { + c.Fatalf("exec mknod in --cap-drop=ALL container with --privileged failed: %v, output: %q", err, out) + } + +} + func (s *DockerSuite) TestExecWithImageUser(c *check.C) { name := "testbuilduser" _, err := buildImage(name, diff --git a/man/docker-exec.1.md b/man/docker-exec.1.md index c1de7b59e..312fa397f 100644 --- a/man/docker-exec.1.md +++ b/man/docker-exec.1.md @@ -9,6 +9,7 @@ docker-exec - Run a command in a running container [**-d**|**--detach**[=*false*]] [**--help**] [**-i**|**--interactive**[=*false*]] +[**--privileged**[=*false*]] [**-t**|**--tty**[=*false*]] [**-u**|**--user**[=*USER*]] CONTAINER COMMAND [ARG...] @@ -33,6 +34,13 @@ container is unpaused, and then run **-i**, **--interactive**=*true*|*false* Keep STDIN open even if not attached. The default is *false*. +**--privileged**=*true*|*false* + Give extended privileges to the process to run in a running container. The default is *false*. + + By default, the process run by docker exec in a running container +have the same capabilities of the container. By setting --privileged will give +all the capabilities to the process. + **-t**, **--tty**=*true*|*false* Allocate a pseudo-TTY. The default is *false*. diff --git a/runconfig/exec.go b/runconfig/exec.go index 1f13d7dd0..6fe28ea33 100644 --- a/runconfig/exec.go +++ b/runconfig/exec.go @@ -24,12 +24,13 @@ type ExecConfig struct { // not valid, it will return an error. func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { var ( - flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached") - flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY") - flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background") - flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: [:])") - execCmd []string - container string + flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached") + flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY") + flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background") + flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: [:])") + flPrivileged = cmd.Bool([]string{"-privileged"}, false, "Give extended privileges to the command") + execCmd []string + container string ) cmd.Require(flag.Min, 2) if err := cmd.ParseFlags(args, true); err != nil { @@ -40,13 +41,12 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { execCmd = parsedArgs[1:] execConfig := &ExecConfig{ - User: *flUser, - // TODO(vishh): Expose 'Privileged' once it is supported. - // + //Privileged: job.GetenvBool("Privileged"), - Tty: *flTty, - Cmd: execCmd, - Container: container, - Detach: *flDetach, + User: *flUser, + Privileged: *flPrivileged, + Tty: *flTty, + Cmd: execCmd, + Container: container, + Detach: *flDetach, } // If -d is not set, attach to everything by default From 90326939c8089dbd7b59423415bc67cae6208b08 Mon Sep 17 00:00:00 2001 From: Tim Dettrick Date: Mon, 22 Jun 2015 13:06:07 +1000 Subject: [PATCH 2/2] Updated test to check for `exec --privileged` side-effects Also improving documentation for same feature as part of docker/docker#14113 docs review. Signed-off-by: Tim Dettrick --- docs/reference/commandline/exec.md | 3 +-- integration-cli/docker_cli_exec_test.go | 27 ++++++++++++++++++------- man/docker-exec.1.md | 11 +++++----- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/docs/reference/commandline/exec.md b/docs/reference/commandline/exec.md index b5ddc64dc..2ff120560 100644 --- a/docs/reference/commandline/exec.md +++ b/docs/reference/commandline/exec.md @@ -17,7 +17,7 @@ weight=1 -d, --detach=false Detached mode: run command in the background -i, --interactive=false Keep STDIN open even if not attached - --privileged=false Give extended privileges to the command + --privileged=false Give extended Linux capabilities to the command -t, --tty=false Allocate a pseudo-TTY -u, --user= Username or UID (format: [:]) @@ -53,4 +53,3 @@ This will create a new file `/tmp/execWorks` inside the running container $ docker exec -it ubuntu_bash bash This will create a new Bash session in the container `ubuntu_bash`. - diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go index bce007b15..e22431f85 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -534,18 +534,18 @@ func (s *DockerSuite) TestExecWithUser(c *check.C) { func (s *DockerSuite) TestExecWithPrivileged(c *check.C) { - runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "top") - if out, _, err := runCommandWithOutput(runCmd); err != nil { - c.Fatal(out, err) - } + // Start main loop which attempts mknod repeatedly + dockerCmd(c, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "sh", "-c", `while (true); do if [ -e /exec_priv ]; then cat /exec_priv && mknod /tmp/sda b 8 0 && echo "Success"; else echo "Privileged exec has not run yet"; fi; usleep 10000; done`) - cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sda b 8 0") + // Check exec mknod doesn't work + cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sdb b 8 16") out, _, err := runCommandWithOutput(cmd) if err == nil || !strings.Contains(out, "Operation not permitted") { - c.Fatalf("exec mknod in --cap-drop=ALL container without --privileged should failed") + c.Fatalf("exec mknod in --cap-drop=ALL container without --privileged should fail") } - cmd = exec.Command(dockerBinary, "exec", "--privileged", "parent", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") + // Check exec mknod does work with --privileged + cmd = exec.Command(dockerBinary, "exec", "--privileged", "parent", "sh", "-c", `echo "Running exec --privileged" > /exec_priv && mknod /tmp/sdb b 8 16 && usleep 50000 && echo "Finished exec --privileged" > /exec_priv && echo ok`) out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatal(err, out) @@ -555,6 +555,19 @@ func (s *DockerSuite) TestExecWithPrivileged(c *check.C) { c.Fatalf("exec mknod in --cap-drop=ALL container with --privileged failed: %v, output: %q", err, out) } + // Check subsequent unprivileged exec cannot mknod + cmd = exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sdc b 8 32") + out, _, err = runCommandWithOutput(cmd) + if err == nil || !strings.Contains(out, "Operation not permitted") { + c.Fatalf("repeating exec mknod in --cap-drop=ALL container after --privileged without --privileged should fail") + } + + // Confirm at no point was mknod allowed + logCmd := exec.Command(dockerBinary, "logs", "parent") + if out, _, err := runCommandWithOutput(logCmd); err != nil || strings.Contains(out, "Success") { + c.Fatal(out, err) + } + } func (s *DockerSuite) TestExecWithImageUser(c *check.C) { diff --git a/man/docker-exec.1.md b/man/docker-exec.1.md index 312fa397f..5cfdb5434 100644 --- a/man/docker-exec.1.md +++ b/man/docker-exec.1.md @@ -16,7 +16,7 @@ CONTAINER COMMAND [ARG...] # DESCRIPTION -Run a process in a running container. +Run a process in a running container. The command started using `docker exec` will only run while the container's primary process (`PID 1`) is running, and will not be restarted if the container is restarted. @@ -35,11 +35,12 @@ container is unpaused, and then run Keep STDIN open even if not attached. The default is *false*. **--privileged**=*true*|*false* - Give extended privileges to the process to run in a running container. The default is *false*. + Give the process extended [Linux capabilities](http://man7.org/linux/man-pages/man7/capabilities.7.html) +when running in a container. The default is *false*. - By default, the process run by docker exec in a running container -have the same capabilities of the container. By setting --privileged will give -all the capabilities to the process. + Without this flag, the process run by `docker exec` in a running container has +the same capabilities as the container, which may be limited. Set +`--privileged` to give all capabilities to the process. **-t**, **--tty**=*true*|*false* Allocate a pseudo-TTY. The default is *false*.