diff options
Diffstat (limited to 'libpod/container_internal_linux.go')
| -rw-r--r-- | libpod/container_internal_linux.go | 126 | 
1 files changed, 77 insertions, 49 deletions
| diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 3583f8fdd..dc0418148 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -21,22 +21,25 @@ import (  	cnitypes "github.com/containernetworking/cni/pkg/types/current"  	"github.com/containernetworking/plugins/pkg/ns" +	"github.com/containers/buildah/pkg/chrootuser"  	"github.com/containers/buildah/pkg/overlay" +	butil "github.com/containers/buildah/util"  	"github.com/containers/common/pkg/apparmor" +	"github.com/containers/common/pkg/chown"  	"github.com/containers/common/pkg/config"  	"github.com/containers/common/pkg/subscriptions"  	"github.com/containers/common/pkg/umask" -	"github.com/containers/podman/v2/libpod/define" -	"github.com/containers/podman/v2/libpod/events" -	"github.com/containers/podman/v2/pkg/annotations" -	"github.com/containers/podman/v2/pkg/cgroups" -	"github.com/containers/podman/v2/pkg/criu" -	"github.com/containers/podman/v2/pkg/lookup" -	"github.com/containers/podman/v2/pkg/resolvconf" -	"github.com/containers/podman/v2/pkg/rootless" -	"github.com/containers/podman/v2/pkg/util" -	"github.com/containers/podman/v2/utils" -	"github.com/containers/podman/v2/version" +	"github.com/containers/podman/v3/libpod/define" +	"github.com/containers/podman/v3/libpod/events" +	"github.com/containers/podman/v3/pkg/annotations" +	"github.com/containers/podman/v3/pkg/cgroups" +	"github.com/containers/podman/v3/pkg/criu" +	"github.com/containers/podman/v3/pkg/lookup" +	"github.com/containers/podman/v3/pkg/resolvconf" +	"github.com/containers/podman/v3/pkg/rootless" +	"github.com/containers/podman/v3/pkg/util" +	"github.com/containers/podman/v3/utils" +	"github.com/containers/podman/v3/version"  	"github.com/containers/storage/pkg/archive"  	"github.com/containers/storage/pkg/idtools"  	securejoin "github.com/cyphar/filepath-securejoin" @@ -203,10 +206,17 @@ func (c *Container) resolveWorkDir() error {  	}  	logrus.Debugf("Workdir %q resolved to host path %q", workdir, resolvedWorkdir) -	// No need to create it (e.g., `--workdir=/foo`), so let's make sure -	// the path exists on the container. +	st, err := os.Stat(resolvedWorkdir) +	if err == nil { +		if !st.IsDir() { +			return errors.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID()) +		} +		return nil +	}  	if !c.config.CreateWorkingDir { -		if _, err := os.Stat(resolvedWorkdir); err != nil { +		// 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) {  				return errors.Errorf("workdir %q does not exist on container %s", workdir, c.ID())  			} @@ -216,11 +226,6 @@ func (c *Container) resolveWorkDir() error {  		}  		return nil  	} - -	// Ensure container entrypoint is created (if required). -	rootUID := c.RootUID() -	rootGID := c.RootGID() -  	if err := os.MkdirAll(resolvedWorkdir, 0755); err != nil {  		if os.IsExist(err) {  			return nil @@ -228,7 +233,12 @@ func (c *Container) resolveWorkDir() error {  		return errors.Wrapf(err, "error creating container %s workdir", c.ID())  	} -	if err := os.Chown(resolvedWorkdir, rootUID, rootGID); err != nil { +	// Ensure container entrypoint is created (if required). +	uid, gid, _, err := chrootuser.GetUser(c.state.Mountpoint, c.User()) +	if err != nil { +		return errors.Wrapf(err, "error looking up %s inside of the container %s", c.User(), c.ID()) +	} +	if err := os.Chown(resolvedWorkdir, int(uid), int(gid)); err != nil {  		return errors.Wrapf(err, "error chowning container %s workdir to container root", c.ID())  	} @@ -348,13 +358,28 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {  		return nil, err  	} -	// Check if the spec file mounts contain the label Relabel flags z or Z. -	// If they do, relabel the source directory and then remove the option. +	// Get host UID and GID based on the container process UID and GID. +	hostUID, hostGID, err := butil.GetHostIDs(util.IDtoolsToRuntimeSpec(c.config.IDMappings.UIDMap), util.IDtoolsToRuntimeSpec(c.config.IDMappings.GIDMap), uint32(execUser.Uid), uint32(execUser.Gid)) +	if err != nil { +		return nil, err +	} + +	// Check if the spec file mounts contain the options z, Z or U. +	// If they have z or Z, relabel the source directory and then remove the option. +	// If they have U, chown the source directory and them remove the option.  	for i := range g.Config.Mounts {  		m := &g.Config.Mounts[i]  		var options []string  		for _, o := range m.Options {  			switch o { +			case "U": +				if m.Type == "tmpfs" { +					options = append(options, []string{fmt.Sprintf("uid=%d", execUser.Uid), fmt.Sprintf("gid=%d", execUser.Gid)}...) +				} else { +					if err := chown.ChangeHostPathOwnership(m.Source, true, int(hostUID), int(hostGID)); err != nil { +						return nil, err +					} +				}  			case "z":  				fallthrough  			case "Z": @@ -419,6 +444,21 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {  		if err != nil {  			return nil, errors.Wrapf(err, "mounting overlay failed %q", overlayVol.Source)  		} + +		// Check overlay volume options +		for _, o := range overlayVol.Options { +			switch o { +			case "U": +				if err := chown.ChangeHostPathOwnership(overlayVol.Source, true, int(hostUID), int(hostGID)); err != nil { +					return nil, err +				} + +				if err := chown.ChangeHostPathOwnership(contentDir, true, int(hostUID), int(hostGID)); err != nil { +					return nil, err +				} +			} +		} +  		g.AddMount(overlayMount)  	} @@ -458,7 +498,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {  			break  		}  	} -	if !hasHomeSet { +	if !hasHomeSet && execUser.Home != "" {  		c.config.Spec.Process.Env = append(c.config.Spec.Process.Env, fmt.Sprintf("HOME=%s", execUser.Home))  	} @@ -521,14 +561,14 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {  			}}  		}  		for _, gid := range execUser.Sgids { -			isGidAvailable := false +			isGIDAvailable := false  			for _, m := range gidMappings {  				if gid >= m.ContainerID && gid < m.ContainerID+m.Size { -					isGidAvailable = true +					isGIDAvailable = true  					break  				}  			} -			if isGidAvailable { +			if isGIDAvailable {  				g.AddProcessAdditionalGid(uint32(gid))  			} else {  				logrus.Warnf("additional gid=%d is not present in the user namespace, skip setting it", gid) @@ -1614,13 +1654,12 @@ func (c *Container) makeBindMounts() error {  				return errors.Wrapf(err, "error setting timezone for container %s", c.ID())  			}  			c.state.BindMounts["/etc/localtime"] = localtimePath -  		}  	}  	// Make .containerenv if it does not exist  	if _, ok := c.state.BindMounts["/run/.containerenv"]; !ok { -		var containerenv string +		containerenv := c.runtime.graphRootMountedFlag(c.config.Spec.Mounts)  		isRootless := 0  		if rootless.IsRootless() {  			isRootless = 1 @@ -1635,7 +1674,7 @@ id=%q  image=%q  imageid=%q  rootless=%d -`, version.Version.String(), c.Name(), c.ID(), imageName, imageID, isRootless) +%s`, version.Version.String(), c.Name(), c.ID(), imageName, imageID, isRootless, containerenv)  		}  		containerenvPath, err := c.writeStringToRundir(".containerenv", containerenv)  		if err != nil { @@ -1674,8 +1713,9 @@ rootless=%d  // generateResolvConf generates a containers resolv.conf  func (c *Container) generateResolvConf() (string, error) {  	var ( -		nameservers    []string -		cniNameServers []string +		nameservers      []string +		cniNameServers   []string +		cniSearchDomains []string  	)  	resolvConf := "/etc/resolv.conf" @@ -1727,6 +1767,10 @@ func (c *Container) generateResolvConf() (string, error) {  			cniNameServers = append(cniNameServers, i.DNS.Nameservers...)  			logrus.Debugf("adding nameserver(s) from cni response of '%q'", i.DNS.Nameservers)  		} +		if i.DNS.Search != nil { +			cniSearchDomains = append(cniSearchDomains, i.DNS.Search...) +			logrus.Debugf("adding search domain(s) from cni response of '%q'", i.DNS.Search) +		}  	}  	dns := make([]net.IP, 0, len(c.runtime.config.Containers.DNSServers)) @@ -1758,10 +1802,11 @@ func (c *Container) generateResolvConf() (string, error) {  	}  	var search []string -	if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 { +	if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 || len(cniSearchDomains) > 0 {  		if !util.StringInSlice(".", c.config.DNSSearch) {  			search = c.runtime.config.Containers.DNSSearches  			search = append(search, c.config.DNSSearch...) +			search = append(search, cniSearchDomains...)  		}  	} else {  		search = resolvconf.GetSearchDomains(resolv.Content) @@ -2278,23 +2323,6 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {  	return passwdPath, groupPath, nil  } -func (c *Container) copyOwnerAndPerms(source, dest string) error { -	info, err := os.Stat(source) -	if err != nil { -		if os.IsNotExist(err) { -			return nil -		} -		return err -	} -	if err := os.Chmod(dest, info.Mode()); err != nil { -		return err -	} -	if err := os.Chown(dest, int(info.Sys().(*syscall.Stat_t).Uid), int(info.Sys().(*syscall.Stat_t).Gid)); err != nil { -		return err -	} -	return nil -} -  // Get cgroup path in a format suitable for the OCI spec  func (c *Container) getOCICgroupPath() (string, error) {  	unified, err := cgroups.IsCgroup2UnifiedMode() | 
