Home / Alt manpages / proc_pid_setgroups(5)

  • proc_pid_setgroups(5)
  • File format
  • linux

Control setgroups safely while creating a user namespace

You will learn when to read or write /proc/pid/setgroups while setting up a Linux user namespace, and how to verify the result before writing a group ID map. Allow about 15 minutes for a read-only check, or longer if you are building a namespace setup around it. The key result is simple: allow and deny describe whether processes in the target user namespace may use setgroups(2), and writing deny is a one-way security decision for that namespace.

1. Check the local kernel and file

The installed proc_pid_setgroups(5) page comes from Linux man-pages 6.7, package version 6.7-2. It documents the file as available since Linux 3.19. This machine is running Linux 6.8.0-139-generic. The file is part of the user namespace interface, so its useful meaning depends on the namespace containing the process you inspect.

Start with your own process. This does not change state and normally needs no elevated privileges:

$ printf 'pid=%s\n' "$$"
pid=24831
$ cat /proc/$$/setgroups
allow

The PID is different on every shell. The initial user namespace normally reports allow. If the file is missing, stop and check that you are on Linux and that the process is visible through the /proc mount you are using. Do not create a replacement file: this is a kernel interface, not ordinary configuration stored on disk.

2. Understand which process the path names

In /proc/pid/setgroups, pid is a process ID, not a user namespace ID. The value describes the user namespace that contains that process. Reading /proc/$$/setgroups therefore checks your shell's namespace; reading a child PID checks the child's namespace, subject to the normal permissions and visibility rules of /proc.

Use these commands to compare the setting with the UID and GID maps without modifying either map:

$ pid=$$
$ printf 'setgroups: '
$ cat "/proc/$pid/setgroups"
setgroups: allow
$ printf 'uid map:\n'
$ cat "/proc/$pid/uid_map"
         0          0 4294967295
$ printf 'gid map:\n'
$ cat "/proc/$pid/gid_map"
         0          0 4294967295

The three-column identity maps above are the dummy maps exposed for the initial user namespace. A newly created user namespace starts without a usable UID or GID mapping. Do not treat the initial namespace output as proof that a newly created namespace is ready for group changes.

3. Know when setgroups is actually permitted

The setting is only one part of the decision. If the target user namespace's /proc/pid/gid_map has not been written, setgroups(2) is not permitted regardless of whether setgroups says allow. Once a valid GID map exists, allow permits the relevant processes to use the system call, subject to their capabilities and the other kernel rules.

This distinction explains a common diagnostic trap: seeing allow does not mean that a process can immediately change supplementary groups. Check both files when diagnosing a namespace setup:

$ pid=$$
$ cat "/proc/$pid/setgroups"
allow
$ cat "/proc/$pid/gid_map"
         0          0 4294967295

For a process in a new namespace, an empty or unwritten group map means group ID operations are still blocked. The exact map content is deployment-specific. Never copy a map from an unrelated process merely because its format looks right.

4. Decide whether the namespace must retain setgroups

Write deny only when the namespace must not change supplementary groups. The kernel allows a privileged process with CAP_SYS_ADMIN in the relevant namespace to write allow or deny before the namespace's GID map is written. In common unprivileged namespace setup, denying first is the step that permits a restricted single-line GID mapping without requiring CAP_SETGID in the parent user namespace.

Many namespace helpers make this choice for you. On this machine, util-linux 2.41.3 documents that unshare --map-root-user, --map-current-user and --map-group imply --setgroups=deny. Read the helper's manual before combining options; do not add a second mechanism just because the resulting file is hard to explain.

Security checkpoint

Writing deny permanently disables setgroups(2) in that user namespace. The kernel also propagates the restriction to child user namespaces. Do not use it in a namespace that must later support group changes, and do not test it against a long-running service unless you have a rollback plan. There is no undo command: attempting to write allow after the restriction has taken effect fails.

5. Apply deny before the GID map, when required

The order matters. For a new user namespace, the intended sequence is to create the namespace, write deny to its setgroups file, and then write a valid GID map. The process doing the write needs the permissions required by the user namespace rules. A typical privileged setup uses an explicit target PID and checks every write:

# Replace TARGET_PID with the child in the new user namespace.
# This is a security-sensitive, one-way change.
$ sudo sh -c 'printf deny > /proc/TARGET_PID/setgroups'
$ sudo cat /proc/TARGET_PID/setgroups
deny
$ sudo cat /proc/TARGET_PID/gid_map
# Continue with the mapping tool only after checking the intended map.

Do not paste the command with the literal placeholder. Resolve the child PID first, confirm that it belongs to the namespace you intend to configure, and record the current setting. If the target has already had gid_map written, writing deny is too late and fails with EPERM.

For an unprivileged workflow, use the namespace tool's documented mapping options rather than hand-writing a privileged shell command. For example, inspect the command before running it:

$ unshare --help | grep -E -- '--map-root-user|--setgroups'
$ unshare --map-root-user sh -c 'cat /proc/self/setgroups; cat /proc/self/uid_map; cat /proc/self/gid_map'
deny
         0       1000          1
         0       1000          1

This example creates a short-lived namespace and exits when the shell exits. The UID, GID and exact result depend on the invoking account and host policy. If unprivileged user namespaces are disabled, the command can fail before the file is created; that is a host policy result, not a reason to edit /proc manually.

6. Diagnose failures without guessing

A failed write commonly means the operation is out of order, the target PID is wrong, the writer lacks the required capability, or the namespace policy forbids the transition. Capture the error and inspect the state again:

$ printf allow | sudo tee /proc/TARGET_PID/setgroups
tee: /proc/TARGET_PID/setgroups: Operation not permitted
$ sudo cat /proc/TARGET_PID/setgroups
deny

That failure is expected after a successful deny decision. It is not repaired by repeating the write, restarting the shell or using a different spelling. If gid_map is already set, the ordering rule also prevents changing the setting to deny. Check the target's namespace identity, map contents and process lifetime before changing the setup.

Keep the original namespace helper command and mapping configuration under review. A namespace can disappear when its last process exits, but that does not make an already-running service's security decision reversible. For a service, stop it through its normal supervisor, restore the previous namespace configuration, and start it only after verifying the replacement in a maintenance window.

Done means

  • You read the target process's setgroups value and identified its user namespace.
  • You checked gid_map separately and understand that allow alone does not enable group changes.
  • You chose deny only when permanent setgroups disablement is intended.
  • You applied the decision before writing gid_map, when the namespace setup required it.
  • You verified the final value and retained a recovery plan for any service or sandbox that depends on the namespace.