Loading learning content...
Every operating system faces a critical question: "What operations can this piece of code perform, and on which resources?" This isn't merely an academic concern—it's the foundation upon which system security, stability, and multi-tenancy rest.
Consider when you run a web browser. That browser needs to access network sockets, read configuration files, allocate memory, and render graphics. But should it be able to format your hard drive? Read your private SSH keys? Modify kernel data structures? Obviously not. Yet both your browser and the kernel are "just code" running on the same processor.
The abstraction that answers this question—that defines what code can do what to which resources—is called a protection domain. Understanding protection domains is understanding the architectural foundation of OS security itself.
By the end of this page, you will understand the theoretical foundations of protection domains: what they are, why they exist, how they relate to processes and users, and how they form the conceptual building blocks upon which access control lists, capabilities, and hardware protection rings are built.
A protection domain (often simply called a domain) is an abstract execution environment that specifies a set of objects and the operations permitted on those objects. Every piece of executing code operates within some protection domain, even if implicitly.
Formal Definition:
A protection domain consists of:
Mathematically, a domain D can be represented as:
D = { <O₁, rights₁>, <O₂, rights₂>, ..., <Oₙ, rightsₙ> }
Where each <Oᵢ, rightsᵢ> is a tuple denoting object Oᵢ and the set of operations permitted on it.
A protection domain is NOT the process itself—it's the context of privileges in which the process operates. Multiple processes can share the same domain, and a single process can transition between domains during execution.
| Domain | Example Objects | Example Rights | Typical Use |
|---|---|---|---|
| User Domain | User files, user ports, heap memory | Read, Write, Execute own files | Regular application execution |
| Kernel Domain | All memory, all devices, all I/O ports | All operations on all objects | Operating system kernel code |
| Driver Domain | Device registers, DMA buffers, interrupts | Read/Write specific device memory | Device driver execution |
| Sandbox Domain | Isolated file directory, limited network | Read only sandbox files, no raw sockets | Untrusted code execution |
| Debug Domain | Target process memory, registers | Read/Write target memory, breakpoints | Debugger attached to process |
Protection domains exist because of a fundamental tension in computing systems:
The Capability Paradox:
Without protection domains, we would face impossible choices: either grant all programs all privileges (security disaster), or grant no programs any privileges (completely useless system).
Historical Context:
Early computers (1940s-1950s) had no protection domains. A bug in any program could crash the entire system, corrupt any data, or halt the machine. The development of time-sharing systems (1960s) made this untenable—multiple users running multiple programs demanded isolation.
The Multics system (1965) was the first to formalize protection domains with rings and capabilities, directly influencing Unix and all modern operating systems.
Without protection domains, an operating system degenerates to a program loader. MS-DOS is the classic example: any program could write anywhere in memory, access any hardware, and crash the entire system. This worked only because it was single-user, single-tasking—and even then, it was fragile.
Understanding protection domains requires distinguishing them from related concepts:
The Relationship Triangle:
USERS
/ \
/ \
↓ ↓
DOMAINS ←→ PROCESSES
Users are principals—entities that can own resources and have rights. Users persist across sessions.
Processes are instances of program execution. They have a lifetime (start-to-termination).
Domains define the privilege context. They specify what processes can do, not that processes exist.
Unix Example: Three UIDs
Unix processes have three user IDs that determine their domain:
The effective UID essentially defines the protection domain. When you run sudo, your process's effective UID becomes root (UID 0), switching you into the kernel's protection domain temporarily.
# Before sudo: Real=1000, Effective=1000 (your domain)
$ sudo whoami
# During sudo: Real=1000, Effective=0 (root domain)
root
# After sudo returns: Real=1000, Effective=1000 (back to your domain)
Protection domains are defined by their rights over objects. Understanding both concepts is essential:
What Are Objects?
In security terms, an object is any system resource that requires controlled access. Objects are passively accessed by subjects (processes executing in domains).
Object Taxonomy:
| Object Type | Examples | Typical Rights | Granularity |
|---|---|---|---|
| Files | Executables, data files, devices | Read, Write, Execute, Append, Delete | Per-file or per-directory |
| Memory Regions | Process address space, shared memory | Read, Write, Execute, Map | Per-page or per-segment |
| I/O Ports | Serial ports, USB endpoints | Read, Write, Control | Per-port or per-device |
| Processes | Other processes in the system | Signal, Debug, Wait, Kill | Per-process |
| System Abstractions | Semaphores, message queues, sockets | Create, Destroy, Read, Write | Per-object |
| Hardware Resources | CPU time, network bandwidth, disk quota | Use, Prioritize, Limit | Per-resource type |
What Are Access Rights?
An access right (or permission) is a specific operation that may or may not be permitted on an object. Rights are granted to domains, not directly to processes or users.
Universal Rights (across all object types):
Object-Specific Rights:
Meta-Rights (rights over rights):
Access rights often have nuanced semantics. 'Read' on a directory means listing contents, while 'Read' on a file means accessing content. 'Execute' on a directory means searching, while 'Execute' on a file means loading it as code. Context matters significantly.
Protection domains can be classified by when and how their object-rights associations change:
Static Domains:
In a static domain system, domains are defined at system configuration time and remain fixed during execution. The set of objects and rights in each domain does not change.
Characteristics:
Example: A dedicated web server process running with a fixed user ID and fixed file permissions. The domain never changes.
Dynamic Domains:
In a dynamic domain system, the contents of a domain can change during execution. Objects can be added or removed, and rights can be acquired or released.
Characteristics:
Real-World Example: Android Permissions
Android uses dynamic domains through the permission system:
This dynamic domain model allows Android to implement the principle of least privilege while adapting to user preferences.
How is a process associated with a domain? Different operating systems use different policies:
Policy 1: One Domain per User
Each user has exactly one domain. All processes started by the user execute in that domain.
Policy 2: One Domain per Process
Each process has its own unique domain. The domain is created when the process starts and destroyed when it terminates.
Policy 3: Domain per Program
Each program (executable) defines a domain. All executions of that program share the domain.
| Policy | Granularity | Isolation | Flexibility | Implementation Complexity |
|---|---|---|---|---|
| One Domain/User | Coarse | Low | Low | Simple |
| One Domain/Process | Fine | High | High | Complex |
| One Domain/Program | Medium | Medium | Medium | Moderate |
| Hierarchical (Rings) | Layered | Medium | Medium | Hardware-assisted |
| Hybrid (Unix) | Mixed | Variable | High | Moderate |
Policy 4: Hierarchical Domains (Rings)
Domains are arranged in a hierarchy. Inner domains have more privileges than outer domains. A process in an outer ring must request service from an inner ring to perform privileged operations.
Policy 5: Hybrid Policy (Modern Unix/Linux)
Modern Unix combines multiple policies:
This hybrid approach provides the flexibility to implement security policies ranging from simple user isolation to complex mandatory access controls.
Regardless of association policy, the guiding principle is the same: a process should execute in a domain containing only the rights necessary for its current task. This minimizes the damage from bugs, attacks, or misconfiguration.
The most powerful way to visualize and reason about protection domains is the access matrix model, introduced by Butler Lampson in 1971.
The Access Matrix:
An access matrix is a two-dimensional table where:
Example Access Matrix:
│ File1 │ File2 │ Printer │ Process2 │ Domain D2 │
──────────────┼────────┼────────┼─────────┼──────────┼───────────┤
Domain D1 │ R, W │ R │ Print │ Signal │ Switch │
──────────────┼────────┼────────┼─────────┼──────────┼───────────┤
Domain D2 │ R │ R, W, X│ - │ - │ - │
──────────────┼────────┼────────┼─────────┼──────────┼───────────┤
Domain D3 │ Owner │ - │ Admin │ Debug │ Switch │
──────────────┴────────┴────────┴─────────┴──────────┴───────────┘
Key Observations:
Empty cells mean no access whatsoever. Domain D2 cannot use the printer at all.
Domains as objects: Notice "Domain D2" is a column. This allows rights like "Switch" (ability to enter that domain) to be formally modeled.
Rights vary by context: Domain D1 can read both files, but only write File1.
Special rights: "Owner" implies all rights plus the ability to modify rights. "Admin" implies device management.
Why This Model Matters:
The access matrix provides:
Note that the access matrix is a logical model. No real system stores the entire matrix—it would be enormous and mostly empty. Instead, systems store compressed representations (ACLs store non-empty cells by column; capabilities store non-empty cells by row).
A system with 10,000 domains and 1,000,000 objects would have 10 billion cells. In practice, most cells are empty (no access). Efficient implementations (ACLs, capabilities) exploit this sparsity by only storing non-empty entries.
Security researchers have identified several formal properties that protection domain systems should satisfy:
Safety Property:
A system is safe with respect to right R if, starting from an initial access matrix state, there is no sequence of legal operations that would give an unauthorized subject right R to an object.
Harrison, Ruzzo, and Ullman proved in 1976 that the general safety problem is undecidable—there is no algorithm that can determine whether an arbitrary access control system is safe.
Containment Property:
A domain D1 is contained within domain D2 if every right in D1 is also in D2. Formally: D1 ⊆ D2
Containment is useful for hierarchical domains—Ring 0 "contains" Ring 3 because Ring 0 has all Ring 3 rights plus additional privileges.
The Confinement Problem:
One of the most challenging formal problems is confinement: ensuring that a process cannot leak information outside its domain. Even if a process cannot write to external files, it might:
Lampson proved the confinement problem is challenging because covert channels exist in any realistic system. Modern mitigations (constant-time algorithms, resource partitioning) reduce but cannot eliminate this risk.
Information Flow Analysis:
Beyond access control, security often requires controlling information flow. The Bell-LaPadula model adds:
These rules ensure information flows only in permitted directions, preventing both direct and indirect leakage.
We've established the foundational concept of protection domains. Let's consolidate the critical insights:
What's Next:
Now that we understand what protection domains are, we'll explore domain switching—how processes transition between domains. This is the mechanism that enables setuid programs, system calls, exception handlers, and controlled privilege escalation. Understanding domain switching is essential for comprehending both the security of protection systems and their vulnerabilities.
You now understand the fundamental concept of protection domains. This abstraction underpins all access control mechanisms in operating systems. Next, we'll see how domains interact through the mechanism of domain switching.