From 88f82ceab2b14b0523a56cd8c6b3a9cec8a323e2 Mon Sep 17 00:00:00 2001 From: Doug Rabson Date: Thu, 25 Aug 2022 08:47:42 +0100 Subject: libpod: Move jointMountAndExec to container_copy_linux.go This also moves the logic for resolving paths in running and stopped containers tp container_copy_linux.go. On FreeBSD, we can execute the function argument to joinMountAndExec directly using host-relative paths since the host mount namespace includes all the container mounts. [NO NEW TESTS NEEDED] Signed-off-by: Doug Rabson --- libpod/container_copy_linux.go | 88 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 libpod/container_copy_linux.go (limited to 'libpod/container_copy_linux.go') diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go new file mode 100644 index 000000000..3b029f08f --- /dev/null +++ b/libpod/container_copy_linux.go @@ -0,0 +1,88 @@ +package libpod + +import ( + "fmt" + "os" + "runtime" + + "github.com/containers/podman/v4/libpod/define" + "golang.org/x/sys/unix" +) + +// joinMountAndExec executes the specified function `f` inside the container's +// mount and PID namespace. That allows for having the exact view on the +// container's file system. +// +// Note, if the container is not running `f()` will be executed as is. +func (c *Container) joinMountAndExec(f func() error) error { + if c.state.State != define.ContainerStateRunning { + return f() + } + + // Container's running, so we need to execute `f()` inside its mount NS. + errChan := make(chan error) + go func() { + runtime.LockOSThread() + + // Join the mount and PID NS of the container. + getFD := func(ns LinuxNS) (*os.File, error) { + nsPath, err := c.namespacePath(ns) + if err != nil { + return nil, err + } + return os.Open(nsPath) + } + + mountFD, err := getFD(MountNS) + if err != nil { + errChan <- err + return + } + defer mountFD.Close() + + inHostPidNS, err := c.inHostPidNS() + if err != nil { + errChan <- fmt.Errorf("checking inHostPidNS: %w", err) + return + } + var pidFD *os.File + if !inHostPidNS { + pidFD, err = getFD(PIDNS) + if err != nil { + errChan <- err + return + } + defer pidFD.Close() + } + + if err := unix.Unshare(unix.CLONE_NEWNS); err != nil { + errChan <- err + return + } + + if pidFD != nil { + if err := unix.Setns(int(pidFD.Fd()), unix.CLONE_NEWPID); err != nil { + errChan <- err + return + } + } + if err := unix.Setns(int(mountFD.Fd()), unix.CLONE_NEWNS); err != nil { + errChan <- err + return + } + + // Last but not least, execute the workload. + errChan <- f() + }() + return <-errChan +} + +func (c *Container) resolveCopyTarget(mountPoint string, containerPath string) (string, string, error) { + // If the container is running, we will execute the copy + // inside the container's mount namespace so we return a path + // relative to the container's root. + if c.state.State == define.ContainerStateRunning { + return "/", c.pathAbs(containerPath), nil + } + return c.resolvePath(mountPoint, containerPath) +} -- cgit v1.2.3-54-g00ecf