backend / linux bash / 11_file_permissions.md

File Permissions and Ownership

6 interview angles 8 min read source

File Permissions and Ownership

Every file has an owner (user), a group, and three sets of read/write/execute bits — for owner, group, others. Plus three special bits (setuid, setgid, sticky). The interview question is “what does chmod 755 mean?” and “why is my script ‘permission denied’ even though I chmod +x’d it?”

ls -l output

-rwxr-xr-x  1 alice  staff  1234 Jan 15 10:30 script.sh

Decoded:

Position Means
- type (- file, d dir, l symlink, c char dev, b block dev, s socket, p pipe)
rwx owner permissions: read, write, execute
r-x group permissions
r-x others’ permissions
1 hard link count
alice owner
staff group
1234 size in bytes
Jan 15 10:30 mtime
script.sh name

What r/w/x mean

For files:

Bit Allows
r read the file content
w modify the file content
x execute as a program

For directories:

Bit Allows
r list filenames in the directory
w create / delete / rename files in the directory
x enter the directory (cd), access files inside by name

The directory x bit is critical and confusing. Without x on a directory, you can’t cd into it or access any file by name — even if you have read on the file itself.

Octal mode

Each rwx triplet maps to a single octal digit:

rwx Binary Octal
000 0
–x 001 1
-w- 010 2
-wx 011 3
r– 100 4
r-x 101 5
rw- 110 6
rwx 111 7

Mnemonic: r=4, w=2, x=1. Sum the bits you want.

Common modes:

Octal Symbolic Use
644 rw-r--r-- typical file (owner can edit; everyone can read)
755 rwxr-xr-x typical executable / dir (owner full; others read+execute)
600 rw------- private file (only owner can read/write — for SSH keys, secrets)
700 rwx------ private directory
777 rwxrwxrwx “world writable” — almost always wrong
666 rw-rw-rw- world-writable file — almost always wrong

chmod — change permissions

chmod 755 script.sh                  # octal mode
chmod +x script.sh                   # add execute (for everyone)
chmod u+x script.sh                  # add execute for owner only
chmod g-w file                       # remove group write
chmod o= file                        # remove all others' permissions
chmod a+r file                       # add read for all (a = u+g+o)
chmod -R 755 dir                     # recursive

Symbolic syntax:

Who + - = What
u (user/owner), g (group), o (others), a (all) + add, - remove, = set exactly r, w, x
chmod u=rwx,g=rx,o= file              # owner all, group rx, others none
chmod -R u+rwX,go=rX dir              # capital X = execute only for dirs / already-executable files

Capital X is “set execute only on directories or files that already have any execute bit.” Useful for chmod -R on a tree of files + dirs (you want dirs traversable but most files don’t need x).

chown — change ownership

chown alice file                      # change owner
chown alice:staff file                # change owner and group
chown :staff file                      # change group only
chown -R alice:staff /home/alice      # recursive
chgrp staff file                       # change group only (alternative)

Only root can change owner. Owner can change group (to one they belong to).

umask — default permissions for new files

When you create a file, its mode is determined by the program’s request AND umask:

file_mode = requested_mode AND NOT umask

Default umask: 022. Means:

  • Strip write for group and others.
  • File requested as 666 → 666 AND NOT 022 = 644.
  • Directory requested as 777 → 777 AND NOT 022 = 755.

To make new files private by default:

umask 077                              # strip ALL group/others perms
touch newfile                          # 600

Set in ~/.bashrc for permanence.

Special permission bits

Three additional bits beyond rwx:

Bit Symbol Octal (4-digit) Effect
setuid s in user x 4xxx run as the file’s owner, not the invoker
setgid s in group x 2xxx run as the file’s group; on dirs: new files inherit dir’s group
sticky t in others x 1xxx only the owner can delete/rename their files (used on /tmp)
chmod 4755 file                       # setuid + 755
chmod u+s file                        # setuid via symbolic
chmod 2755 dir                        # setgid on dir
chmod 1777 /tmp                       # sticky on /tmp (default)

setuid example: passwd

ls -l /usr/bin/passwd
-rwsr-xr-x  1 root root  ...  /usr/bin/passwd

The s in user-execute = setuid. When any user runs passwd, it runs as root (so it can edit /etc/shadow). This is how non-root users can change their password.

setgid on directory

mkdir shared
chmod 2775 shared                     # setgid + 775
chgrp dev shared

Now any file created in shared inherits dev group (instead of the creator’s primary group). Used for shared workspaces.

