Linux Admin

Linux File Permissions: chmod, chown, umask, and ACLs

Part of pathway: Linux Mastery: 300 Commands

The 9 Bits That Run Everything

Every file and directory on Linux carries 9 permission bits arranged in three groups of three: user, group, other. Each group has read (r), write (w), and execute (x). Plus three special bits (setuid, setgid, sticky) you’ll meet less often. That’s it. Everything else is shorthand or syntactic sugar.

This article is a working reference for Linux file permissions and ownership: how to read them, how to set them with both numeric and symbolic syntax, what each bit actually does, and the gotchas that catch people in production.

Reading Permissions: ls -l

$ ls -l install.sh
-rwxr-xr-x  1 alice  developers  2148 Mar 15 09:32 install.sh

The first character is the file type: - regular file, d directory, l symbolic link, c character device, b block device, s socket, p named pipe.

Then three groups of three:

  • rwxuser (owner) can read, write, execute
  • r-xgroup can read, execute (NOT write)
  • r-xother can read, execute (NOT write)

Octal: The Numeric Shorthand

Bit Value Meaning
r 4 read
w 2 write
x 1 execute

Sum the values for each group. Three groups give you three digits: the famous octal mode.

Octal rwx Common use
755 rwxr-xr-x Executable scripts, public dirs
644 rw-r--r-- Regular files (config, docs)
700 rwx------ Private executables (SSH keys, secrets)
600 rw------- Private regular files
777 rwxrwxrwx Almost never the right answer
666 rw-rw-rw- Almost never the right answer

If you find yourself typing chmod 777 or chmod 666 in production, stop and ask why. The right answer is almost always tighter.

chmod — Two Syntaxes

Numeric (octal)

chmod 755 install.sh                  # rwxr-xr-x
chmod 600 ~/.ssh/id_rsa                # rw-------
chmod -R 644 docs/                     # recursive (careful!)
chmod 4755 /usr/bin/passwd             # leading 4 = setuid

Symbolic (more readable for incremental changes)

chmod u+x script.sh                    # add user-execute
chmod g-w sensitive.txt                # remove group-write
chmod o= secret                        # strip other's permissions
chmod a+r public.txt                   # all (user, group, other) +r
chmod u+rwx,g+rx,o-rwx file            # multiple at once

The symbolic form is the right choice when you want to add or remove ONE permission without touching the others. The numeric form is the right choice when you want to set everything explicitly.

chmod -R Carefully

Recursive chmod is the most common foot-gun in Linux ops. Two patterns:

# BAD: gives execute to every file, including data files
chmod -R 755 /var/www/html

# GOOD: separate handling for files and directories
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;

Or use the symbolic X (capital) which adds execute only where it already makes sense (already-executable files, or directories):

chmod -R u+rwX,go+rX,go-w /var/www/html

Ownership: chown and chgrp

chown alice file.txt                  # change owner only
chown alice:developers file.txt        # owner AND group
chown :developers file.txt             # group only (alternative: chgrp)
chgrp developers file.txt              # group only
chown -R alice:dev /var/www/html       # recursive
chown --reference=existing.txt new.txt # match another file's ownership

Only root can change a file’s owner. A regular user can change the group, but only to a group they’re a member of.

umask — Default Permissions for New Files

The umask is a bitmask SUBTRACTED from 666 (or 777 for directories) to get the default mode of newly created files.

umask                                  # show current
umask 022                              # default for most distros
umask 077                              # paranoid: only owner
umask New file New directory
022 644 (rw-r--r--) 755 (rwxr-xr-x)
027 640 (rw-r-----) 750 (rwxr-x---)
077 600 (rw-------) 700 (rwx------)

Set in ~/.bashrc or /etc/profile for persistence. Many production environments use 027 for tighter defaults.

The Three Special Bits

setuid (4xxx) — run as the file’s owner

$ ls -l /usr/bin/passwd
-rwsr-xr-x  1 root root  68208 Apr  4 /usr/bin/passwd

That s in the user-execute slot means the program runs with the owner’s privileges (root, here) regardless of who invokes it. Required for passwd to write to /etc/shadow. Set with chmod u+s or octal leading 4: chmod 4755 file.

Setuid binaries are a security-sensitive surface. Audit yours: find / -type f -perm -4000 2>/dev/null

setgid (2xxx)

On a directory: new files inherit the directory’s group, not the creator’s primary group. Useful for shared project directories. chmod g+s dir/ or octal leading 2.

Sticky bit (1xxx)

On a directory: only the file’s owner can delete or rename it, even if other users have write permission on the directory. The classic example is /tmp:

$ ls -ld /tmp
drwxrwxrwt  17 root root  4096 May  6 16:22 /tmp

That t at the end is the sticky bit. Without it, anyone could delete anyone else’s files in /tmp. Set with chmod +t dir/ or octal leading 1.

ACLs — When 9 Bits Aren’t Enough

Need user bob specifically to read this file, even though he’s not in the group? POSIX ACLs:

setfacl -m u:bob:r-- file.txt          # grant bob read
setfacl -m g:audit:rx /var/log/app/    # grant audit group rx
getfacl file.txt                       # display ACL
setfacl -x u:bob file.txt              # remove bob's ACL entry
setfacl -b file.txt                    # remove ALL ACLs

Files with ACLs show a + at the end of ls -l: -rw-r--r--+.

Common Pitfalls

  • chmod -R 755 on a code tree. Suddenly every .py file is executable. Use find -type f + find -type d separately, or X in symbolic mode.
  • SSH key permissions too loose. SSH refuses keys with group/other-readable perms. chmod 600 ~/.ssh/id_rsa; chmod 700 ~/.ssh.
  • Web server can’t read uploaded files. Files written by the application user with umask 077 won’t be readable by the web user. Fix: chmod 644 or align umask, or use ACLs.
  • setuid script shebang. Setuid on shell scripts is ignored by Linux for security reasons. Setuid only works on compiled binaries.
  • chown not enough. Ownership change without permission change can leave a file unreadable to its new owner if the existing perms blocked them.
  • Forgetting that read on a directory means “list”, write means “create/delete entries,” execute means “cd into.”

Conclusion

Five mental models that make permissions click:

  1. Three groups, three bits each. 9 bits.
  2. Octal: r=4 w=2 x=1, sum per group, three digits total.
  3. Symbolic: u/g/o/a + +/-/= + rwx. Use for incremental changes.
  4. For directories: r = list, w = create/delete, x = enter.
  5. When 9 bits aren’t enough, use ACLs, not chmod 777.

Related Linux Admin troubleshooting

For common errors and fixes related to this topic, see:

Leave a Reply