diff options
author | Valentin Rothberg <rothberg@redhat.com> | 2021-03-09 08:54:21 +0100 |
---|---|---|
committer | Valentin Rothberg <rothberg@redhat.com> | 2021-03-09 10:45:15 +0100 |
commit | 1f2f7e74590090fe8ba68b25f83f2ca08e2f201d (patch) | |
tree | 3c9a30568c48013fe06b4020f53ace64124b8ae6 | |
parent | 31b11b5cd62093d86891d32e0912661814d6b78b (diff) | |
download | podman-1f2f7e74590090fe8ba68b25f83f2ca08e2f201d.tar.gz podman-1f2f7e74590090fe8ba68b25f83f2ca08e2f201d.tar.bz2 podman-1f2f7e74590090fe8ba68b25f83f2ca08e2f201d.zip |
podman cp: evaluate symlink correctly when copying from container
When copying from a container, make sure to evaluate the symlinks
correctly. Add tests copying a symlinked directory from a running and
a non-running container to execute both path-resolution paths.
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
-rw-r--r-- | libpod/container_stat_linux.go | 42 | ||||
-rw-r--r-- | test/system/065-cp.bats | 40 |
2 files changed, 73 insertions, 9 deletions
diff --git a/libpod/container_stat_linux.go b/libpod/container_stat_linux.go index 307b75c14..0b4d9e2df 100644 --- a/libpod/container_stat_linux.go +++ b/libpod/container_stat_linux.go @@ -64,6 +64,13 @@ func (c *Container) stat(ctx context.Context, containerMountPoint string, contai containerPath = "/." } + // Wildcards are not allowed. + // TODO: it's now technically possible wildcards. + // We may consider enabling support in the future. + if strings.Contains(containerPath, "*") { + return nil, "", "", copy.ErrENOENT + } + if c.state.State == define.ContainerStateRunning { // If the container is running, we need to join it's mount namespace // and stat there. @@ -88,7 +95,8 @@ func (c *Container) stat(ctx context.Context, containerMountPoint string, contai } if statInfo.IsSymlink { - // Evaluated symlinks are always relative to the container's mount point. + // Symlinks are already evaluated and always relative to the + // container's mount point. absContainerPath = statInfo.ImmediateTarget } else if strings.HasPrefix(resolvedPath, containerMountPoint) { // If the path is on the container's mount point, strip it off. @@ -143,15 +151,31 @@ func secureStat(root string, path string) (*copier.StatForItem, error) { if len(globStats) != 1 { return nil, errors.Errorf("internal error: secureStat: expected 1 item but got %d", len(globStats)) } - - stat, exists := globStats[0].Results[glob] // only one glob passed, so that's okay - if !exists { - return nil, copy.ErrENOENT + if len(globStats) != 1 { + return nil, errors.Errorf("internal error: secureStat: expected 1 result but got %d", len(globStats[0].Results)) } - var statErr error - if stat.Error != "" { - statErr = errors.New(stat.Error) + // NOTE: the key in the map differ from `glob` when hitting symlink. + // Hence, we just take the first (and only) key/value pair. + for _, stat := range globStats[0].Results { + var statErr error + if stat.Error != "" { + statErr = errors.New(stat.Error) + } + // If necessary evaluate the symlink + if stat.IsSymlink { + target, err := copier.Eval(root, path, copier.EvalOptions{}) + if err != nil { + return nil, errors.Wrap(err, "error evaluating symlink in container") + } + // Need to make sure the symlink is relative to the root! + target = strings.TrimPrefix(target, root) + target = filepath.Join("/", target) + stat.ImmediateTarget = target + } + return stat, statErr } - return stat, statErr + + // Nothing found! + return nil, copy.ErrENOENT } diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats index 43b21587f..73e807843 100644 --- a/test/system/065-cp.bats +++ b/test/system/065-cp.bats @@ -333,6 +333,46 @@ load helpers } +@test "podman cp symlinked directory from container" { + destdir=$PODMAN_TMPDIR/cp-weird-symlink + mkdir -p $destdir + + # Create 3 files with random content in the container. + local -a randomcontent=( + random-0-$(random_string 10) + random-1-$(random_string 15) + ) + + run_podman run -d --name cpcontainer $IMAGE sleep infinity + run_podman exec cpcontainer sh -c "echo ${randomcontent[0]} > /tmp/containerfile0" + run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /tmp/containerfile1" + run_podman exec cpcontainer sh -c "mkdir /tmp/sub && cd /tmp/sub && ln -s .. weirdlink" + + # Commit the image for testing non-running containers + run_podman commit -q cpcontainer + cpimage="$output" + + # RUNNING container + # NOTE: /dest does not exist yet but is expected to be created during copy + run_podman cp cpcontainer:/tmp/sub/weirdlink $destdir/dest + run cat $destdir/dest/containerfile0 $destdir/dest/containerfile1 + is "${lines[0]}" "${randomcontent[0]}" "eval symlink - running container" + is "${lines[1]}" "${randomcontent[1]}" "eval symlink - running container" + + run_podman kill cpcontainer + run_podman rm -f cpcontainer + run rm -rf $srcdir/dest + + # CREATED container + run_podman create --name cpcontainer $cpimage + run_podman cp cpcontainer:/tmp/sub/weirdlink $destdir/dest + run cat $destdir/dest/containerfile0 $destdir/dest/containerfile1 + is "${lines[0]}" "${randomcontent[0]}" "eval symlink - created container" + is "${lines[1]}" "${randomcontent[1]}" "eval symlink - created container" + run_podman rm -f cpcontainer +} + + @test "podman cp file from host to container volume" { srcdir=$PODMAN_TMPDIR/cp-test-volume mkdir -p $srcdir |