Ver Fonte

Fix `/proc/<pid>/oom_score_adj: invalid argument` error caused by empty env name

This fix is part of the fix for issue 25099. In 25099, if an env
has a empty name, then `docker run` will throw out an error:
```
ubuntu@ubuntu:~/docker$ docker run -e =A busybox true
docker: Error response from daemon: invalid header field value "oci runtime error:
container_linux.go:247: starting container process caused \"process_linux.go:295:
setting oom score for ready process caused \\\"write /proc/83582/oom_score_adj:
invalid argument\\\"\"\n".
```

This fix validates the Env in the container spec before it is sent
to containerd/runc.

Integration tests have been created to cover the changes.

This fix is part of fix for 25099 (not complete yet, non-utf case
may require a fix in `runc`).
This fix is related to 25300.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Yong Tang há 8 anos atrás
pai
commit
818d55c34b

+ 8 - 0
daemon/container.go

@@ -15,6 +15,7 @@ import (
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/truncindex"
+	"github.com/docker/docker/runconfig/opts"
 	"github.com/docker/go-connections/nat"
 )
 
@@ -232,6 +233,13 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostCon
 				return nil, fmt.Errorf("invalid hostname format: %s", config.Hostname)
 			}
 		}
+
+		// Validate if Env contains empty variable or not (e.g., ``, `=foo`)
+		for _, env := range config.Env {
+			if _, err := opts.ValidateEnv(env); err != nil {
+				return nil, err
+			}
+		}
 	}
 
 	if hostConfig == nil {

+ 40 - 0
integration-cli/docker_api_create_test.go

@@ -42,3 +42,43 @@ func (s *DockerSuite) TestAPICreateWithNotExistImage(c *check.C) {
 	c.Assert(getErrorMessage(c, body), checker.Equals, expected)
 
 }
+
+// Test for #25099
+func (s *DockerSuite) TestAPICreateEmptyEnv(c *check.C) {
+	name := "test1"
+	config := map[string]interface{}{
+		"Image": "busybox",
+		"Env":   []string{"", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
+		"Cmd":   []string{"true"},
+	}
+
+	status, body, err := sockRequest("POST", "/containers/create?name="+name, config)
+	c.Assert(err, check.IsNil)
+	c.Assert(status, check.Equals, http.StatusInternalServerError)
+	expected := "invalid environment variable:"
+	c.Assert(getErrorMessage(c, body), checker.Contains, expected)
+
+	name = "test2"
+	config = map[string]interface{}{
+		"Image": "busybox",
+		"Env":   []string{"=", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
+		"Cmd":   []string{"true"},
+	}
+	status, body, err = sockRequest("POST", "/containers/create?name="+name, config)
+	c.Assert(err, check.IsNil)
+	c.Assert(status, check.Equals, http.StatusInternalServerError)
+	expected = "invalid environment variable: ="
+	c.Assert(getErrorMessage(c, body), checker.Contains, expected)
+
+	name = "test3"
+	config = map[string]interface{}{
+		"Image": "busybox",
+		"Env":   []string{"=foo", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
+		"Cmd":   []string{"true"},
+	}
+	status, body, err = sockRequest("POST", "/containers/create?name="+name, config)
+	c.Assert(err, check.IsNil)
+	c.Assert(status, check.Equals, http.StatusInternalServerError)
+	expected = "invalid environment variable: =foo"
+	c.Assert(getErrorMessage(c, body), checker.Contains, expected)
+}

+ 19 - 0
integration-cli/docker_cli_run_test.go

@@ -4830,3 +4830,22 @@ func (s *DockerSuite) TestRunHypervIsolationWithCPUCountCPUSharesAndCPUPercent(c
 	out = inspectField(c, "test", "HostConfig.CPUPercent")
 	c.Assert(out, check.Equals, "80")
 }
+
+// Test for #25099
+func (s *DockerSuite) TestRunEmptyEnv(c *check.C) {
+	testRequires(c, DaemonIsLinux)
+
+	expectedOutput := "invalid environment variable:"
+
+	out, _, err := dockerCmdWithError("run", "-e", "", "busybox", "true")
+	c.Assert(err, checker.NotNil)
+	c.Assert(out, checker.Contains, expectedOutput)
+
+	out, _, err = dockerCmdWithError("run", "-e", "=", "busybox", "true")
+	c.Assert(err, checker.NotNil)
+	c.Assert(out, checker.Contains, expectedOutput)
+
+	out, _, err = dockerCmdWithError("run", "-e", "=foo", "busybox", "true")
+	c.Assert(err, checker.NotNil)
+	c.Assert(out, checker.Contains, expectedOutput)
+}

+ 5 - 0
runconfig/opts/opts.go

@@ -26,8 +26,13 @@ func ValidateAttach(val string) (string, error) {
 // As on ParseEnvFile and related to #16585, environment variable names
 // are not validate what so ever, it's up to application inside docker
 // to validate them or not.
+//
+// The only validation here is to check if name is empty, per #25099
 func ValidateEnv(val string) (string, error) {
 	arr := strings.Split(val, "=")
+	if arr[0] == "" {
+		return "", fmt.Errorf("invalid environment variable: %s", val)
+	}
 	if len(arr) > 1 {
 		return val, nil
 	}