diff --git a/buildfile.go b/buildfile.go index 00c747d6d0..3c4229d8bf 100644 --- a/buildfile.go +++ b/buildfile.go @@ -278,6 +278,9 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error { if strings.HasSuffix(dest, "/") { destPath = destPath + "/" } + if !strings.HasPrefix(origPath, b.context) { + return fmt.Errorf("Forbidden path: %s", origPath) + } fi, err := os.Stat(origPath) if err != nil { return err diff --git a/buildfile_test.go b/buildfile_test.go index 9d002f0665..d89c40d16c 100644 --- a/buildfile_test.go +++ b/buildfile_test.go @@ -423,3 +423,52 @@ func TestBuildImageWithoutCache(t *testing.T) { t.Fail() } } + +func TestForbiddenContextPath(t *testing.T) { + runtime, err := newTestRuntime() + if err != nil { + t.Fatal(err) + } + defer nuke(runtime) + + srv := &Server{ + runtime: runtime, + pullingPool: make(map[string]struct{}), + pushingPool: make(map[string]struct{}), + } + + context := testContextTemplate{` + from {IMAGE} + maintainer dockerio + add ../../ test/ + `, + [][2]string{{"test.txt", "test1"}, {"other.txt", "other"}}, nil} + + httpServer, err := mkTestingFileServer(context.remoteFiles) + if err != nil { + t.Fatal(err) + } + defer httpServer.Close() + + idx := strings.LastIndex(httpServer.URL, ":") + if idx < 0 { + t.Fatalf("could not get port from test http server address %s", httpServer.URL) + } + port := httpServer.URL[idx+1:] + + ip := srv.runtime.networkManager.bridgeNetwork.IP + dockerfile := constructDockerfile(context.dockerfile, ip, port) + + buildfile := NewBuildFile(srv, ioutil.Discard, false, true) + _, err = buildfile.Build(mkTestContext(dockerfile, context.files, t)) + + if err == nil { + t.Log("Error should not be nil") + t.Fail() + } + + if err.Error() != "Forbidden path: /" { + t.Logf("Error message is not expected: %s", err.Error()) + t.Fail() + } +}