Home / Alt manpages / proc_pid_exe(5)

  • proc_pid_exe(5)
  • File format
  • linux

Find a Process's Real Binary with /proc/pid/exe

A process is misbehaving and the name in ps tells you nothing about which binary is actually running. /proc/<pid>/exe answers that in one command: it is a link to the exact executable the kernel loaded, and it still points there even if someone has since deleted or replaced the file on disk.

Allow about ten minutes. You need a shell and a process you are allowed to inspect. The examples follow the /proc/<pid>/exe interface documented by Linux man-pages 6.7, installed here from Debian package manpages 6.7-2.

  • Most checks are unprivileged. Ordinary commands against your own processes need no special access.
  • sudo is not the default fix. The kernel's ptrace access check can block another user's process on purpose, and that is not a bug to route around.

1. Pick a process you control

Start with a harmless process whose lifetime you control. sleep gives you a stable PID for the next checks:

$ sleep 60 &
[1] 12345
$ PID=$!
$ printf 'PID: %s\n' "$PID"
PID: 12345

The number is an example and will differ on your machine. Keep the shell variable in the same shell session. If you already have a PID from a service or incident, set PID to that number instead, but check that it still identifies the intended process before acting on it.

Checkpoint

Confirm the process exists before reading its proc entry.

$ kill -0 "$PID"
$ ps -p "$PID" -o pid=,comm=,args=
  12345 sleep           sleep 60

kill -0 sends no signal. It only asks the kernel whether the process can be found and checked. A process can exit between this check and the next command, so a missing entry is sometimes just a race, not a mistake.

Use readlink to print the link target without dereferencing it:

$ readlink "/proc/$PID/exe"
/usr/bin/sleep

That is the pathname of the executable the process actually ran, which is more useful than the command name alone. Several programs can share a name, and a process may have started from a path you no longer remember. The result is a pathname, not a command line: arguments such as 60 belong in /proc/$PID/cmdline or ps, not in exe.

Resolve through any intermediate symbolic links when you need the final filesystem object:

$ readlink -e "/proc/$PID/exe"
/usr/bin/sleep

readlink -e requires the complete resolved path to exist. For an ordinary installed binary, both commands often print the same text, but that is not a promise they fail the same way.

Inspect the proc entry as a link without opening the executable:

$ stat -c '%F %N' "/proc/$PID/exe"
symbolic link '/proc/12345/exe' -> '/usr/bin/sleep'

The proc entry is a special symbolic link. Opening it dereferences the link and opens the executable itself. That distinction matters in scripts: readlink asks for the pathname, while a program that opens the path receives the executable file.

Warning

Permissions here are enforced by a PTRACE_MODE_READ_FSCREDS check. If readlink reports permission denied for another account's process, use the appropriate account, group or operational procedure rather than weakening host security controls for convenience. A container boundary or an active security module can still block you even with elevated privileges.

4. Run a controlled copy, only when it is safe

The link can be dereferenced as a command, which starts another copy of the same executable. That changes process state by creating a child, so use a harmless command and a short explicit timeout:

$ timeout 2s "/proc/$PID/exe" 0
$ printf 'exit status: %s\n' "$?"
exit status: 0

For sleep, the argument 0 makes the copy exit immediately. A status of zero only means this copy of sleep accepted the argument and finished. It does not prove the original process is healthy, or that the two share an environment, credentials or file descriptors.

Warning

Do not substitute a server, maintenance utility or unknown program into this example without understanding its side effects. Running an executable can write files, connect to networks, change data or start more processes. A pathname under /proc does not make the program safe.

5. Recognise a deleted executable

A process can keep running after its executable has been unlinked. Reproduce the state in a temporary directory with a tiny test program:

$ work=$(mktemp -d)
$ printf '#!/bin/sh\nprintf deleted-demo-ok\nsleep 2\n' > "$work/demo"
$ chmod 755 "$work/demo"
$ "$work/demo" &
[1] 23456
$ PID=$!
$ rm -- "$work/demo"
$ readlink "/proc/$PID/exe"
/tmp/tmp.ABC123/demo (deleted)

The (deleted) suffix is part of the link text, not a status message. It tells you the original directory entry is gone, not that the running process has stopped: the kernel keeps the executable object open until the last reference goes away.

Wait for the test process and remove only the temporary directory once it has finished:

$ wait "$PID"
deleted-demo-ok
$ rmdir "$work"

Recovery

There is no recovery command for the removed test file. In a real incident, do not delete or replace a running service binary until you have preserved the package or deployment evidence you need and agreed a restart plan.

Common traps

Proc entries describe live kernel state, not a snapshot you can trust between commands. A process can exit right after ps succeeds, or its executable can be replaced while you are inspecting it. Treat errors such as No such file or directory as a reason to retry, not proof that your earlier result was wrong.

For a multithreaded process, the link can become unavailable once the main thread has terminated, commonly after pthread_exit. That is a property of process state, not evidence the executable was deleted. If the result matters, record the PID, timestamp and exact command output at the time you read it.

Done means

  • Checked a live PID and read /proc/$PID/exe with readlink.
  • Told apart the recorded pathname from its fully resolved target.
  • Understood the permission model: access is gated by a ptrace check, not by file mode alone.
  • Treated dereferencing the link as execution, with real side effects, not a safe read.
  • Recognised the (deleted) suffix and know it does not mean the process has exited.
  • Cleaned up the temporary test process and directory.