diff options
author | Doug Rabson <dfr@rabson.org> | 2022-08-27 14:19:17 +0100 |
---|---|---|
committer | Doug Rabson <dfr@rabson.org> | 2022-09-05 10:17:49 +0100 |
commit | 232eea5a00f542081e0bade13b21b8b44b0ad906 (patch) | |
tree | 184513cebe37dd7e4e3d19f195963cab02af4605 /libpod | |
parent | a5ee3cb79065907548e95fef5709f08f51041b69 (diff) | |
download | podman-232eea5a00f542081e0bade13b21b8b44b0ad906.tar.gz podman-232eea5a00f542081e0bade13b21b8b44b0ad906.tar.bz2 podman-232eea5a00f542081e0bade13b21b8b44b0ad906.zip |
libpod: Move isWorkDirSymlink, resolveWorkDir to container_internal_common.go
[NO NEW TESTS NEEDED]
Signed-off-by: Doug Rabson <dfr@rabson.org>
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_internal_common.go | 113 | ||||
-rw-r--r-- | libpod/container_internal_freebsd.go | 113 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 113 |
3 files changed, 113 insertions, 226 deletions
diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 2b11ff5b6..476ae1989 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -14,6 +14,7 @@ import ( "time" cdi "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" + "github.com/containers/buildah/pkg/chrootuser" "github.com/containers/buildah/pkg/overlay" butil "github.com/containers/buildah/util" "github.com/containers/common/pkg/apparmor" @@ -480,3 +481,115 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { return g.Config, nil } + +// isWorkDirSymlink returns true if resolved workdir is symlink or a chain of symlinks, +// and final resolved target is present either on volume, mount or inside of container +// otherwise it returns false. Following function is meant for internal use only and +// can change at any point of time. +func (c *Container) isWorkDirSymlink(resolvedPath string) bool { + // We cannot create workdir since explicit --workdir is + // set in config but workdir could also be a symlink. + // If it's a symlink, check if the resolved target is present in the container. + // If so, that's a valid use case: return nil. + + maxSymLinks := 0 + for { + // Linux only supports a chain of 40 links. + // Reference: https://github.com/torvalds/linux/blob/master/include/linux/namei.h#L13 + if maxSymLinks > 40 { + break + } + resolvedSymlink, err := os.Readlink(resolvedPath) + if err != nil { + // End sym-link resolution loop. + break + } + if resolvedSymlink != "" { + _, resolvedSymlinkWorkdir, err := c.resolvePath(c.state.Mountpoint, resolvedSymlink) + if isPathOnVolume(c, resolvedSymlinkWorkdir) || isPathOnBindMount(c, resolvedSymlinkWorkdir) { + // Resolved symlink exists on external volume or mount + return true + } + if err != nil { + // Could not resolve path so end sym-link resolution loop. + break + } + if resolvedSymlinkWorkdir != "" { + resolvedPath = resolvedSymlinkWorkdir + _, err := os.Stat(resolvedSymlinkWorkdir) + if err == nil { + // Symlink resolved successfully and resolved path exists on container, + // this is a valid use-case so return nil. + logrus.Debugf("Workdir is a symlink with target to %q and resolved symlink exists on container", resolvedSymlink) + return true + } + } + } + maxSymLinks++ + } + return false +} + +// resolveWorkDir resolves the container's workdir and, depending on the +// configuration, will create it, or error out if it does not exist. +// Note that the container must be mounted before. +func (c *Container) resolveWorkDir() error { + workdir := c.WorkingDir() + + // If the specified workdir is a subdir of a volume or mount, + // we don't need to do anything. The runtime is taking care of + // that. + if isPathOnVolume(c, workdir) || isPathOnBindMount(c, workdir) { + logrus.Debugf("Workdir %q resolved to a volume or mount", workdir) + return nil + } + + _, resolvedWorkdir, err := c.resolvePath(c.state.Mountpoint, workdir) + if err != nil { + return err + } + logrus.Debugf("Workdir %q resolved to host path %q", workdir, resolvedWorkdir) + + st, err := os.Stat(resolvedWorkdir) + if err == nil { + if !st.IsDir() { + return fmt.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID()) + } + return nil + } + if !c.config.CreateWorkingDir { + // No need to create it (e.g., `--workdir=/foo`), so let's make sure + // the path exists on the container. + if err != nil { + if os.IsNotExist(err) { + // If resolved Workdir path gets marked as a valid symlink, + // return nil cause this is valid use-case. + if c.isWorkDirSymlink(resolvedWorkdir) { + return nil + } + return fmt.Errorf("workdir %q does not exist on container %s", workdir, c.ID()) + } + // This might be a serious error (e.g., permission), so + // we need to return the full error. + return fmt.Errorf("error detecting workdir %q on container %s: %w", workdir, c.ID(), err) + } + return nil + } + if err := os.MkdirAll(resolvedWorkdir, 0755); err != nil { + if os.IsExist(err) { + return nil + } + return fmt.Errorf("error creating container %s workdir: %w", c.ID(), err) + } + + // Ensure container entrypoint is created (if required). + uid, gid, _, err := chrootuser.GetUser(c.state.Mountpoint, c.User()) + if err != nil { + return fmt.Errorf("error looking up %s inside of the container %s: %w", c.User(), c.ID(), err) + } + if err := os.Chown(resolvedWorkdir, int(uid), int(gid)); err != nil { + return fmt.Errorf("error chowning container %s workdir to container root: %w", c.ID(), err) + } + + return nil +} diff --git a/libpod/container_internal_freebsd.go b/libpod/container_internal_freebsd.go index c180528cb..f460ca49a 100644 --- a/libpod/container_internal_freebsd.go +++ b/libpod/container_internal_freebsd.go @@ -21,7 +21,6 @@ import ( metadata "github.com/checkpoint-restore/checkpointctl/lib" "github.com/checkpoint-restore/go-criu/v5/stats" - "github.com/containers/buildah/pkg/chrootuser" "github.com/containers/buildah/pkg/overlay" "github.com/containers/common/libnetwork/etchosts" "github.com/containers/common/libnetwork/resolvconf" @@ -150,118 +149,6 @@ func (c *Container) prepare() error { return nil } -// isWorkDirSymlink returns true if resolved workdir is symlink or a chain of symlinks, -// and final resolved target is present either on volume, mount or inside of container -// otherwise it returns false. Following function is meant for internal use only and -// can change at any point of time. -func (c *Container) isWorkDirSymlink(resolvedPath string) bool { - // We cannot create workdir since explicit --workdir is - // set in config but workdir could also be a symlink. - // If it's a symlink, check if the resolved target is present in the container. - // If so, that's a valid use case: return nil. - - maxSymLinks := 0 - for { - // Linux only supports a chain of 40 links. - // Reference: https://github.com/torvalds/linux/blob/master/include/linux/namei.h#L13 - if maxSymLinks > 40 { - break - } - resolvedSymlink, err := os.Readlink(resolvedPath) - if err != nil { - // End sym-link resolution loop. - break - } - if resolvedSymlink != "" { - _, resolvedSymlinkWorkdir, err := c.resolvePath(c.state.Mountpoint, resolvedSymlink) - if isPathOnVolume(c, resolvedSymlinkWorkdir) || isPathOnBindMount(c, resolvedSymlinkWorkdir) { - // Resolved symlink exists on external volume or mount - return true - } - if err != nil { - // Could not resolve path so end sym-link resolution loop. - break - } - if resolvedSymlinkWorkdir != "" { - resolvedPath = resolvedSymlinkWorkdir - _, err := os.Stat(resolvedSymlinkWorkdir) - if err == nil { - // Symlink resolved successfully and resolved path exists on container, - // this is a valid use-case so return nil. - logrus.Debugf("Workdir is a symlink with target to %q and resolved symlink exists on container", resolvedSymlink) - return true - } - } - } - maxSymLinks++ - } - return false -} - -// resolveWorkDir resolves the container's workdir and, depending on the -// configuration, will create it, or error out if it does not exist. -// Note that the container must be mounted before. -func (c *Container) resolveWorkDir() error { - workdir := c.WorkingDir() - - // If the specified workdir is a subdir of a volume or mount, - // we don't need to do anything. The runtime is taking care of - // that. - if isPathOnVolume(c, workdir) || isPathOnBindMount(c, workdir) { - logrus.Debugf("Workdir %q resolved to a volume or mount", workdir) - return nil - } - - _, resolvedWorkdir, err := c.resolvePath(c.state.Mountpoint, workdir) - if err != nil { - return err - } - logrus.Debugf("Workdir %q resolved to host path %q", workdir, resolvedWorkdir) - - st, err := os.Stat(resolvedWorkdir) - if err == nil { - if !st.IsDir() { - return fmt.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID()) - } - return nil - } - if !c.config.CreateWorkingDir { - // No need to create it (e.g., `--workdir=/foo`), so let's make sure - // the path exists on the container. - if err != nil { - if os.IsNotExist(err) { - // If resolved Workdir path gets marked as a valid symlink, - // return nil cause this is valid use-case. - if c.isWorkDirSymlink(resolvedWorkdir) { - return nil - } - return fmt.Errorf("workdir %q does not exist on container %s", workdir, c.ID()) - } - // This might be a serious error (e.g., permission), so - // we need to return the full error. - return fmt.Errorf("error detecting workdir %q on container %s: %w", workdir, c.ID(), err) - } - return nil - } - if err := os.MkdirAll(resolvedWorkdir, 0755); err != nil { - if os.IsExist(err) { - return nil - } - return fmt.Errorf("error creating container %s workdir: %w", c.ID(), err) - } - - // Ensure container entrypoint is created (if required). - uid, gid, _, err := chrootuser.GetUser(c.state.Mountpoint, c.User()) - if err != nil { - return fmt.Errorf("error looking up %s inside of the container %s: %w", c.User(), c.ID(), err) - } - if err := os.Chown(resolvedWorkdir, int(uid), int(gid)); err != nil { - return fmt.Errorf("error chowning container %s workdir to container root: %w", c.ID(), err) - } - - return nil -} - // cleanupNetwork unmounts and cleans up the container's network func (c *Container) cleanupNetwork() error { if c.config.NetNsCtr != "" { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index bd50ceb45..16a576947 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -23,7 +23,6 @@ import ( "github.com/checkpoint-restore/go-criu/v5/stats" "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/buildah" - "github.com/containers/buildah/pkg/chrootuser" "github.com/containers/buildah/pkg/overlay" "github.com/containers/common/libnetwork/etchosts" "github.com/containers/common/libnetwork/resolvconf" @@ -175,118 +174,6 @@ func (c *Container) prepare() error { return nil } -// isWorkDirSymlink returns true if resolved workdir is symlink or a chain of symlinks, -// and final resolved target is present either on volume, mount or inside of container -// otherwise it returns false. Following function is meant for internal use only and -// can change at any point of time. -func (c *Container) isWorkDirSymlink(resolvedPath string) bool { - // We cannot create workdir since explicit --workdir is - // set in config but workdir could also be a symlink. - // If it's a symlink, check if the resolved target is present in the container. - // If so, that's a valid use case: return nil. - - maxSymLinks := 0 - for { - // Linux only supports a chain of 40 links. - // Reference: https://github.com/torvalds/linux/blob/master/include/linux/namei.h#L13 - if maxSymLinks > 40 { - break - } - resolvedSymlink, err := os.Readlink(resolvedPath) - if err != nil { - // End sym-link resolution loop. - break - } - if resolvedSymlink != "" { - _, resolvedSymlinkWorkdir, err := c.resolvePath(c.state.Mountpoint, resolvedSymlink) - if isPathOnVolume(c, resolvedSymlinkWorkdir) || isPathOnBindMount(c, resolvedSymlinkWorkdir) { - // Resolved symlink exists on external volume or mount - return true - } - if err != nil { - // Could not resolve path so end sym-link resolution loop. - break - } - if resolvedSymlinkWorkdir != "" { - resolvedPath = resolvedSymlinkWorkdir - _, err := os.Stat(resolvedSymlinkWorkdir) - if err == nil { - // Symlink resolved successfully and resolved path exists on container, - // this is a valid use-case so return nil. - logrus.Debugf("Workdir is a symlink with target to %q and resolved symlink exists on container", resolvedSymlink) - return true - } - } - } - maxSymLinks++ - } - return false -} - -// resolveWorkDir resolves the container's workdir and, depending on the -// configuration, will create it, or error out if it does not exist. -// Note that the container must be mounted before. -func (c *Container) resolveWorkDir() error { - workdir := c.WorkingDir() - - // If the specified workdir is a subdir of a volume or mount, - // we don't need to do anything. The runtime is taking care of - // that. - if isPathOnVolume(c, workdir) || isPathOnBindMount(c, workdir) { - logrus.Debugf("Workdir %q resolved to a volume or mount", workdir) - return nil - } - - _, resolvedWorkdir, err := c.resolvePath(c.state.Mountpoint, workdir) - if err != nil { - return err - } - logrus.Debugf("Workdir %q resolved to host path %q", workdir, resolvedWorkdir) - - st, err := os.Stat(resolvedWorkdir) - if err == nil { - if !st.IsDir() { - return fmt.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID()) - } - return nil - } - if !c.config.CreateWorkingDir { - // No need to create it (e.g., `--workdir=/foo`), so let's make sure - // the path exists on the container. - if err != nil { - if os.IsNotExist(err) { - // If resolved Workdir path gets marked as a valid symlink, - // return nil cause this is valid use-case. - if c.isWorkDirSymlink(resolvedWorkdir) { - return nil - } - return fmt.Errorf("workdir %q does not exist on container %s", workdir, c.ID()) - } - // This might be a serious error (e.g., permission), so - // we need to return the full error. - return fmt.Errorf("error detecting workdir %q on container %s: %w", workdir, c.ID(), err) - } - return nil - } - if err := os.MkdirAll(resolvedWorkdir, 0755); err != nil { - if os.IsExist(err) { - return nil - } - return fmt.Errorf("error creating container %s workdir: %w", c.ID(), err) - } - - // Ensure container entrypoint is created (if required). - uid, gid, _, err := chrootuser.GetUser(c.state.Mountpoint, c.User()) - if err != nil { - return fmt.Errorf("error looking up %s inside of the container %s: %w", c.User(), c.ID(), err) - } - if err := os.Chown(resolvedWorkdir, int(uid), int(gid)); err != nil { - return fmt.Errorf("error chowning container %s workdir to container root: %w", c.ID(), err) - } - - return nil -} - // cleanupNetwork unmounts and cleans up the container's network func (c *Container) cleanupNetwork() error { if c.config.NetNsCtr != "" { |