Access control is the mechanism by which an operating system decides who — or what — gets to do what with which resources. It’s the connective tissue between authentication (verifying identity) and the countless individual decisions an OS makes every second: can this process read that file, can this user install software, can this thread write to that region of memory. Nearly everything else in OS security — permissions, privilege levels, sandboxing, ACLs — is really just a specific implementation of access control. This article covers the major access control models, how they’re implemented across operating systems, and how they interact with the broader security architecture of a modern system.
What Access Control Actually Governs
Every access control decision, regardless of model or platform, answers the same basic question: given a subject (a user, process, or thread requesting access), an object (a file, device, network socket, memory region, or other resource), and an action (read, write, execute, delete, and so on), should this specific request be allowed?
Subject: process running as user "alice"
Object: /etc/shadow
Action: read
Access Control Decision → DENIED (alice lacks read permission on this file)
This decision happens constantly and largely invisibly — every file open, every system call touching a resource, every network connection attempt is, underneath, an access control check.
The Major Access Control Models
Discretionary Access Control (DAC)
In DAC, the owner of a resource decides who else can access it and to what degree — access is at the resource owner’s discretion, hence the name. This is the traditional UNIX/Linux permission model (owner/group/other read/write/execute bits) and the default behavior of Windows NTFS permissions: if you own a file, you can grant or revoke access to it for other users, without needing a central authority’s approval.
DAC’s core weakness is exactly its flexibility: because any resource owner can grant access, there’s no guarantee that access remains consistent with organizational security policy — a well-meaning but careless user can grant overly broad access to a sensitive file, and nothing in the DAC model itself prevents that.
Mandatory Access Control (MAC)
MAC flips that model: access decisions are enforced by a central system policy, not left to individual resource owners. Even if a file’s owner wants to grant broader access, the system-enforced MAC policy can still refuse it, because the policy is defined and controlled outside any individual user’s discretion.
- SELinux (Security-Enhanced Linux, originally developed by the NSA) implements MAC by assigning security contexts (labels) to every process and resource, and enforcing rules about which labeled processes may interact with which labeled resources — a web server process labeled
httpd_tmight be permitted to read files labeledhttpd_sys_content_tbut denied access to files labeleduser_home_t, regardless of standard UNIX permission bits, which are still checked separately underneath. - AppArmor (common on Ubuntu/Debian-family distributions) implements a similar concept using path-based profiles rather than SELinux’s label-based approach, generally considered simpler to configure at some cost in granularity.
- iOS’s app sandbox is effectively a MAC system — no matter what a user or even the app developer might want, the OS-enforced sandbox policy strictly limits what any given app can access, a major reason iOS has historically had a smaller practical malware problem than more DAC-reliant platforms.
Role-Based Access Control (RBAC)
RBAC assigns permissions to roles representing job functions, then assigns users to those roles, rather than managing individual user-to-permission assignments directly. This dramatically simplifies administration at scale — onboarding a new database administrator means assigning them the “DBA” role rather than manually replicating dozens of individual permission grants — and is the dominant model in enterprise identity systems and cloud IAM platforms (AWS IAM roles, Azure RBAC, Kubernetes RBAC).
Role: "Backup Operator"
├── Permission: read all files (for backup purposes)
├── Permission: NOT write/modify files
└── Permission: NOT delete files
Users assigned: alice, bob (both operate the backup system)
Windows implements a form of RBAC natively through built-in and custom security groups, where NTFS/share permissions and many system privileges are granted to groups rather than individual accounts.
Attribute-Based Access Control (ABAC)
ABAC evaluates access dynamically using multiple attributes — of the subject (department, clearance level, device compliance status), the object (data sensitivity classification, owner), and the environment (time of day, network location, current threat level) — combined through policy logic, rather than relying on static role assignment alone. This enables far more contextual, fine-grained decisions: “allow access to financial records only if the user is in the Finance role, the request originates from a company-managed device, and it’s during business hours” is a natural ABAC policy but awkward to express in pure RBAC.
Rule-Based Access Control
A related but distinct concept: access is governed by explicit, administrator-defined rules (often IF-THEN logic) rather than roles or attributes per se — firewall rule sets are a classic example, where each rule explicitly states conditions and an allow/deny outcome, evaluated in order.
How Access Control Decisions Actually Get Enforced: The Reference Monitor Concept
Underlying virtually all of these models is the theoretical concept of a reference monitor — a component that mediates every access attempt between subjects and objects, is itself tamper-proof, and is small/verifiable enough to be trusted completely. In practice, operating system kernels implement this role: the Windows kernel’s Security Reference Monitor (SRM) checks every object access against the requesting process’s access token and the object’s security descriptor; the Linux kernel enforces DAC permission checks (and, when configured, MAC checks via SELinux/AppArmor’s Linux Security Modules hook framework) for every relevant system call.
Process requests: open("/etc/shadow", O_RDONLY)
│
▼
[Kernel intercepts syscall]
│
▼
[Reference Monitor / Security Subsystem]
│
├── Check DAC permissions (owner/group/other bits)
├── Check MAC policy (SELinux/AppArmor, if enabled)
└── Check any applicable capability requirements
│
▼
Allow or Deny
Access Control Lists (ACLs) as an Implementation Mechanism
ACLs are a common way to implement DAC (and sometimes elements of RBAC): a list attached to a resource specifying which subjects have which permissions.
- NTFS ACLs on Windows are highly granular, supporting dozens of distinct permission types (read, write, execute, delete, take ownership, change permissions, and more), assignable to any number of users or groups, with inheritance controlling how permissions propagate from parent folders to child objects.
- POSIX ACLs on Linux extend the basic owner/group/other model to support arbitrary additional user/group permission entries when the basic three-category model isn’t granular enough.
- Capability-based access control, used in some specialized systems and partially in Linux (via
capabilities(7)), takes a different philosophical approach: instead of asking “does this subject have permission to access this object” (requiring a check against the object’s ACL every time), a capability is an unforgeable token that a subject possesses, and simply holding the capability grants the associated access — access control is embedded in possession of the token itself rather than looked up per-request.
Access Control Across Platforms: A Comparative View
| Platform | Primary Model(s) |
|---|---|
| Windows | DAC (NTFS ACLs) + RBAC (security groups) + integrity levels (Mandatory Integrity Control) |
| Linux | DAC (owner/group/other, POSIX ACLs) + optional MAC (SELinux/AppArmor) + capabilities |
| macOS | DAC (UNIX permissions) + sandboxing entitlements (MAC-like) + TCC privacy framework |
| Android | Per-app UID sandboxing (a form of MAC) + runtime permissions (ABAC-like context sensitivity) |
| iOS | Strict app sandbox (MAC) + explicit per-capability user consent |
Windows deserves a specific mention for Mandatory Integrity Control (MIC), introduced with Vista: every process and object is assigned an integrity level (Low, Medium, High, System), and lower-integrity processes are restricted from modifying higher-integrity objects regardless of standard DAC permissions — this is part of what makes browser sandboxing effective on Windows, since a browser rendering process running at Low integrity is blocked from writing to most of the file system even if the logged-in user’s account would otherwise have DAC permission to do so.
A Practical Example: Layered Access Control in Action
Consider a request to modify a file on an enterprise Linux server with SELinux enabled:
- DAC check: Does the requesting user (or the process’s effective UID) have write permission on the file per standard UNIX permission bits?
- POSIX ACL check (if present): Does an extended ACL entry grant or restrict this specific user beyond the basic DAC bits?
- MAC check (SELinux): Does the security policy permit a process with this specific security context to write to an object with this file’s security context, independent of what the DAC/ACL layers already decided?
All three layers must permit the action for it to succeed — any single layer denying access is sufficient to block the request, which is precisely the point of defense in depth applied to access control specifically: a misconfiguration or oversight in one layer doesn’t automatically translate into a full compromise if the other layers are correctly configured.
Formal Access Control Models: A Brief Theoretical Note
Access control as a field has a rigorous academic foundation worth briefly acknowledging, since several formal models introduced decades ago still directly shape how modern systems reason about permission structures:
- The Bell-LaPadula model (1973), developed for military and government classification systems, formalizes confidentiality-focused MAC through two core rules: “no read up” (a subject at a given clearance level cannot read data classified above their level) and “no write down” (a subject cannot write data down to a lower classification level, preventing accidental or intentional leakage of sensitive information to less-trusted contexts). This model directly influenced later MAC implementations, including aspects of SELinux’s design philosophy.
- The Biba model (1975) addresses the complementary concern of integrity rather than confidentiality — preventing lower-integrity data or processes from corrupting higher-integrity ones, which is conceptually exactly what Windows’ Mandatory Integrity Control implements: a Low-integrity browser rendering process is prevented from writing to Medium or High-integrity system resources, directly mirroring Biba’s “no write up” principle.
- The Clark-Wilson model (1987) focuses specifically on well-formed transactions and separation of duties in commercial (rather than military) contexts, formalizing the idea that certain data can only be modified through specific, controlled procedures rather than direct, unconstrained access — a concept that underlies why financial systems enforce transaction workflows (like requiring dual approval for large transfers) rather than simply granting or denying raw read/write access to account balance data.
Understanding these formal models isn’t merely academic — they explain why certain access control systems are structured the way they are, and recognizing which underlying model a given system’s design borrows from (confidentiality-focused Bell-LaPadula-style thinking versus integrity-focused Biba-style thinking, for instance) can clarify what specific threat that system’s designers were actually trying to prevent.
Access Control and the Principle of Fail-Safe Defaults
A closely related design principle, also originating from the same 1975 Saltzer and Schroeder paper that formalized least privilege, is fail-safe defaults: an access control system should deny access by default, requiring explicit permission grants to allow anything, rather than defaulting to permissive access and requiring explicit restrictions to deny it. This principle shows up concretely across every access control implementation discussed above — a newly created file with no explicit ACL entries should not be readable by everyone; a newly deployed firewall should default to denying inbound traffic rather than allowing it; a newly provisioned cloud IAM role should start with zero permissions rather than broad ones. Systems that violate fail-safe defaults — where a misconfiguration or an omitted rule results in more access than intended rather than less — are considerably more dangerous in practice, since the failure mode of “accidentally too permissive” is silent and often goes unnoticed until actively exploited, whereas “accidentally too restrictive” tends to surface immediately as a visible, easily-reported functional problem.
Best Practices
- Apply least privilege as the guiding principle behind every access control configuration decision, regardless of which model is in use.
- Use MAC (SELinux/AppArmor) in addition to DAC on Linux systems handling sensitive data or exposed to untrusted input, since it provides a meaningful additional layer beyond standard permissions.
- Prefer RBAC over direct, individual permission assignment at any meaningful scale — it dramatically simplifies auditing and reduces the chance of inconsistent, drifted permissions across similar users.
- Regularly audit ACLs and group memberships for unused, overly broad, or stale grants — access control configuration reliably drifts over time without active maintenance.
- Consider ABAC or context-aware policy for particularly sensitive resources where static role assignment doesn’t adequately capture the risk factors that should influence an access decision (device trust, location, time).
- Don’t treat any single access control layer as sufficient on its own — layer DAC, MAC, and application-level authorization together for genuinely sensitive systems.
Summary
Access control is the general mechanism by which an operating system governs what subjects (users, processes) can do to which objects (files, resources), implemented through models ranging from discretionary (owner-controlled) to mandatory (centrally enforced policy) to role- and attribute-based approaches suited to enterprise and dynamic-context scenarios. Underneath every model, the kernel’s reference monitor concept enforces decisions on every relevant access attempt, and real-world systems typically layer multiple models together — DAC plus optional MAC on Linux, NTFS ACLs plus Mandatory Integrity Control on Windows, strict per-app sandboxing on mobile platforms — reflecting the reality that no single access control model perfectly balances flexibility, administrability, and security on its own.
FAQs
What’s the difference between DAC and MAC in simple terms? DAC lets a resource’s owner decide who else gets access; MAC enforces a centrally defined policy that not even the resource owner can override, providing stronger, more consistent guarantees at the cost of administrative flexibility.
Why would a system use both DAC and MAC together, like Linux with SELinux? Because they provide independent, complementary layers of protection — DAC offers familiar, flexible day-to-day permission management, while MAC provides a strict backstop that limits the damage even if DAC permissions are misconfigured or a process is compromised.
Is RBAC a replacement for DAC or MAC? Not exactly — RBAC is primarily an administrative model for organizing permission assignments (grouping into roles), and is often implemented on top of an underlying DAC or MAC enforcement mechanism rather than replacing it outright.
What is Mandatory Integrity Control on Windows, and how does it relate to MAC? It’s Windows’ own form of mandatory access control, assigning integrity levels to processes and objects and restricting lower-integrity processes from modifying higher-integrity ones — conceptually similar in spirit to SELinux/AppArmor, though narrower in scope, primarily used for sandboxing scenarios like browser process isolation.
How does access control relate to the principle of least privilege? Least privilege is a guiding principle for how access control should be configured — regardless of which model (DAC, MAC, RBAC, ABAC) is in use, applying least privilege means granting only the minimum access each subject genuinely needs, rather than defaulting to broad or convenient access.
References
- NIST SP 800-162 — Guide to Attribute Based Access Control (ABAC)
- NIST SP 800-53 — Access Control Family (AC controls)
- Red Hat Documentation — SELinux User’s and Administrator’s Guide
- Microsoft Learn — Access Control Overview (Windows) and Mandatory Integrity Control