Threads and Processes
What You Will Learn
- The difference between a process and a thread
- How the OS schedules threads
- How threads communicate and share memory
- How race conditions arise and why they matter in security
What Is It?
A process is an independent running program with its own memory space. A thread is a unit of execution within a process. Multiple threads share the same memory space but run concurrently.
Understanding processes and threads is essential for exploit development, privilege escalation, and understanding how operating systems work at a low level.
Why It Matters
Security relevance includes:
- Race conditions can be exploited for privilege escalation (TOCTOU bugs)
- Thread injection is a core technique in malware and process injection
- Shared memory between threads creates attack surfaces
- Debugging tools like GDB and WinDbg work at the thread/process level
Key Concepts
Process vs Thread
| Process | Thread | |
|---|---|---|
| Memory | Own address space | Shares address space with other threads |
| Creation cost | Expensive (new address space) | Cheap (same address space) |
| Communication | IPC required | Direct memory access |
| Crash impact | Isolated | Can crash whole process |
Creating Threads in C
#include <pthread.h>
#include <stdio.h>
void *thread_func(void *arg) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
pthread_join(tid, NULL); // wait for thread to finish
return 0;
}
Compile with:
gcc -o program program.c -lpthread
Creating Processes (fork)
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// Child process
printf("Child PID: %d\n", getpid());
} else {
// Parent process
printf("Parent PID: %d, Child PID: %d\n", getpid(), pid);
wait(NULL); // wait for child to finish
}
return 0;
}
Race Condition (TOCTOU)
A TOCTOU (Time of Check to Time of Use) race condition occurs when a program checks a condition and then uses a resource, but the resource changes between the check and the use.
// Vulnerable code
if (access("file.txt", W_OK) == 0) { // CHECK
// Attacker swaps file.txt to /etc/passwd here
open("file.txt", O_WRONLY); // USE
}
An attacker can exploit this to write to privileged files by racing the window between check and use.
Mutex (Mutual Exclusion)
Mutexes prevent race conditions by allowing only one thread to access a resource at a time:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void increment() {
pthread_mutex_lock(&lock);
counter++; // protected critical section
pthread_mutex_unlock(&lock);
}
Inter-Process Communication (IPC)
Processes cannot share memory directly. They communicate via:
- Pipes: One-way data channel (
|in shell) - Named Pipes (FIFOs): Pipe with a filesystem name
- Shared Memory:
mmap()orshmget()— fastest IPC - Sockets: Network or Unix domain sockets
- Signals: Asynchronous notifications (
SIGTERM,SIGKILL)
# Inspect process memory maps
cat /proc/<pid>/maps
# List threads in a process
ls /proc/<pid>/task/
# Send signal to process
kill -9 <pid>