Unix Permissions
Unix/Linux File Permissions
Unix-like systems control access to files, directories, devices and other system resources through a permission model whose core principle is simple: every access decision is based on the identity of the requesting user and a set of permission bits attached to the resource.
Three Permission Types
| Permission | On files | On directories |
|---|---|---|
Read (r) | Read the file's contents | List the filenames it contains |
Write (w) | Modify the file's contents | Create or delete files within it |
Execute (x) | Run the file as a program | Access the directory's contents (traverse it) |
A dash (-) in place of any of these means that permission is not granted.
Three Classes of Users
Every file has three separate sets of permissions, one for each class of user: the owner (u), usually the user who created the file and typically given full control; the group (g), covering users who belong to the file's group and allowing shared permissions for team access; and others (o), everyone else on the system, who normally get the most restrictive permissions of the three.
Reading Permissions: ls -l
A directory listing shows all three permission sets at once:
-rwxr-xr-- 1 alice staff 1234 Jun 30 10:00 script.sh
| Position | Meaning | Value |
|---|---|---|
| 1 | File type | - (regular file) |
| 2–4 | Owner (alice) | rwx |
| 5–7 | Group (staff) | r-x |
| 8–10 | Others | r-- |
Numeric (Octal) Permissions
Each permission has a numeric value — read is 4, write is 2, execute is 1 — and the three values for a given class are summed to give one octal digit: rwx is 4+2+1=7, r-x is 4+0+1=5, r-- is 4+0+0=4. So chmod 754 script.sh sets the owner to rwx (7), the group to r-x (5), and others to r-- (4) — the same permissions shown in the ls -l example above.
| Command | Result | Typical use |
|---|---|---|
chmod 644 file | rw-r--r-- | Config files, documents |
chmod 755 file | rwxr-xr-x | Public scripts, binaries |
Changing Ownership
chown changes a file's owner (and, optionally, its group), and requires appropriate privileges — usually sudo:
# Change owner to bob
sudo chown bob file.txt
# Change owner and group
sudo chown bob:developers file.txt
# Recursive (all files in a directory)
sudo chown -R bob:developers /project/
Changing Permissions
chmod changes a file's permission bits, either symbolically or numerically:
# Symbolic mode
chmod u+x script.sh # add execute for owner
chmod g-w file.txt # remove write for group
chmod o=r file.txt # set others to read-only
chmod a+r file.txt # add read for all
# Numeric mode
chmod 755 script.sh # rwxr-xr-x
chmod 600 key.pem # rw-------
Special Permissions
Beyond the basic read/write/execute bits, Unix has three special permission bits worth knowing. Set User ID (SUID), numeric value 4000, makes a program run with its owner's privileges rather than the invoking user's — /usr/bin/passwd is a classic example, since changing a password requires writing to /etc/shadow, which ordinary users cannot do directly:
chmod u+s program
Set Group ID (SGID), numeric value 2000, makes new files created within a directory inherit that directory's group rather than the creating user's default group — useful for shared team directories:
chmod g+s directory
The sticky bit restricts deletion within a world-writable directory so that only a file's own owner (or root) can delete or rename it — exactly the property needed on shared, world-writable directories like /tmp and /var/tmp, to stop one user deleting another's files:
chmod +t /tmp
Directory Permissions in Practice
Directories specifically require execute permission to access their contents at all, which produces some easily-overlooked combinations: r-- allows listing filenames but not opening any of them; r-x allows listing and opening files whose names are known; -wx allows creating or accessing files without being able to list what's there; and rwx gives full access. To stop others from listing a directory's contents entirely:
chmod o-rwx private_dir
Default Permissions (umask)
umask controls the default permissions given to newly created files and directories. The maximum a newly created file or directory can start with is 666 (files) or 777 (directories); the actual permissions granted are that maximum minus the umask. A umask of 022 therefore leaves new files at 644 and new directories at 755:
# View current umask
umask
# Set umask for current session
umask 077
Permission Pitfalls
A handful of mistakes account for most real permission problems: making a script world-writable (chmod 777 script.sh), so any user on the system can silently modify it; setting SUID on a custom script rather than a trusted system binary, which is a serious privilege-escalation risk since the script now runs with its owner's privileges regardless of who invokes it; a shared, writable directory that is missing the sticky bit, letting any user delete files they don't own; and an over-permissive umask such as 000, which leaves every newly created file readable (and writable) by everyone.
Security Best Practices
The principle of least privilege — grant only the permissions a file or process actually needs, nothing more — is the single most important rule here, and it is one of the eight design principles Saltzer and Schroeder set out in their foundational 1975 paper on protection in computer systems, alongside fail-safe defaults and complete mediation [1]. In practice: private keys should be 600, not 644. Permissions are also worth auditing regularly rather than trusted to stay correct once set:
# Find world-writable files
find / -perm -o+w -type f 2>/dev/null
# Find SUID/SGID binaries
find / -perm -4000 -type f 2>/dev/null
# Find files owned by a user or group that no longer exists
find / -nouser -o -nogroup 2>/dev/null
Groups are the standard mechanism for collaboration without over-granting access to everyone:
# Create a shared group
sudo groupadd developers
# Add users to the group
sudo usermod -aG developers alice
# Set directory group ownership
sudo chown :developers /project/
sudo chmod 770 /project/
And finally: avoid running as root day-to-day. Use sudo only when a specific operation genuinely needs elevated privileges, and never leave a root shell open longer than that operation takes.
Real-World Permission Issues
Most permission-related incidents share a common shape: a resource ends up more accessible than intended, and the failure only becomes visible once something goes wrong. /etc/shadow being readable by a non-root user is a critical breach in itself, since it exposes password hashes for offline cracking; a webserver configuration file being world-readable can expose database credentials directly. World-writable web directories let an attacker upload a malicious script (a "web shell") that the server will then execute, often leading to complete compromise. And a custom SUID binary with its own bug — a buffer overflow, say — can turn a minor coding mistake into a direct path to root, since the flawed code was already running with elevated privileges by design; see Buffer Overflows & Fuzzing for how those bugs actually get found and exploited.
Access Control Lists (ACLs)
The owner/group/others model assigns exactly one set of permissions per class, which is not always fine-grained enough. Access Control Lists extend it with per-user and per-group permissions on top of the basic model:
# Grant a specific user read-only access
setfacl -m u:bob:r file.txt
# Grant a specific group read+execute access
setfacl -m g:developers:rx /project/
# Set a default ACL, inherited by new files created within a directory
setfacl -d -m g:developers:rwx /project/
# View a file's ACL
getfacl file.txt
Unix Permissions in Security Context
Permissions are one layer of a broader defence-in-depth strategy, not a complete answer on their own — they matter precisely because they keep working even when some other control fails. They interact with, rather than replace, other controls: user authentication verifies who is asking; firewalls (see Port Scanning & Firewalls) control what can reach a host over the network in the first place; encryption (see Introduction & Encryption) protects data at rest even if access controls are somehow bypassed; and mandatory access control systems such as SELinux or AppArmor enforce policy that even a compromised root process cannot override, going beyond what discretionary Unix permissions alone can guarantee. Anderson's Security Engineering covers how the Unix/POSIX discretionary access-control model sits alongside these other layers, and where its real-world weaknesses have historically shown up, in much greater depth [2]. Particular areas worth deliberate attention: web server file permissions, database file protection, SSH key permissions (chmod 600 ~/.ssh/id_rsa), log file permissions (to prevent tampering with an audit trail), and cron job file permissions.
Ethical Considerations
Configuring permissions correctly is partly a technical skill and partly a duty: system administrators are responsible for setting appropriate permissions on shared infrastructure, and developers are responsible for requesting no more privilege than their software genuinely needs. In shared environments, permissions decisions have real privacy implications — an overly permissive setting can expose one user's files to everyone else on the system — and there is a genuine, ongoing balance to strike between security and usability, since a permission model too strict to work with in practice tends to get worked around rather than respected.
Summary
- Unix permissions are organised around three classes — owner, group, others — and three permission types: read, write, execute.
- Permissions can be set symbolically or numerically (octal); numeric mode sums 4/2/1 per class.
- SUID, SGID and the sticky bit are special-purpose bits with real security implications if misapplied.
- ACLs extend the basic model with per-user and per-group permissions.
- Least privilege and regular auditing are the two habits that catch most real-world permission mistakes before they become incidents.
References
- Saltzer, J. H. & Schroeder, M. D. (1975). The Protection of Information in Computer Systems. Proceedings of the IEEE, 63(9), 1278–1308. https://doi.org/10.1109/PROC.1975.9939
- Anderson, R. (2020). Security Engineering: A Guide to Building Dependable Distributed Systems (3rd ed.). Wiley. Freely available online at https://www.cl.cam.ac.uk/archive/rja14/book.html