Skip to content

Warn when device group is not mapped in rootless user namespaces - #29208

Draft
bhartigautam156 wants to merge 3 commits into
podman-container-tools:mainfrom
bhartigautam156:fix/podman_container_ownership
Draft

Warn when device group is not mapped in rootless user namespaces#29208
bhartigautam156 wants to merge 3 commits into
podman-container-tools:mainfrom
bhartigautam156:fix/podman_container_ownership

Conversation

@bhartigautam156

Copy link
Copy Markdown

Fixes: #28364

Problem

When running a rootless container with --device /dev/XXX with --userns=keep-id --group-add keep-groups , devices that belong to groups not mapped in the user namespace silently appear as nobody:nobody inside the container and are completely inaccessible. There is no error message, no warning and the container just starts and the device doesn't work.
For example:

podman run -i --rm --userns=keep-id --group-add keep-groups --device /dev/input/ alpine ls -l /dev/input/event0

Output:

crw-rw----  1 nobody  nobody  ...  event0

The root cause is that the device's group GID is not listed in /etc/subgid. When the rootless user namespace is created, only GIDs in /etc/subgid get mapped so anything else shows up as nobody.

I tried fixing this automatically using idmapped mounts and injecting GIDs directly into the namespace, but both approaches hit kernel-level limitations as you can't map a GID that isn't already in /etc/subgid without root privileges. Automatically editing system files like /etc/subgid was also ruled out because that's an admin decision, not something Podman should do silently.

Solution

Since I can't fix the mapping automatically, I made the failure visible and actionable.Before Podman enters the user namespace, it saves two things to a temporary file:

  • The host supplementary groups of the current user
  • The real host GIDs of any devices passed via --device

This is necessary because once inside the user namespace, GIDs get remapped and we lose track of what the original host GIDs were.Then when the device is being set up for the container, it check:

  1. What is the real host GID of this device?
  2. Is the current user a member of that group on the host?
  3. Is that GID listed in /etc/subgid?

Based on this, one of two warnings are showed: If the user is not even a member of the device group:
lets say a group input and the device GID is 994

Device event0 is owned by group 'input' (GID 994).
You are not a member of this group on the host.
Access will be denied inside the container.
To fix run:
sudo usermod -aG input ubuntu
Then log out and log back in.

If the user is a member but the GID is not in /etc/subgid:

Device event0 is owned by group 'input' (GID 994).
You are a member of this group on the host, but GID 994 is not in /etc/subgid.
The device will appear as 'nobody:nobody' inside the container and access will be denied.
To fix this, run:
echo "ubuntu:994:1" | sudo tee -a /etc/subgid && podman system migrate

After the user runs the suggested fix and tries again, the device works correctly and no warning is shown.

A note on how devices appear inside the container

The ownership shown inside the container can be a little misleading. For example, on the host a device may be owned by:
root:input but after the required /etc/subgid mapping is added, the same device inside the container may appear as:
nobody:bin or, when viewed with numeric IDs 65534:1
This is expected.

  • The owner (nobody / UID 65534) is the kernel's overflow UID because the device owner's UID (root) is not mapped into the rootless user namespace.
  • The group (bin / GID 1) is not the host's group name. It is simply the container's name for container GID 1. In this case, container GID 1 is correctly mapped to the host's input group (GID 994) through /etc/subgid.

In other words, the displayed group name inside the container is independent of the host's group name. As long as the numeric GID is mapped correctly, the device permissions work as expected. This PR only detects missing mappings and provides actionable warnings; it does not attempt to preserve host group names inside the container.

Files changed

pkg/rootless/rootless_linux.go : Before entering the user namespace, saves the user's host groups and the GIDs of all devices passed via --device to temporary files. This is the only place where the real host GIDs are available.
pkg/specgen/generate/config_linux.go : When adding a device to the container spec, checks whether the device's GID is accessible and emits the appropriate warning if not.

Tests added

