Skip to content

Detect Docker containers in nested cgroup hierarchies (rootless Docker) - #959

Open
MsfPablo wants to merge 2 commits into
dalance:masterfrom
MsfPablo:docker-rootless-cgroup
Open

Detect Docker containers in nested cgroup hierarchies (rootless Docker)#959
MsfPablo wants to merge 2 commits into
dalance:masterfrom
MsfPablo:docker-rootless-cgroup

Conversation

@MsfPablo

Copy link
Copy Markdown

Problem

The Docker column identifies a process's container by matching its cgroup path with two hard-coded prefixes:

if cgroup_name.starts_with("/docker") { ... }
else if cgroup_name.starts_with("/system.slice/docker-") { ... }

This assumes the container's cgroup sits at a fixed place in the hierarchy. That holds for cgroup v1 (/docker/<id>) and for rootful, systemd-managed Docker on cgroup v2 (/system.slice/docker-<id>.scope), but rootless Docker nests the container scope under the invoking user's slice:

/user.slice/user-1000.slice/user@1000.service/user.slice/docker-<64-hex-id>.scope

Neither branch matches, so the Docker column is silently empty for rootless Docker users even though the container ID is right there in the path.

Fix

Search for a container cgroup component at any depth rather than requiring a specific prefix:

  • docker-<id>.scope as a whole path component (rootful and rootless cgroup v2, and any other nesting)
  • docker followed by <id> (cgroup v1, including nested variants)

To avoid becoming too permissive, the ID must be a complete component of exactly 64 hex digits — which is the form Docker container IDs take, and the form of the keys in the container-ID→name map this value is looked up in. So docker.service, docker-desktop.scope, and prefix-docker-<id>.scope are not matched.

The extraction is pulled out into a standalone container_id_from_cgroup function so it can be unit-tested directly. Behaviour for rootful Docker is unchanged.

Tests

Five unit tests added in src/columns/docker.rs covering cgroup v1, cgroup v2 rootful (existing behaviour), cgroup v2 rootless (the fix), a set of non-container cgroup paths, and a guard that the ID must be a whole path component.

Verification

Because the affected code is #[cfg(any(target_os = "linux", target_os = "android"))], it was checked against the Linux target from a macOS host:

$ cargo fmt --check                                                        # clean
$ cargo clippy --target x86_64-unknown-linux-gnu --all-targets -- -D warnings
error: you seem to want to iterate on a map's values --> src/main.rs:191:24

That one lint is pre-existing — it reproduces identically on an unmodified checkout (verified via git stash), and this change introduces no new clippy findings.

The new tests were executed by temporarily relaxing the cfg gate so the parsing function (pure string logic, platform-independent) builds on the host:

running 5 tests
.....
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 12 filtered out

I do not have a Linux machine with rootless Docker to hand, so the end-to-end behaviour is verified by the unit tests against the documented cgroup path shape rather than against a live rootless daemon. Happy to adjust if the maintainers' rootless setups produce a different path.


Disclosure: this change was written with AI assistance (Claude). It has been reviewed by me before submission.

Pablo Garcia and others added 2 commits August 16, 2026 15:47
The Docker column matched cgroup paths by prefix, requiring the
container's cgroup to sit directly under /system.slice (rootful Docker)
or /docker (cgroup v1). Rootless Docker nests the container scope under
the invoking user's slice, e.g.

  /user.slice/user-1000.slice/user@1000.service/user.slice/docker-<id>.scope

which matched neither branch, so the column was silently empty.

Match a `docker-<id>.scope` or `docker/<id>` path component at any
depth instead, requiring the ID to be a full 64-hex-digit component so
unrelated units such as docker.service are not picked up.
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.

1 participant