Sticky bit on /tmp

ls -ld /tmp
drwxrwxrwt  ... /tmp

The t at the end = sticky. Anyone can write to /tmp, but only the owner of a file can delete it. Without sticky, world-writable + everyone can delete = chaos.

Why “permission denied” even after chmod +x

Common causes:

  1. No x on a parent directory. Can’t cd into a dir without x on it. ls -ld /path/to/dir shows the dir’s perms.
  2. Script’s shebang interpreter doesn’t exist or isn’t executable. #!/bin/python (typo for #!/usr/bin/env python) → “no such file” disguised as permission error.
  3. Filesystem is mounted noexec. mount | grep <fs> to check; common on /tmp in hardened systems.
  4. SELinux / AppArmor. Different layer; getenforce, dmesg for denied messages.
  5. Script line endings are CRLF (Windows). Run dos2unix script.sh.

The error “bad interpreter” is shebang-related; “permission denied” is unix permissions or noexec.

Recursive chmod patterns

The classic mistake:

chmod -R 644 /var/www         # removes x from directories — site breaks

Without x on directories, you can’t traverse them. Right way:

find /var/www -type d -exec chmod 755 {} +
find /var/www -type f -exec chmod 644 {} +

Or with chmod -R u+rwX,go=rX:

chmod -R u=rwX,g=rX,o=rX /var/www

Capital X = “execute only on dirs or already-executable files.”

ACLs (advanced)

Standard rwx is owner/group/others — only one group. ACLs (Access Control Lists) let you grant per-user or per-group permissions:

setfacl -m u:bob:rwx file              # give bob rwx
setfacl -m g:devs:rx dir               # give devs group rx
getfacl file                            # show ACLs

Files with ACLs show a + after the rwx in ls -l:

-rw-r--r--+ 1 alice staff ...

Used in shared filesystems where one-group-per-file isn’t enough. Most apps don’t need ACLs.

Capabilities (modern alternative to setuid)

Setuid root = “run with full root powers” — overkill if you only need one privilege (e.g. bind to port < 1024).

Capabilities split root into ~40 distinct privileges:

sudo setcap 'cap_net_bind_service=+ep' /usr/bin/python3
# now python can bind to port 80 without being root

Cleaner and safer than setuid. Used by modern web servers (nginx, caddy) to bind low ports.

Common pitfalls

  • chmod 777 thing “to fix permissions” is the most common security antipattern. Means anyone can read/write/execute. Find the actual permission you need.
  • chown -R on a tree owned partly by other users changes their files too. Easy to break with sudo.
  • Removing x from a directory thinking it’s like removing read — kills traversal. Use capital X in recursive chmod.
  • umask 000 because something complained about permissions — now everything you create is world-readable/writable.
  • Setuid on a script — most kernels ignore setuid on scripts (security hole). Setuid only works on compiled binaries.

Common interview confusions

  • chmod 755 means read for everyone.” — 755 = rwxr-xr-x = owner all, group r+x, others r+x. Yes, includes read for everyone.
  • x on a directory means I can list it.”r lets you list; x lets you traverse and access by name. They’re orthogonal.
  • “setuid lets you run as root.” — only if the file’s owner is root. setuid runs as the file’s owner, whoever that is.
  • “Permission denied means file permissions.” — could be: directory traversal, noexec mount, SELinux, missing shebang interpreter, CRLF line endings. The error message is generic.

Interview angle

  • “What does chmod 755 mean?”rwxr-xr-x. Owner: read/write/execute. Group: read/execute. Others: read/execute. Standard for executables and directories.
  • “What’s the difference between r and x on a directory?”r lets you list filenames; x lets you traverse (cd) and access files by name. Both usually granted together; x without r (--x) is a “lookup-only” directory.
  • “What’s umask?” — bitmask subtracted from default permissions when files are created. Default 022 means group/others lose write. Set 077 for “everything I create is private.”
  • “What’s setuid and when is it used?” — file runs as its owner instead of the invoker. Classic example: /usr/bin/passwd is setuid root so users can change their passwords. Modern alternative: capabilities (more granular).
  • “What’s the sticky bit?” — on a directory, only the file owner can delete or rename their own files. Used on /tmp so users can write there but can’t delete each other’s files.
  • “How do you safely chmod -R on a tree of files and dirs?” — separate dirs and files: find . -type d -exec chmod 755 {} +; find . -type f -exec chmod 644 {} +. Or use capital X: chmod -R u=rwX,g=rX,o=rX ..