C++ / a working model

159 / 163   ·   C11   ·   8 min

Access Control

Keep this sentence

This chapter shows how an operating system converts a security policy into a concrete allow-or-deny verdict for every resource request, emphasizing the duties of the reference monitor, the subject-object model, and the efficiency-versus-flexibility trade-offs of access-control lists versus capabilities.

In this lesson
  1. The Core Challenge of Access Decisions
  2. Subjects, Objects and Authorization
  3. Lists versus Tokens: Two Classic Mechanisms
  4. Cheap Special Cases via Virtualization
  5. Example
  6. Exercise

Official chapter PDF

The Core Challenge of Access Decisions

Once identity is established the kernel must instantly decide whether the request complies with policy. The decision occurs after the system-call trap but before the operation itself, inside a component called the reference monitor. That monitor has to be both correct and fast; otherwise either illegal operations slip through or the whole machine becomes unusable.

Subjects, Objects and Authorization

A subject is typically a process acting for a user, an object is a file, device or memory region, and an access mode is read, write or execute. Authorization simply asks whether that particular subject-object-mode triple is permitted by policy. Any omitted check violates the principle of complete mediation.

Lists versus Tokens: Two Classic Mechanisms

An access-control list hangs a roster of permitted subjects on the object, like a guest list at a club door. A capability is an unforgeable token given to the subject, like a key that opens only one lock. Lists make revocation centralized, tokens make possession decentralized; the operating system must pick one data structure or the other.

Cheap Special Cases via Virtualization

Once a process is given exclusive virtual memory or a virtual device, later accesses need no further software mediation; the hardware page tables or device mapping already enforce isolation. This “authorize once, use freely” pattern amortizes the check cost over the mapping step and therefore reduces overhead without weakening security.

Pitfalls

  • Checking only at open time and skipping later reads or writes leaves a TOCTOU window.
  • Once a capability has been copied, precise revocation becomes nearly impossible.
  • Overly coarse ACLs prevent administrators from expressing fine-grained policy.

Run an example

Minimum C11 · complete program · Download .c

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool check_access(const char *subject, const char *object, char access) {
    if (strcmp(object, "/home/report") == 0) {
        if (strcmp(subject, "alice") == 0) return (access == 'r' || access == 'w');
        if (strcmp(subject, "bob") == 0) return (access == 'r');
        return false;
    }
    if (strcmp(object, "/etc/config") == 0) {
        return (strcmp(subject, "root") == 0);
    }
    return false;
}

int main(void) {
    struct {
        const char *user;
        const char *file;
        char mode;
    } tests[] = {
        {"alice", "/home/report", 'w'},
        {"bob", "/home/report", 'w'},
        {"bob", "/home/report", 'r'},
        {"root", "/etc/config", 'r'},
        {"alice", "/etc/config", 'r'}
    };
    int n = sizeof(tests) / sizeof(tests[0]);
    for (int i = 0; i < n; i++) {
        bool ok = check_access(tests[i].user, tests[i].file, tests[i].mode);
        printf("%s %c %s -> %s\n", tests[i].user, tests[i].mode, tests[i].file, ok ? "yes" : "no");
    }
    return 0;
}

Compile locally

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-55-access-control.c -o example && ./example

Expected result

alice w /home/report -> yes
bob w /home/report -> no
bob r /home/report -> yes
root r /etc/config -> yes
alice r /etc/config -> no

CHECK YOUR UNDERSTANDING

Close the answer. Explain it.

Why does an operating system typically perform the access check only at open time rather than on every subsequent read or write?

Show a reference answer

The file descriptor returned by a successful open acts as a capability; later operations simply use that descriptor, preserving the original policy while avoiding repeated kernel traps.

Check the sources

Drafts and official chapters change. The version mark is only the example’s minimum.

Back to the catalog