Linux file permissions, from rwx to capabilities
What ls -l is really telling you — and how the bits decide who can do what.
Explain like I'm 5
Every file in Linux is like a little clubhouse with a sign on the door. The sign answers two questions: who is this about, and what are they allowed to do?
There are three kinds of who: you (the owner), your group (your friends), and everyone else. And three kinds of what: look at it (read), change it (write), and use/run it (execute).
Linux permissions answer “what can the owner, the group, and everyone else each do — read, write, or execute — to this file?”
Beginner
Run ls -l and you get lines like this:
$ ls -l report.txt
-rw-r--r-- 1 alice staff 4096 Jun 20 09:14 report.txtThat first column, -rw-r--r--, is the permissions. Read it in four chunks:
| Chunk | Meaning |
|---|---|
- | File type: - file, d directory, l symlink. |
rw- | Owner (alice): read + write, no execute. |
r-- | Group (staff): read only. |
r-- | Other (everyone else): read only. |
The three permission bits are always in the order r (read), w (write), x (execute); a - means that permission is off. After the permissions, alice staff are the owning user and owning group.
You change permissions with chmod, and ownership with chown:
chmod g+w report.txt # add write for group
chown alice:devs report.txt # set owner alice, group devsIntermediate
Each permission has a number: read = 4, write = 2, execute = 1. Add them per group and you get the familiar three-digit octal mode.
On a file, x means run it as a program. On a directory, x means you may traverse into it (cd, and access files by name). So a directory often needs r-x: r to list its contents, x to enter it. Read without execute on a directory is nearly useless.
| Permission | On a file | On a directory |
|---|---|---|
| r | read contents | list the names inside |
| w | modify contents | create/delete/rename entries |
| x | execute as a program | enter/traverse (access entries by name) |
umask controls the default permissions of newly created files. It's a mask of bits to remove from the base mode (666 for files, 777 for directories). The common 022 yields 644 files and 755 directories.
chmod -R 755 . on a source tree is a classic mistake: it stamps the execute bit onto every file, not just directories. Use the capital X — chmod -R u+rwX,go+rX . — which adds execute only to directories and files that are already executable. It does the right thing for both at once.
Both calculations are fiddly by hand — the chmod calculator and umask calculator do them instantly.
Advanced
Beyond the nine basic bits there's a fourth octal digit for special bits, and they're where a lot of subtle behaviour (and risk) lives.
| Bit | Octal | Effect |
|---|---|---|
| setuid | 4000 | An executable runs with the owner's privileges, not the caller's. passwd uses this to edit /etc/shadow as root. |
| setgid | 2000 | On a binary: run as the owning group. On a directory: new files inherit the directory's group — great for shared project folders. |
| sticky | 1000 | On a directory: only a file's owner (or root) can delete it, even if others can write. This is why anyone can create files in /tmp but not delete each other's. |
In a long listing these appear in the execute column: s (setuid/setgid with execute), S (set but no execute), t/T (sticky). For example /tmp shows drwxrwxrwt.
ACLs (Access Control Lists) extend the model when plain user/group/other isn't enough — for example granting one extra user write access without changing the group. A + at the end of the mode in ls -l signals ACLs are present.
setfacl -m u:bob:rwx project/ # give bob rwx, no group change
getfacl project/ # view the ACL
# the trailing + means ACLs are set:
# drwxr-xr-x+ 2 alice devs 4096 ... projectA default ACL on a directory (setfacl -d -m u:bob:rwx project/) is inherited by everything created inside it later — the closest Linux gets to Windows-style inheritance. It's the clean way to make a shared project directory where new files are automatically accessible to a team, without relying on setgid + umask gymnastics.
Deep dive
Permissions are a core part of Linux security, and a few patterns are classic findings in any audit.
World-writable files (o+w) let any user tamper with them — catastrophic for scripts or config that run as root. Rogue setuid-root binaries are a top privilege-escalation vector: a bug in a setuid-root program runs with root power. Hunt for both regularly.
# Every setuid-root binary on the system
find / -perm -4000 -user root -type f 2>/dev/null
# World-writable files (excluding symlinks)
find / -xdev -type f -perm -0002 2>/dev/null
# World-writable directories without the sticky bit (risky)
find / -xdev -type d -perm -0002 ! -perm -1000 2>/dev/nullHow it works under the hood. Every process has a UID/GID (and effective UID/GID). When you open a file, the kernel compares your effective IDs against the file's owner/group/other bits, in that order, and grants the first matching class. That's why if you're the owner, the group and other bits never apply to you — even if they're more permissive.
Instead of giving a program all of root via setuid, Linux capabilities grant just the slice it needs. ping no longer needs setuid-root — it only needs CAP_NET_RAW. Set with setcap cap_net_raw+ep /usr/bin/ping; inspect with getcap. Smaller blast radius if the binary is exploited.
Some protections live in filesystem attributes, not the permission bits. chattr +i file makes a file immutable — even root cannot modify or delete it until chattr -i clears the flag (check with lsattr). Handy for locking down config or audit logs, and a favourite hiding spot for malware persistence, so it's worth knowing it exists.
Note too that inside a container, UID 0 may be mapped to an unprivileged host UID via a user namespace, so "root" in the container has none of root's power on the host — the permission model still applies, just remapped (see how containers work).
Worth knowing that Mandatory Access Control (SELinux, AppArmor) layers on top of these discretionary permissions. Even if the rwx bits would allow an action, an SELinux policy can still deny it — which is why ls -l looks fine but access is refused, and why you check ausearch/dmesg for denials.
Linux permissions grant read/write/execute to three classes — owner, group, other — checked first-match by the kernel against a process's effective UID/GID. Octal modes encode them (r=4, w=2, x=1); umask sets defaults; setuid/setgid/sticky add special behaviour; ACLs and capabilities add precision; and MAC (SELinux/AppArmor) can override it all. Most security incidents trace back to world-writable files or careless setuid-root binaries.
Frequently asked questions
What does chmod 755 mean?
Owner gets read+write+execute (7 = 4+2+1), group gets read+execute (5 = 4+1), and other gets read+execute (5). It's a common mode for executables and directories that everyone may use but only the owner may modify.
What's the difference between execute on a file and on a directory?
On a file, execute means you can run it as a program. On a directory, execute means you can traverse into it and access files by name. To list a directory's contents you also need read; to enter and use it you need execute.
What is the sticky bit used for?
On a directory, the sticky bit restricts deletion so that only a file's owner (or root) can remove it, even when others have write permission. The classic example is /tmp, which is world-writable but has the sticky bit so users can't delete each other's files.
What does umask 022 do?
umask removes permission bits from the default base mode. With 022, the group and other write bits are removed, so new files default to 644 (rw-r--r--) and new directories to 755 (rwxr-xr-x).
Why can't I access a file even though the permissions look right?
Common causes: you lack execute (traverse) permission on a parent directory in the path; an ACL or the first-match class rule applies different bits than you expect; or a Mandatory Access Control system like SELinux/AppArmor is denying it regardless of the rwx bits. Check the full path's permissions and the audit log.
ShellQuest turns concepts like this into bite-sized lessons, puzzles and labs you actually practise.
Join the waitlist