File Permissions & Ownership
Every file, directory and device in Linux is guarded by a permission model: read, write and execute for the owner, the group and everyone else. Learn to read ls -l output, change modes with chmod in octal and symbolic form, manage ownership with chown and chgrp, control default modes with umask, and understand the setuid, setgid and sticky bits that production systems rely on every day.
What is this?
Every file, directory and device on Linux carries an owner (a user), a group, and nine permission bits arranged into three triples — read, write and execute — that apply to the owner, the group, and everyone else. The kernel enforces these bits on every open, read, write and execute system call, so a wrong mode is either a security hole or the exact reason a service suddenly refuses to start. Get this model right and you can make any file readable only by its owner, share a directory with a team, and keep an attacker out of your secrets.
Why do you need it?
- Keeps secrets secret: a 600-mode file is readable only by its owner, so credentials, keys and configs never leak to other users on the same host.
- Root is one typo away from disaster: chmod -R 777 /etc can cripple a server, so disciplined permissions are a survival skill, not a nicety.
- Shared infrastructure works without root: directories owned by a shared group let whole teams read and write the same code safely.
- Containers and CI/CD bake permissions into images: deployments fail at startup when the runtime user cannot read config or write logs.
- Interview fundamentals: permission checks, setuid binaries and umask are core Linux internals every SRE is expected to explain cold.
Mental model
A locked filing cabinet with a key for the owner, a shared key for the team, and a glass panel everyone else can look through
The rwx permission model
Each file is a cabinet. The owner holds a personal key (user bits), the owner's group shares a team key (group bits), and everyone else can only read the label (other bits). Root is the building super who opens any cabinet regardless. Linux decides which key applies by checking the caller's identity once, from most specific to least.
How it works
- Every file is described by an inode that stores a numeric user id (uid), a numeric group id (gid) and a mode — a 16-bit number whose lower nine bits are the read/write/execute triples for user, group and other.
- The kernel resolves access on every system call: if the caller's uid matches the file owner, the user triple applies; otherwise if the uid is in the file's group, the group triple applies; otherwise the other triple applies — exactly one triple is ever consulted.
- Octal is a compact encoding: each triple is a 3-bit number where read = 4, write = 2, execute = 1, so chmod 755 means owner 7 (rwx), group 5 (r-x), other 5 (r-x). The three digits are additive, never decimal.
- The special bits live above the nine: setuid = 4000, setgid = 2000, sticky = 1000. chmod 4755 sets setuid, which makes an executable run with the file owner's privileges — this is why unprivileged users can change their password via /usr/bin/passwd.
- On directories the bits mean something extra: write lets you add or delete entries, execute lets you traverse into the directory, setgid makes new entries inherit the directory's group, and the sticky bit means only the owner (or root) can delete entries inside.
How the kernel decides whether a process may open a file.
Key commands
ls -lThe permission string is ten characters: a file type, then the user/group/other triples, then link count, owner, group, size, date and name.
drwxrwsr-x 2 root web 4096 Aug 8 10:00 /srv/www -rw-r--r-- 1 root root 120 Aug 8 10:01 notes.txt -rwsr-xr-x 1 root root 22176 Aug 8 10:02 helper
chmod 755 deploy.shSet rwxr-xr-x in octal: owner reads/writes/executes, group and others only read and execute.
No output on success — confirm with ls -l deploy.sh
chmod u+x,g-w,o=r deploy.shSymbolic mode: add execute for the owner, remove write for the group, force others to read-only.
No output on success — the mode is applied atomically.
chown deploy:web app.confChange owner to user deploy and group to web in one command. Only root may change a file's owner.
No output on success — verify with stat or ls -l.
chgrp -R web /srv/wwwRecursively change only the group; the owner is left untouched.
No output on success — every entry under /srv/www now belongs to group web.
umaskPrint the current umask — the bits subtracted from the default 666 (files) and 777 (directories).
0022
stat -c '%a %U:%G %n' notes.txtPrint mode in octal, owner, group and filename — far easier to script than parsing ls output.
644 root:root notes.txt
Examples
Lock down a shared deployment directory
# 1. Put the directory under the web groupsudo chgrp web /srv/www # 2. Owner and group get full access, everyone else gets nonesudo chmod 770 /srv/www # 3. Set the setgid bit so new files inherit the web groupsudo chmod g+s /srv/www # 4. Remove a stale world-readable filesudo chmod o-r /srv/www/old-notes.txt # 5. Verify with ls -lls -ld /srv/wwwls -l /srv/wwwchmod 770 gives root and the web group full read/write/execute while blocking everyone else. The g+s (setgid) bit makes every new file and subdirectory inherit group web, so developers never need chown. ls -ld confirms the directory shows drwxrws--- — the s in the group position is the setgid bit.
In production
- Web servers run as a dedicated user (www-data) that can only read the web root — a compromised app process cannot rewrite its own code or configs.
- Setuid helpers are everywhere: /usr/bin/passwd, sudo and ping carry setuid root so unprivileged users can perform specific privileged operations without full root.
- Shared CI artifacts use setgid directories so every pipeline job writes into the same group without per-user chown dances.
- The sticky bit on /tmp and /run lets everyone create files but only their owner (or root) delete them, stopping denial-of-service via deletion of other users' sockets.
- Container images set read-only mounts and per-user ownership so a compromised container process cannot modify host-visible data.
Best practices
- Apply least privilege: start at 600 or 700 and widen only as far as the app genuinely needs.
- Share with groups, never 777: chgrp a directory to the team group and chmod g+rwX instead of world-writable.
- Verify with stat -c '%a %U:%G %n' rather than eyeballing ls -l.
- Reserve setuid for packaged, reviewed binaries — never write your own setuid shell scripts.
- Keep secrets at 600 and owned by a dedicated service account, never world-readable.
- Audit for dangerous modes regularly: find / -type f -perm -0002 lists every world-writable file.
Common mistakes
- Reaching for chmod 777 'to make it work' — it works until the host is compromised, then it is a gift to every user.
- Running chmod -R 777 on a whole tree, silently opening logs, sockets and configs you never thought about.
- Forgetting that directory write permission controls creating and deleting entries: a 777 directory means anyone can delete files they don't own unless the sticky bit is set.
- Assuming octal is decimal: 700 grants full access to the owner only, while 777 grants it to everyone.
- Changing ownership to a name when the kernel checks numbers — a typo'd uid can quietly hand files to the wrong account.
Common issues
Permission denied for a user who should have accessThe user is neither the owner nor a member of the file's group, so only the others triple applies — or an ancestor directory lacks execute (x), so the path cannot be traversed.
Run stat -c '%A %U:%G' on the file and id on the user; chgrp the file to the user's group, and ensure every directory in the path is +x.
Service cannot write its log or pid file after a deployThe runtime user owns nothing in the directory — files were created by a different uid (often root).
chown -R the runtime user over the directory, or apply chmod g+s so new files inherit the shared group, then chmod g+rwX.
New files don't belong to the shared groupThe creator's primary group differs from the intended shared group and the directory has no setgid bit.
Run chmod g+s on the directory; every new entry will inherit the directory's group from then on.
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit setA botched chmod -R stripped the setuid bit from /usr/bin/sudo (its correct mode is 4755).
Boot into single-user or recovery mode and run chmod 4755 /usr/bin/sudo, then audit what else lost its special bits.
Debugging tips
- ls -ld shows the directory's own mode; ls -l on the parent tells you whether you can actually create files inside it.
- stat -c '%a %u %g' prints mode, uid and gid numerically — compare those against id to catch mismatch.
- namei -l /path/to/file walks every path component and prints its permissions, revealing which ancestor blocks you.
- Test as the real user: sudo -u alice cat /srv/app.conf instead of reasoning about the model in your head.
- Watch for a trailing + in ls -l: that signals extended ACLs layered on top of the classic bits (getfacl shows them).
Interview checkpoint
Hands-on lab
- Decode the 10-character permission string into rwx triples
- Change modes with octal and symbolic chmod
- Change owner and group with chown and chgrp
- Control default modes with umask
- Apply setgid to a shared directory and verify inheritance
Master file permissions, ownership and umask
15 min · beginner
Quick quiz
What do the letters rwx stand for in the output of ls -l?
Which octal mode grants rw-r--r--?
On a world-writable directory without the sticky bit, any user can delete a file owned by someone else.
What does the s in the permission string -rwsr-xr-x indicate?
A CI job must let a build script (owned by root) write deployment files as root when an unprivileged runner triggers it — without giving anyone the root password. Which mechanism fits best?
Which command prints a file's mode as a number, its owner, its group and its name?
Cheat sheet
-rwxr-xr-xtype, then owner/group/others triplesd, -, l, b, c, p, sdirectory, file, symlink, block/char device, fifo, socket1 root root 4096hard links, owner, group, sizetrailing +extended ACLs active — inspect with getfacl4 = read2 = write, 1 = execute — sum to build a triple755rwxr-xr-x — owner full, group/others read + execute644rw-r--r-- — the default mode for files600rw------- — secrets and keys700rwx------ — private directories777rwxrwxrwx — dangerous; everyone gets everythingchmod u+x script.shadd execute for the ownerchmod g-w,g+r fileremove write, add read for the groupchmod a+r READMEa = all three classes at oncechmod -R g+rwX shared/X = execute only for directories, not fileschown alice filechange owner (root only)chown alice:web fileowner and group in one stepchown :web filechange only the groupchgrp -R web dirchange group recursively, owner untouchedchmod 4755 /usr/bin/sudosetuid — runs as the file ownerchmod 2755 run.shsetgid — runs as the group; dirs inherit groupchmod 1777 /tmpsticky — only owner/root delete entriesumask 022default files 644, default dirs 755umask 077default files 600, default dirs 700 — private by default