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 71debed
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 14 deletions.
35 changes: 21 additions & 14 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 @@ -1817,13 +1817,20 @@ func (b *Executor) deleteSuccessfulIntermediateCtrs() error {

func (s *StageExecutor) EnsureContainerPath(path string) error {
targetPath := filepath.Join(s.mountPoint, path)
_, err := os.Lstat(targetPath)
joinedPath, err := os.Lstat(targetPath)
if err != nil && os.IsNotExist(err) {
err = os.MkdirAll(targetPath, 0755)
}
if err != nil {
return errors.Wrapf(err, "error ensuring container path %q", path)
}
// If a symlink, check that the target directory exists in the container.
// If not, make it.
if joinedPath.Mode()&os.ModeSymlink != 0 {
if symTarget, err2 := os.Readlink(targetPath); err2 == nil {
os.MkdirAll(filepath.Join(s.mountPoint, symTarget), 0755)
}
}
return nil
}

Expand Down
16 changes: 16 additions & 0 deletions tests/bud.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,22 @@ 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 ${TESTSDIR}/bud/workdir-symlink/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 -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
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.

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

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

0 comments on commit 71debed

Please sign in to comment.