Skip to content

Fix: Skip legacy v1 controller lines when parsing cgroup v2 path#651

Merged
jnovy merged 1 commit intocontainers:mainfrom
jnovy:fix/cgroup-v2-mixed-hierarchy-parsing
Mar 31, 2026
Merged

Fix: Skip legacy v1 controller lines when parsing cgroup v2 path#651
jnovy merged 1 commit intocontainers:mainfrom
jnovy:fix/cgroup-v2-mixed-hierarchy-parsing

Conversation

@jnovy
Copy link
Copy Markdown
Collaborator

@jnovy jnovy commented Mar 31, 2026

Description

Fixes #650

On systems with mixed cgroup hierarchies (cgroup v2 as primary but with legacy v1 controllers also mounted, e.g. net_cls mounted by PIA VPN), /proc/<pid>/cgroup contains entries like:

1:net_cls:/
0::/user.slice/user-1000.slice/user@1000.service/user.slice/podman-conmon-abc123.scope

When process_cgroup_subsystem_path() was called with cgroup2=true, it iterated through lines looking for a match but did not verify that the line actually belonged to the cgroup v2 unified hierarchy (0::). It would match the first line (1:net_cls:/), extract / as the cgroup path, and construct /sys/fs/cgroup/ as the base path for looking up memory.events.

This caused:

  • Continuous warning spam: Failed to open cgroup memory.events file
  • OOM monitoring silently broken — conmon could never detect OOM kills
  • Affected any system where a v1 controller was mounted alongside the v2 unified hierarchy

Root Cause

In src/cgroup.c, the cgroup2 code path in process_cgroup_subsystem_path() did not validate that the parsed line had hierarchy ID 0 and an empty controller field, which are the defining characteristics of a cgroup v2 unified hierarchy entry per proc(5).

Fix

Added a check to skip lines that don't match the cgroup v2 format (0::<path>). Specifically, lines with a non-zero hierarchy ID or a non-empty controller field are now skipped with continue, ensuring only the actual v2 unified hierarchy entry is used.

Testing

Impact

Minimal — only affects the cgroup v2 parsing path. The v1 path is completely unchanged. The fix adds a strict check that aligns with the kernel's documented format for /proc/<pid>/cgroup.

@jnovy jnovy requested a review from giuseppe March 31, 2026 08:37
src/cgroup.c Outdated
* with mixed cgroup mounts.
*/
if (line[0] != '0' || line[1] != ':' || *ptr != '\0') {
*path = ':'; /* restore the delimiter for next iteration */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how will it be reused?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — it won't be. The getline() on the next loop iteration completely overwrites the buffer, so restoring the delimiter was unnecessary (and actually buggy: after path++, *path points to the cgroup path's first character, not the original : delimiter).

Removed the line and simplified the if-block to a single-statement continue. Force-pushed.

When a system has cgroup v2 as the primary hierarchy but also has
legacy v1 controllers mounted (e.g. net_cls mounted by VPN software),
/proc/<pid>/cgroup may contain mixed entries like:

  1:net_cls:/
  0::/user.slice/user-1000.slice/...

The process_cgroup_subsystem_path() function, when called with
cgroup2=true, previously returned the path from the very first line
it encountered. On mixed systems, this would be the v1 controller
line (e.g. '1:net_cls:/'), causing conmon to extract '/' as the
cgroup path. This resulted in looking for memory.events at
/sys/fs/cgroup/memory.events (the root cgroup), which doesn't exist,
causing continuous warning spam in the journal.

Fix this by checking that the line matches the cgroup v2 unified
hierarchy format '0::' before returning the path. Lines with non-zero
hierarchy IDs or non-empty controller fields are now correctly skipped.

Fixes: containers#650

Signed-off-by: Jindrich Novy <jnovy@redhat.com>
@jnovy jnovy force-pushed the fix/cgroup-v2-mixed-hierarchy-parsing branch from 54023c3 to 3bf4bd9 Compare March 31, 2026 10:52
Copy link
Copy Markdown
Member

@giuseppe giuseppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jnovy jnovy merged commit cee92c3 into containers:main Mar 31, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect parsing of /proc/$pid/cgroup when mixed cgroups are present

2 participants