Skip to content

[Linux] Managed cgroup v2 memory limit traversal can escape the hierarchy mount root #133470

Closed

Description

@cuishuang

Description

The managed cgroup v2 memory limit traversal in src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs can walk above the cgroup hierarchy mount root.

FindCGroupPath can legitimately return the hierarchy mount itself when the current process is assigned to the visible cgroup hierarchy root. For example:

hierarchyRoot = /some/container
hierarchyMount = /sys/fs/cgroup
cgroupPathRelativeToMount = /some/container

This produces:

/sys/fs/cgroup

TryGetMemoryLimitV2 currently uses a do/while loop that moves to the parent directory before checking whether the mount root has been reached. When the current path is already equal to the mount path, the traversal therefore continues above the cgroup hierarchy and can eventually dereference a null path.

The CoreCLR C++ implementation already protects this boundary (PR #130377), but the managed Common implementation does not.

Reproduction Steps

  1. Run on Linux with cgroup v2 enabled.
  2. Place the current process at the cgroup hierarchy mount root.
  3. Call Interop.cgroups.TryGetMemoryLimit.
  4. Observe that the managed traversal attempts to walk above the mount root and can fail while resolving the parent path.

Expected behavior

When the current cgroup path equals the hierarchy mount path, traversal should stop at that path and must not inspect any parent directory.

Actual behavior

The loop executes its body and calls Path.GetDirectoryName even when the current path is already the hierarchy mount root. The traversal can continue through parent directories and eventually reach a null path.

Regression?

The issue appears to be a latent edge case in the managed cgroup v2 implementation. The corresponding CoreCLR native implementation was already fixed in #130377.

Known Workarounds

No reliable application-level workaround. The fallback to procfs is not reached if the traversal throws before returning from TryGetMemoryLimit.

Configuration

  • OS: Linux
  • cgroup version: v2
  • Affected code: managed Common cgroup interop
  • Relevant environments: containers and cgroup namespaces whose visible root is the current process cgroup

Other information

The proposed fix changes the loop so that it only reads and moves upward while the current path is below the hierarchy mount root. It also adds tests for the equality case and for nested paths that must stop at the mount root.

Activity

  1. dotnet-policy-service commented on Sep 9, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/area-system-io
    See info in area-owners.md if you want to be subscribed.

  2. added
    os-linuxLinux OS (any supported distro)
    and removed
    untriagedNew issue has not been triaged by the area owner
    on Sep 9, 2026
  3. added this to the 12.0.0 milestone on Sep 9, 2026
  4. janvorli commented on Sep 9, 2026

    @janvorli
    Member

    @jeffhandley I think we might want to fix it in .NET 11 so that we don't have different handling in native and managed parts of the runtime. I've fixed this problem in native in #130377 and haven't realized we have this managed implementation with the same problem. @cuishuang has already created a PR for a fix.

  5. adamsitnik commented on Sep 9, 2026

    @adamsitnik
    Member

    @jeffhandley I think we might want to fix it in .NET 11 so that we don't have different handling in native and managed parts of the runtime. I've fixed this problem in native in #130377 and haven't realized we have this managed implementation with the same problem. @cuishuang has already created a PR for a fix.

    Jeff is (or at least should be) offline this week. It sounds very reasonable @janvorli ! I am going to set the 11 milestone

  6. modified the milestones: 12.0.0, 11.0.0 on Sep 9, 2026
  7. added a commit that references this issue on Sep 11, 2026
  8. locked and limited conversation to collaborators on Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions