From e15141a1fd920da2eb02e9f5f634dcd43592dc8c Mon Sep 17 00:00:00 2001 From: Chris Henzie Date: Tue, 10 Mar 2026 17:14:44 -0700 Subject: [PATCH] Move cgroup namespace placement higher in spec builder Moves cgroup namespace addition logic higher in buildLinuxSpec so it runs before any custom spec adjusters (such as WithMounts). This is necessary because subsequent spec adjusters may want to inspect the set of namespaces to make decisions (e.g., configuring mount options based on whether or not they are shared with the host). Signed-off-by: Chris Henzie --- internal/cri/server/container_create.go | 16 +++---- .../cri/server/container_create_linux_test.go | 46 +++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/internal/cri/server/container_create.go b/internal/cri/server/container_create.go index 7ddb1b3937..43e612a073 100644 --- a/internal/cri/server/container_create.go +++ b/internal/cri/server/container_create.go @@ -792,6 +792,14 @@ func (c *criService) buildLinuxSpec( } }() + // cgroupns is used for hiding /sys/fs/cgroup from containers. + // For compatibility, cgroupns is not used when running in cgroup v1 mode or in privileged. + // https://github.com/containers/libpod/issues/4363 + // https://github.com/kubernetes/enhancements/blob/0e409b47497e398b369c281074485c8de129694f/keps/sig-node/20191118-cgroups-v2.md#cgroup-namespace + if isUnifiedCgroupsMode() && !securityContext.GetPrivileged() { + specOpts = append(specOpts, oci.WithLinuxNamespace(runtimespec.LinuxNamespace{Type: runtimespec.CgroupNamespace})) + } + var ociSpecOpts oci.SpecOpts if ociRuntime.CgroupWritable { ociSpecOpts = customopts.WithMountsCgroupWritable(c.os, config, extraMounts, mountLabel, runtimeHandler) @@ -930,14 +938,6 @@ func (c *criService) buildLinuxSpec( annotations.DefaultCRIAnnotations(sandboxID, containerName, imageName, sandboxConfig, false)..., ) - // cgroupns is used for hiding /sys/fs/cgroup from containers. - // For compatibility, cgroupns is not used when running in cgroup v1 mode or in privileged. - // https://github.com/containers/libpod/issues/4363 - // https://github.com/kubernetes/enhancements/blob/0e409b47497e398b369c281074485c8de129694f/keps/sig-node/20191118-cgroups-v2.md#cgroup-namespace - if isUnifiedCgroupsMode() && !securityContext.GetPrivileged() { - specOpts = append(specOpts, oci.WithLinuxNamespace(runtimespec.LinuxNamespace{Type: runtimespec.CgroupNamespace})) - } - return specOpts, nil } diff --git a/internal/cri/server/container_create_linux_test.go b/internal/cri/server/container_create_linux_test.go index 0242c0e83d..a37a849aa3 100644 --- a/internal/cri/server/container_create_linux_test.go +++ b/internal/cri/server/container_create_linux_test.go @@ -487,6 +487,52 @@ func TestPrivilegedBindMount(t *testing.T) { } } +func TestCgroupNamespace(t *testing.T) { + testPid := uint32(1234) + c := newTestCRIService() + testSandboxID := "sandbox-id" + testContainerName := "container-name" + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + + tests := []struct { + desc string + privileged bool + expectCgroupNamespace bool + }{ + { + desc: "non-privileged container should get cgroup namespace", + privileged: false, + expectCgroupNamespace: true, + }, + { + desc: "privileged container should not get cgroup namespace", + privileged: true, + expectCgroupNamespace: false, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + containerConfig.Linux.SecurityContext.Privileged = tt.privileged + sandboxConfig.Linux.SecurityContext.Privileged = tt.privileged + + spec, err := c.buildContainerSpec(currentPlatform, t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime, nil) + assert.NoError(t, err) + + hasCgroupNS := false + for _, ns := range spec.Linux.Namespaces { + if ns.Type == runtimespec.CgroupNamespace { + hasCgroupNS = true + break + } + } + + assert.Equal(t, tt.expectCgroupNamespace, hasCgroupNS) + }) + } +} + func TestMountPropagation(t *testing.T) { sharedLookupMountFn := func(string) (mount.Info, error) {