summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go6
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_internal.go6
-rw-r--r--libpod/container_internal_linux.go6
-rw-r--r--libpod/container_log_linux.go2
-rw-r--r--libpod/define/container.go2
-rw-r--r--libpod/define/pod_inspect.go2
-rw-r--r--libpod/info.go29
-rw-r--r--libpod/networking_linux.go28
-rw-r--r--libpod/options.go24
-rw-r--r--libpod/pod.go1
-rw-r--r--libpod/pod_api.go5
-rw-r--r--libpod/runtime_pod_infra_linux.go37
13 files changed, 114 insertions, 36 deletions
diff --git a/libpod/container.go b/libpod/container.go
index f3f4b27b7..80fd35c09 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -240,7 +240,7 @@ type ContainerImageVolume struct {
type ContainerSecret struct {
// Secret is the secret
*secrets.Secret
- // UID is tbe UID of the secret file
+ // UID is the UID of the secret file
UID uint32
// GID is the GID of the secret file
GID uint32
@@ -1020,8 +1020,8 @@ func (c *Container) RWSize() (int64, error) {
}
// IDMappings returns the UID/GID mapping used for the container
-func (c *Container) IDMappings() (storage.IDMappingOptions, error) {
- return c.config.IDMappings, nil
+func (c *Container) IDMappings() storage.IDMappingOptions {
+ return c.config.IDMappings
}
// RootUID returns the root user mapping from container
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 72a969fe6..e15030c15 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -376,6 +376,6 @@ type ContainerMiscConfig struct {
// EnvSecrets are secrets that are set as environment variables
EnvSecrets map[string]*secrets.Secret `json:"secret_env,omitempty"`
// InitContainerType specifies if the container is an initcontainer
- // and if so, what type: always or oneshot are possible non-nil entries
+ // and if so, what type: always or once are possible non-nil entries
InitContainerType string `json:"init_container_type,omitempty"`
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 8ffcccf4c..3f7a4807d 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -367,6 +367,12 @@ func (c *Container) setupStorageMapping(dest, from *storage.IDMappingOptions) {
return
}
*dest = *from
+ // If we are creating a container inside a pod, we always want to inherit the
+ // userns settings from the infra container. So clear the auto userns settings
+ // so that we don't request storage for a new uid/gid map.
+ if c.PodID() != "" && !c.IsInfra() {
+ dest.AutoUserNs = false
+ }
if dest.AutoUserNs {
overrides := c.getUserOverrides()
dest.AutoUserNsOpts.PasswdFile = overrides.ContainerEtcPasswdPath
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index f30f622ac..f21aebb09 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -659,7 +659,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
- if c.config.IDMappings.AutoUserNs {
+ if c.config.UserNsCtr == "" && c.config.IDMappings.AutoUserNs {
if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil {
return nil, err
}
@@ -1782,7 +1782,7 @@ func (c *Container) generateResolvConf() (string, error) {
cniResponse := c.state.NetworkStatus
for _, i := range cniResponse {
for _, ip := range i.IPs {
- // Note: only using To16() does not work since it also returns a vaild ip for ipv4
+ // Note: only using To16() does not work since it also returns a valid ip for ipv4
if ip.Address.IP.To4() == nil && ip.Address.IP.To16() != nil {
ipv6 = true
}
@@ -1884,7 +1884,7 @@ func (c *Container) generateResolvConf() (string, error) {
return "", err
}
- return filepath.Join(c.state.RunDir, "resolv.conf"), nil
+ return destPath, nil
}
// generateHosts creates a containers hosts file
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index d4afaa52a..11f1be7f9 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -79,7 +79,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
break
}
if cursorError != nil {
- return errors.Wrap(cursorError, "inital journal cursor")
+ return errors.Wrap(cursorError, "initial journal cursor")
}
// We need the container's events in the same journal to guarantee
diff --git a/libpod/define/container.go b/libpod/define/container.go
index f0aca92aa..bb44a6a4a 100644
--- a/libpod/define/container.go
+++ b/libpod/define/container.go
@@ -34,5 +34,5 @@ const (
AlwaysInitContainer = "always"
// OneShotInitContainer is a container that only runs as init once
// and is then deleted.
- OneShotInitContainer = "oneshot"
+ OneShotInitContainer = "once"
)
diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go
index a17304875..f91fd198d 100644
--- a/libpod/define/pod_inspect.go
+++ b/libpod/define/pod_inspect.go
@@ -105,6 +105,8 @@ type InspectPodInfraConfig struct {
CPUSetCPUs string `json:"cpuset_cpus,omitempty"`
// Pid is the PID namespace mode of the pod's infra container
PidNS string `json:"pid_ns,omitempty"`
+ // UserNS is the usernamespace that all the containers in the pod will join.
+ UserNS string `json:"userns,omitempty"`
}
// InspectPodContainerInfo contains information on a container in a pod.
diff --git a/libpod/info.go b/libpod/info.go
index cdc73780f..2b48ea590 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -141,19 +141,24 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
}
info.CGroupsVersion = cgroupVersion
- if rootless.IsRootless() {
- if path, err := exec.LookPath("slirp4netns"); err == nil {
- version, err := programVersion(path)
- if err != nil {
- logrus.Warnf("Failed to retrieve program version for %s: %v", path, err)
- }
- program := define.SlirpInfo{
- Executable: path,
- Package: packageVersion(path),
- Version: version,
- }
- info.Slirp4NetNS = program
+ slirp4netnsPath := r.config.Engine.NetworkCmdPath
+ if slirp4netnsPath == "" {
+ slirp4netnsPath, _ = exec.LookPath("slirp4netns")
+ }
+ if slirp4netnsPath != "" {
+ version, err := programVersion(slirp4netnsPath)
+ if err != nil {
+ logrus.Warnf("Failed to retrieve program version for %s: %v", slirp4netnsPath, err)
+ }
+ program := define.SlirpInfo{
+ Executable: slirp4netnsPath,
+ Package: packageVersion(slirp4netnsPath),
+ Version: version,
}
+ info.Slirp4NetNS = program
+ }
+
+ if rootless.IsRootless() {
uidmappings, err := rootless.ReadMappingsProc("/proc/self/uid_map")
if err != nil {
return nil, errors.Wrapf(err, "error reading uid mappings")
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 8e9b5997c..2ed2bb01b 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -173,11 +173,27 @@ func (r *RootlessCNI) Do(toRun func() error) error {
// the link target will be available in the mount ns.
// see: https://github.com/containers/podman/issues/10855
resolvePath := "/etc/resolv.conf"
- resolvePath, err = filepath.EvalSymlinks(resolvePath)
- if err != nil {
- return err
+ for i := 0; i < 255; i++ {
+ // Do not use filepath.EvalSymlinks, we only want the first symlink under /run.
+ // If /etc/resolv.conf has more than one symlink under /run, e.g.
+ // -> /run/systemd/resolve/stub-resolv.conf -> /run/systemd/resolve/resolv.conf
+ // we would put the netns resolv.conf file to the last path. However this will
+ // break dns because the second link does not exists in the mount ns.
+ // see https://github.com/containers/podman/issues/11222
+ link, err := os.Readlink(resolvePath)
+ if err != nil {
+ // if there is no symlink exit
+ break
+ }
+ resolvePath = filepath.Join(filepath.Dir(resolvePath), link)
+ if strings.HasPrefix(resolvePath, "/run/") {
+ break
+ }
+ if i == 254 {
+ return errors.New("too many symlinks while resolving /etc/resolv.conf")
+ }
}
- logrus.Debugf("The actual path of /etc/resolv.conf on the host is %q", resolvePath)
+ logrus.Debugf("The path of /etc/resolv.conf in the mount ns is %q", resolvePath)
// When /etc/resolv.conf on the host is a symlink to /run/systemd/resolve/stub-resolv.conf,
// we have to mount an empty filesystem on /run/systemd/resolve in the child namespace,
// so as to isolate the directory from the host mount namespace.
@@ -1219,7 +1235,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
return err
}
- // OCICNI will set the loopback adpter down on teardown so we should set it up again
+ // OCICNI will set the loopback adapter down on teardown so we should set it up again
err = c.state.NetNS.Do(func(_ ns.NetNS) error {
link, err := netlink.LinkByName("lo")
if err != nil {
@@ -1229,7 +1245,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
return err
})
if err != nil {
- logrus.Warnf("failed to set loopback adpter up in the container: %v", err)
+ logrus.Warnf("failed to set loopback adapter up in the container: %v", err)
}
// Reload ports when there are still connected networks, maybe we removed the network interface with the child ip.
// Reloading without connected networks does not make sense, so we can skip this step.
diff --git a/libpod/options.go b/libpod/options.go
index 071b085e7..b94ef88ba 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -956,8 +956,9 @@ func WithUserNSFrom(nsCtr *Container) CtrCreateOption {
}
ctr.config.UserNsCtr = nsCtr.ID()
- ctr.config.IDMappings = nsCtr.config.IDMappings
-
+ if err := JSONDeepCopy(nsCtr.IDMappings(), &ctr.config.IDMappings); err != nil {
+ return err
+ }
g := generate.Generator{Config: ctr.config.Spec}
g.ClearLinuxUIDMappings()
@@ -968,7 +969,6 @@ func WithUserNSFrom(nsCtr *Container) CtrCreateOption {
for _, gidmap := range nsCtr.config.IDMappings.GIDMap {
g.AddLinuxGIDMapping(uint32(gidmap.HostID), uint32(gidmap.ContainerID), uint32(gidmap.Size))
}
- ctr.config.IDMappings = nsCtr.config.IDMappings
return nil
}
}
@@ -2423,6 +2423,24 @@ func WithVolatile() CtrCreateOption {
}
ctr.config.Volatile = true
+
+ return nil
+ }
+}
+
+// WithPodUserns sets the userns for the infra container in a pod.
+func WithPodUserns(userns specgen.Namespace) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if !pod.config.InfraContainer.HasInfraContainer {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod userns as no infra container is being created")
+ }
+
+ pod.config.InfraContainer.Userns = userns
+
return nil
}
}
diff --git a/libpod/pod.go b/libpod/pod.go
index 0fef7f6f3..7df15df7b 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -117,6 +117,7 @@ type InfraContainerConfig struct {
Slirp4netns bool `json:"slirp4netns,omitempty"`
NetworkOptions map[string][]string `json:"network_options,omitempty"`
ResourceLimits *specs.LinuxResources `json:"resource_limits,omitempty"`
+ Userns specgen.Namespace `json:"userns,omitempty"`
}
// ID retrieves the pod's ID
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index 90d67dbb0..716eb2e5b 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -32,14 +32,14 @@ func (p *Pod) startInitContainers(ctx context.Context) error {
if rc != 0 {
return errors.Errorf("init container %s exited with code %d", initCon.ID(), rc)
}
- // If the container is an oneshot init container, we need to remove it
+ // If the container is a once init container, we need to remove it
// after it runs
if initCon.Config().InitContainerType == define.OneShotInitContainer {
icLock := initCon.lock
icLock.Lock()
if err := p.runtime.removeContainer(ctx, initCon, false, false, true); err != nil {
icLock.Unlock()
- return errors.Wrapf(err, "failed to remove oneshot init container %s", initCon.ID())
+ return errors.Wrapf(err, "failed to remove once init container %s", initCon.ID())
}
// Removing a container this way requires an explicit call to clean up the db
if err := p.runtime.state.RemoveContainerFromPod(p, initCon); err != nil {
@@ -593,6 +593,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
infraConfig.CPUQuota = p.CPUQuota()
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
infraConfig.PidNS = p.PidMode()
+ infraConfig.UserNS = p.config.InfraContainer.Userns.String()
if len(p.config.InfraContainer.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer))
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index d4f861118..49213032e 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -8,7 +8,9 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/rootless"
+ "github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -110,9 +112,7 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
options = append(options, WithNetworkOptions(p.config.InfraContainer.NetworkOptions))
}
}
- // PostConfigureNetNS should not be set since user namespace sharing is not implemented
- // and rootless networking no longer supports post configuration setup
- options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, p.config.InfraContainer.Networks))
+ options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, !p.config.InfraContainer.Userns.IsHost(), netmode, p.config.InfraContainer.Networks))
}
// For each option in InfraContainerConfig - if set, pass into
@@ -158,11 +158,39 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
g.Config.Linux.Namespaces = newNS
}
}
+
+ for _, ctl := range r.config.Containers.DefaultSysctls {
+ sysctl := strings.SplitN(ctl, "=", 2)
+ if len(sysctl) < 2 {
+ return nil, errors.Errorf("invalid default sysctl %s", ctl)
+ }
+
+ // Ignore net sysctls if --net=host
+ if p.config.InfraContainer.HostNetwork && strings.HasPrefix(sysctl[0], "net.") {
+ logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctl[0], sysctl[1])
+ continue
+ }
+
+ g.AddLinuxSysctl(sysctl[0], sysctl[1])
+ }
+
g.SetRootReadonly(true)
g.SetProcessArgs(infraCtrCommand)
logrus.Debugf("Using %q as infra container command", infraCtrCommand)
+ mapopt, err := util.ParseIDMapping(namespaces.UsernsMode(p.config.InfraContainer.Userns.String()), []string{}, []string{}, "", "")
+ if err != nil {
+ return nil, err
+ }
+ user, err := specgen.SetupUserNS(mapopt, p.config.InfraContainer.Userns, &g)
+ if err != nil {
+ return nil, err
+ }
+ if user != "" {
+ options = append(options, WithUser(user))
+ }
+
g.RemoveMount("/dev/shm")
if isRootless {
g.RemoveMount("/dev/pts")
@@ -210,14 +238,15 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName))
options = append(options, WithName(containerName))
options = append(options, withIsInfra())
+ options = append(options, WithIDMappings(*mapopt))
if len(p.config.InfraContainer.ConmonPidFile) > 0 {
options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile))
}
newRes := new(spec.LinuxResources)
newRes.CPU = new(spec.LinuxCPU)
newRes.CPU = p.ResourceLim().CPU
-
g.Config.Linux.Resources.CPU = newRes.CPU
+
return r.newContainer(ctx, g.Config, options...)
}