Fixes #9375
Signed-off-by: Alexandr Morozov <lk4d4@docker.com>
| ... | ... |
@@ -478,3 +478,41 @@ func TestCpVolumePath(t *testing.T) {
|
| 478 | 478 |
|
| 479 | 479 |
logDone("cp - volume path")
|
| 480 | 480 |
} |
| 481 |
+ |
|
| 482 |
+func TestCpToDot(t *testing.T) {
|
|
| 483 |
+ out, exitCode, err := dockerCmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "echo lololol > /test") |
|
| 484 |
+ if err != nil || exitCode != 0 {
|
|
| 485 |
+ t.Fatal("failed to create a container", out, err)
|
|
| 486 |
+ } |
|
| 487 |
+ |
|
| 488 |
+ cleanedContainerID := stripTrailingCharacters(out) |
|
| 489 |
+ defer deleteContainer(cleanedContainerID) |
|
| 490 |
+ |
|
| 491 |
+ out, _, err = dockerCmd(t, "wait", cleanedContainerID) |
|
| 492 |
+ if err != nil || stripTrailingCharacters(out) != "0" {
|
|
| 493 |
+ t.Fatal("failed to set up container", out, err)
|
|
| 494 |
+ } |
|
| 495 |
+ |
|
| 496 |
+ tmpdir, err := ioutil.TempDir("", "docker-integration")
|
|
| 497 |
+ if err != nil {
|
|
| 498 |
+ t.Fatal(err) |
|
| 499 |
+ } |
|
| 500 |
+ defer os.RemoveAll(tmpdir) |
|
| 501 |
+ cwd, err := os.Getwd() |
|
| 502 |
+ if err != nil {
|
|
| 503 |
+ t.Fatal(err) |
|
| 504 |
+ } |
|
| 505 |
+ defer os.Chdir(cwd) |
|
| 506 |
+ if err := os.Chdir(tmpdir); err != nil {
|
|
| 507 |
+ t.Fatal(err) |
|
| 508 |
+ } |
|
| 509 |
+ _, _, err = dockerCmd(t, "cp", cleanedContainerID+":/test", ".") |
|
| 510 |
+ if err != nil {
|
|
| 511 |
+ t.Fatalf("couldn't docker cp to \".\" path: %s", err)
|
|
| 512 |
+ } |
|
| 513 |
+ content, err := ioutil.ReadFile("./test")
|
|
| 514 |
+ if string(content) != "lololol\n" {
|
|
| 515 |
+ t.Fatal("Wrong content in copied file %q, should be %q", content, "lololol\n")
|
|
| 516 |
+ } |
|
| 517 |
+ logDone("cp - to dot path")
|
|
| 518 |
+} |
| ... | ... |
@@ -530,10 +530,13 @@ loop: |
| 530 | 530 |
} |
| 531 | 531 |
} |
| 532 | 532 |
|
| 533 |
- // Prevent symlink breakout |
|
| 534 | 533 |
path := filepath.Join(dest, hdr.Name) |
| 535 |
- if !strings.HasPrefix(path, dest) {
|
|
| 536 |
- return breakoutError(fmt.Errorf("%q is outside of %q", path, dest))
|
|
| 534 |
+ rel, err := filepath.Rel(dest, path) |
|
| 535 |
+ if err != nil {
|
|
| 536 |
+ return err |
|
| 537 |
+ } |
|
| 538 |
+ if strings.HasPrefix(rel, "..") {
|
|
| 539 |
+ return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
|
|
| 537 | 540 |
} |
| 538 | 541 |
|
| 539 | 542 |
// If path exits we almost always just want to remove and replace it |
| ... | ... |
@@ -92,12 +92,14 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
|
| 92 | 92 |
} |
| 93 | 93 |
|
| 94 | 94 |
path := filepath.Join(dest, hdr.Name) |
| 95 |
- base := filepath.Base(path) |
|
| 96 |
- |
|
| 97 |
- // Prevent symlink breakout |
|
| 98 |
- if !strings.HasPrefix(path, dest) {
|
|
| 99 |
- return breakoutError(fmt.Errorf("%q is outside of %q", path, dest))
|
|
| 95 |
+ rel, err := filepath.Rel(dest, path) |
|
| 96 |
+ if err != nil {
|
|
| 97 |
+ return err |
|
| 98 |
+ } |
|
| 99 |
+ if strings.HasPrefix(rel, "..") {
|
|
| 100 |
+ return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
|
|
| 100 | 101 |
} |
| 102 |
+ base := filepath.Base(path) |
|
| 101 | 103 |
|
| 102 | 104 |
if strings.HasPrefix(base, ".wh.") {
|
| 103 | 105 |
originalBase := base[len(".wh."):]
|