Skip to content

nsenter failed when only map self gid with newgidmap #3553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
eZioPan opened this issue May 4, 2025 · 2 comments
Open

nsenter failed when only map self gid with newgidmap #3553

eZioPan opened this issue May 4, 2025 · 2 comments

Comments

@eZioPan
Copy link

eZioPan commented May 4, 2025

Let's assume user_a has GID 1000, and an entry in /etc/subgid user_a:10000:100.

When user run following commands:

unshare --user -- catatonit -P &
newuidmap <PID> 0 1000 1
newgidmap <PID> 0 1000 1
nsenter --target <PID> --user

nsenter will return nsenter: setgroups failed: Operation not permitted, since /proc/<PID>/setgroups has been set to deny.

But if user add an extra gid map, then nsenter works:

unshare --user -- catatonit -P &
newuidmap <PID> 0 1000 1
# add a range within /etc/subgid
newgidmap <PID> 0 1000 1 1 10000 10
nsenter --target <PID> --user

Since now newgidmap set /proc/<PID>/setgroups to allow.

This will block user namespace with only 1 self gid map, and will need to add at least an extra gidmap entry to work.

related issue: shadow-maint/shadow#1256

@eZioPan eZioPan changed the title nsenter failed when only map own gid with newgidmap nsenter failed when only map self gid with newgidmap May 4, 2025
@karelzak
Copy link
Collaborator

karelzak commented May 5, 2025

From unshare man page:

since Linux 3.19 a further restriction applies: the kernel gives permission to call
setgroups(2) only after the GID map (/proc/pid*/gid_map*) has been set. The GID map is
writable by root when setgroups(2) is enabled (i.e., allow, the default), and the GID map
becomes writable by unprivileged processes when setgroups(2) is permanently disabled
(with deny).

This means that "deny" in setgroups is required by the kernel for unprivileged users to write to gid_map.

See also man user_namespaces to get more details.

Note that unshare can also init the maps for your:

$ unshare --user --map-root-user -- cat /proc/self/{uid_map,gid_map,setgroups}
         0       1000          1
         0       1000          1
deny

 $ unshare --user --map-current-user -- cat /proc/self/{uid_map,gid_map,setgroups}
      1000       1000          1
      1000       1000          1
deny

$ unshare --user --map-auto -- cat /proc/self/{uid_map,gid_map,setgroups}
         0     100000      65536
         0     100000      65536
allow
'''

@eZioPan
Copy link
Author

eZioPan commented May 5, 2025

This means that "deny" in setgroups is required by the kernel for unprivileged users to write to gid_map.

Yes, I know unprivileged users need to write "deny" to /proc/<PID>/setgroups to write /proc/<PID>/gid_map. But nsenter use setgroups() to drop extra gid before and/or after enter the user namespace. I mean, we could make a exception that, if there is only one gid map, and outer gid is user's gid itself, then we don't use setgroups() to drop extra gid (there is no need to do that), thus nsenter don't need SetGID permission, such that it is not related whether /proc/<PID>/setgroups is "deny" or "allow".

Note that unshare can also init the maps for your:

For the unshare part, unshare use newgidmap as external helper program, since most system will set CAP_SETGID on it, so that newgidmap can change /proc/<PID>/setgroups back to allow after change /proc/<PID>/gid_map. But I think there might missing one logic in source code of newgidmap that it forget to set setgroups back to allow, when there is only one and user self gid map exist. (As the related issue I point to shadow repo)

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

No branches or pull requests

2 participants