Home / Alt manpages / proc_pid_exe(5)

  • proc_pid_exe(5)
  • File format
  • linux

Inspect a Linux Process's Executable with /proc/pid/exe

You will finish with a practical way to identify the executable behind a running Linux process, resolve its real path, spot a binary that has been deleted, and run a controlled second copy. The examples use the /proc/<pid>/exe interface documented by Linux man-pages 6.7, installed here from Debian package manpages 6.7-2.

Allow about ten minutes. You need a shell and a process you are allowed to inspect. Most checks are ordinary, unprivileged commands. Reading another user's process may be blocked by the kernel's ptrace access check, so do not treat sudo as the first or automatic fix.

1. Choose a process you own

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 that 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.

Use readlink to print the link target without dereferencing it:

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

This is the pathname of the executable the process actually ran. It is more useful than the command name alone, because several programs can have similar names and a process may have been started from a pathname you no longer remember. The result is a pathname, not a shell command line: arguments such as 60 belong in /proc/$PID/cmdline or ps, not in exe.

Resolve the path 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. That does not mean the two operations have the same failure behaviour.

You can 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.

Permissions are enforced by a PTRACE_MODE_READ_FSCREDS check. If readlink reports permission denied for a process owned by another account, use an appropriate account, group and operational procedure. Do not weaken host security controls merely to make an inspection command convenient. Elevated privileges may still be subject to other policy such as a container boundary or an active security module.

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

The link can be dereferenced as a command, which starts another copy of the same executable. This changes process state by creating a child process, so use a harmless command and an explicit short 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 means that this copy of sleep accepted the argument and completed; it does not prove that the original process is healthy or that the two processes have identical environment, credentials or file descriptors.

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 continue 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 suffix (deleted) is part of the link text. It tells you that the original directory entry is gone, not necessarily that the running process stopped. The process may still execute because the kernel retains the open executable object.

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

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

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.

6. Handle races and multithreaded processes

Proc entries describe live kernel state. A process can exit 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 the observation, not as proof that the original result was wrong.

For a multithreaded process, the link may become unavailable after the main thread has terminated, commonly after pthread_exit. That is a property of the process state, not evidence that the executable was deleted. Record the PID, timestamp and exact command output when the result matters.

Done means

  • You checked a live PID and read /proc/$PID/exe with readlink.
  • You know the difference between the recorded pathname and its fully resolved target.
  • You understand that access is subject to a ptrace permission check.
  • You treated dereferencing the link as executing a real program with real side effects.
  • You can recognise the (deleted) suffix and distinguish it from a process that has exited.
  • Your temporary test process and directory have been cleaned up.