Who is asking, and what do they want to do?
Across this rung you have built up everything a file IS: an abstraction with attributes, opened through a descriptor into the open-file table, found by walking a path through directories, and named — perhaps several times over — by hard links and symbolic links. Every one of those operations quietly assumed you were allowed to do it. This guide is about that assumption. Protection is the file system's answer to a single question asked on every access: this particular asker wants to perform this particular action on this particular file — yes or no?
Notice the three pieces in that question, because every access-control scheme is just a way to encode answers to it: a subject (who is asking — a user, or really the process acting on their behalf), an object (what they want it done to — here, a file or directory), and an operation (read, write, execute, delete). The kernel is the building manager who checks your badge at every door. You hand over a request; it consults its records; it opens the door or refuses. Crucially, this check lives in the kernel, on the privileged side of the user/kernel boundary you met in the foundations rung — a user program cannot simply decide to skip it, because the decision is made by code the user program cannot touch.
The big picture: the access matrix
Before the rwx bits make sense, it helps to see the ideal they approximate. Imagine an enormous table — the access matrix — with one row per subject and one column per object, and in each cell the exact set of operations that subject may perform on that object. Row 'alice', column '/home/alice/diary.txt', cell says 'read, write'. Row 'bob', same column, cell is empty: bob may do nothing. This table is the complete, exact truth of who-can-do-what. Every real protection system is a way to store this table without actually building something so vast it would dwarf the files themselves.
The matrix is mostly empty (most subjects can touch almost no objects), so nobody stores it whole. There are two natural ways to slice it instead. Slice it by COLUMN and you store, with each object, the list of subjects allowed to touch it — that is exactly an access-control list (ACL), and it is how most file systems work. Slice it by ROW and you give each subject a list of the objects it may touch, like a key ring — that is a capability list, the model behind file descriptors and token-based cloud systems. The familiar rwx permission bits, as we will see, are a compressed third option: an ACL squeezed down so hard it fits in a handful of bits.
the access matrix (ideal, mostly empty)
diary.txt report.doc /bin/ls
alice rw rw x
bob -- r x
carol -- -- x
by COLUMN -> store with each FILE the list of who may touch it = ACL
by ROW -> give each USER a list of files they may touch = capabilitiesThe rwx bits: a clever nine-bit shorthand
The Unix designers made a frugal bet: instead of storing a full list of users per file, store the answer for just THREE categories of subject. Every file records its owner (a single user) and an owning group (a named set of users), and then carries three groups of three permission bits — read, write, execute — one group for the owner, one for the group, one for everyone else ("other"). That is nine bits total, and you have already seen where they live: right inside the file's inode, alongside the size and timestamps, as one of the file attributes from the first guide of this rung. The bits travel with the inode, not with any name, so all of a file's hard links share the same permissions — there is only one inode.
You read the nine bits left to right as three triples: owner, group, other. The string rwxr-xr-x means the owner may read, write, and execute; the group may read and execute but not write; and everyone else may also read and execute but not write. A dash is a missing permission. The same nine bits are often written as a three-digit octal number, because each triple is exactly three bits: r is 4, w is 2, x is 1, and you add them up per triple. So rwx is 4+2+1 = 7, r-x is 4+0+1 = 5, and the whole thing is 755 — which is why "chmod 755" and "rwxr-xr-x" say the very same thing.
How the kernel actually checks is a detail worth getting right, because it surprises people. It does NOT combine the three triples. It picks the single most specific one and uses only that. If you are the file's owner, the kernel checks the OWNER bits and stops — even if the group or other bits are more generous. If you are not the owner but are in the file's group, it checks the GROUP bits and stops. Otherwise it checks OTHER. A genuine consequence: an owner can be locked out of their own file while strangers can read it, with permissions like ---r--r--, because owner is checked first and finds no rights. The most specific bucket wins, generous or not.
Read, write, execute — and the trap of directories
For an ordinary file the three permissions mean what you would guess. Read lets you see the bytes; write lets you change them; execute lets you run the file as a program. Note the OS does not infer "this is runnable" from the file's name or contents — it asks the execute bit. This is the same separation the file-type guide stressed: a name extension is a hint, but the kernel trusts the metadata. Without the execute bit set, a perfectly valid program simply will not run, and with it set on a data file, the kernel will dutifully try to execute nonsense.
Directories are where beginners get bitten, because the SAME three letters mean something different there. Recall from the directories guide that a directory is really a file whose contents are a list mapping names to inode numbers. So: read on a directory lets you LIST the names inside it. write on a directory lets you CHANGE that list — create, rename, or delete entries — which is why you can delete a file you cannot even write to, as long as you can write the directory that names it. And execute on a directory has nothing to do with running anything; it means "search" — permission to traverse THROUGH this directory to reach things named beneath it. This is the bit a path walk actually checks at each step.
When three buckets are not enough: ACLs
The nine-bit scheme is wonderfully compact, but it can only ever express three answers: one for the owner, one for one group, one for everyone else. Real life routinely needs more. Suppose alice owns a report and wants bob to read AND write it, carol to read it only, the 'finance' group to read it, and nobody else to see it at all. There is no assignment of owner/group/other bits that captures that — bob and carol need different rights, but "other" gives everyone the same answer. The bits have run out of expressiveness. This is the moment an access-control list earns its keep.
An ACL drops the three-bucket compromise and stores, attached to the file, an explicit list of entries — each entry naming a specific user or group and the exact permissions they get. It is the per-file COLUMN of the access matrix made real: 'bob: rw', 'carol: r', 'finance group: r', and a default for everyone else. Now each subject can get a tailored answer. The classic rwx bits do not vanish, by the way; on modern systems they survive as a compact special case, and an ACL is the general form you reach for when the three buckets cannot say what you mean. Windows leans on ACLs by default; Linux and macOS keep the rwx bits as the everyday case and layer ACLs on top when needed.
ACLs are strictly more expressive, so why not use them everywhere? The honest trade-off is cost and clarity. An ACL takes more space than nine bits and is slower to check, but the deeper price is human: a file with twenty ACL entries is far harder to reason about than rwxr-x---, and a permission you cannot easily see is a permission that quietly grants access you forgot about. This connects to a principle that should now feel familiar from the protection rung — the principle of least privilege: grant each subject the minimum rights it needs and no more. Both bits and ACLs serve that goal; bits keep it simple, ACLs keep it precise, and a thoughtful admin reaches for whichever makes the actual policy easiest to state AND to audit.
Honest limits: what permissions do not promise
It is tempting to feel safe once your files have tidy permissions, so let us be precise about what they do and do not buy you. First, there is almost always one subject the bits do not constrain at all: the superuser (root on Unix). Root is checked against the permission bits and, by design, passes everything — the building manager who holds the master key. Permission bits protect users from each other; they do not protect anyone from root, and they do not protect a file from a kernel-level attacker who has already crossed the privilege boundary. Recall the protection domain idea: root simply operates in a domain that contains essentially all rights.
Second, permissions assume the kernel already knows WHO is asking, and they say nothing about how it learned that. If an attacker steals your password or hijacks a process running as you, the permission check works perfectly — and faithfully grants the attacker everything YOU were allowed. Getting identity right is a separate problem (authentication), and turning a low-privilege foothold into a high one is its own attack class (least privilege exists precisely to shrink the damage when that happens). Permissions answer "may this subject?"; they trust someone else to have answered "who is this subject?" correctly.
- A process makes a request, e.g. open("/a/b/c.txt", read). The library wraps it as a system call and traps into the kernel — the only path to a permission decision.
- The kernel resolves the path, checking execute (search) permission on each directory along the way: / then /a then /a/b. Any failure stops the walk with a denial.
- Reaching c.txt, the kernel reads its inode to find the owner, group, and (rwx) bits or ACL — the metadata that holds the answer.
- It compares the asking subject against that metadata, choosing the most specific match (owner, else group, else other; or the matching ACL entry) and granting only those rights.
- If the requested operation is allowed, the call proceeds and returns a descriptor; otherwise it returns a permission-denied error and the file is never touched.
That walk closes the loop on the whole rung: a path resolved through directories (guide 3), an inode reached perhaps via a hard link (guide 4), permission checked against its bits or ACL, and finally a descriptor handed back into the open-file table (guide 2) — at which point the file (guide 1) is yours to read or write. Permissions are the gate this whole machine passes through, and now you can see exactly how each piece you learned fits together to answer one small, constant question: yes, or no?