pkg/specgen/generate/config_linux_test.go: Unit tests for isGIDInSubgid() covering: GID inside range, GID outside range, boundary values (first and last GID in range), GID explicitly added as a single entry, empty subgid file, and wrong username.
test/e2e/run_device_test.go : This runs a rootless container with /dev/input and verifies that a warning is emitted mentioning either missing subgid mapping or missing group membership. The test is skipped automatically if not running in rootless mode or if /dev/input` is not available on the host.

  • The e2e test depends on /dev/input/ being present on the host. If there is a better way to test this in CI, I am open to suggestions.

Checklist

Ensure you have completed the following checklist for your pull request to be reviewed:

  • Certify you wrote the patch or otherwise have the right to pass it on as an open-source patch by signing all
    commits. (git commit -s). (If needed, use git commit -s --amend). The author email must match
    the sign-off email address. See CONTRIBUTING.md
    for more information.
  • Referenced issues using Fixes: #00000 in commit message (if applicable)
  • Tests have been added/updated (or no tests are needed)
  • Documentation has been updated (or no documentation changes are needed)
  • All commits pass make validatepr (format/lint checks)
  • Release note entered in the section below (or None if no user-facing changes)

Does this PR introduce a user-facing change?

Added a warning when rootless containers cannot access devices due to missing GID mappings in `/etc/subgid`, with exact commands to fix the issue.

Signed-off-by: bhartigautam156 <bharti.gautam@suse.com>
Signed-off-by: bhartigautam156 <bharti.gautam@suse.com>
Signed-off-by: bhartigautam156 <bharti.gautam@suse.com>
@bhartigautam156 bhartigautam156 changed the title Fix/podman container ownership Warn when device group is not mapped in rootless user namespaces Jul 16, 2026

@Luap99 Luap99 left a comment

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.

That is a lot of code for a very niche use case that is ultimately not going to fix anything either other than a warning. It adds unnecessary state for users who do not need it and ultimately the state is possible incorrect either with the fork exec model. We create the userns once, when you capture the groups there and then store them that means the groups can be out of date later when podman is executed from a different context.

I am also not a fan of suggesting to add the group to subgid,the additional mappings which are then different from subuid will get a whole lot more complex.It will also map the group the same random gid at the end of the range so that alone does not grant the container access either.

Aside from the fact that this does not work properly as written.

The simplest solution to keep your group is --group-add keep-groups with crun (works as long as your container does not call setgroups, i.e. when switching uses in the container). That allows access even when it shows up as nobody.

And please note https://github.com/podman-container-tools/podman/blob/main/LLM_POLICY.md

Comment on lines +369 to +372
// Save device GIDs from --device flags BEFORE re-exec.
// After re-exec device GIDs may be unmapped (appear as 65534).
SaveDeviceGIDsFromArgs(stateDir)

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.

that it wrong and will not work, parsing os.Args is incorrect and most commands will never get here as we use the c shortcut code after the first podman command all the time, so you can do this exactly once for the first podman command after boot which is not helpful at all.

@bhartigautam156

Copy link
Copy Markdown
Author

I agree that suggesting edits to /etc/subgid is not a good approach. But I want to clarify that this was not my first choice either as I have also mentioned in the PR description, I had earlier a different approach idmapped mounts and injecting GIDs directly into the namespace. But both hit kernel-level limitations that cannot be worked around without root privileges, which is why I fell back to the this approach.
Also regarding --group-add keep-groups , I tested this again based on your comment with this time setgroups is not called , but still the device is still inaccessible:

$ podman run -i --rm --userns=keep-id --group-add keep-groups \
  --network=host \
  --device /dev/input/event0 alpine cat /dev/input/event0
cat: can't open '/dev/input/event0': Permission denied
$ strace -e trace=setgroups -f podman run -i --rm --userns=keep-id \
  --group-add keep-groups --network=host \
  --device /dev/input/event0 alpine cat /dev/input/event0 2>&1 | grep setgroups
(no output)

I am open to suggestions on a better approach as this one is not acceptable

@Luap99

Luap99 commented Jul 17, 2026

Copy link
Copy Markdown
Member

did you use crun? keep-groups atm only works with crun as other runtimes do not have this implemented

@bhartigautam156

Copy link
Copy Markdown
Author

did you use crun? keep-groups atm only works with crun as other runtimes do not have this implemented

Yes , I have used crun

$ podman info | grep -i crun
    name: crun
    package: crun_1.21-1ubuntu3_amd64
    path: /usr/bin/crun
      crun version 1.21
      rundir: /run/user/1000/crun

@bhartigautam156

Copy link
Copy Markdown
Author

Hi @Luap99, any update on this? I tested keep-groups with crun and setgroups is never called but the device is still inaccessible. Happy to rework the approach entirely if you can point me in the right direction.

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.

--device does not preserve group ownership in rootless --userns=keep-id

2 participants