Home / Alt manpages / proc_pid_gid_map(5)

  • proc_pid_gid_map(5)
  • File format
  • linux

Read and Check Linux User Namespace Group Mappings

You will finish with a reliable way to read /proc/PID/gid_map, interpret each mapping line, and recognise why a new user namespace may need a group mapping before a program can use group credentials. The examples use Linux man-pages 6.7, installed here as package version 6.7-2.

Allow about fifteen minutes. You need a shell with /proc mounted and the util-linux unshare command for the optional namespace test. Reading an existing map is ordinary, unprivileged work. Creating a namespace or writing a map changes process state, so test only with a short-lived child and do not experiment inside a service.

1. Inspect the map for your current shell

Replace PID with a process ID when you are investigating another process. For the current shell, $$ is the shell's own PID:

$ cat /proc/$$/gid_map
         0          0 4294967295

The three columns are, in order, the first group ID in the process's user namespace, the first group ID in the parent or viewing namespace, and the length of the contiguous range. This line therefore maps almost the complete 32-bit group-ID space starting at zero. The value 4294967295 is deliberately left out because the unsigned 32-bit value is also the representation of (gid_t)-1, used by several interfaces to mean "no group ID".

Checkpoint: record the exact PID and map before drawing conclusions. A process can be in a different user namespace from your shell, and the values shown can depend on the namespace of the process that opened the file.

2. Check both UID and GID maps together

gid_map is the group-ID counterpart of uid_map. A paired check often explains a failure more quickly than looking at one file in isolation:

$ printf 'uid_map: '; cat /proc/$$/uid_map
uid_map:          0          0 4294967295
$ printf 'gid_map: '; cat /proc/$$/gid_map
gid_map:          0          0 4294967295

Do not treat the labels above as part of the proc file output. They are printed by printf; the file itself contains whitespace-separated numbers and newline-terminated mapping records.

System calls such as getgid(2) return a group ID as mapped into the caller's user namespace. File ownership checks work in the opposite direction: the process's credentials are mapped towards the initial user namespace when the kernel checks a file. A group ID that looks like 0 inside a namespace is therefore not automatically the host's group ID 0.

3. Create a disposable namespace only if the host permits it

The following command asks unshare to create a user namespace and run a shell in it. It makes no persistent configuration change, but the kernel or container policy may forbid unprivileged user namespaces. It is an ordinary command, so start without sudo:

$ unshare --user --map-root-user sh -c 'cat /proc/self/uid_map; cat /proc/self/gid_map; id'
         0       1004          1
         0       1004          1
uid=0(root) gid=0(root) groups=0(root)

The displayed host ID is an example. On a machine that permits the operation, --map-root-user arranges a one-line identity mapping for the invoking user, and the child sees that mapped identity as ID 0. The exact whitespace and account names can differ.

If you get Operation not permitted, stop there. It commonly means that user namespaces are disabled or restricted by the host, container runtime or security policy. It is not evidence that /proc/PID/gid_map is malformed. Do not work around the restriction with elevated privileges unless you administer the host and have a specific reason.

Checkpoint: if the child starts, save its PID from inside the child when you need to inspect it from another shell. Otherwise inspect its maps before the command exits, as the process and its proc entries disappear when it finishes.

4. Understand what a writable map permits

A newly created user namespace starts with no UID or GID mapping. The map for one process in that namespace can be written once to define it. A successful map has at least one line, positive range lengths, non-overlapping ranges, and a write smaller than the system page size performed at the start of the file. Linux 4.15 and later permit up to 340 lines; Linux 4.14 and earlier used a five-line limit.

Writing gid_map is security-sensitive. The writer needs the relevant CAP_SETGID capability and must be in the child user namespace or its parent. The target group IDs must themselves be mapped in the parent. If the writer lacks the parent capability, the permitted fallback is one line mapping the writer's effective group ID, and setgroups(2) must first be disabled by writing deny to /proc/PID/setgroups.

That deny write is permanent for the user namespace. Treat it as an intentional security boundary, not as a routine troubleshooting command. There is no undo operation for it, and the child namespace must be recreated if the choice was wrong.

Since Linux 5.12, mappings that map parent UID 0 have an additional CAP_SETFCAP requirement. This is a UID rule, but it matters when you configure both maps for a container-like workload.

5. Diagnose the usual read and write failures

  • An empty map means that the namespace has not received a mapping yet. Calls that change group IDs will fail until a valid GID map exists.
  • EPERM usually means the writer is in the wrong namespace, lacks the required capability, or is attempting a second write. Check the process namespace and credentials before changing the map.
  • EINVAL points to invalid map data: a non-positive length, overlapping ranges, no newline-terminated record, too many bytes, or a write that did not start at offset zero.
  • A permission error while opening another process's map can be caused by proc ownership and dumpability, especially after an effective-ID change. Inspect the target process and its namespace rather than guessing a different mapping.

For a read-only comparison, check the namespace identity as well as the map:

$ readlink /proc/$$/ns/user
user:[4026531837]
$ cat /proc/$$/gid_map
         0          0 4294967295

The namespace inode is host-specific. Compare it with readlink /proc/PID/ns/user for the process you are investigating; equal values indicate membership in the same user namespace.

Done means

  • You can read the three fields in /proc/PID/gid_map in the correct order.
  • You checked uid_map alongside gid_map when investigating credentials.
  • You know whether this host permits an unprivileged disposable user namespace.
  • You can distinguish an empty map, invalid data and insufficient mapping permissions.
  • You have not changed a persistent file, service or existing namespace, and you understand that setgroups denial cannot be undone inside a namespace.