Browse Source

Change path breakout detection logic in archive package

Fixes #9375

Signed-off-by: Alexandr Morozov <lk4d4@docker.com>

Conflicts:
	integration-cli/docker_cli_cp_test.go
		removed extra test
Alexandr Morozov 10 năm trước cách đây
mục cha
commit
994e4a1c69
3 tập tin đã thay đổi với 51 bổ sung8 xóa
  1. 38 0
      integration-cli/docker_cli_cp_test.go
  2. 6 3
      pkg/archive/archive.go
  3. 7 5
      pkg/archive/diff.go

+ 38 - 0
integration-cli/docker_cli_cp_test.go

@@ -371,3 +371,41 @@ func TestCpUnprivilegedUser(t *testing.T) {
 
 	logDone("cp - unprivileged user")
 }
+
+func TestCpToDot(t *testing.T) {
+	out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test")
+	if err != nil || exitCode != 0 {
+		t.Fatal("failed to create a container", out, err)
+	}
+
+	cleanedContainerID := stripTrailingCharacters(out)
+	defer deleteContainer(cleanedContainerID)
+
+	out, _, err = dockerCmd(t, "wait", cleanedContainerID)
+	if err != nil || stripTrailingCharacters(out) != "0" {
+		t.Fatal("failed to set up container", out, err)
+	}
+
+	tmpdir, err := ioutil.TempDir("", "docker-integration")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+	cwd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Chdir(cwd)
+	if err := os.Chdir(tmpdir); err != nil {
+		t.Fatal(err)
+	}
+	_, _, err = dockerCmd(t, "cp", cleanedContainerID+":/test", ".")
+	if err != nil {
+		t.Fatalf("couldn't docker cp to \".\" path: %s", err)
+	}
+	content, err := ioutil.ReadFile("./test")
+	if string(content) != "lololol\n" {
+		t.Fatal("Wrong content in copied file %q, should be %q", content, "lololol\n")
+	}
+	logDone("cp - to dot path")
+}

+ 6 - 3
pkg/archive/archive.go

@@ -473,10 +473,13 @@ loop:
 			}
 		}
 
-		// Prevent symlink breakout
 		path := filepath.Join(dest, hdr.Name)
-		if !strings.HasPrefix(path, dest) {
-			return breakoutError(fmt.Errorf("%q is outside of %q", path, dest))
+		rel, err := filepath.Rel(dest, path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(rel, "..") {
+			return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
 		}
 
 		// If path exits we almost always just want to remove and replace it

+ 7 - 5
pkg/archive/diff.go

@@ -81,12 +81,14 @@ func UnpackLayer(dest string, layer ArchiveReader) error {
 		}
 
 		path := filepath.Join(dest, hdr.Name)
-		base := filepath.Base(path)
-
-		// Prevent symlink breakout
-		if !strings.HasPrefix(path, dest) {
-			return breakoutError(fmt.Errorf("%q is outside of %q", path, dest))
+		rel, err := filepath.Rel(dest, path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(rel, "..") {
+			return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
 		}
+		base := filepath.Base(path)
 
 		if strings.HasPrefix(base, ".wh.") {
 			originalBase := base[len(".wh."):]