Originally published on DevToolHub.
Linux file permissions come down to three numbers and a handful of special bits, but the numbers trip people up because the math isn't explained where you'd actually see it — on the command line. chmod 755, chmod 2775, umask 022 all make sense once you see where each digit comes from. This covers the actual bit math, plus the two gotchas that cause real incidents: chmod silently ignoring symlinks, and the sticky bit doing something completely different depending on whether it's set on a file or a directory.
How chmod's Numeric Mode Actually Works
A chmod numeric mode is up to four octal digits, and each one is a sum of three values: read is 4, write is 2, execute is 1. chmod 644 file.txt breaks down as 6 (4+2, read+write) for the owner, 4 (read only) for the group, and 4 (read only) for everyone else. chmod 755 script.sh gives the owner 7 (4+2+1, full access) and read-plus-execute (5) to the group and everyone else — the standard mode for a script or directory you want others to run or enter but not modify.
The fourth digit, when you include it, is where setuid, setgid, and the sticky bit live: setuid is 4, setgid is 2, and the sticky bit is 1. chmod 2755 /shared/scripts sets setgid (2) on top of the usual 755, and setuid binaries like passwd (mode 4755-style) are how a normal user can temporarily run as root to change their own password entry in /etc/shadow.
What Setuid and Setgid Actually Do
Setgid on a directory is the one worth remembering: any new file created inside inherits the directory's group instead of the creating user's primary group. That's the standard fix for shared team directories where everyone's files need to stay in the same group without each person manually running chgrp afterward.
Linux automatically clears the setgid bit on a regular file if the file's group doesn't match your effective group ID or one of your supplementary group IDs, unless you have elevated privileges. That's a real security guard, not a bug — it stops a chmod from silently granting elevated group execution to a file whose ownership doesn't actually support it.
Directories behave differently here too: chmod preserves a directory's setuid and setgid bits by default even when you don't mention them. To actually clear them with a numeric mode you need a leading zero, minus, or equals sign — chmod 0755 dir clears both bits explicitly, where chmod 755 dir alone leaves them untouched.
The Sticky Bit Means Something Different on Files vs. Directories
On a directory, the sticky bit (mode 1000, the t in drwxrwxrwt) is what makes /tmp safe to be world-writable. It stops any user from deleting or renaming a file they don't own inside that directory, even though everyone technically has write access to the directory itself — only the file's owner (or the directory's owner) can remove it.
On a regular file, the sticky bit meant something else on older Unix systems: it told the kernel to keep the program's compiled text image on the swap device so it loaded faster next run. Modern Linux kernels ignore this for regular files — if you see it set on a plain file today, it's legacy cruft, not a real optimization.
The Gotcha Nobody Reads Until It Bites: chmod and Symlinks
chmod does not change the permissions of a symbolic link itself. The underlying chmod system call can't change a symlink's own permissions on most systems, and chmod deliberately changes the permissions of whatever the link points to instead. Run chmod 700 mylink expecting the link to become private, and you've actually changed the mode of the target file — possibly a shared file you didn't mean to touch.
If you specifically need to affect the link and not its target, chmod -h (or --no-dereference) is the flag. Get this backwards on a script that walks a directory tree containing symlinks, and you can change permissions on files well outside the directory you thought you were locking down.
chown: Changing Owner and Group Together
chown has four distinct forms. chown alice file changes only the owner. chown alice:devs file changes both owner and group. chown :devs file changes only the group — identical to chgrp devs file. And chown alice: file (a bare colon with no group name) sets the owner to alice and resets the group to alice's login group, which is easy to trigger by accident if you meant to type a group name and didn't.
umask: Why New Files Don't Show Up as 777
umask doesn't touch existing files — it sets the file mode creation mask for the current shell, subtracting permissions from everything created afterward in that session. A umask of 022 is why an editor requesting 666 for a new file actually gets 644: the mask's 022 removes group and other write access from whatever the creating program asked for.
The mask only applies going forward, and only in its own execution environment. Running umask inside a subshell, a nohup invocation, or a find -exec doesn't change the mask of the shell that launched it. If a deployment script sets umask 077 at the top expecting it to lock down every file it writes, confirm the mask is actually inherited by whatever subprocess is doing the writing.
Quick Summary:
- Numeric chmod is four octal digits: special bits (setuid 4 + setgid 2 + sticky 1), then owner, group, other — each a sum of read(4)/write(2)/execute(1)
- Setgid on a directory makes new files inherit the directory's group; Linux clears setgid automatically if the file's group doesn't match your effective or supplementary groups
- The sticky bit means "only the owner can delete their own files" on a directory (the /tmp mechanism), but is an obsolete swap-caching hint on a regular file
- chmod changes a symlink's target, not the link itself, unless you pass -h/--no-dereference
- umask only affects files created after it's set, in the same shell — it does nothing to existing files or a parent shell when set inside a subshell
Full breakdown at DevToolHub.
Top comments (0)