From 2cce4791b0e75201cb65daad07d4203d1c4c2996 Mon Sep 17 00:00:00 2001 From: Lei Jitang Date: Sat, 11 Apr 2015 11:04:24 +0800 Subject: [PATCH 1/2] Add `-u|--user` flag to docker exec for running command as a different user Signed-off-by: Lei Jitang --- contrib/completion/bash/docker | 2 +- daemon/exec.go | 1 + daemon/execdriver/native/exec.go | 4 ++-- docs/man/docker-exec.1.md | 9 +++++++ docs/sources/reference/commandline/cli.md | 1 + integration-cli/docker_cli_exec_test.go | 29 +++++++++++++++++++++++ runconfig/exec.go | 7 +++--- 7 files changed, 46 insertions(+), 7 deletions(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index ad48f2886c..ef7f0f3356 100755 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -407,7 +407,7 @@ _docker_events() { _docker_exec() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) ) ;; *) __docker_containers_running diff --git a/daemon/exec.go b/daemon/exec.go index f91600da7a..fa26dca7d5 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -138,6 +138,7 @@ func (d *Daemon) ContainerExecCreate(job *engine.Job) error { Tty: config.Tty, Entrypoint: entrypoint, Arguments: args, + User: config.User, } execConfig := &execConfig{ diff --git a/daemon/execdriver/native/exec.go b/daemon/execdriver/native/exec.go index 2edd3313b1..ed89269e27 100644 --- a/daemon/execdriver/native/exec.go +++ b/daemon/execdriver/native/exec.go @@ -14,7 +14,7 @@ import ( "github.com/docker/libcontainer/utils" ) -// TODO(vishh): Add support for running in privileged mode and running as a different user. +// 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 { @@ -28,7 +28,7 @@ func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo Args: append([]string{processConfig.Entrypoint}, processConfig.Arguments...), Env: c.ProcessConfig.Env, Cwd: c.WorkingDir, - User: c.ProcessConfig.User, + User: processConfig.User, } if processConfig.Tty { diff --git a/docs/man/docker-exec.1.md b/docs/man/docker-exec.1.md index e7554419ec..c1de7b59ed 100644 --- a/docs/man/docker-exec.1.md +++ b/docs/man/docker-exec.1.md @@ -10,6 +10,7 @@ docker-exec - Run a command in a running container [**--help**] [**-i**|**--interactive**[=*false*]] [**-t**|**--tty**[=*false*]] +[**-u**|**--user**[=*USER*]] CONTAINER COMMAND [ARG...] # DESCRIPTION @@ -35,6 +36,14 @@ container is unpaused, and then run **-t**, **--tty**=*true*|*false* Allocate a pseudo-TTY. The default is *false*. +**-u**, **--user**="" + Sets the username or UID used and optionally the groupname or GID for the specified command. + + The followings examples are all valid: + --user [user | user:group | uid | uid:gid | user:gid | uid:group ] + + Without this argument the command will be run as root in the container. + The **-t** option is incompatible with a redirection of the docker client standard input. diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index b9f506a6c8..855e40d08b 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -1115,6 +1115,7 @@ You'll need two shells for this example. -d, --detach=false Detached mode: run command in the background -i, --interactive=false Keep STDIN open even if not attached -t, --tty=false Allocate a pseudo-TTY + -u, --user= Username or UID (format: [:]) The `docker exec` command runs a new command in a running container. diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go index 9fcee32a7a..505690a11b 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -665,3 +665,32 @@ func TestRunMutableNetworkFiles(t *testing.T) { } logDone("run - mutable network files") } + +func TestExecWithUser(t *testing.T) { + defer deleteAllContainers() + + runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "busybox", "top") + if out, _, err := runCommandWithOutput(runCmd); err != nil { + t.Fatal(out, err) + } + + cmd := exec.Command(dockerBinary, "exec", "-u", "1", "parent", "id") + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") { + t.Fatalf("exec with user by id expected daemon user got %s", out) + } + + cmd = exec.Command(dockerBinary, "exec", "-u", "root", "parent", "id") + out, _, err = runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if !strings.Contains(out, "uid=0(root) gid=0(root)") { + t.Fatalf("exec with user by root expected root user got %s", out) + } + + logDone("exec - with user") +} diff --git a/runconfig/exec.go b/runconfig/exec.go index 1bcdad1599..01ddeaf548 100644 --- a/runconfig/exec.go +++ b/runconfig/exec.go @@ -21,8 +21,7 @@ type ExecConfig struct { func ExecConfigFromJob(job *engine.Job) (*ExecConfig, error) { execConfig := &ExecConfig{ - // TODO(vishh): Expose 'User' once it is supported. - //User: job.Getenv("User"), + User: job.Getenv("User"), // TODO(vishh): Expose 'Privileged' once it is supported. //Privileged: job.GetenvBool("Privileged"), Tty: job.GetenvBool("Tty"), @@ -45,6 +44,7 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { 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 ) @@ -57,8 +57,7 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { execCmd = parsedArgs[1:] execConfig := &ExecConfig{ - // TODO(vishh): Expose '-u' flag once it is supported. - User: "", + User: *flUser, // TODO(vishh): Expose '-p' flag once it is supported. Privileged: false, Tty: *flTty, From 72a500e9e5929b038816d8bd18d462a19e571c99 Mon Sep 17 00:00:00 2001 From: Lei Jitang Date: Sat, 11 Apr 2015 11:26:37 +0800 Subject: [PATCH 2/2] Add docker exec run a command in privileged mode Signed-off-by: Lei Jitang --- contrib/completion/bash/docker | 2 +- daemon/exec.go | 1 + daemon/execdriver/native/exec.go | 5 +++- docs/man/docker-exec.1.md | 8 +++++++ docs/sources/reference/commandline/cli.md | 1 + integration-cli/docker_cli_exec_test.go | 28 +++++++++++++++++++++++ runconfig/exec.go | 21 ++++++++--------- 7 files changed, 53 insertions(+), 13 deletions(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index ef7f0f3356..f669352119 100755 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -407,7 +407,7 @@ _docker_events() { _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 fa26dca7d5..46c255a7cf 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -139,6 +139,7 @@ func (d *Daemon) ContainerExecCreate(job *engine.Job) error { Entrypoint: entrypoint, Arguments: args, User: config.User, + Privileged: config.Privileged, } execConfig := &execConfig{ diff --git a/daemon/execdriver/native/exec.go b/daemon/execdriver/native/exec.go index ed89269e27..04239fdac7 100644 --- a/daemon/execdriver/native/exec.go +++ b/daemon/execdriver/native/exec.go @@ -14,7 +14,6 @@ import ( "github.com/docker/libcontainer/utils" ) -// 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 { @@ -31,6 +30,10 @@ func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo User: processConfig.User, } + if processConfig.Privileged { + p.Capabilities = execdriver.GetAllCapabilities() + } + if processConfig.Tty { config := active.Config() rootuid, err := config.HostUID() diff --git a/docs/man/docker-exec.1.md b/docs/man/docker-exec.1.md index c1de7b59ed..312fa397f5 100644 --- a/docs/man/docker-exec.1.md +++ b/docs/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/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 855e40d08b..cfbd3398ee 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -1114,6 +1114,7 @@ You'll need two shells for this example. -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 505690a11b..8906da2526 100644 --- a/integration-cli/docker_cli_exec_test.go +++ b/integration-cli/docker_cli_exec_test.go @@ -694,3 +694,31 @@ func TestExecWithUser(t *testing.T) { logDone("exec - with user") } + +func TestExecWithPrivileged(t *testing.T) { + defer deleteAllContainers() + + runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "top") + if out, _, err := runCommandWithOutput(runCmd); err != nil { + t.Fatal(out, err) + } + + cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sda b 8 0") + out, _, err := runCommandWithOutput(cmd) + fmt.Printf("%s", out) + if err == nil || !strings.Contains(out, "Operation not permitted") { + t.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 { + t.Fatal(err, out) + } + + if actual := strings.TrimSpace(out); actual != "ok" { + t.Fatalf("exec mknod in --cap-drop=ALL container with --privileged failed: %v, output: %q", err, out) + } + + logDone("exec - exec command in a container with privileged") +} diff --git a/runconfig/exec.go b/runconfig/exec.go index 01ddeaf548..e634d30813 100644 --- a/runconfig/exec.go +++ b/runconfig/exec.go @@ -22,8 +22,7 @@ type ExecConfig struct { func ExecConfigFromJob(job *engine.Job) (*ExecConfig, error) { execConfig := &ExecConfig{ User: job.Getenv("User"), - // TODO(vishh): Expose 'Privileged' once it is supported. - //Privileged: job.GetenvBool("Privileged"), + Privileged: job.GetenvBool("Privileged"), Tty: job.GetenvBool("Tty"), AttachStdin: job.GetenvBool("AttachStdin"), AttachStderr: job.GetenvBool("AttachStderr"), @@ -41,12 +40,13 @@ func ExecConfigFromJob(job *engine.Job) (*ExecConfig, 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 { @@ -57,9 +57,8 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) { execCmd = parsedArgs[1:] execConfig := &ExecConfig{ - User: *flUser, - // TODO(vishh): Expose '-p' flag once it is supported. - Privileged: false, + User: *flUser, + Privileged: *flPrivileged, Tty: *flTty, Cmd: execCmd, Container: container,