From ee7a956c5483b85ca0de3595270d861a5ebfb2a9 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Tue, 9 May 2017 21:07:40 +1000 Subject: [PATCH] client: check tty before creating exec job This is necessary in order to avoid execId leaks in the case where a `docker exec -it` is run without a terminal available for the client. You can reproduce this issue by running the following command many times. % nohup docker exec -it some_container true The container `some_container` will have execIDs that will never normally be cleaned up (because the client died before they were started). In addition, this patch adds a docker-inspect step to ensure that we give "container does not exist" errors consistently. Signed-off-by: Valentin Rothberg Signed-off-by: Aleksa Sarai --- cli/command/container/exec.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/cli/command/container/exec.go b/cli/command/container/exec.go index 27328960e6..df8a8a6696 100644 --- a/cli/command/container/exec.go +++ b/cli/command/container/exec.go @@ -80,6 +80,19 @@ func runExec(dockerCli *command.DockerCli, opts *execOptions, container string, ctx := context.Background() client := dockerCli.Client() + // We need to check the tty _before_ we do the ContainerExecCreate, because + // otherwise if we error out we will leak execIDs on the server (and + // there's no easy way to clean those up). But also in order to make "not + // exist" errors take precedence we do a dummy inspect first. + if _, err := client.ContainerInspect(ctx, container); err != nil { + return err + } + if !execConfig.Detach { + if err := dockerCli.In().CheckTty(execConfig.AttachStdin, execConfig.Tty); err != nil { + return err + } + } + response, err := client.ContainerExecCreate(ctx, container, *execConfig) if err != nil { return err @@ -91,12 +104,8 @@ func runExec(dockerCli *command.DockerCli, opts *execOptions, container string, return nil } - //Temp struct for execStart so that we don't need to transfer all the execConfig - if !execConfig.Detach { - if err := dockerCli.In().CheckTty(execConfig.AttachStdin, execConfig.Tty); err != nil { - return err - } - } else { + // Temp struct for execStart so that we don't need to transfer all the execConfig. + if execConfig.Detach { execStartCheck := types.ExecStartCheck{ Detach: execConfig.Detach, Tty: execConfig.Tty,