Isolation, Kernel Organization, and System Call APIs Note on System Call APIs
Introduction and Motivation: The Necessity of Isolation
Scenario Without Isolation: To understand isolation, one must consider a system lacking it. In such a system, several critical failures occur:
Single Buggy Process: A bug in a process can corrupt kernel memory, leading to a full system crash.
Malicious Process: Without boundaries, a malicious process can read secrets directly from other processes.
Greedy Process: A process can monopolize the CPU, causing starvation for all other tasks.
Crashing Driver: A faulty driver can take down the entire Operating System (OS).
Historical Context: Early Batch Systems (1950s–1960s):
These systems ran one job at a time.
A single bug required a physical reboot of the machine.
There were no concurrent users and no security model was required.
Drivers of Change: Several technological shifts made isolation mandatory:
Timesharing: Enabling multiple users on a single machine.
Networked Systems: The introduction of untrusted inputs from external networks.
Multi-process Workloads: The need to run many applications simultaneously.
Commercial Software: The prevalence of software with unknown quality and potential vulnerabilities.
Defining Isolation and Protection
Isolation (Property): The property that a fault, bug, or attack in one component cannot propagate beyond its defined boundary. Isolation is effectively about containment; the damage stays "inside the box."
Protection (Mechanism): The mechanism that enforces isolation. This is the hardware or software that prevents violations of the defined boundaries. Protection is the actual enforcement of the goal that is isolation.
Comparison of Isolation vs. Protection:
Nature: Isolation is a conceptual boundary; Protection is an enforcement mechanism.
Definition Source: Isolation is defined by OS/architecture design; Protection is defined by hardware and the kernel.
Examples: Isolation includes address spaces and privilege levels; Protection includes page table bits, , and syscall gates.
Failure Mode: Isolation failure leads to spreading contamination; Protection failure is a hardware fault or kernel bug.
Cost: Isolation has conceptual overhead; Protection has runtime overhead.
The Four-Way Tradeoff of Isolation
Every isolation decision involves a tradeoff between four properties:
Performance: More isolation equals higher overhead (e.g., switching between syscall and function calls). Less isolation is faster due to fewer switches.
Safety: More isolation ensures faults are contained. Less isolation allows bugs to propagate freely.
Usability: More isolation can feel restrictive (e.g., browser sandboxing). Less isolation is flexible but risky (e.g., privilege escalation).
Complexity: More isolation requires more kernel code (e.g., microkernels). Less isolation involves a simpler system (e.g., monolithic kernels).
The Isolation Taxonomy: What and Why We Isolate
Why Isolate Processes?
Fault Containment: Crashes should not propagate.
Security: Processes must not read memory belonging to others.
Resource Fairness: Preventing a single process from starving others of CPU or memory.
Accountability: The OS must identify which entity is performing specific actions.
Taxonomy of Layers:
App vs. App: Process A cannot read Process B's memory.
App vs. Kernel: User code cannot execute privileged instructions.
User vs. Admin: Normal users cannot modify system files.
Device vs. Device: Direct Memory Access () from a Network Interface Card () cannot access Graphic Processing Unit () memory.
Resource Isolation Mechanisms:
CPU Isolation: Enforced by preemptive scheduling and hardware Current Privilege Levels (). Each process believes it owns the CPU.
Memory Isolation: Enforced by the Memory Management Unit () using per-process page tables. Kernel memory is mapped into the address space but remains inaccessible in user mode.
Device Isolation: I/O ports are restricted to Ring 0. is used for isolation. Drivers typically live in the kernel.
Filesystem/Namespace Isolation: Unix permissions (owner/group/other), jails, and Linux namespaces (, , , ).
Kernel Organization: Monolithic vs. Microkernels
The Kernel Content Question:
Must Be in Kernel: Hardware abstraction, memory management, CPU scheduling, and trap handling.
Probably in Kernel: Filesystems, device drivers, and the network stack.
Could/Should be in User Space: Filesystem servers, protocol stacks, applications, window systems, and language runtimes.
Monolithic Kernels (e.g., Linux, FreeBSD, xv6):
All OS services (Scheduler, FS, Network, Drivers) execute in the kernel address space with full privilege.
Advantages: High performance (no context switching for services), direct access between components, simpler Inter-Process Communication () via function calls.
Disadvantages: A bug anywhere can crash the system; large attack surface (Linux kernel is approximately lines of code); difficult to formally verify.
Microkernels (e.g., Mach, seL4, QNX, Fuchsia/Zircon):
A minimal kernel handles only , address spaces, scheduling, and Interrupt Request () dispatch. Services like filesystems and drivers run in user space.
Advantages: Fault isolation (drivers can be restarted); smaller Trusted Computing Base (); modularity; high security ( is formally verified).
Disadvantages: High overhead; performance can be to slower for I/O; complex asynchronous design.
The IPC Performance Gap:
Microkernel Filesystem Read: Requires a syscall to kernel, message send to file server, context switch to file server, file server work, message reply back, and context switch back to caller.
Monolithic Filesystem Read: Requires a syscall to kernel, followed by a direct function call to filesystem code.
Hardware Isolation Support
x86 Protection Rings:
Ring 0: Kernel (privileged).
Ring 1–2: Optional (rarely used, intended for OS services/drivers).
Ring 3: User applications (unprivileged).
Current Privilege Level (CPL):
Stored in the two lowest bits of the (code segment) register.
: Ring 0 (Kernel Mode).
: Ring 3 (User Mode).
The hardware checks on every memory access against the Descriptor Privilege Level ().
Restricted Operations in Ring 3:
User mode cannot execute instructions like , , or .
User mode cannot modify page tables or change privilege levels directly (must use a trap).
I/O port access requires an check.
Privilege Transitions:
Entering Kernel (Ring 3 → Ring 0): Via system call ( or ), hardware interrupts (timer, I/O), or exceptions (page fault).
Returning to User (Ring 0 → Ring 3): Via (restores , , ) or (faster path).
System Call APIs
Definition: A controlled gate allowing user code to request kernel services without granting kernel privileges.
Syscall Counts:
Linux (x86-64):
FreeBSD / macOS:
Windows (NT):
xv6:
Invocation Mechanisms:
int 0x80: Classic x86 software interrupt. CPU saves state, switches to kernel stack. Slower due to full interrupt path.
syscall / sysenter: Modern fast paths. Does not use the Interrupt Descriptor Table (). Kernel entry point is stored in the (Model Specific Register).
API Stability and Evolution:
A primary constraint for Linux is "not breaking userspace." Binaries from must run in .
New features are added by creating new syscalls (e.g., , ) rather than modifying existing ones.
API Design Challenges: You only ship it once; you cannot predict future needs (e.g., the need for to prevent race conditions); versioning is effectively impossible.
xv6 Implementation Details
xv6 System Call Path:
User program calls a function like .
User-side stub in executes: .
CPU switches to , saves state, and jumps to entry via .
saves remaining registers and calls in .
identifies and calls .
in uses the value in to index into a static dispatch table of function pointers.
The handler (e.g., ) executes, and the return value is placed back in .
The Trap Frame: A structure containing state saved by hardware (, , , , , and error code) and software (general-purpose and segment registers).
Adding a Syscall to xv6:
Define number in .
Implement handler in a file.
Register in the dispatch table in .
Declare for user space in and .
Validate arguments using , , or .
Virtual Memory and Time Slicing
Memory Isolation: Each process has its own page table. In xv6, . Memory above this is supervisor-only ().
Page Table Bits:
U/S: User/Supervisor ( kernel only).
R/W: Read/Write ( read-only).
P: Present ( fault on access).
NX: No-Execute (prevents code injection).
Time Slicing: OS divides CPU time into quanta (e.g., ). A hardware timer interrupt triggers a context switch.
Cooperative Scheduling: Process voluntarily yields (dangerous, infinite loops stall system).
Preemptive Scheduling: Mandatory for multi-user systems; OS forces the yield.
Context Switch Costs: Register save/restore (), flush (), and cache cold start ().
Kernel Concurrency Models
Many-to-One: Multiple user threads map to one kernel thread. If one user thread blocks, all threads in that process block.
One-to-One (Linux pthreads, Windows): Each user thread has a corresponding kernel thread. Allows true parallelism. High memory overhead ( per kernel stack).
Many-to-Many (Go goroutines, Solaris): user threads multiplexed over kernel threads. Complex implementation but supports massive concurrency.
Concurrency inside the Kernel: Multicore kernels must be re-entrant. Shared structures like the process table and memory allocator must be protected. xv6 uses spinlocks that disable interrupts during acquisition to prevent data races. Failure to synchronize leads to catastrophic corruption.
Questions & Discussion
What happens if the filesystem crashes? In a monolithic kernel, it results in a kernel panic and system reboot. In a microkernel, the server crashes but the kernel can restart it, potentially leaving other processes unaffected. In an exokernel, the crash is limited to the specific application managing its own storage.
Why does hardware enforce protection? Software is bypassable; a process could jump to any address. Hardware enforcement is unconditional and acts as the root of trust for the Trusted Computing Base ().
Why are microkernels difficult? Primarily due to the cumulative latency of context switching which can make I/O significantly slower than monolithic equivalents.