UNIX File Permissions
The 9-bit permission model
UNIX file permissions use a simplified ACL scheme with three fixed domains:
| Domain | Representation | Bits |
|---|---|---|
| User (owner) | u | Read, Write, eXecute |
| Group | g | Read, Write, eXecute |
| Other (everyone else) | o | Read, Write, eXecute |
Each file has a 9-bit permission mask, typically displayed as rwxrwxrwx (user/group/other). The kernel stores these bits in the file’s inode.
Octal representation
Permissions are commonly given in octal, where r = 4, w = 2, x = 1:
| Numeric | Bits | Meaning |
|---|---|---|
7 | rwx | Read + write + execute |
6 | rw- | Read + write |
5 | r-x | Read + execute |
4 | r-- | Read only |
0 | --- | No access |
So chmod 640 file means: owner rw- (6), group r-- (4), other --- (0).
Special permission bits
| Bit | Octal | Meaning |
|---|---|---|
SetUID (s) | 4000 | File executes with the owner’s UID, not the caller’s. Used by passwd, sudo |
SetGID (s) | 2000 | File executes with the file’s group; on directories, new files inherit the directory’s group |
Sticky bit (t) | 1000 | On a directory, only the file owner (or root) can delete or rename files — used on /tmp |
SetUID is a powerful (and dangerous) mechanism: a SetUID root programme runs with full kernel privileges. Vulnerabilities in SetUID programmes are a classic privilege-escalation vector.
Access check algorithm
When process P tries to open file F for operation O:
- If P’s effective UID is 0 (root), access is granted unconditionally (unless the file system is mounted
noexecor read-only, or the file is on NFS withroot_squash). - If P’s effective UID equals F’s owner UID, the owner permission bits are checked.
- Else, if P’s effective GID (or any supplementary group) equals F’s group GID, the group permission bits are checked.
- Else, the other permission bits are checked.
For directories, r permits listing, w permits creating/deleting entries, and x permits traversal (using the directory in a path).
The open-time check
UNIX checks permissions at open() time, not at each read() or write(). The returned file descriptor acts as a capability — once obtained, the process can use it until close() even if the file’s permissions are subsequently changed. This is efficient (check once, use many times) but means a process can retain access to a file whose permissions have been revoked, as long as it does not close and reopen the descriptor.
Performing the check on every read()/write() would be safer but more expensive, and would require handling the case where a descriptor becomes invalid mid-operation.
The root user
UID 0 (root) bypasses all permission checks. This is a convention implemented in the kernel, not a property of the permission bits. The username “root” is just a mapping in /etc/passwd; what matters is UID 0. If you change root’s UID to 1000, processes running under that UID lose special privileges, and the old UID 0 (now unnamed in /etc/passwd) retains them.
Past Paper Questions
2025 Paper 2 Question 3(c): Describe how an administrator might configure users, groups and file permissions to create files with specific permission patterns. [7 marks]
2025 Paper 2 Question 3(d): What happens if root’s UID is changed from 0 to 1000? [4 marks]