The Most Boring Security Model—Still Running the Internet
Every developer has done it. You're debugging a deployment issue at 2 AM, something isn't working, and in desperation you type chmod 777. The problem goes away. You move on, vaguely aware you just committed a security sin but unsure exactly why.
Here's the thing: Unix permissions aren't complicated. They're deliberately simple. And that simplicity is the entire point.
Modern systems—containers, Kubernetes, cloud infrastructure—all still sit on Unix assumptions. The permission model designed in the 1970s remains the foundation of how we protect files, processes, and systems today. Most developers know chmod 755 but couldn't explain why that specific combination exists or what it actually means.
This article won't be a cheat sheet. It's a mental model. Once you understand how Unix permissions think, you'll never need to memorize flags again.
The Mental Model: A Building With Rooms and Keys
Forget the technical jargon for a moment. Think of a Unix system as a building.
- Files and directories are rooms
- Users are people
- Groups are clubs or teams that share access
- Permissions define what happens when someone tries to enter a room
The critical insight: permissions don't decide who you are. They decide what happens when you touch something. Your identity is established elsewhere (authentication). Permissions are purely about what actions are allowed once you're inside the building.
This is fundamentally different from how many modern access systems work, and it's worth understanding why.
Identity First: User, Group, Others
Every file in Unix has exactly three permission categories:
| Category | Symbol | The Analogy |
|---|---|---|
| Owner | u | The person whose name is on the lease |
| Group | g | Roommates or team members |
| Others | o | Everyone else on Earth |
When you access a file, Unix checks these in order: owner → group → others. First match wins. There's no negotiation, no "best of multiple groups," no complex policy evaluation.
This is where many people think Unix is "dumb." It's not—it's deterministic.
If you own a file, your owner permissions apply. Period. Even if you're also in the group and the group has more permissions than you do as owner, you get the owner permissions.
# Alice owns this file with read-only for owner, but full access for group
-r--rwx--- alice developers secret.txt
# Alice tries to write to it... DENIED
# Even though she's in 'developers' group, owner permissions apply first
This predictability is a feature, not a bug. You can reason about access by looking at ownership alone.
Read, Write, Execute — What They Actually Mean
This is where online tutorials usually fail. Let's do it properly.
For Files
| Permission | Symbol | What It Does |
|---|---|---|
| Read | r | Open and view the contents |
| Write | w | Modify or truncate the contents |
| Execute | x | Run the file as a program |
Straightforward enough. But here's where it gets interesting.
For Directories
Directories are not files. The permissions mean something completely different:
| Permission | Symbol | What It Does |
|---|---|---|
| Read | r | List what's inside (see filenames) |
| Write | w | Create, delete, or rename entries |
| Execute | x | Enter the directory (traverse into it) |
The building analogy makes this intuitive:
- Read = See the room layout through a window
- Write = Rearrange the furniture
- Execute = Walk through the door
Here's the mind-bender: execute on directories is the most important permission in Unix. Without it, you can't cd into a directory, and you can't access any file inside it—even if you have full permissions on those files.
# Directory with read but no execute
dr--r--r-- alice alice secret-folder/
# You can list the contents
$ ls secret-folder/
passwords.txt keys.txt
# But you can't access anything inside
$ cat secret-folder/passwords.txt
cat: secret-folder/passwords.txt: Permission denied
This is why you'll often see 755 on directories but 644 on files. Directories need execute to be traversable.
The ls -l Rosetta Stone
Let's decode a typical permission string:
-rwxr-x---
Break it into four sections:
| Position | Value | Meaning |
|---|---|---|
| 1 | - | File type (- = file, d = directory, l = link) |
| 2-4 | rwx | Owner permissions |
| 5-7 | r-x | Group permissions |
| 8-10 | --- | Others permissions |
So -rwxr-x--- means:
- Regular file
- Owner can read, write, and execute
- Group can read and execute (not write)
- Others have no access
Think of each three-character block as an access badge. The owner's badge has all three stamps; the group's badge is missing the write stamp; others have a blank badge.
# Common patterns you'll see
drwxr-xr-x # Directory: everyone can enter and list, only owner can modify
-rw-r--r-- # File: everyone can read, only owner can write
-rwx------ # Executable: only owner can run it
When the first character is d, it's a directory. When it's l, it's a symbolic link. The rest follows the same pattern.
chmod: Symbolic vs Numeric
There are two ways to change permissions: symbolic (human-readable) and numeric (compact). Neither is "better"—they're tools for different situations.
Symbolic Mode
Uses letters and operators to modify permissions:
# Add execute for owner
chmod u+x script.sh
# Remove write for group and others
chmod go-w config.txt
# Set exact permissions for everyone
chmod a=r public.txt
The syntax: [who][operator][permissions]
- Who:
u(owner),g(group),o(others),a(all) - Operator:
+(add),-(remove),=(set exactly) - Permissions:
r,w,x
Symbolic mode is great for incremental changes. "Add execute permission" is clearer than recalculating a number.
Numeric Mode
Uses octal (base-8) numbers. Each permission has a value:
| Permission | Value |
|---|---|
| Read | 4 |
| Write | 2 |
| Execute | 1 |
Add them up for each category:
# rwx = 4+2+1 = 7
# r-x = 4+0+1 = 5
# r-- = 4+0+0 = 4
chmod 754 script.sh # rwxr-xr--
chmod 644 config.txt # rw-r--r--
chmod 700 secret.sh # rwx------
Why octal? Because it maps perfectly to the three-bit permission model. Each digit (0-7) represents exactly one three-character block. It's not cryptic—it's honest. The number tells you exactly what's happening with no ambiguity.
Numeric mode is ideal for scripts and when you need to set permissions absolutely.
Ownership Is Power: chown and chgrp
Permissions control what you can do. Ownership controls who you are in relation to a file.
# Change owner
chown alice file.txt
# Change group
chgrp developers file.txt
# Change both at once
chown alice:developers file.txt
Here's the security-critical part: only root can change file ownership. Regular users can only give away files to groups they belong to (via chgrp), not claim ownership of others' files.
This is the landlord principle: only the building owner can reassign apartments. Tenants can't just move into someone else's unit.
Why 777 Is Almost Always Wrong
When you chmod 777, you're saying: "Anyone on this system can do anything to this file."
It's the equivalent of leaving your apartment door open, unlocked, with a sign saying "free stuff." In a multi-user environment, it's a security failure. In a container or server environment, it often signals a failure to understand the problem.
Usually, 777 happens because:
- The actual owner or group is wrong
- The service is running as the wrong user
- Parent directory permissions are blocking access
The fix is never "give everyone full access." The fix is understanding why access is being denied and correcting the root cause.
Groups as Simplified RBAC
If you've read my previous article on RBAC, you know that Role-Based Access Control assigns permissions through roles. Unix groups are a primitive version of this—with intentional limitations.
# Common system groups
www-data # Web server processes
docker # Docker socket access
sudo # Administrative privileges
Key differences from modern RBAC:
| Unix Groups | Modern RBAC |
|---|---|
| One group per file | Multiple roles per resource |
| Static assignment | Dynamic, contextual |
| Local to system | Distributed, federated |
| No inheritance | Role hierarchies |
Unix groups are RBAC with the ambition dial turned way down. But here's the thing: that's often enough. The simplicity makes the system auditable. You can ls -la a directory and immediately understand who has access.
Controlled Rule-Breaking: setuid, setgid, Sticky Bit
Sometimes the basic model isn't enough. Unix provides three special permission bits for controlled exceptions.
setuid (Set User ID)
When a file has setuid, it runs with the owner's permissions, not the user's.
-rwsr-xr-x root root /usr/bin/passwd
# ^-- 's' instead of 'x' = setuid
The passwd command needs to modify /etc/shadow, which only root can write. Instead of making every user root, the executable runs as root regardless of who invokes it.
setgid (Set Group ID)
Similar concept for groups. On directories, setgid has a special meaning: new files inherit the directory's group, not the creator's primary group.
drwxrwsr-x developers developers /shared/project/
# ^-- setgid on directory
This is essential for team collaboration. Everyone's files in /shared/project/ automatically belong to the developers group.
Sticky Bit
On directories, the sticky bit means only the file owner (or root) can delete files—even if others have write permission on the directory.
drwxrwxrwt root root /tmp
# ^-- 't' = sticky bit
This is why you can't delete other users' files in /tmp, even though everyone has write access.
These aren't hacks—they're formalized privilege leaks. The system acknowledges that sometimes you need to bend the rules, and provides structured ways to do so safely.
When Permissions "Look Right" But Still Fail
Experienced sysadmins know this pain: permissions look correct, but access is still denied. Common culprits:
Missing Execute on Parent Directories
To access /home/alice/projects/secret.txt, you need execute on /home, /home/alice, AND /home/alice/projects. Any gap breaks the chain.
Filesystem Mount Options
A filesystem mounted with noexec won't run executables regardless of file permissions:
mount -o noexec /dev/sdb1 /mnt/usb
# Now chmod +x does nothing for files here
ACLs Overriding Classic Permissions
Access Control Lists extend the basic model. If ACLs are in play, what you see with ls -l might not tell the whole story.
# Check for ACLs
getfacl file.txt
SELinux and AppArmor
Mandatory Access Control systems like SELinux can deny access even when permissions allow it. They operate at a different layer entirely.
The lesson: Unix permissions are necessary but not always sufficient. They're the foundation, not the complete security picture.
Why This Model Survived 50 Years
The Unix permission model emerged from research systems in the early 1970s. It's still the foundation of Linux, macOS, BSD, and countless embedded systems. Why?
Minimal primitives. Three categories, three operations, one owner, one group. Everything builds from this.
Composability. You can understand any permission string by decomposing it into its parts. No hidden state, no implicit rules.
Human-readable. ls -l gives you immediate insight. No need for special tools or queries.
Auditable. You can mentally trace access for any file in seconds.
Modern systems add complexity because they need it—multi-tenant cloud environments, dynamic resources, contextual access. But that complexity comes with cost: misconfiguration, unexpected interactions, and harder mental models.
Unix permissions are the opposite. They sacrifice flexibility for clarity. And for local, file-based access control, that trade-off has proven remarkably durable.
Learn chmod, But Understand the Model
Memorizing flags is useless. Understanding the mental model makes you dangerous.
When you see a permission problem, don't reach for 777. Instead, ask:
- Who owns this? Is it the right user and group?
- What category am I? Owner, group, or other?
- What am I trying to do? Read, write, or execute?
- Is the path accessible? Check parent directories.
- Is something else blocking? ACLs, SELinux, mount options?
Once you internalize this, chmod stops being magic. It becomes a precise tool for expressing exactly what access you want.
The Unix permission model isn't sophisticated. It's not flexible. It's not modern.
It just works.
Next in this series: how Docker bends Unix permissions without breaking them, and why container security still relies on these 50-year-old primitives.
