summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/source/markdown/podman-container-inspect.1.md2
-rw-r--r--docs/source/markdown/podman-create.1.md14
-rw-r--r--docs/source/markdown/podman-run.1.md4
-rw-r--r--libpod/container.go7
-rw-r--r--libpod/container_config.go4
-rw-r--r--libpod/container_inspect.go27
-rw-r--r--libpod/container_internal.go38
-rw-r--r--libpod/container_internal_linux.go6
-rw-r--r--libpod/options.go24
-rw-r--r--libpod/runtime_ctr.go4
-rw-r--r--pkg/specgen/generate/container.go7
-rw-r--r--pkg/specgen/generate/namespaces.go11
-rw-r--r--pkg/specgen/generate/security.go2
-rw-r--r--pkg/specgenutil/specgen.go2
-rw-r--r--test/system/190-run-ipcns.bats70
15 files changed, 177 insertions, 45 deletions
diff --git a/docs/source/markdown/podman-container-inspect.1.md b/docs/source/markdown/podman-container-inspect.1.md
index 9945fca7c..4e45bcc40 100644
--- a/docs/source/markdown/podman-container-inspect.1.md
+++ b/docs/source/markdown/podman-container-inspect.1.md
@@ -219,7 +219,7 @@ $ podman container inspect foobar
"DnsSearch": [],
"ExtraHosts": [],
"GroupAdd": [],
- "IpcMode": "private",
+ "IpcMode": "shareable",
"Cgroup": "",
"Cgroups": "default",
"Links": null,
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index c4d27e321..4f0a3993b 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -504,10 +504,16 @@ To specify multiple static IPv6 addresses per container, set multiple networks u
#### **--ipc**=*ipc*
-Default is to create a private IPC namespace (POSIX SysV IPC) for the container
- `container:<name|id>`: reuses another container shared memory, semaphores and message queues
- `host`: use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.
- `ns:<path>` path to an IPC namespace to join.
+Set the IPC namespace mode for a container. The default is to create
+a private IPC namespace.
+
+- "": Use Podman's default, defined in containers.conf.
+- **container:**_id_: reuses another container's shared memory, semaphores, and message queues
+- **host**: use the host's shared memory, semaphores, and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.
+- **none**: private IPC namespace, with /dev/shm not mounted.
+- **ns:**_path_: path to an IPC namespace to join.
+- **private**: private IPC namespace.
+= **shareable**: private IPC namespace with a possibility to share it with other containers.
#### **--label**, **-l**=*label*
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index e4ccd0368..d88eb20a4 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -528,9 +528,13 @@ To specify multiple static IPv6 addresses per container, set multiple networks u
Set the IPC namespace mode for a container. The default is to create
a private IPC namespace.
+- "": Use Podman's default, defined in containers.conf.
- **container:**_id_: reuses another container shared memory, semaphores and message queues
- **host**: use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.
+- **none**: private IPC namespace, with /dev/shm not mounted.
- **ns:**_path_: path to an IPC namespace to join.
+- **private**: private IPC namespace.
+= **shareable**: private IPC namespace with a possibility to share it with other containers.
#### **--label**, **-l**=*key*=*value*
diff --git a/libpod/container.go b/libpod/container.go
index 578f16905..bc3cab439 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -291,6 +291,13 @@ func (c *Container) Config() *ContainerConfig {
return returnConfig
}
+// ConfigNoCopy returns the configuration used by the container.
+// Note that the returned value is not a copy and must hence
+// only be used in a reading fashion.
+func (c *Container) ConfigNoCopy() *ContainerConfig {
+ return c.config
+}
+
// DeviceHostSrc returns the user supplied device to be passed down in the pod
func (c *Container) DeviceHostSrc() []spec.LinuxDevice {
return c.config.DeviceHostSrc
diff --git a/libpod/container_config.go b/libpod/container_config.go
index ea644764c..c08cd7604 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -120,6 +120,10 @@ type ContainerRootFSConfig struct {
// with the size specified in ShmSize and populate this with the path of
// said tmpfs.
ShmDir string `json:"ShmDir,omitempty"`
+ // NoShmShare indicates whether /dev/shm can be shared with other containers
+ NoShmShare bool `json:"NOShmShare,omitempty"`
+ // NoShm indicates whether a tmpfs should be created and mounted on /dev/shm
+ NoShm bool `json:"NoShm,omitempty"`
// ShmSize is the size of the container's SHM. Only used if ShmDir was
// not set manually at time of creation.
ShmSize int64 `json:"shmSize"`
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index c9d0b8a6c..14290ca0d 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -703,32 +703,31 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
}
hostConfig.CapAdd = capAdd
hostConfig.CapDrop = capDrop
-
- // IPC Namespace mode
- ipcMode := ""
- if c.config.IPCNsCtr != "" {
- ipcMode = fmt.Sprintf("container:%s", c.config.IPCNsCtr)
- } else if ctrSpec.Linux != nil {
+ switch {
+ case c.config.IPCNsCtr != "":
+ hostConfig.IpcMode = fmt.Sprintf("container:%s", c.config.IPCNsCtr)
+ case ctrSpec.Linux != nil:
// Locate the spec's IPC namespace.
// If there is none, it's ipc=host.
// If there is one and it has a path, it's "ns:".
// If no path, it's default - the empty string.
-
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == spec.IPCNamespace {
if ns.Path != "" {
- ipcMode = fmt.Sprintf("ns:%s", ns.Path)
+ hostConfig.IpcMode = fmt.Sprintf("ns:%s", ns.Path)
} else {
- ipcMode = "private"
+ break
}
- break
}
}
- if ipcMode == "" {
- ipcMode = "host"
- }
+ case c.config.NoShm:
+ hostConfig.IpcMode = "none"
+ case c.config.NoShmShare:
+ hostConfig.IpcMode = "private"
+ }
+ if hostConfig.IpcMode == "" {
+ hostConfig.IpcMode = "shareable"
}
- hostConfig.IpcMode = ipcMode
// Cgroup namespace mode
cgroupMode := ""
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index f1f467879..c7567a55e 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1507,26 +1507,28 @@ func (c *Container) mountStorage() (_ string, deferredErr error) {
return c.state.Mountpoint, nil
}
- mounted, err := mount.Mounted(c.config.ShmDir)
- if err != nil {
- return "", errors.Wrapf(err, "unable to determine if %q is mounted", c.config.ShmDir)
- }
-
- if !mounted && !MountExists(c.config.Spec.Mounts, "/dev/shm") {
- shmOptions := fmt.Sprintf("mode=1777,size=%d", c.config.ShmSize)
- if err := c.mountSHM(shmOptions); err != nil {
- return "", err
- }
- if err := os.Chown(c.config.ShmDir, c.RootUID(), c.RootGID()); err != nil {
- return "", errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
+ if !c.config.NoShm {
+ mounted, err := mount.Mounted(c.config.ShmDir)
+ if err != nil {
+ return "", errors.Wrapf(err, "unable to determine if %q is mounted", c.config.ShmDir)
}
- defer func() {
- if deferredErr != nil {
- if err := c.unmountSHM(c.config.ShmDir); err != nil {
- logrus.Errorf("Unmounting SHM for container %s after mount error: %v", c.ID(), err)
- }
+
+ if !mounted && !MountExists(c.config.Spec.Mounts, "/dev/shm") {
+ shmOptions := fmt.Sprintf("mode=1777,size=%d", c.config.ShmSize)
+ if err := c.mountSHM(shmOptions); err != nil {
+ return "", err
}
- }()
+ if err := os.Chown(c.config.ShmDir, c.RootUID(), c.RootGID()); err != nil {
+ return "", errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
+ }
+ defer func() {
+ if deferredErr != nil {
+ if err := c.unmountSHM(c.config.ShmDir); err != nil {
+ logrus.Errorf("Unmounting SHM for container %s after mount error: %v", c.ID(), err)
+ }
+ }
+ }()
+ }
}
// We need to mount the container before volumes - to ensure the copyup
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 11ca169ca..98ba3404f 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1963,8 +1963,10 @@ func (c *Container) makeBindMounts() error {
}
}
- // SHM is always added when we mount the container
- c.state.BindMounts["/dev/shm"] = c.config.ShmDir
+ if c.config.ShmDir != "" {
+ // If ShmDir has a value SHM is always added when we mount the container
+ c.state.BindMounts["/dev/shm"] = c.config.ShmDir
+ }
if c.config.Passwd == nil || *c.config.Passwd {
newPasswd, newGroup, err := c.generatePasswdAndGroup()
diff --git a/libpod/options.go b/libpod/options.go
index 2e5454393..34c06cc5d 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -559,6 +559,30 @@ func WithShmDir(dir string) CtrCreateOption {
}
}
+// WithNOShmMount tells libpod whether to mount /dev/shm
+func WithNoShm(mount bool) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ ctr.config.NoShm = mount
+ return nil
+ }
+}
+
+// WithNoShmShare tells libpod whether to share containers /dev/shm with other containers
+func WithNoShmShare(share bool) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ ctr.config.NoShmShare = share
+ return nil
+ }
+}
+
// WithSystemd turns on systemd mode in the container
func WithSystemd() CtrCreateOption {
return func(ctr *Container) error {
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index f92898b1c..7edd49fd1 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -174,6 +174,8 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
return nil, errors.Wrapf(err, "converting containers.conf ShmSize %s to an int", r.config.Containers.ShmSize)
}
ctr.config.ShmSize = size
+ ctr.config.NoShm = false
+ ctr.config.NoShmShare = false
ctr.config.StopSignal = 15
ctr.config.StopTimeout = r.config.Engine.StopTimeout
@@ -514,7 +516,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
}
}
- if !MountExists(ctr.config.Spec.Mounts, "/dev/shm") && ctr.config.ShmDir == "" {
+ if !MountExists(ctr.config.Spec.Mounts, "/dev/shm") && ctr.config.ShmDir == "" && !ctr.config.NoShm {
ctr.config.ShmDir = filepath.Join(ctr.bundlePath(), "shm")
if err := os.MkdirAll(ctr.config.ShmDir, 0700); err != nil {
if !os.IsExist(err) {
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index b38b0e695..f7ea2edfa 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -428,9 +428,12 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s
case "cgroup":
specg.CgroupNS = specgen.Namespace{NSMode: specgen.Default} //default
case "ipc":
- if conf.ShmDir == "/dev/shm" {
+ switch conf.ShmDir {
+ case "/dev/shm":
specg.IpcNS = specgen.Namespace{NSMode: specgen.Host}
- } else {
+ case "":
+ specg.IpcNS = specgen.Namespace{NSMode: specgen.None}
+ default:
specg.IpcNS = specgen.Namespace{NSMode: specgen.Default} //default
}
case "uts":
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 9ce45aaf0..05c2d1741 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -134,8 +134,17 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if err != nil {
return nil, errors.Wrapf(err, "error looking up container to share ipc namespace with")
}
+ if ipcCtr.ConfigNoCopy().NoShmShare {
+ return nil, errors.Errorf("joining IPC of container %s is not allowed: non-shareable IPC (hint: use IpcMode:shareable for the donor container)", ipcCtr.ID())
+ }
toReturn = append(toReturn, libpod.WithIPCNSFrom(ipcCtr))
- toReturn = append(toReturn, libpod.WithShmDir(ipcCtr.ShmDir()))
+ if !ipcCtr.ConfigNoCopy().NoShm {
+ toReturn = append(toReturn, libpod.WithShmDir(ipcCtr.ShmDir()))
+ }
+ case specgen.None:
+ toReturn = append(toReturn, libpod.WithNoShm(true))
+ case specgen.Private:
+ toReturn = append(toReturn, libpod.WithNoShmShare(true))
}
// UTS
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index 988c29832..ec52164ab 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -222,7 +222,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
for sysctlKey, sysctlVal := range defaultSysctls {
// Ignore mqueue sysctls if --ipc=host
if noUseIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
- logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to host", sysctlKey, sysctlVal)
+ logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to %q", sysctlKey, sysctlVal, s.IpcNS.NSMode)
continue
}
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 7d4fca846..17c88f609 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -190,7 +190,7 @@ func setNamespaces(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions)
}
}
if c.IPC != "" {
- s.IpcNS, err = specgen.ParseNamespace(c.IPC)
+ s.IpcNS, err = specgen.ParseIPCNamespace(c.IPC)
if err != nil {
return err
}
diff --git a/test/system/190-run-ipcns.bats b/test/system/190-run-ipcns.bats
new file mode 100644
index 000000000..9327d8ec7
--- /dev/null
+++ b/test/system/190-run-ipcns.bats
@@ -0,0 +1,70 @@
+#!/usr/bin/env bats -*- bats -*-
+# shellcheck disable=SC2096
+#
+# Tests for podman build
+#
+
+load helpers
+
+@test "podman --ipc=host" {
+ run readlink /proc/self/ns/ipc
+ hostipc=$output
+ run_podman run --rm --ipc=host $IMAGE readlink /proc/self/ns/ipc
+ is "$output" "$hostipc" "HostIPC and container IPC should be same"
+}
+
+@test "podman --ipc=none" {
+ run readlink /proc/self/ns/ipc
+ hostipc=$output
+ run_podman run --rm --ipc=none $IMAGE readlink /proc/self/ns/ipc
+ if [[ $output == "$hostipc" ]]; then
+ die "hostipc and containeripc should be different"
+ fi
+ run_podman 1 run --rm --ipc=none $IMAGE ls /dev/shm
+ is "$output" "ls: /dev/shm: No such file or directory" "Should fail with missing /dev/shm"
+}
+
+@test "podman --ipc=private" {
+ run readlink /proc/self/ns/ipc
+ hostipc=$output
+ run_podman run -d --ipc=private --name test $IMAGE sleep 100
+ if [[ $output == "$hostipc" ]]; then
+ die "hostipc and containeripc should be different"
+ fi
+ run_podman 125 run --ipc=container:test --rm $IMAGE readlink /proc/self/ns/ipc
+ is "$output" ".*is not allowed: non-shareable IPC (hint: use IpcMode:shareable for the donor container)" "Containers should not share private ipc namespace"
+ run_podman stop -t 0 test
+ run_podman rm test
+}
+
+@test "podman --ipc=shareable" {
+ run readlink /proc/self/ns/ipc
+ hostipc=$output
+ run_podman run -d --ipc=shareable --name test $IMAGE sleep 100
+ if [[ $output == "$hostipc" ]]; then
+ die "hostipc and containeripc should be different"
+ fi
+ run_podman run --ipc=container:test --rm $IMAGE readlink /proc/self/ns/ipc
+ if [[ $output == "$hostipc" ]]; then
+ die "hostipc and containeripc should be different"
+ fi
+ run_podman stop -t 0 test
+ run_podman rm test
+}
+
+@test "podman --ipc=container@test" {
+ run readlink /proc/self/ns/ipc
+ hostipc=$output
+ run_podman run -d --name test $IMAGE sleep 100
+ run_podman exec test readlink /proc/self/ns/ipc
+ if [[ $output == "$hostipc" ]]; then
+ die "hostipc and containeripc should be different"
+ fi
+ testipc=$output
+ run_podman run --ipc=container:test --rm $IMAGE readlink /proc/self/ns/ipc
+ is "$output" "$testipc" "Containers should share ipc namespace"
+ run_podman stop -t 0 test
+ run_podman rm test
+}
+
+# vim: filetype=sh