Prerequisites
- Terminal access to a Linux machine — a VM or cloud instance
- A non-root user with sudo access
- Comfort with cd, ls, and cat
What You'll Learn
- Read and set permissions using both symbolic (u+x) and octal (755) notation
- Explain the difference between chmod, chown, and chgrp
- Use setuid, setgid, and the sticky bit correctly
- Predict what permissions a new file will get from a given umask value
Theory
Every file and directory on a Linux system carries three permission triads — owner, group, and other — each holding a read (r), write (w), and execute (x) bit. Run ls -l and the first ten characters of each line show this directly: a leading file-type character (- for a regular file, d for a directory, l for a symlink) followed by three rwx triads.
Octal vs. symbolic notation
Octal notation collapses each triad into a single digit by summing r=4, w=2, x=1. chmod 755 file means owner=7 (rwx), group=5 (r-x), other=5 (r-x). Symbolic notation instead targets who (u/g/o/a) and what to change (+/-/=): chmod u+x,g-w fileadds execute for the owner and removes write for the group, leaving every other bit untouched — something octal notation can't do without first reading the existing mode.
Execute permission on a directory means something different
On a directory, the execute bit doesn't mean "run it" — it means "traverse it" (cd into it, or access files inside by exact name). The read bit on a directory means "list its contents". A directory with r-x but no wlets you list and enter it, but not create or delete files inside — which is why "permission denied" on a file write is often actually a directory permission problem.
Special permission bits
| Bit | On a file | On a directory |
|---|---|---|
| setuid (4000) | Runs with the file owner's privileges, not the caller's | No effect |
| setgid (2000) | Runs with the file's group privileges | New files inherit the directory's group |
| sticky (1000) | No effect (ignored on most modern filesystems) | Only the owner can delete/rename their own files inside |
Architecture
The kernel evaluates permissions in a strict order — it stops at the first matching category, which has a surprising consequence: a process can end up with fewer rights via the group triad than it would have gotten via other, if the owner check fails but the group check matches a more restrictive triad.
Owner check → group check → other — the first match wins, later triads are never consulted
Hands-On Lab
Work through these in order on a scratch directory:
mkdir ~/perm-lab && cd ~/perm-lab
touch script.sh data.txt
# Symbolic notation
chmod u+x script.sh
ls -l script.sh # -rwxr--r--
# Octal notation — same result as: chmod u=rwx,g=r,o=r
chmod 744 script.sh
# Ownership
sudo chown "$USER":"$USER" data.txt
sudo chown root:root data.txt # requires sudo — you don't own 'root' as a target group by default
# umask: check current default, then test its effect
umask # e.g. 0022
touch fresh-file.txt
ls -l fresh-file.txt # 644 on most distros (666 - 022)
mkdir fresh-dir
ls -ld fresh-dir # 755 (777 - 022)
# setgid on a shared directory: new files inherit the directory's group
sudo mkdir /srv/shared
sudo chgrp devteam /srv/shared
sudo chmod 2775 /srv/sharedBest Practices
Least privilege by default
Never reach forchmod 777 to make an error go away — it grants write access to every user on the system. Diagnose the actual owner/group mismatch instead; 777 is almost never the correct fix.Use setgid for shared team directories
On a directory multiple users write into, set the setgid bit (chmod g+s) and a shared group owner so every new file automatically inherits the team's group instead of the creating user's personal group.Common Mistakes
Confusing directory execute with 'runnable'
Removing execute from a directory doesn't stop scripts inside it from running — it stops anyone fromcd-ing into it or accessing files by name at all, which usually breaks far more than intended.Forgetting -R changes everything, unconditionally
chmod -R 755 dir/ applies 755 to files too, which strips any file that needed to stay non-executable (like config files) down to the same executable mode as scripts. Use find dir/ -type f -exec chmod 644 {} + and find dir/ -type d -exec chmod 755 {} + to set files and directories differently in one pass.Troubleshooting
"Permission denied" despite correct rwx bits: check three things beyond the basic mode: (1) every parent directory in the path needs execute permission for your user, not just the final directory; (2) SELinux or AppArmor may deny access even when DAC (the rwx model) allows it — check with ls -Z and ausearch -m avc -ts recent on SELinux systems; (3) an ACL (getfacl file) can grant or restrict access beyond what ls -l shows — a + after the mode string in ls -l output signals an ACL is present.
Interview Questions
Cheat Sheet
Permissions & Ownership
chmod 755 file.shSet rwxr-xr-x (owner rwx, group/others r-x)chmod u+x file.shAdd execute permission for the owner onlychown user:group fileChange owner and group of a filechown -R user:group dir/Change ownership recursivelyumask 022Set default permission mask for new files/directoriesgetfacl fileShow extended ACLs on a fileFrequently Asked Questions
Summary
Permissions are three rwx triads evaluated in owner → group → other order with a first-match rule; octal notation sets all three at once, symbolic notation edits specific bits; setuid/setgid/sticky solve three distinct problems (privilege escalation on execution, group inheritance, and shared-directory delete protection); and umask sets the ceiling every new file and directory is created under.