Home / Alt manpages / proc_pid_ns(5)

  • proc_pid_ns(5)
  • File format
  • linux

Inspect Linux Namespace Membership Through /proc/pid/ns

You will finish with a repeatable way to see which Linux namespaces a process belongs to, compare two processes, and preserve a namespace reference for a later operation. The examples only inspect state. They do not enter a namespace or change a service.

Before you start

You need a Linux system with procfs mounted and a shell. This was checked with Linux 6.8.0-139-generic, util-linux 2.41.3, and the Debian manpages package 6.7-2. The exact namespace list can differ with the kernel version and configuration. Allow about five minutes for the inspection.

Use an ordinary account first. Reading another process's namespace links can be limited by procfs visibility and ptrace access checks. Use elevated privileges only when you have a clear reason to inspect a process that your account cannot see.

Checkpoint: identify the target process

Choose a process ID in the PID namespace visible to your shell. The shell's own process is a safe target for learning the layout:

target=$$
printf '%s\n' "$target"
ls -l "/proc/$target/ns"

The directory contains symbolic links such as mnt, net, pid, user, and uts. A current kernel may also show cgroup and time entries, plus pid_for_children and time_for_children. The manpage defines this directory as one entry for each namespace that supports manipulation through setns(2); it is not a general list of every possible isolation feature.

Expected output has the shape below. The inode numbers are examples, not stable values:

lrwxrwxrwx 1 user user 0 ... mnt -> mnt:[4026531841]
lrwxrwxrwx 1 user user 0 ... net -> net:[4026531840]
lrwxrwxrwx 1 user user 0 ... pid -> pid:[4026531836]
lrwxrwxrwx 1 user user 0 ... user -> user:[4026531837]

Read a namespace identity

Readlink prints the link target without following it as an ordinary filesystem path:

readlink "/proc/$target/ns/mnt"
readlink "/proc/$target/ns/pid"
readlink "/proc/$target/ns/pid_for_children"

Each result names a namespace type and an inode-like identifier, for example mnt:[4026531841]. A matching identifier for the same namespace type is useful evidence that two processes share that namespace. Do not compare the number from mnt with the number from net: the type is part of the identity.

pid describes the namespace containing the process. pid_for_children describes the PID namespace that subsequently created children will use, so it can differ after namespace operations. It may be empty before the first child is created. This is a common source of false conclusions when debugging containers.

Compare two processes

Compare the same namespace type for two visible processes. Replace 1234 with a real target PID:

other=1234
for kind in mnt net pid user uts; do
    printf '%-5s ' "$kind"
    readlink "/proc/$$/ns/$kind" "/proc/$other/ns/$kind"
done

Identical link targets mean the processes are in the same instance of that namespace. Different targets mean they are separate instances. A process can share some namespaces and not others, so inspect the types relevant to the problem instead of treating namespace membership as one all-or-nothing state.

For a script that needs a numeric comparison, use the device and inode returned by stat(2) rather than parsing display text:

stat -Lc '%n dev=%d inode=%i' "/proc/$$/ns/mnt" "/proc/$other/ns/mnt"

Processes in the same namespace have matching device and inode values for that namespace link. A failure such as No such file or directory usually means the target exited, the PID is not visible in this PID namespace, or the path was mistyped. Re-check the PID immediately before reading it.

Keep a namespace alive when required

Opening a namespace link gives a file descriptor referring to that namespace. Keeping the descriptor open keeps the namespace alive even if its processes exit. The shell can demonstrate the lifetime without making a persistent mount:

exec 9>"/proc/$target/ns/mnt"
readlink "/proc/$target/ns/mnt"
printf 'descriptor 9 is held open by this shell\n'
exec 9>&-

The final command closes the descriptor. Do not mistake this for entering the namespace: an open descriptor is only a handle. A program can pass such a descriptor to setns(2), but that is a security-sensitive operation with capability and namespace-specific restrictions.

Safety boundaries and recovery

Do not run setns or a namespace-entry tool against a production process merely to see what happens. Joining a mount, user, network, IPC, time, UTS, or cgroup namespace changes the calling thread's view of system resources. PID namespace reassociation is especially easy to misunderstand: it affects the namespace used for future children, not the caller's own PID namespace.

If you later use a tool such as nsenter, review its exact manpage, identify every namespace option, and run a harmless read-only command first. Prefix that command with sudo only when the target and the required capabilities justify it. There is no universal undo command for a namespace transition; exit the temporary process or shell and start a new shell in its original context.

Namespace links are also permission-checked. A readable /proc/$target directory does not guarantee that every link can be dereferenced. Treat denied access as an access boundary, not as proof that the process has no namespace.

Done means

  • You can list the namespace links for a chosen PID.
  • You can read and compare the same namespace type across two processes.
  • You know that pid and pid_for_children answer different questions.
  • You can explain that an open descriptor keeps a namespace alive but does not join it.
  • You have avoided changing a service or entering a namespace just to inspect it.