Lab 02 โ Process Security: Credentials, /proc Inspection & Signals¶
| Field | Details |
|---|---|
| Course | SCIA-360 โ Operating System Security |
| Topic | Process Management Security |
| Chapter | 2 |
| Difficulty | โญ Beginner |
| Estimated Time | 45โ60 minutes |
| Environment | Docker โ ubuntu:22.04 |
Overview¶
Every running process on Linux carries a security context: real and effective UIDs, GIDs, supplementary groups, and capability sets. The kernel exposes all of this through /proc/PID/status. In this lab you will inspect process credentials directly from /proc, observe how credentials are inherited when a parent spawns a child, discover how environment variables passed to processes can be read by any root process via /proc/PID/environ, and verify that Docker's PID namespace isolation prevents containers from seeing each other's processes.
By the end of this lab you will understand:
- What fields in
/proc/PID/statusrepresent a process's security context - How credential inheritance works and why it matters for privilege management
- Why passing secrets via environment variables is a security anti-pattern
- How Linux PID namespaces enforce process isolation between containers
Container environment
All commands run inside a throwaway Docker container unless explicitly noted as host commands. Do not skip the cleanup step at the end.
Prerequisites¶
- Completed Lab 01
- Comfortable with basic bash: variable expansion, backgrounding (
&),su - Chapter 2 reading on process lifecycle and credentials
Part 1 โ Process Credentials via /proc¶
Step 1.1 โ Start the Container and Install Tools¶
All remaining commands in Parts 1โ3 run inside this container.
Step 1.2 โ Inspect Your Own Process Credentials¶
Expected output:
Uid field format: real effective saved-set filesystem
| UID Field | Meaning |
|---|---|
| Real UID | Who actually owns the process (who launched it) |
| Effective UID | Used for permission checks โ can differ for SUID binaries |
| Saved-set UID | Stored during exec() to allow privilege dropping and restoration |
| Filesystem UID | Used for filesystem access checks (Linux-specific) |
Why four UIDs?
The distinction between real and effective UID is what makes SUID binaries work. A normal user (real UID 1000) running /usr/bin/passwd will have an effective UID of 0 (root) โ allowing it to write /etc/shadow โ while the real UID remains 1000.
๐ธ Screenshot checkpoint 02a โ Capture /proc/$$/status output showing Name, Pid, PPid, Uid, and Gid fields.
Step 1.3 โ Create a Non-Root User and Compare Credentials¶
Expected output: All four Uid fields show 1000 โ alice's UID. Compare this to the root shell where all four fields were 0.
Default UID assignment
useradd assigns the next available UID starting at 1000 on most Linux distributions. UIDs 0โ999 are reserved for system accounts. This is why the first manually created user is typically UID 1000.
๐ธ Screenshot checkpoint 02b โ Capture alice's credential output showing UID=1000.
Part 2 โ Process Hierarchy and Inheritance¶
Step 2.1 โ Inspect a Background Process¶
sleep 300 &
SLEEP_PID=$!
echo "sleep PID: $SLEEP_PID"
cat /proc/$SLEEP_PID/status | grep -E 'Name|Pid|PPid|Uid'
ls -la /proc/$SLEEP_PID/exe
cat /proc/$SLEEP_PID/cmdline | tr '\0' ' ' && echo
Expected output:
Name: sleepPPid:matches the bash shell's PID ($$)Uid: 0 0 0 0โ inherited from parent bash (root)exe -> /usr/bin/sleepcmdline: sleep 300
Credential inheritance
When a process calls fork(), the child inherits an exact copy of the parent's credentials. This includes real UID, effective UID, all GIDs, and the full capability set. A privileged parent spawning an untrusted child inadvertently grants that child all its privileges unless it explicitly drops them with setuid() before executing untrusted code.
๐ธ Screenshot checkpoint 02c โ Capture the sleep process inspection showing PPid, Uid, exe, and cmdline.
Step 2.2 โ File Descriptor Inheritance¶
Expected output: File descriptors 0, 1, and 2 โ stdin, stdout, and stderr โ pointing to the same terminal as the parent shell. The child inherited the parent's open file table.
FD inheritance and security
A child process inherits all open file descriptors from its parent unless they are marked O_CLOEXEC (close-on-exec). This is why long-running daemons that fork() to spawn children should mark sensitive file descriptors (e.g., database connections, private keys) as O_CLOEXEC โ otherwise every child process can read and write them.
Step 2.3 โ Kill the Process and Observe /proc Cleanup¶
Expected output: An error message indicating no such file or directory, followed by "Process gone โ /proc entry removed".
/proc is purely dynamic
/proc is a virtual filesystem backed entirely by kernel memory. There are no files on disk. When a process terminates, the kernel immediately removes its /proc/PID directory. This is why you cannot forensically analyze a dead process through /proc โ the information is gone the moment the process exits.
๐ธ Screenshot checkpoint 02d โ Capture the ls /proc/$SLEEP_PID error confirming the entry is gone.
Part 3 โ Environment Variables as a Security Risk¶
Step 3.1 โ Set Sensitive Environment Variables¶
export SECRET_TOKEN="api-key-abc123"
export DB_PASSWORD="supersecret"
env | grep -E 'SECRET|PASSWORD'
This simulates a common (but insecure) pattern: passing secrets to applications via environment variables.
Step 3.2 โ Read Environment Variables via /proc¶
Expected output:
Critical security finding
/proc/PID/environ exposes the complete environment of any process to:
- The process owner itself
- Any process running as root
In a shared container environment where multiple services run as root, any service that is compromised can read the secrets of every other root-owned process through /proc. This makes environment variable secret injection fundamentally unsafe in multi-service or multi-tenant environments.
๐ธ Screenshot checkpoint 02e โ Capture the /proc/PID/environ output revealing both secrets.
Step 3.3 โ Safer Secret Handling Alternatives¶
echo 'WORST: ENV instructions in Dockerfile โ visible in image layers and history'
echo 'BAD: Passing secrets as -e flags to docker run โ visible in /proc/PID/environ'
echo 'BETTER: Mount secrets as files with chmod 600, readable only by target user'
echo 'BEST: Use tmpfs-backed secret mounts (Docker Swarm secrets / Kubernetes Secrets)'
Docker secrets vs. environment variables
Docker Swarm and Kubernetes both provide a secrets mechanism that mounts the secret value as a file in a tmpfs (RAM-only) mount at a well-known path. The file is only readable by the container's designated user, is never written to disk, and does not appear in /proc/PID/environ.
Part 4 โ Process Isolation Between Containers¶
Step 4.1 โ Exit the First Container¶
Type exit to leave the container, returning to your host shell.
Step 4.2 โ Launch Two Containers and Verify Isolation¶
Run these commands on your host:
docker run -d --name proc-b ubuntu:22.04 sleep 3600
docker run --rm ubuntu:22.04 bash -c 'ps aux'
docker stop proc-b && docker rm proc-b
Expected output: The second container's ps aux output shows only its own process (ps itself, or bash as PID 1). The sleep 3600 process running in proc-b is completely invisible.
PID namespaces
Linux PID namespaces give each container a private PID number space. From inside a container, the namespace appears to contain only its own processes starting from PID 1. The host kernel manages all PIDs globally, but the namespace boundary prevents containers from enumerating or signaling each other's processes. This is the kernel mechanism that underpins Docker's process isolation guarantee.
Namespace โ security boundary alone
PID namespaces prevent enumeration of other containers' processes, but a container running with --privileged or with certain Linux capabilities can break out of the namespace boundary. Namespace isolation is one layer of defense, not the complete story.
๐ธ Screenshot checkpoint 02f โ Capture the second container's ps aux output showing only its own process(es).
Cleanup¶
Assessment¶
Screenshot Checklist¶
| ID | Description | Points |
|---|---|---|
| 02a | /proc/$$/status output โ Name, Pid, PPid, Uid, Gid fields visible | 7 |
| 02b | alice's credentials โ Uid and Gid showing 1000 | 6 |
| 02c | sleep process inspection โ PPid, Uid, exe symlink, cmdline | 7 |
| 02d | /proc entry gone after kill โ error message visible | 5 |
| 02e | Secrets exposed via /proc/PID/environ โ both variables visible | 8 |
| 02f | Isolated process list โ second container shows only its own processes | 7 |
| Screenshot Total | 40 |
/proc Field Annotation Exercise¶
Complete the following table based on your observations during the lab (20 points). For each /proc field, write one sentence describing what it contains and its security relevance.
/proc File / Field | What It Contains | Security Relevance |
|---|---|---|
/proc/PID/status โ Uid | ||
/proc/PID/status โ PPid | ||
/proc/PID/exe | ||
/proc/PID/cmdline | ||
/proc/PID/fd/ | ||
/proc/PID/environ |
Reflection Questions¶
Answer each question in 3โ5 sentences. (40 points โ 10 points each)
Question 1
In Step 3.2, you read SECRET_TOKEN and DB_PASSWORD from /proc/PID/environ as root. What does this mean for the common practice of injecting database credentials into containerized applications via environment variables (e.g., docker run -e DB_PASSWORD=...)? Describe the specific threat scenario in a multi-service environment running as root, and name a safer alternative.
Question 2
The sleep process inherited UID 0 from its parent bash shell. Define "process credential inheritance" in your own words. What specific security risk does it create when a privileged parent process (e.g., a web server running as root) uses fork() to spawn an untrusted child process such as a user-supplied plugin or script? What system call should the parent use before executing untrusted code to mitigate this risk?
Question 3
After you killed the sleep process, its /proc/PID directory disappeared immediately โ no cleanup was needed. Is /proc a real filesystem stored on disk? Explain what type of filesystem it is, where its data comes from, and what this tells you about the purpose and limitations of /proc as a forensic tool for investigating crashed or killed processes.
Question 4
In Part 4, a container running alongside yours could not see your processes via ps aux. Name the specific Linux kernel feature that provides this isolation. Then describe one concrete real-world scenario โ for example in a cloud hosting or CI/CD environment โ where this isolation is important for security, and explain what could go wrong if this isolation did not exist.
Grading Rubric¶
| Component | Points |
|---|---|
| Screenshots (6 ร weighted) | 40 |
/proc field annotation exercise | 20 |
| Reflection questions (4 ร 10) | 40 |
| Total | 100 |
Reflection grading criteria
Full credit requires: (1) a correct technical claim, (2) a specific explanation of the mechanism, and (3) a security implication or real-world consequence. Restating the lab procedure without explanation receives no more than 5/10.