diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2022-03-02 10:56:26 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-02 10:56:26 -0500 |
commit | ed59b89a43c6d9f0bf691e536738fb8450bedfa9 (patch) | |
tree | ed3c97ca2cb90b11b557b4db9dcab97ee2e623c6 /libpod | |
parent | 7877b02aacf3e8d3d37f6283c6b8aa81688fd120 (diff) | |
parent | 0bd0ad59436436e93ac81ce46059d8618ed7766c (diff) | |
download | podman-ed59b89a43c6d9f0bf691e536738fb8450bedfa9.tar.gz podman-ed59b89a43c6d9f0bf691e536738fb8450bedfa9.tar.bz2 podman-ed59b89a43c6d9f0bf691e536738fb8450bedfa9.zip |
Merge pull request #13399 from flouthoc/resolve-workdir-symlink
container: workdir resolution must consider `symlink` if explicitly configured
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_internal_linux.go | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index cef9e2c04..1517a7df7 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -173,6 +173,57 @@ 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 its a symlink lets check if resolved link is present + // on the container or not. + + // If we can resolve symlink and resolved link is present on the container + // then return nil cause its a valid use-case. + + 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. @@ -205,6 +256,11 @@ func (c *Container) resolveWorkDir() error { // 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 errors.Errorf("workdir %q does not exist on container %s", workdir, c.ID()) } // This might be a serious error (e.g., permission), so |