Loading learning content...
After a user has been authenticated (their identity verified), the operating system faces an equally critical question: What is this user allowed to do?
This is the domain of authorization—the process of determining whether a verified identity has permission to perform a requested operation on a specific resource. While authentication answers "Who are you?", authorization answers "What can you do?"
Authorization is among the most consequential decisions an operating system makes. A single flaw in authorization logic can expose sensitive data to unauthorized access, allow privilege escalation attacks, or enable complete system compromise. The 2017 Equifax breach, which exposed 147 million records, stemmed partly from authorization failures. The 2020 SolarWinds attack exploited authorization weaknesses to move laterally across networks.
Understanding authorization models isn't just academic—it's essential knowledge for building secure systems at any scale.
By the end of this page, you will understand the fundamental models that govern authorization decisions, their mathematical foundations, their tradeoffs in different security contexts, and how modern operating systems implement these concepts. You'll gain the vocabulary and mental models to reason about authorization in any system you build or analyze.
Before examining specific models, we must establish the fundamental concepts that all authorization systems share. These concepts form the vocabulary for precise discussion of access control.
The Authorization Triple
Every authorization decision fundamentally involves three elements:
The authorization system's job is to determine whether a given (subject, operation, object) triple should be allowed or denied.
1234567891011121314151617181920
// The fundamental authorization decisionfunction authorize(subject: Subject, operation: Operation, object: Object): Decision { // Option 1: Explicit allow if (policyExplicitlyAllows(subject, operation, object)) { return ALLOW; } // Option 2: Explicit deny if (policyExplicitlyDenies(subject, operation, object)) { return DENY; } // Option 3: No explicit rule - use default return DEFAULT_POLICY; // Usually DENY (fail-safe default)} // Example authorization checks:// authorize(user_alice, READ, /etc/passwd) -> ALLOW (world-readable)// authorize(user_alice, WRITE, /etc/shadow) -> DENY (root only)// authorize(kernel, WRITE, /dev/mem) -> ALLOW (privileged)The Reference Monitor Concept
The reference monitor is the abstract machine that mediates all access between subjects and objects. First formalized in the 1972 Anderson Report, the reference monitor has three essential properties:
In practice, the operating system kernel serves as the reference monitor. System calls cross the user-kernel boundary, and the kernel enforces authorization before granting access to protected resources.
Complete mediation requires that literally every access path goes through the authorization check. Covert channels (timing, storage, or shared resources that leak information) represent paths that bypass the reference monitor. Achieving true complete mediation in complex systems remains an open challenge.
Authorization vs. Access Control
These terms are often used interchangeably, but there's a subtle distinction:
An authorization policy specifies what is allowed. An access control mechanism enforces that policy. This separation is crucial—the same authorization policy can be enforced by different mechanisms, and the same mechanism can enforce different policies.
| Term | Definition | Example |
|---|---|---|
| Subject | Active entity requesting access | User process, kernel thread, network service |
| Object | Resource being accessed | File, socket, memory page, IPC channel |
| Principal | The authenticated identity associated with a subject | User ID (UID), service account, X.509 certificate |
| Permission | A specific operation allowed on an object | read, write, execute, delete, setattr |
| Policy | Rules defining which accesses are permitted | DAC rules, SELinux policy, RBAC configuration |
| Reference Monitor | Abstract machine enforcing policy | OS kernel, hypervisor, database engine |
The Access Matrix is the fundamental abstraction for reasoning about authorization. Introduced by Lampson in 1971 and formalized by Graham and Denning in 1972, the access matrix provides a complete representation of all access rights in a system.
Structure of the Access Matrix
The access matrix A is a two-dimensional structure where:
Each cell contains zero or more rights from a defined set R = {r₁, r₂, ..., rₖ}. Common rights include:
Access Matrix for a Simple Unix-like System============================================ │ /etc/passwd │ /etc/shadow │ /home/alice │ /bin/ls │ process_42───────────────┼─────────────┼─────────────┼─────────────┼─────────┼───────────root │ r, w, own │ r, w, own │ r, w, own │ r, x │ controlalice │ r │ - │ r, w, own │ r, x │ controlbob │ r │ - │ - │ r, x │ -shadow (group) │ r │ r │ - │ - │ - Key: r = read, w = write, x = execute own = can modify permissions (column) control = can modify process (row) - = no access Observations:- root has universal access (superuser)- alice owns her home directory (can grant/revoke access)- /bin/ls is executable by all, writable by none (integrity protected)- /etc/shadow is readable only by root and shadow group membersSubjects as Objects
A crucial insight is that subjects can also be objects. A process (subject) can be killed, signaled, traced, or debugged by other processes. This is represented by including each subject as a column in the matrix.
When subject Sᵢ has the control right over subject Sⱼ (in column Sⱼ), Sᵢ can modify Sⱼ's capabilities. This models administrative hierarchies and process management.
Special Rights: Own and Control
Two meta-rights are essential for matrix management:
These meta-rights create power structures within the access matrix.
Lampson identified six primitive operations for modifying the access matrix: create subject, delete subject, create object, delete object, enter right (add a right to a cell), and delete right (remove a right from a cell). All authorization policy changes can be expressed as sequences of these primitives.
The Implementation Problem
The access matrix is conceptually elegant but impractical to implement directly. Consider a system with:
Direct representation would require 10,000 × 1,000,000 × 32 = 320 GB just for the matrix, most of which would be empty (sparse).
This motivates two practical implementations:
We'll explore these implementations in subsequent pages. For now, understand that the access matrix is a conceptual model, not a direct implementation strategy.
Butler Lampson's protection model extends the access matrix with a formal framework for reasoning about authorization changes over time. This model addresses a crucial question: Given the current state of the access matrix, which future states are reachable?
Protection System Components
A protection system is defined by the tuple (S, O, R, C):
State and State Transitions
The protection state at any moment is captured by:
Commands trigger state transitions. Each command has:
12345678910111213141516171819202122232425262728293031323334
// Example commands in Lampson's model command CREATE_FILE(creator: Subject, newFile: Object): precondition: creator ∈ S_current // creator must exist newFile ∉ O_current // file must not already exist effect: O_current := O_current ∪ {newFile} A[creator, newFile] := {read, write, execute, own} command GRANT_READ(owner: Subject, grantee: Subject, file: Object): precondition: own ∈ A[owner, file] // owner must have own right grantee ∈ S_current // grantee must exist effect: A[grantee, file] := A[grantee, file] ∪ {read} command TRANSFER_OWN(owner: Subject, newOwner: Subject, file: Object): precondition: own ∈ A[owner, file] control ∈ A[owner, newOwner] // must have control over new owner effect: A[newOwner, file] := A[newOwner, file] ∪ {own} A[owner, file] := A[owner, file] - {own} command EXECUTE_SETUID(user: Subject, setuidProgram: Object, targetFile: Object): // Model for setuid execution - subject temporarily gains program owner's rights precondition: execute ∈ A[user, setuidProgram] setuid ∈ attributes(setuidProgram) // program has setuid bit effect: let programOwner = owner(setuidProgram) in // Execution context gains programOwner's rights on targetFile A[executionContext, targetFile] := A[programOwner, targetFile]The Safety Question
Lampson's model enables formal reasoning about the Safety Question:
Given initial state Q₀ and set of commands C, is there a sequence of commands that leaks right r to subject s for object o?
A system is safe with respect to right r if there's no way for an unauthorized subject to obtain r through any sequence of valid commands.
Harrison-Ruzzo-Ullman Result
In 1976, Harrison, Ruzzo, and Ullman proved a devastating result about the safety question:
In the general access matrix model, the safety question is undecidable.
This means no algorithm can determine, for all possible protection systems, whether a given right can leak. The proof works by showing that an access matrix system can simulate a Turing machine, making the safety question equivalent to the halting problem.
The undecidability of general safety doesn't mean we must abandon formal analysis. It means we must either: (1) restrict the model to decidable subsets (mono-operational systems), (2) use approximation techniques (type systems, information flow analysis), or (3) verify specific finite configurations rather than general safety. All modern security models adopt one of these strategies.
Mono-Operational Systems
Safety becomes decidable when each command performs at most one primitive operation. In this restricted model:
Most practical discretionary access control systems are not strictly mono-operational, so additional analysis techniques are required.
Take-Grant Model
Developed by Lipton and Snyder in 1977, the Take-Grant model is a restricted access matrix model where safety is decidable. It uses graph-based representations and has efficient algorithms for answering safety questions. We'll explore this in the context of capability systems.
Authorization models can be categorized based on how they determine access rights and who controls them. The three fundamental categories are:
Additionally, Attribute-Based Access Control (ABAC) has emerged as a flexible hybrid approach.
Each model answers differently the fundamental question: Who decides what access is permitted?
| Aspect | DAC | MAC | RBAC | ABAC |
|---|---|---|---|---|
| Control Authority | Resource owner | Central policy | Role administrator | Attribute evaluator |
| Policy Location | Per-object metadata | System-wide labels | Role-permission mapping | Policy engine rules |
| Flexibility | High (users decide) | Low (fixed lattice) | Medium (roles evolve) | Very high (any attribute) |
| Administration | Decentralized | Centralized | Hierarchical | Policy-based |
| Security Guarantee | Weak (user error) | Strong (formal proof) | Medium (role design) | Depends on policy |
| Revocation | Immediate (modify object) | Immediate (change label) | Immediate (remove role) | Immediate (update attribute) |
| Common Use | File systems, databases | Military, government | Enterprise IT | Cloud, microservices |
Discretionary Access Control (DAC)
In DAC, the owner of a resource has discretion over who can access it. The owner can grant, revoke, or transfer access rights at will.
Characteristics:
Traditional Unix permissions are DAC: the file owner sets read/write/execute for owner, group, and others.
Vulnerability: DAC cannot prevent authorized users from copying information to locations accessible by unauthorized users. A user with read access can copy content elsewhere—DAC provides no confidentiality guarantee against malicious insiders.
Mandatory Access Control (MAC)
In MAC, a central policy authority assigns security labels to subjects and objects. Access decisions are based on comparing labels according to fixed rules that users cannot override.
Characteristics:
The Bell-LaPadula model (confidentiality) and Biba model (integrity) are foundational MAC models. SELinux implements MAC through type enforcement.
Strength: MAC can provide mathematical guarantees that information does not flow to unauthorized entities, regardless of user behavior or programming errors.
Role-Based Access Control (RBAC)
In RBAC, access is determined by roles assigned to subjects, not by individual subject identity. Permissions are associated with roles, and subjects acquire permissions by being assigned to roles.
Characteristics:
NIST standardized RBAC with hierarchies (role inheritance), constraints (separation of duty), and session management.
Advantage: RBAC maps naturally to organizational structures. When an employee changes departments, only their role assignments change—not individual permissions across thousands of resources.
Attribute-Based Access Control (ABAC)
ABAC generalizes previous models by making access decisions based on attributes of subjects, objects, actions, and the environment. Policies are expressed as rules over attribute values.
Characteristics:
ABAC is highly expressive and can simulate DAC, MAC, and RBAC as special cases.
Trade-off: ABAC's flexibility comes with complexity. Policy analysis, debugging failed access, and ensuring policy consistency become harder as attribute sets grow.
Most production systems combine models. A cloud platform might use: RBAC for user management, DAC for user-created resources, MAC (labels) for regulatory compliance, and ABAC for fine-grained API authorization. Understanding each model enables you to compose them appropriately.
Authorization models can be evaluated against formal security properties. These properties give precise meaning to statements like "the system is secure" and enable mathematical proofs.
Simple Security Property (No Read Up)
A system satisfies the simple security property if subjects can only read objects at or below their security level.
Formally: If subject S with clearance level L(S) reads object O with classification L(O), then:
L(S) ≥ L(O) (dominates)
This prevents subjects from reading information classified above their clearance.
Star Property (*-Property, No Write Down)
A system satisfies the *-property if subjects can only write to objects at or above their security level.
Formally: If subject S with clearance level L(S) writes object O with classification L(O), then:
L(O) ≥ L(S) (dominates)
This prevents subjects from copying high-classification data to low-classification containers.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
// Bell-LaPadula Model: Multilevel Security for Confidentiality // Security levels form a lattice (e.g., TOP_SECRET > SECRET > CONFIDENTIAL > UNCLASSIFIED)enum SecurityLevel { UNCLASSIFIED, CONFIDENTIAL, SECRET, TOP_SECRET } // Each subject has a clearance level// Each object has a classification levelfunction clearance(subject: Subject): SecurityLevel;function classification(object: Object): SecurityLevel; function authorizeBellLaPadula( subject: Subject, operation: Operation, object: Object): Decision { let subjectLevel = clearance(subject); let objectLevel = classification(object); switch (operation) { case READ: // Simple Security Property: No read up // Subject can read object only if subject dominates object if (subjectLevel >= objectLevel) { return ALLOW; } return DENY; case WRITE: // *-Property: No write down // Subject can write object only if object dominates subject if (objectLevel >= subjectLevel) { return ALLOW; } return DENY; case EXECUTE: // Execute typically requires read access if (subjectLevel >= objectLevel) { return ALLOW; } return DENY; }} // Example: Alice (SECRET clearance) tries to:// - Read TOP_SECRET document: DENY (would violate simple security)// - Write UNCLASSIFIED file: DENY (would violate *-property)// - Read CONFIDENTIAL memo: ALLOW (clearance dominates)// - Write SECRET report: ALLOW (classification matches or dominates)Tranquility Properties
The Bell-LaPadula model also defines tranquility:
Weak tranquility allows administrative operations while preserving security invariants.
Biba Model: Integrity Properties
While Bell-LaPadula focuses on confidentiality, the Biba model (1977) addresses integrity. It reverses the flow direction:
This prevents untrusted data from corrupting trusted data.
| Property | Bell-LaPadula (Confidentiality) | Biba (Integrity) |
|---|---|---|
| Focus | Prevent unauthorized disclosure | Prevent unauthorized modification |
| Read Rule | No read up (can't read above clearance) | No read down (can't read below integrity) |
| Write Rule | No write down (can't write below clearance) | No write up (can't write above integrity) |
| Information Flow | High → Low forbidden | Low → High forbidden |
| Threat Model | Malicious reader | Malicious writer |
| Real-World Example | Military classification | Software integrity levels |
Bell-LaPadula and Biba are duals of each other. Confidentiality restricts information flow downward; integrity restricts it upward. Achieving both simultaneously is difficult—a subject at a single level can only read and write at exactly that level, limiting practical utility. Real systems typically prioritize one property or use separate mechanisms for each.
Classical access control protects data at rest—who can read or write files. But data doesn't stay static. Once read, it flows through programs, is transformed, combined with other data, and written elsewhere. Information Flow Control (IFC) tracks data as it moves through a system.
The Problem Access Control Misses
Consider this scenario:
Traditional access control checked permissions at each step but didn't track the information flow. IFC addresses this by labeling data and following its propagation.
Labels and Lattices
Information flow uses security labels organized in a lattice (a partially ordered set where every pair of elements has a unique least upper bound and greatest lower bound).
Security Lattice for Multilevel Security========================================== Classic Four-Level Military Lattice: TOP_SECRET ↑ SECRET ↑ CONFIDENTIAL ↑ UNCLASSIFIED Information can flow upward: UNCLASSIFIED → CONFIDENTIAL → SECRET → TOP_SECRETInformation CANNOT flow downward. Compartmented Lattice (with categories): (TS, {A, B}) / \ (TS, {A}) (TS, {B}) \ / (TS, {}) | SECRET | CONFIDENTIAL | UNCLASSIFIED Categories (A, B) are disjoint compartments.(TS, {A}) means: Top Secret clearance with access to compartment A.(TS, {A, B}) dominates both (TS, {A}) and (TS, {B}). Join (Least Upper Bound): join((S, {A}), (S, {B})) = (S, {A, B}) Meet (Greatest Lower Bound): meet((S, {A}), (S, {B})) = (S, {})Security Labels in Practice
When data from multiple sources is combined, the resulting data inherits the join (least upper bound) of the input labels. This ensures the result is protected at the level of the most sensitive input.
Example:
This automatic label propagation is called taint tracking in some systems.
Explicit and Implicit Flows
IFC must track both:
Explicit Flows — Direct data movement
y = x; copies x's value (and label) to y
Implicit Flows — Information revealed through control flow
if (secret) { y = 1; } reveals secret's value through y (if y = 1, secret was true)
Tracking implicit flows is harder and can lead to label creep (everything becomes highly classified) if not carefully managed.
Strict non-interference (information never flows to lower levels) is impractical. Real systems need controlled downgrading: declassification (reducing confidentiality label) and endorsement (increasing integrity label). These operations are security-critical and must be carefully controlled—typically limited to trusted code or explicit administrator action.
Decentralized Information Flow Control (DIFC)
Traditional IFC uses a centralized authority to assign labels. Decentralized IFC allows principals to create their own labels and grant declassification rights.
The Flume system (SOSP 2007) and Asbestos (SOSP 2005) implemented DIFC at the OS level. Key concepts:
DIFC enables powerful security patterns: a web server can receive a request, spawn a sandboxed worker with a tag for that user's data, and prevent that worker from leaking data to other users' workers.
The Clark-Wilson model (1987) was developed for commercial environments where integrity—not just confidentiality—is paramount. Unlike military models focused on preventing disclosure, Clark-Wilson addresses practical business concerns: preventing fraud, ensuring data accuracy, and maintaining audit trails.
Core Philosophy
Clark-Wilson recognizes that in commercial systems:
Key Concepts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
// Clark-Wilson Model Applied to Banking // CDIs (Constrained Data Items) - require integrity protectiontype AccountBalance = CDI<Decimal>;type TransactionLog = CDI<LogEntry[]>; // UDIs (Unconstrained Data Items) - untrusted inputtype DepositRequest = UDI<{ accountId: string, amount: number }>; // IVP (Integrity Verification Procedure)// Verifies that the sum of all account balances equals total assetsfunction verifyBalanceIntegrity(): boolean { let totalInAccounts = sum(allAccounts.map(a => a.balance)); let totalAssets = ledger.totalAssets; return totalInAccounts === totalAssets;} // TP (Transformation Procedure) - certified to maintain integrity@TransformationProcedure@RequiresRole("teller")@SeparationOfDuty("authorizer", "executor") // Different person must authorizefunction processDeposit( request: DepositRequest, // UDI input account: AccountBalance, // CDI to modify log: TransactionLog // CDI for audit): Result<void> { // 1. Validate UDI input if (request.amount <= 0 || request.amount > MAX_DEPOSIT) { log.append({ type: "REJECTED", reason: "invalid amount", ... }); return Err("Invalid deposit amount"); } // 2. Transform CDI let newBalance = account.value + request.amount; // 3. Maintain invariants assert(newBalance >= account.value); // No overflow // 4. Update CDI atomically atomic { account.value = newBalance; log.append({ type: "DEPOSIT", amount: request.amount, ... }); } // 5. Post-condition assert(verifyBalanceIntegrity()); return Ok(());} // Certification Rules:// CR1: IVP must verify all CDIs in consistent state// CR2: TP must transform CDIs from valid state to valid state// CR3: Users can only execute TPs through well-defined interfaces// CR4: User access is certified: (User, TP, {CDIs}) triples// CR5: TPs reject UDIs that would cause invalid CDI statesCertification and Enforcement Rules
Clark-Wilson defines two types of rules:
Certification Rules (CR) — Requirements for certifiers (auditors/administrators)
Enforcement Rules (ER) — Requirements for the system to enforce
While not always explicitly named, Clark-Wilson principles appear throughout modern system design: stored procedures in databases (TPs acting on CDIs), input validation layers, internal vs. external data segregation, and mandatory code review for changes to sensitive procedures. The model provides a vocabulary for reasoning about commercial integrity requirements.
Separation of Duties
A key Clark-Wilson contribution is formalizing separation of duties — no single person should have enough authority to complete a sensitive transaction alone. This prevents fraud through:
Modern RBAC systems implement these constraints through mutual exclusion rules on role assignments.
Modern operating systems and platforms implement authorization through layered architectures that combine multiple models. Let's examine how theory meets practice.
Unix/Linux Authorization Stack
The traditional Unix model is fundamentally DAC with owner/group/other permissions:
Modern Linux extends this with:
1234567891011121314151617181920212223242526272829303132
// Simplified Linux VFS authorization flow // When a process opens a file, the kernel performs authorization:int vfs_open(struct path *path, struct file *file, const struct cred *cred) { struct inode *inode = path->dentry->d_inode; // Step 1: Check traditional Unix permissions (DAC) int error = inode_permission(inode, calculate_mode(file->f_flags)); if (error) return error; // Permission denied // Step 2: Check POSIX ACLs if present error = posix_acl_permission(inode, cred, calculate_mask(file->f_flags)); if (error) return error; // Step 3: Invoke Linux Security Module (SELinux, AppArmor, etc.) // LSM hooks provide MAC layer error = security_inode_permission(inode, calculate_mask(file->f_flags)); if (error) return error; // MAC policy denied // Step 4: Additional capability checks for special files if (is_device(inode) && !capable(CAP_SYS_RAWIO)) return -EPERM; // All checks passed return do_dentry_open(file, inode, cred);} // Key insight: Multiple authorization layers, each can deny access// If ANY layer denies, access is denied (default-deny composition)Windows Security Architecture
Windows uses a sophisticated authorization system combining:
The Windows access check is more complex than Unix, supporting:
| System/Platform | Primary Model | Secondary Models | Notable Features |
|---|---|---|---|
| Linux (traditional) | DAC (mode bits) | Capabilities | Simple, fast, limited granularity |
| Linux + SELinux | DAC + MAC | Type Enforcement | Mandatory policies, policy complexity |
| Windows (NTFS) | DAC (DACLs) | Integrity Levels (MAC) | Fine-grained ACEs, inheritance |
| AWS IAM | ABAC + RBAC | Resource-based policies | Identity and resource policies, policy evaluation order |
| Kubernetes | RBAC | Pod Security Standards | Namespace scoping, API-centric |
| PostgreSQL | DAC + RBAC | Row-Level Security | Object privileges, policies on tables |
When multiple authorization layers exist, their composition determines the final decision. Most systems use default-deny: ALL layers must permit access. Some use default-allow with explicit denies (less secure). Understanding your system's composition semantics is critical for security analysis.
We've established the theoretical foundations of authorization. Let's consolidate the key concepts before diving into specific models in subsequent pages.
What's Next
This page established the conceptual framework. The following pages dive deep into specific models:
Each page will connect implementation details back to the theoretical foundations established here.
You now understand the fundamental concepts underlying all authorization systems: subjects, objects, operations, the access matrix abstraction, formal security properties, and the spectrum of control models. This foundation enables you to analyze and design authorization systems in any context—from operating systems to cloud platforms to application-level access control.