From 5ce91364b32a54d49e8b2668bbb9d1a00492228d Mon Sep 17 00:00:00 2001
From: Alexandr Morozov <lk4d4@docker.com>
Date: Wed, 26 Nov 2014 23:00:13 -0800
Subject: [PATCH] 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
---
 archive/archive.go |  9 ++++++---
 archive/diff.go    | 12 +++++++-----
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/archive/archive.go b/archive/archive.go
index 13f447c..74c6014 100644
--- a/archive/archive.go
+++ b/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
diff --git a/archive/diff.go b/archive/diff.go
index e546763..80bb197 100644
--- a/archive/diff.go
+++ b/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."):]