Merge pull request #9536 from jmguzik/enable-cgroupsv2-sec-opts

Enable cgroupsv2 rw mount via security-opt unmask
This commit is contained in:
OpenShift Merge Robot 2021-03-03 12:28:54 -05:00 committed by GitHub
commit 87e20560ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 3 deletions

View File

@ -859,7 +859,7 @@ Security Options
- `unmask=ALL or /path/1:/path/2` : Paths to unmask separated by a colon. If set to **ALL**, it will - `unmask=ALL or /path/1:/path/2` : Paths to unmask separated by a colon. If set to **ALL**, it will
unmask all the paths that are masked or made read only by default. unmask all the paths that are masked or made read only by default.
The default masked paths are **/proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug, /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware, and /sys/fs/selinux.** The default paths that are read only are **/proc/asound, /proc/bus, /proc/fs, /proc/irq, /proc/sys, /proc/sysrq-trigger**. The default masked paths are **/proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug, /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware, and /sys/fs/selinux.** The default paths that are read only are **/proc/asound, /proc/bus, /proc/fs, /proc/irq, /proc/sys, /proc/sysrq-trigger, /sys/fs/cgroup**.
- `proc-opts=OPTIONS` : Comma separated list of options to use for the /proc mount. More details for the - `proc-opts=OPTIONS` : Comma separated list of options to use for the /proc mount. More details for the
possible mount options are specified at **proc(5)** man page. possible mount options are specified at **proc(5)** man page.

View File

@ -908,7 +908,7 @@ Security Options
for the possible mount options are specified at **proc(5)** man page. for the possible mount options are specified at **proc(5)** man page.
- **unmask**=_ALL_ or _/path/1:/path/2_: Paths to unmask separated by a colon. If set to **ALL**, it will - **unmask**=_ALL_ or _/path/1:/path/2_: Paths to unmask separated by a colon. If set to **ALL**, it will
unmask all the paths that are masked or made read only by default. unmask all the paths that are masked or made read only by default.
The default masked paths are **/proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug, /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware, and /sys/fs/selinux.**. The default paths that are read only are **/proc/asound**, **/proc/bus**, **/proc/fs**, **/proc/irq**, **/proc/sys**, **/proc/sysrq-trigger**. The default masked paths are **/proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug, /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware, and /sys/fs/selinux.**. The default paths that are read only are **/proc/asound**, **/proc/bus**, **/proc/fs**, **/proc/irq**, **/proc/sys**, **/proc/sysrq-trigger**, **/sys/fs/cgroup**.
Note: Labeling can be disabled for all containers by setting **label=false** in the **containers.conf**(5) file. Note: Labeling can be disabled for all containers by setting **label=false** in the **containers.conf**(5) file.

View File

@ -2,12 +2,14 @@ package generate
import ( import (
"context" "context"
"path"
"strings" "strings"
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/image" "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go" spec "github.com/opencontainers/runtime-spec/specs-go"
@ -157,8 +159,32 @@ func canMountSys(isRootless, isNewUserns bool, s *specgen.SpecGenerator) bool {
return true return true
} }
func getCGroupPermissons(unmask []string) string {
ro := "ro"
rw := "rw"
cgroup := "/sys/fs/cgroup"
cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
if !cgroupv2 {
return ro
}
if unmask != nil && unmask[0] == "ALL" {
return rw
}
for _, p := range unmask {
if path.Clean(p) == cgroup {
return rw
}
}
return ro
}
// SpecGenToOCI returns the base configuration for the container.
func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *image.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string) (*spec.Spec, error) { func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *image.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string) (*spec.Spec, error) {
cgroupPerm := "ro" cgroupPerm := getCGroupPermissons(s.Unmask)
g, err := generate.New("linux") g, err := generate.New("linux")
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -304,6 +304,42 @@ var _ = Describe("Podman run", func() {
}) })
It("podman run security-opt unmask on /sys/fs/cgroup", func() {
SkipIfCgroupV1("podman umask on /sys/fs/cgroup will fail with cgroups V1")
SkipIfRootless("/sys/fs/cgroup rw access is needed")
rwOnCGroups := "/sys/fs/cgroup cgroup2 rw"
session := podmanTest.Podman([]string{"run", "--security-opt", "unmask=ALL", "--security-opt", "mask=/sys/fs/cgroup", ALPINE, "cat", "/proc/mounts"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(rwOnCGroups))
session = podmanTest.Podman([]string{"run", "--security-opt", "unmask=/sys/fs/cgroup", ALPINE, "cat", "/proc/mounts"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(rwOnCGroups))
session = podmanTest.Podman([]string{"run", "--security-opt", "unmask=/sys/fs/cgroup///", ALPINE, "cat", "/proc/mounts"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(rwOnCGroups))
session = podmanTest.Podman([]string{"run", "--security-opt", "unmask=ALL", ALPINE, "cat", "/proc/mounts"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(rwOnCGroups))
session = podmanTest.Podman([]string{"run", "--security-opt", "unmask=/sys/fs/cgroup", "--security-opt", "mask=/sys/fs/cgroup", ALPINE, "cat", "/proc/mounts"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(rwOnCGroups))
session = podmanTest.Podman([]string{"run", "--security-opt", "unmask=/sys/fs/cgroup", ALPINE, "ls", "/sys/fs/cgroup"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).ToNot(BeEmpty())
})
It("podman run seccomp test", func() { It("podman run seccomp test", func() {
session := podmanTest.Podman([]string{"run", "-it", "--security-opt", strings.Join([]string{"seccomp=", forbidGetCWDSeccompProfile()}, ""), ALPINE, "pwd"}) session := podmanTest.Podman([]string{"run", "-it", "--security-opt", strings.Join([]string{"seccomp=", forbidGetCWDSeccompProfile()}, ""), ALPINE, "pwd"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()