From ec969e4dcd46d83bad38f398fe784be1ff9d0095 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Tue, 3 Jun 2025 10:37:19 +0200 Subject: [PATCH 1/5] genpolicy: remove redundant group check https://github.com/kata-containers/kata-containers/pull/11077 established that the GID from the image config is never used for deriving the primary group of the container process. This commit removes the associated logic that derived a GID from a named group. Signed-off-by: Markus Rudy --- src/tools/genpolicy/src/registry.rs | 54 ++--------------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/src/tools/genpolicy/src/registry.rs b/src/tools/genpolicy/src/registry.rs index 8784a73ab8..7bea8d1f2e 100644 --- a/src/tools/genpolicy/src/registry.rs +++ b/src/tools/genpolicy/src/registry.rs @@ -104,6 +104,7 @@ struct PasswdRecord { /// A single record in a Unix group file. #[derive(Debug)] struct GroupRecord { + #[allow(dead_code)] pub name: String, #[allow(dead_code)] pub validate: bool, @@ -286,24 +287,6 @@ impl Container { } } - fn get_gid_from_group_name(&self, name: &str) -> Result { - if self.group.is_empty() { - return Err(anyhow!( - "No /etc/group file is available, unable to parse gids from group name" - )); - } - match parse_group_file(&self.group) { - Ok(records) => { - if let Some(record) = records.iter().find(|&r| r.name == name) { - Ok(record.gid) - } else { - Err(anyhow!("Failed to find name {} in /etc/group", name)) - } - } - Err(inner_e) => Err(anyhow!("Failed to parse /etc/group - error {inner_e}")), - } - } - fn parse_user_string(&self, user: &str) -> u32 { if user.is_empty() { return 0; @@ -325,34 +308,6 @@ impl Container { } } - fn parse_group_string(&self, group: &str) -> u32 { - if group.is_empty() { - return 0; - } - - match group.parse::() { - Ok(id) => { - warn!( - concat!( - "Parsed gid {} from OCI container image config, but not using it. ", - "GIDs are only picked up by the runtime from /etc/passwd." - ), - id - ); - 0 - } - // If the group is not a number, interpret it as a group name. - Err(outer_e) => { - debug!( - "Failed to parse {} as u32, using it as a group name - error {outer_e}", - group - ); - - self.get_gid_from_group_name(group).unwrap_or(0) - } - } - } - // Convert Docker image config to policy data. pub fn get_process( &self, @@ -392,22 +347,17 @@ impl Container { debug!("Parsing uid from user[0] = {}", &user[0]); process.User.UID = self.parse_user_string(user[0]); - debug!("Parsing gid from user[1] = {:?}", user[1]); - process.User.GID = self.parse_group_string(user[1]); - debug!( "Overriding OCI container GID with UID:GID mapping from /etc/passwd" ); - process.User.GID = - self.get_gid_from_passwd_uid(process.User.UID).unwrap_or(0); } } else { debug!("Parsing uid from image_user = {}", image_user); process.User.UID = self.parse_user_string(image_user); debug!("Using UID:GID mapping from /etc/passwd"); - process.User.GID = self.get_gid_from_passwd_uid(process.User.UID).unwrap_or(0); } + process.User.GID = self.get_gid_from_passwd_uid(process.User.UID).unwrap_or(0); } } From 02ad39ddf1136de96c0242bf860831f1425f7af4 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Tue, 3 Jun 2025 11:17:23 +0200 Subject: [PATCH 2/5] genpolicy: push down warning about missing passwd file The warning used to trigger even if the passwd file was not needed. This commit moves it down to where it actually matters. Signed-off-by: Markus Rudy --- src/tools/genpolicy/src/registry.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tools/genpolicy/src/registry.rs b/src/tools/genpolicy/src/registry.rs index 7bea8d1f2e..93dc5d359d 100644 --- a/src/tools/genpolicy/src/registry.rs +++ b/src/tools/genpolicy/src/registry.rs @@ -300,10 +300,16 @@ impl Container { "Failed to parse {} as u32, using it as a user name - error {outer_e}", user ); - let (uid, _) = self - .get_uid_gid_from_passwd_user(user.to_string().clone()) - .unwrap_or((0, 0)); - uid + match self.get_uid_gid_from_passwd_user(user.to_string().clone()) { + Ok((uid, _)) => uid, + Err(err) => { + warn!( + "could not resolve named user {}, defaulting to uid 0: {}", + user, err + ); + 0 + } + } } } } @@ -329,10 +335,6 @@ impl Container { * 6. Be erroneus, somehow */ if let Some(image_user) = &docker_config.User { - if self.passwd.is_empty() { - warn!("No /etc/passwd file is available, unable to parse gids from user"); - } - if !image_user.is_empty() { if image_user.contains(':') { debug!("Splitting Docker config user = {:?}", image_user); From eeb3d1384bd3ae42c28a45c998ee578e58a1c0d4 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Tue, 3 Jun 2025 17:46:40 +0200 Subject: [PATCH 3/5] genpolicy: compare additionalGIDs as sets The additional GIDs are handled by genpolicy as a BTreeSet. This set is then serialized to an ordered JSON array. On the containerd side, the GIDs are added to a list in the order they are discovered in /etc/group, and the main GID of the user is prepended to that list. This means that we don't have any guarantees that the input GIDs will be sorted. Since the order does not matter here, comparing the list of GIDs as sets is close enough. Signed-off-by: Markus Rudy --- src/tools/genpolicy/rules.rego | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/genpolicy/rules.rego b/src/tools/genpolicy/rules.rego index 6e131f34bd..92778d96b9 100644 --- a/src/tools/genpolicy/rules.rego +++ b/src/tools/genpolicy/rules.rego @@ -736,7 +736,7 @@ allow_user(p_process, i_process) { p_user.GID == i_user.GID print("allow_user: input additionalGids =", i_user.AdditionalGids, "policy additionalGids =", p_user.AdditionalGids) - p_user.AdditionalGids == i_user.AdditionalGids + {e | some e in p_user.AdditionalGids} == {e | some e in i_user.AdditionalGids} } allow_args(p_process, i_process, s_name) { From a1baaf6fe20926160e1c38ac08c2767db2388653 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Tue, 3 Jun 2025 17:54:44 +0200 Subject: [PATCH 4/5] genpolicy: ignore groups with same name as user containerd does not automatically add groups to the list of additional GIDs when the groups have the same name as the user: https://github.com/containerd/containerd/blob/f482992/pkg/oci/spec_opts.go#L852-L854 This is a bug and should be corrected, but it has been present since at least 1.6.0 and thus affects almost all containerd deployments in existence. Thus, we adopt the same behavior and ignore groups with the same name as the user when calculating additional GIDs. Signed-off-by: Markus Rudy --- src/tools/genpolicy/src/registry.rs | 4 +- src/tools/genpolicy/tests/policy/main.rs | 5 + .../testdata/createcontainer/gid/pod.yaml | 12 + .../createcontainer/gid/testcases.json | 669 ++++++++++++++++++ 4 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/pod.yaml create mode 100644 src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/testcases.json diff --git a/src/tools/genpolicy/src/registry.rs b/src/tools/genpolicy/src/registry.rs index 93dc5d359d..d2545cf8bb 100644 --- a/src/tools/genpolicy/src/registry.rs +++ b/src/tools/genpolicy/src/registry.rs @@ -271,7 +271,9 @@ impl Container { record.user_list.iter().for_each(|u| { match self.get_uid_gid_from_passwd_user(u.to_string()) { Ok((record_uid, _)) => { - if record_uid == uid { + if record_uid == uid && &record.name != u { + // The second condition works around containerd bug + // https://github.com/containerd/containerd/issues/11937. groups.push(record.gid); } }, diff --git a/src/tools/genpolicy/tests/policy/main.rs b/src/tools/genpolicy/tests/policy/main.rs index 0967bb060c..b3163ebb74 100644 --- a/src/tools/genpolicy/tests/policy/main.rs +++ b/src/tools/genpolicy/tests/policy/main.rs @@ -233,6 +233,11 @@ mod tests { runtests("createcontainer/generate_name").await; } + #[tokio::test] + async fn test_create_container_gid() { + runtests("createcontainer/gid").await; + } + #[tokio::test] async fn test_state_create_container() { runtests("state/createcontainer").await; diff --git a/src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/pod.yaml b/src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/pod.yaml new file mode 100644 index 0000000000..29c77c6b2f --- /dev/null +++ b/src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/pod.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: v1 +kind: Pod +metadata: + name: gid-experiment + labels: + app: gid-experiment +spec: + runtimeClassName: kata-cc-isolation + containers: + - name: gid + image: "ghcr.io/burgerdev/weird-images/gid:latest@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0" diff --git a/src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/testcases.json b/src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/testcases.json new file mode 100644 index 0000000000..1fe8fa72a8 --- /dev/null +++ b/src/tools/genpolicy/tests/policy/testdata/createcontainer/gid/testcases.json @@ -0,0 +1,669 @@ +[ + { + "description": "image with unusual group setup, see https://github.com/burgerdev/weird-images/tree/74b32e2/src/gid", + "allowed": true, + "request": { + "type": "CreateContainer", + "OCI": { + "Annotations": { + "io.katacontainers.pkg.oci.bundle_path": "/run/containerd/io.containerd.runtime.v2.task/k8s.io/gid", + "io.katacontainers.pkg.oci.container_type": "pod_container", + "io.kubernetes.cri.container-name": "gid", + "io.kubernetes.cri.container-type": "container", + "io.kubernetes.cri.image-name": "ghcr.io/burgerdev/weird-images/gid@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0", + "io.kubernetes.cri.sandbox-id": "8667fea11fc4fc70d427cc3645950ac83cc7d33ca515a8774ab95043f0096bb8", + "io.kubernetes.cri.sandbox-name": "gid-experiment", + "io.kubernetes.cri.sandbox-namespace": "default", + "io.kubernetes.cri.sandbox-uid": "31df313a-931f-4979-a405-cc3f3ccb6a56" + }, + "Hooks": null, + "Hostname": "", + "Linux": { + "CgroupsPath": "kubepods-burstable-pod31df313a_931f_4979_a405_cc3f3ccb6a56.slice:cri-containerd:gid", + "Devices": [], + "GIDMappings": [], + "IntelRdt": null, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "MountLabel": "", + "Namespaces": [ + { + "Path": "", + "Type": "ipc" + }, + { + "Path": "", + "Type": "uts" + }, + { + "Path": "", + "Type": "mount" + } + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ], + "Resources": { + "BlockIO": null, + "CPU": { + "Cpus": "", + "Mems": "", + "Period": 100000, + "Quota": 0, + "RealtimePeriod": 0, + "RealtimeRuntime": 0, + "Shares": 2 + }, + "Devices": [], + "HugepageLimits": [], + "Memory": { + "DisableOOMKiller": false, + "Kernel": 0, + "KernelTCP": 0, + "Limit": 0, + "Reservation": 0, + "Swap": 0, + "Swappiness": 0 + }, + "Network": null, + "Pids": null + }, + "RootfsPropagation": "", + "Seccomp": null, + "Sysctl": {}, + "UIDMappings": [] + }, + "Mounts": [ + { + "destination": "/proc", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "source": "proc", + "type_": "proc" + }, + { + "destination": "/dev", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ], + "source": "tmpfs", + "type_": "tmpfs" + }, + { + "destination": "/dev/pts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ], + "source": "devpts", + "type_": "devpts" + }, + { + "destination": "/dev/mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "source": "mqueue", + "type_": "mqueue" + }, + { + "destination": "/sys", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ], + "source": "sysfs", + "type_": "sysfs" + }, + { + "destination": "/sys/fs/cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "relatime", + "ro" + ], + "source": "cgroup", + "type_": "cgroup" + }, + { + "destination": "/etc/hosts", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-4a4c20d48254d738-hosts", + "type_": "bind" + }, + { + "destination": "/dev/termination-log", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-72cfcc0e64a0d1af-termination-log", + "type_": "bind" + }, + { + "destination": "/etc/hostname", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-89f0faae823d569c-hostname", + "type_": "bind" + }, + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-8c0d97703dbbb30e-resolv.conf", + "type_": "bind" + }, + { + "destination": "/dev/shm", + "options": [ + "rbind" + ], + "source": "/run/kata-containers/sandbox/shm", + "type_": "bind" + }, + { + "destination": "/var/run/secrets/kubernetes.io/serviceaccount", + "options": [ + "rbind", + "rprivate", + "ro" + ], + "source": "/run/kata-containers/shared/containers/gid-be44d3a46e427870-serviceaccount", + "type_": "bind" + } + ], + "Process": { + "ApparmorProfile": "cri-containerd.apparmor.d", + "Args": [ + "/entrypoint.sh" + ], + "Capabilities": { + "Ambient": [], + "Bounding": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "Effective": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "Inheritable": [], + "Permitted": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ] + }, + "ConsoleSize": null, + "Cwd": "/", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOSTNAME=gid-experiment", + "KUBERNETES_PORT_443_TCP=tcp://10.0.0.1:443", + "KUBERNETES_PORT_443_TCP_PROTO=tcp", + "KUBERNETES_PORT_443_TCP_PORT=443", + "KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1", + "KUBERNETES_SERVICE_HOST=10.0.0.1", + "KUBERNETES_SERVICE_PORT=443", + "KUBERNETES_SERVICE_PORT_HTTPS=443", + "KUBERNETES_PORT=tcp://10.0.0.1:443" + ], + "NoNewPrivileges": false, + "OOMScoreAdj": 994, + "Rlimits": [], + "SelinuxLabel": "", + "Terminal": false, + "User": { + "AdditionalGids": [ + 1 + ], + "GID": 1, + "UID": 2, + "Username": "" + } + }, + "Root": { + "Path": "/run/kata-containers/shared/containers/gid/rootfs", + "Readonly": false + }, + "Solaris": null, + "Version": "1.1.0", + "Windows": null + }, + "container_id": "gid", + "devices": [], + "exec_id": "gid", + "sandbox_pidns": false, + "shared_mounts": [], + "stderr_port": 0, + "stdin_port": 0, + "stdout_port": 0, + "storages": [ + { + "driver": "image_guest_pull", + "driver_options": [ + "image_guest_pull={\"metadata\":{\"io.katacontainers.pkg.oci.bundle_path\":\"/run/containerd/io.containerd.runtime.v2.task/k8s.io/gid\",\"io.katacontainers.pkg.oci.container_type\":\"pod_container\",\"io.kubernetes.cri.container-name\":\"gid\",\"io.kubernetes.cri.container-type\":\"container\",\"io.kubernetes.cri.image-name\":\"ghcr.io/burgerdev/weird-images/gid@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0\",\"io.kubernetes.cri.sandbox-id\":\"8667fea11fc4fc70d427cc3645950ac83cc7d33ca515a8774ab95043f0096bb8\",\"io.kubernetes.cri.sandbox-name\":\"gid-experiment\",\"io.kubernetes.cri.sandbox-namespace\":\"default\",\"io.kubernetes.cri.sandbox-uid\":\"31df313a-931f-4979-a405-cc3f3ccb6a56\"}}" + ], + "fs_group": null, + "fstype": "overlay", + "mount_point": "/run/kata-containers/gid/rootfs", + "options": [], + "source": "ghcr.io/burgerdev/weird-images/gid@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0" + } + ], + "string_user": null + } + }, + { + "description": "image with unusual group setup, but bad additional group", + "allowed": false, + "request": { + "type": "CreateContainer", + "OCI": { + "Annotations": { + "io.katacontainers.pkg.oci.bundle_path": "/run/containerd/io.containerd.runtime.v2.task/k8s.io/gid", + "io.katacontainers.pkg.oci.container_type": "pod_container", + "io.kubernetes.cri.container-name": "gid", + "io.kubernetes.cri.container-type": "container", + "io.kubernetes.cri.image-name": "ghcr.io/burgerdev/weird-images/gid@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0", + "io.kubernetes.cri.sandbox-id": "8667fea11fc4fc70d427cc3645950ac83cc7d33ca515a8774ab95043f0096bb8", + "io.kubernetes.cri.sandbox-name": "gid-experiment", + "io.kubernetes.cri.sandbox-namespace": "default", + "io.kubernetes.cri.sandbox-uid": "31df313a-931f-4979-a405-cc3f3ccb6a56" + }, + "Hooks": null, + "Hostname": "", + "Linux": { + "CgroupsPath": "kubepods-burstable-pod31df313a_931f_4979_a405_cc3f3ccb6a56.slice:cri-containerd:gid", + "Devices": [], + "GIDMappings": [], + "IntelRdt": null, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "MountLabel": "", + "Namespaces": [ + { + "Path": "", + "Type": "ipc" + }, + { + "Path": "", + "Type": "uts" + }, + { + "Path": "", + "Type": "mount" + } + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ], + "Resources": { + "BlockIO": null, + "CPU": { + "Cpus": "", + "Mems": "", + "Period": 100000, + "Quota": 0, + "RealtimePeriod": 0, + "RealtimeRuntime": 0, + "Shares": 2 + }, + "Devices": [], + "HugepageLimits": [], + "Memory": { + "DisableOOMKiller": false, + "Kernel": 0, + "KernelTCP": 0, + "Limit": 0, + "Reservation": 0, + "Swap": 0, + "Swappiness": 0 + }, + "Network": null, + "Pids": null + }, + "RootfsPropagation": "", + "Seccomp": null, + "Sysctl": {}, + "UIDMappings": [] + }, + "Mounts": [ + { + "destination": "/proc", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "source": "proc", + "type_": "proc" + }, + { + "destination": "/dev", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ], + "source": "tmpfs", + "type_": "tmpfs" + }, + { + "destination": "/dev/pts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ], + "source": "devpts", + "type_": "devpts" + }, + { + "destination": "/dev/mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ], + "source": "mqueue", + "type_": "mqueue" + }, + { + "destination": "/sys", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ], + "source": "sysfs", + "type_": "sysfs" + }, + { + "destination": "/sys/fs/cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "relatime", + "ro" + ], + "source": "cgroup", + "type_": "cgroup" + }, + { + "destination": "/etc/hosts", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-4a4c20d48254d738-hosts", + "type_": "bind" + }, + { + "destination": "/dev/termination-log", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-72cfcc0e64a0d1af-termination-log", + "type_": "bind" + }, + { + "destination": "/etc/hostname", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-89f0faae823d569c-hostname", + "type_": "bind" + }, + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rprivate", + "rw" + ], + "source": "/run/kata-containers/shared/containers/gid-8c0d97703dbbb30e-resolv.conf", + "type_": "bind" + }, + { + "destination": "/dev/shm", + "options": [ + "rbind" + ], + "source": "/run/kata-containers/sandbox/shm", + "type_": "bind" + }, + { + "destination": "/var/run/secrets/kubernetes.io/serviceaccount", + "options": [ + "rbind", + "rprivate", + "ro" + ], + "source": "/run/kata-containers/shared/containers/gid-be44d3a46e427870-serviceaccount", + "type_": "bind" + } + ], + "Process": { + "ApparmorProfile": "cri-containerd.apparmor.d", + "Args": [ + "/entrypoint.sh" + ], + "Capabilities": { + "Ambient": [], + "Bounding": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "Effective": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "Inheritable": [], + "Permitted": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ] + }, + "ConsoleSize": null, + "Cwd": "/", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOSTNAME=gid-experiment", + "KUBERNETES_PORT_443_TCP=tcp://10.0.0.1:443", + "KUBERNETES_PORT_443_TCP_PROTO=tcp", + "KUBERNETES_PORT_443_TCP_PORT=443", + "KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1", + "KUBERNETES_SERVICE_HOST=10.0.0.1", + "KUBERNETES_SERVICE_PORT=443", + "KUBERNETES_SERVICE_PORT_HTTPS=443", + "KUBERNETES_PORT=tcp://10.0.0.1:443" + ], + "NoNewPrivileges": false, + "OOMScoreAdj": 994, + "Rlimits": [], + "SelinuxLabel": "", + "Terminal": false, + "User": { + "AdditionalGids": [ + 1, + 123 + ], + "GID": 1, + "UID": 2, + "Username": "" + } + }, + "Root": { + "Path": "/run/kata-containers/shared/containers/gid/rootfs", + "Readonly": false + }, + "Solaris": null, + "Version": "1.1.0", + "Windows": null + }, + "container_id": "gid", + "devices": [], + "exec_id": "gid", + "sandbox_pidns": false, + "shared_mounts": [], + "stderr_port": 0, + "stdin_port": 0, + "stdout_port": 0, + "storages": [ + { + "driver": "image_guest_pull", + "driver_options": [ + "image_guest_pull={\"metadata\":{\"io.katacontainers.pkg.oci.bundle_path\":\"/run/containerd/io.containerd.runtime.v2.task/k8s.io/gid\",\"io.katacontainers.pkg.oci.container_type\":\"pod_container\",\"io.kubernetes.cri.container-name\":\"gid\",\"io.kubernetes.cri.container-type\":\"container\",\"io.kubernetes.cri.image-name\":\"ghcr.io/burgerdev/weird-images/gid@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0\",\"io.kubernetes.cri.sandbox-id\":\"8667fea11fc4fc70d427cc3645950ac83cc7d33ca515a8774ab95043f0096bb8\",\"io.kubernetes.cri.sandbox-name\":\"gid-experiment\",\"io.kubernetes.cri.sandbox-namespace\":\"default\",\"io.kubernetes.cri.sandbox-uid\":\"31df313a-931f-4979-a405-cc3f3ccb6a56\"}}" + ], + "fs_group": null, + "fstype": "overlay", + "mount_point": "/run/kata-containers/gid/rootfs", + "options": [], + "source": "ghcr.io/burgerdev/weird-images/gid@sha256:bdbb485bb9e3baf381a2957b9369b6051c6113097a5f8dcee27faff17624a2c0" + } + ], + "string_user": null + } + } +] From 1c240de58d13fc591b2ed4848d2beb8b934399a3 Mon Sep 17 00:00:00 2001 From: Markus Rudy Date: Wed, 4 Jun 2025 17:13:44 +0200 Subject: [PATCH 5/5] genpolicy: don't parse /etc/passwd in a loop Instead of looping over the users per group and parsing passwd for each user, we can do the reverse lookup uid->user up front and then compare the names directly. This has the nice side-effect of silencing warnings about non-existent users mentioned in /etc/group, which is not relevant for policy decisions. Signed-off-by: Markus Rudy --- src/tools/genpolicy/src/registry.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/tools/genpolicy/src/registry.rs b/src/tools/genpolicy/src/registry.rs index d2545cf8bb..bf92f33ac3 100644 --- a/src/tools/genpolicy/src/registry.rs +++ b/src/tools/genpolicy/src/registry.rs @@ -258,29 +258,34 @@ impl Container { } } + fn get_user_from_passwd_uid(&self, uid: u32) -> Result { + for record in parse_passwd_file(&self.passwd)? { + if record.uid == uid { + return Ok(record.user); + } + } + Err(anyhow!("No user found with uid {uid}")) + } + pub fn get_additional_groups_from_uid(&self, uid: u32) -> Result> { if self.group.is_empty() || self.passwd.is_empty() { return Err(anyhow!( "No /etc/group, /etc/passwd file is available, unable to parse additional group membership from uid" )); } + + let user = self.get_user_from_passwd_uid(uid)?; + match parse_group_file(&self.group) { Ok(records) => { let mut groups = Vec::new(); for record in records.iter() { record.user_list.iter().for_each(|u| { - match self.get_uid_gid_from_passwd_user(u.to_string()) { - Ok((record_uid, _)) => { - if record_uid == uid && &record.name != u { - // The second condition works around containerd bug - // https://github.com/containerd/containerd/issues/11937. - groups.push(record.gid); - } - }, - Err(inner_e) => warn!( - "/etc/group indicates a user {u} that is not in /etc/passwd - error {inner_e}" - ), - }; + if u == &user && &record.name != u { + // The second condition works around containerd bug + // https://github.com/containerd/containerd/issues/11937. + groups.push(record.gid); + } }); } Ok(groups)