Warn when device group is not mapped in rootless user namespaces - #29208
Warn when device group is not mapped in rootless user namespaces#29208bhartigautam156 wants to merge 3 commits into
Conversation
Signed-off-by: bhartigautam156 <bharti.gautam@suse.com>
Signed-off-by: bhartigautam156 <bharti.gautam@suse.com>
Signed-off-by: bhartigautam156 <bharti.gautam@suse.com>
Luap99
left a comment
There was a problem hiding this comment.
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
| // Save device GIDs from --device flags BEFORE re-exec. | ||
| // After re-exec device GIDs may be unmapped (appear as 65534). | ||
| SaveDeviceGIDsFromArgs(stateDir) | ||
|
|
There was a problem hiding this comment.
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.
|
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. $ 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 |
|
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 |
|
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. |
Fixes: #28364
Problem
When running a rootless container with
--device/dev/XXXwith--userns=keep-id--group-add keep-groups, devices that belong to groups not mapped in the user namespace silently appear asnobody:nobodyinside 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:
Output:
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/subgidget 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/subgidwithout root privileges. Automatically editing system files like/etc/subgidwas 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:
--deviceThis 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:
/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: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:inputbut after the required/etc/subgidmapping is added, the same device inside the container may appear as:nobody:binor, when viewed with numeric IDs65534:1This is expected.
nobody/ UID65534) is the kernel's overflow UID because the device owner's UID (root) is not mapped into the rootless user namespace.bin/ GID1) is not the host's group name. It is simply the container's name for container GID1. In this case, container GID1is correctly mapped to the host'sinputgroup (GID994) 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--deviceto 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 forisGIDInSubgid()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/inputand 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./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:
commits. (
git commit -s). (If needed, usegit commit -s --amend). The author email must matchthe sign-off email address. See CONTRIBUTING.md
for more information.
Fixes: #00000in commit message (if applicable)make validatepr(format/lint checks)Noneif no user-facing changes)Does this PR introduce a user-facing change?