mirror of
https://github.com/containers/podman.git
synced 2025-07-03 09:17:15 +08:00
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>
This commit is contained in:
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user