From Executable to Process
One program, several different things
Section titled “One program, several different things”People use the word program for source code, an executable file, and a running process. Conversation usually survives this. Investigation does better when we are precise.
- Source code describes behavior in a language such as C.
- An executable file stores information and machine code in a format Linux knows how to load.
- A process is one running instance with an identity, memory, execution state, and operating-system resources.
The executable is a file. It can sit on disk for years without doing anything. A process exists only while that program is running.
This distinction matters because a vulnerability may belong to instructions stored in an executable, but the evidence of its behavior appears in a process: memory changes, a crash, a file operation, or an unexpected system call.
Knowledge check
Question 1 of 2
Knowledge check complete
You answered all 2 questions correctly.
Inspect an executable before running it
Section titled “Inspect an executable before running it”We will use sleep, a small utility that waits for a specified amount of time. Find the executable selected by your shell:
command -v sleepOn Ubuntu, the result will normally be /usr/bin/sleep. command -v asks the shell which command it would run for that name. This is better evidence than assuming every Linux installation stores a tool in the same place.
Store the result in a shell variable so later commands use the exact path you found:
sleep_path="$(command -v sleep)"printf '%s\n' "$sleep_path"Inspect the file:
file "$sleep_path"stat "$sleep_path"file should identify an ELF executable or shared object for your machine’s architecture. stat reports filesystem evidence such as size, ownership, permissions, and timestamps. At this point we have inspected a file; no sleep process was required.
Ask the shell to start it
Section titled “Ask the shell to start it”Run sleep for two minutes and place it in the background:
sleep 120 &The ampersand tells the shell not to wait for this command to finish before returning the prompt. The shell will print a job number and a process ID, commonly shortened to PID.
The shell also stores the PID of the most recently started background process in $!. Save it immediately:
sleep_pid=$!printf 'PID: %s\n' "$sleep_pid"A variable beginning with $ is expanded by the shell before the command runs. Quoting "$sleep_pid" preserves it as one argument and is a good habit even though a PID contains no spaces.
Inspect the process:
ps -p "$sleep_pid" -o pid,ppid,stat,comm,argsThe headings mean:
| Field | What it tells us |
|---|---|
PID |
The identity Linux assigned this process |
PPID |
The process ID of its parent, normally your shell here |
STAT |
A compact description of its current process state |
COMMAND or COMM |
The short command name |
COMMAND or ARGS |
The command and arguments used to start it |
Your PID and parent PID will differ from anyone else’s. That difference is expected evidence, not a failure to match the screenshot that does not exist.
What happened between the command and the process?
Section titled “What happened between the command and the process?”The complete startup path contains details we will uncover throughout the module. A useful first model is:
- The shell interpreted the command line and found the
sleepexecutable. - The shell asked the Linux kernel to create and start a process.
- Linux inspected the executable format.
- The loader mapped the required code and data into the new process’s virtual address space.
- Linux prepared the arguments and initial execution state.
- The processor began executing at the program’s designated entry point.
“Linux ran the file” is convenient shorthand, but it hides every interesting question. Which parts were mapped? Where did execution begin? How did the argument 120 reach the program? Those questions are the rest of this module.
Connect the process back to the file
Section titled “Connect the process back to the file”Linux exposes information about running processes through /proc. Each process receives a directory named with its PID.
List the process directory:
ls -ld "/proc/$sleep_pid"Now inspect the exe entry:
ls -l "/proc/$sleep_pid/exe"readlink "/proc/$sleep_pid/exe"exe is a symbolic link associated with the executable loaded for that process. readlink prints its target. The result should lead back to the same executable identified by command -v sleep, although one path may use a symbolic link or equivalent canonical location.
This gives us an evidence chain:
command name → executable path → PID → /proc/PID/exe → executable pathOne executable, two processes
Section titled “One executable, two processes”Start a second instance:
sleep 120 &second_pid=$!printf 'First PID: %s\nSecond PID: %s\n' "$sleep_pid" "$second_pid"Inspect them together:
ps -p "$sleep_pid,$second_pid" -o pid,ppid,stat,comm,argsBoth processes came from the same executable and received the same argument. They still have different PIDs. Each process also has its own /proc directory and runtime state.
Use readlink on both:
readlink "/proc/$sleep_pid/exe"readlink "/proc/$second_pid/exe"The targets should agree even though the PIDs do not. This is the difference between shared origin and separate running instances.
Knowledge check
Question 1 of 2
Knowledge check complete
You answered all 2 questions correctly.
Clean up the experiment
Section titled “Clean up the experiment”Do not leave the two processes around and hope they eventually become someone else’s problem. Ask them to terminate:
kill "$sleep_pid" "$second_pid"wait "$sleep_pid" "$second_pid"kill sends a termination signal by default. wait asks the shell to collect the final status of its background children. You may see a short Terminated message; that describes the expected result of our cleanup.
Confirm that neither process remains:
ps -p "$sleep_pid,$second_pid" -o pid,stat,comm,argsOnly the headings should remain. Their /proc directories should also be gone because /proc reflects processes that currently exist.
Record the evidence
Section titled “Record the evidence”Add a short table to your research notebook:
| Question | Evidence |
|---|---|
| Which executable did the shell select? | command -v output |
| What kind of file was it? | Relevant file output |
| Which PIDs were created? | Saved PIDs and ps output |
| What executable did each process use? | Both readlink results |
| What disappeared after cleanup? | Final ps result and /proc observation |
Then explain, in your own words, why deleting a process and deleting an executable file are not the same operation.
What this gives us as researchers
Section titled “What this gives us as researchers”You can now move deliberately between an executable on disk and a process created from it. You can identify the executable selected by the shell, record a process identity, inspect Linux’s live process view, and support the claim that several processes share one executable without confusing them for one running object.
Next, Reading an ELF File will open the executable itself and ask what Linux found inside that made loading possible.