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 <dfr@rabson.org>
This commit is contained in:
Doug Rabson
2022-08-25 08:47:42 +01:00
parent 75d6e7bae5
commit 88f82ceab2
2 changed files with 92 additions and 81 deletions

View File

@ -5,11 +5,8 @@ package libpod
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
buildahCopiah "github.com/containers/buildah/copier"
@ -21,7 +18,6 @@ import (
"github.com/containers/storage/pkg/idtools"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) {
@ -56,15 +52,10 @@ func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir boo
}
}
if c.state.State == define.ContainerStateRunning {
resolvedRoot = "/"
resolvedPath = c.pathAbs(path)
} else {
resolvedRoot, resolvedPath, err = c.resolvePath(mountPoint, path)
if err != nil {
unmount()
return nil, err
}
resolvedRoot, resolvedPath, err = c.resolveCopyTarget(mountPoint, path)
if err != nil {
unmount()
return nil, err
}
var idPair *idtools.IDPair
@ -220,71 +211,3 @@ func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxI
}
return convertedIDMap
}
// 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
}

View File

@ -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)
}