Skip to content

Commit

Permalink
Handle WORKDIR with dangling target
Browse files Browse the repository at this point in the history
When the WORKDIR is a symlink and the target directory does not exist, RUN
commands would fail.  If the target doesn't exist, create the directory in
the container.  This also converts the code to use SecureJoin so that if
a symlink is in the middle of a filepath, it will be converted correctly.

Fixes: containers#1569

Tip of the hat to @karelyatin for the initial fix

Signed-off-by: TomSweeneyRedHat <[email protected]>
  • Loading branch information
TomSweeneyRedHat committed May 7, 2019
1 parent e9184ea commit f59fcf3
Show file tree
Hide file tree
Showing 10 changed files with 344 additions and 15 deletions.
30 changes: 15 additions & 15 deletions imagebuildah/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/containers/image/types"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/cyphar/filepath-securejoin"
docker "github.com/fsouza/go-dockerclient"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -480,22 +481,21 @@ func (s *StageExecutor) volumeCacheRestore() error {
}

// Copy copies data into the working tree. The "Download" field is how
// imagebuilder tells us the instruction was "ADD" and not "COPY".
// imagebuilder tells us the instruction was "ADD" and not "COPY"
func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) error {
for _, copy := range copies {
// If the file exists, check to see if it's a symlink.
// If it is a symlink, convert to it's target otherwise
// the symlink will be overwritten.
fileDest, _ := os.Lstat(filepath.Join(s.mountPoint, copy.Dest))
if fileDest != nil {
if fileDest.Mode()&os.ModeSymlink != 0 {
if symLink, err := resolveSymlink(s.mountPoint, copy.Dest); err == nil {
copy.Dest = symLink
} else {
return errors.Wrapf(err, "error reading symbolic link to %q", copy.Dest)
}
}
// Check the file and see if part of it is a symlink.
// Convert it to the target if so.
finalPath, err := securejoin.SecureJoin(s.mountPoint, copy.Dest)
if err != nil {
return errors.Wrapf(err, "error resolving symlinks for copy destination %s", copy.Dest)
}
targetDest := strings.Split(finalPath, s.mountPoint)
if len(targetDest) != 2 {
return errors.Wrapf(err, "error resolving copy destination %s", copy.Dest)
}
copy.Dest = targetDest[1]

if copy.Download {
logrus.Debugf("ADD %#v, %#v", excludes, copy)
} else {
Expand Down Expand Up @@ -1816,8 +1816,8 @@ func (b *Executor) deleteSuccessfulIntermediateCtrs() error {
}

func (s *StageExecutor) EnsureContainerPath(path string) error {
targetPath := filepath.Join(s.mountPoint, path)
_, err := os.Lstat(targetPath)
targetPath, err := securejoin.SecureJoin(s.mountPoint, path)
_, err = os.Lstat(targetPath)
if err != nil && os.IsNotExist(err) {
err = os.MkdirAll(targetPath, 0755)
}
Expand Down
41 changes: 41 additions & 0 deletions tests/bud.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,47 @@ load helpers
run_buildah --debug=false run ${ctr} ls -alF /tempest
expect_output --substring "/tempest -> /var/lib/tempest/"

run_buildah --debug=false run ${ctr} ls -alF /etc/notareal.conf
expect_output --substring "\-rw\-rw\-r\-\-"
}

@test "bud WORKDIR isa symlink no target dir" {
target=alpine-image
ctr=alpine-ctr
run_buildah --debug=false bud --signature-policy ${TESTSDIR}/policy.json -t ${target} -f Dockerfile-2 ${TESTSDIR}/bud/workdir-symlink
expect_output --substring "STEP 2: RUN ln -sf "

run_buildah --debug=false from --signature-policy ${TESTSDIR}/policy.json --name=${ctr} ${target}
expect_output --substring ${ctr}

run_buildah --debug=false run ${ctr} ls -alF /tempest
expect_output --substring "/tempest -> /var/lib/tempest/"

run_buildah --debug=false run ${ctr} ls /tempest
expect_output --substring "Dockerfile-2"

run_buildah --debug=false run ${ctr} ls -alF /etc/notareal.conf
expect_output --substring "\-rw\-rw\-r\-\-"
}

@test "bud WORKDIR isa symlink no target dir and follow on dir" {
target=alpine-image
ctr=alpine-ctr
run_buildah --debug=false bud --signature-policy ${TESTSDIR}/policy.json -t ${target} -f Dockerfile-3 ${TESTSDIR}/bud/workdir-symlink
expect_output --substring "STEP 2: RUN ln -sf "

run_buildah --debug=false from --signature-policy ${TESTSDIR}/policy.json --name=${ctr} ${target}
expect_output --substring ${ctr}

run_buildah --debug=false run ${ctr} ls -alF /tempest
expect_output --substring "/tempest -> /var/lib/tempest/"

run_buildah --debug=false run ${ctr} ls /tempest
expect_output --substring "Dockerfile-3"

run_buildah --debug=false run ${ctr} ls /tempest/tom
expect_output --substring "Dockerfile-3"

run_buildah --debug=false run ${ctr} ls -alF /etc/notareal.conf
expect_output --substring "\-rw\-rw\-r\-\-"
}
Expand Down
7 changes: 7 additions & 0 deletions tests/bud/workdir-symlink/Dockerfile-2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# No directory created for the target of the symlink
FROM alpine
RUN ln -sf /var/lib/tempest /tempest
WORKDIR /tempest
RUN touch /etc/notareal.conf
RUN chmod 664 /etc/notareal.conf
COPY Dockerfile-2 ./Dockerfile-2
10 changes: 10 additions & 0 deletions tests/bud/workdir-symlink/Dockerfile-3
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# No directory created for the target of the symlink
FROM alpine
RUN ln -sf /var/lib/tempest /tempest
WORKDIR /tempest/tom
RUN touch /etc/notareal.conf
RUN chmod 664 /etc/notareal.conf
RUN mkdir -p /tempest/tom
COPY Dockerfile-3 ./Dockerfile-3
COPY Dockerfile-3 /tempest/Dockerfile-3
COPY Dockerfile-3 /tempest/tom/Dockerfile-3
1 change: 1 addition & 0 deletions vendor.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/BurntSushi/toml v0.2.0
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
github.com/containernetworking/cni v0.7.0-rc2
github.com/containers/image f52cf78ebfa1916da406f8b6210d8f7764ec1185
github.com/cyphar/filepath-securejoin v0.2.1
github.com/vbauerster/mpb v3.3.4
github.com/mattn/go-isatty v0.0.4
github.com/VividCortex/ewma v1.1.1
Expand Down
28 changes: 28 additions & 0 deletions vendor/github.com/cyphar/filepath-securejoin/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions vendor/github.com/cyphar/filepath-securejoin/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

135 changes: 135 additions & 0 deletions vendor/github.com/cyphar/filepath-securejoin/join.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f59fcf3

Please sign in to comment.