Home / Alt manpages / proc_pid_projid_map(5)

  • proc_pid_projid_map(5)
  • File format
  • linux

Inspect and Map Project IDs with /proc/pid/projid_map

Disk quotas need project IDs to survive a user-namespace boundary, and /proc/pid/projid_map is how that translation gets set up. This guide reads the mapping for a process, identifies the namespace it belongs to, and explains the checks that govern a mapping write. Project IDs are not the same thing as user IDs, group IDs or ordinary process IDs.

Allow about fifteen minutes. You need a shell and a Linux system with procfs mounted. The examples use Linux 6.8 and Linux man-pages 6.7 as installed on this machine. The file has existed since Linux 3.7, but namespace and quota configuration can change the result on another host. Reading it is unprivileged when the relevant /proc entry is readable; do not reach for sudo as a first response to a mapping error.

1. Read your own project-ID map

Start with the process running your shell. The special path /proc/self follows the process that opens it, so you are not guessing a PID:

$ cat /proc/self/projid_map
         0          0 4294967295

Each line has three decimal values: a project-ID range inside the process's user namespace, the corresponding range in its parent user namespace, and the number of consecutive IDs in the range. Here the whole 32-bit project-ID range is mapped to itself. The spacing is formatting, not data your script should parse by column position.

Checkpoint

Capture the file as data, then count fields rather than trusting the visual alignment:

awk 'NF { print "inside=" $1, "parent=" $2, "length=" $3 }' /proc/self/projid_map

A process in a newly created user namespace may show no mapping until its parent has written one. An empty file is a meaningful namespace state, not proof that procfs is broken.

2. Inspect another process without changing it

Swap a real process ID in for PID. These read-only commands need no elevated privileges:

$ PID=12345
$ test -r "/proc/$PID/projid_map" && cat "/proc/$PID/projid_map"
         0          0 4294967295

Use a process that is still running: a missing path usually means the PID exited between commands, not that the mapping file is optional for a live process. If the test fails, inspect the directory and process status without changing anything:

$ ps -p "$PID" -o pid=,user=,comm=
$ ls -l "/proc/$PID/projid_map"
ls: cannot access '/proc/12345/projid_map': Permission denied

The exact error depends on the host's procfs mount options, process ownership and security policy. Reading a different user's process may need elevated privilege, but root access still does not let you ignore the mapping rules below.

3. Interpret the namespace boundary

The file belongs to the user namespace of PID. A project-ID mapping translates IDs seen inside that namespace to IDs in its parent, which matters when a quota-aware operation needs project IDs to survive that boundary. It does not grant quota control by itself, and writing this file does not configure a filesystem quota; quota administration stays a separate task using the filesystem's own quota support.

  • Validity rule. The installed user_namespaces(7) manual says a mapping must use non-overlapping ranges that fit the relevant project-ID space. Break that rule and write(2) fails with EINVAL.
  • Column order. Keep the first two columns in the same coordinate order: inside the target namespace first, then the parent namespace.
  • Not the same as uid_map or gid_map. Those map user and group IDs. projid_map maps project IDs used by disk quotas. A line copied from a UID mapping can look syntactically right while being operationally wrong for your quota design.

4. Check who may write the map

Writing is a security-sensitive namespace operation. Stop before the write if you are not deliberately creating or configuring a user namespace. The writer must be in the target process's user namespace or its parent, and every project ID being mapped must itself have a mapping in the parent namespace; break either rule and write(2) fails with EPERM.

The target map is normally written by the parent after it creates a child in a new user namespace. A representative payload for one project ID:

$ printf '%s\n' '1000 1000 1'
1000 1000 1

That only prints the proposed line; it does not touch the kernel. Do not redirect it into an existing process's mapping file as an experiment. Mapping files are namespace setup interfaces, and a failed or incorrect write can stop the namespace setup you intended. A mapping is also not a quota grant: the filesystem quota configuration must already make sense for the mapped project ID.

5. Test namespace tooling without assuming it will work

A user-namespace helper may create the target namespace and arrange the user mappings before your command runs. Check which implementation and version you will invoke:

$ command -v unshare
/home/linuxbrew/.linuxbrew/bin/unshare
$ unshare --version
unshare from util-linux 2.41.3

Then use a harmless read-only probe that does not write projid_map:

$ unshare --user --map-root-user sh -c 'cat /proc/self/projid_map'
unshare: write failed /proc/self/uid_map: Operation not permitted

On this machine the probe is blocked while unshare tries to write uid_map. On another host it may reach the project-ID read, or fail for the same reason. User namespaces can be restricted by the kernel, container runtime or security policy: that is a host capability boundary, not evidence the project-ID file has a bad format. Do not weaken container or kernel security settings merely to run a demonstration.

If you are building a real mapping workflow, record the creator, target PID, user namespace and parent namespace together. A PID can be reused after a process exits, so a bare PID in a long-running script is not a durable identity; re-open the procfs path immediately before inspection and handle disappearance as a race.

Diagnose a failed write

  • EINVAL. Points to the payload or mapping validity: check decimal values, range length, overlap and namespace coordinate order.
  • EPERM. Points to the writer's namespace, or to a project ID that is not mapped in the parent namespace.
  • ENOENT, or a disappearing procfs path. Usually means the target process ended; create a fresh namespace and do not reuse the old PID.
  • EACCES while reading. Points to procfs visibility or access policy, not necessarily to an invalid map.

After a successful setup, read the target's mapping again and verify the exact line rather than trusting a zero exit status from a wrapper. Keep the namespace process alive while checking it: once it exits, its /proc/$PID files disappear and the mapping goes with the namespace.

Done means

  • Read your own map. You can read /proc/self/projid_map and explain all three columns.
  • Kept the ID types straight. You distinguish project IDs from user IDs, group IDs and process IDs.
  • Understood the scope. The file describes a user-namespace mapping, not a filesystem quota grant.
  • Tested safely. You print a proposed line before writing it and never write to an unrelated live process.
  • Can triage failures. You separate EINVAL, EPERM, process-race failures and read access failures.