Permissions, ownership, and the sticky bit

general / published / guide #36 / ≈ 4 min read

Every file and directory on a Unix-style system has an owner, a group, and a set of permissions saying what the owner, the group, and everyone else is allowed to do with it. Get this wrong and "permission denied" follows you everywhere; get it right and it just works.

Reading a permissions line

Run ls -l in any directory and look at the leftmost column:

-rw-r--r--  1 alice  staff   1234 May 14 09:00 notes.txt
drwxr-xr-x  3 alice  staff    102 May 14 09:00 photos

Decode the first ten characters:

-rwxr-xr--
│└┬┘└┬┘└┬┘
│ │  │  └── permissions for everyone else (read only here)
│ │  └───── permissions for the group     (read + execute)
│ └──────── permissions for the owner     (read + write + execute)
└────────── file type: - regular file, d directory, l symlink

Each three-letter group is read/write/execute (r/w/x) for that audience. A dash means "no, can't."

What execute means on a directory

For a file, x means "this is a program you can run." For a directory, x means "you're allowed to enter (cd into) this directory." You can have a directory you can read (r, list files) but not enter (no x), or one you can enter but not list. The two combine in odd ways — knowing this saves a lot of head-scratching.

Owner and group

The other two columns are who owns the file and which group it belongs to. The owner is one person; the group is potentially many.

Change owner

sudo chown bob notes.txt                # bob now owns it
sudo chown bob:developers notes.txt     # bob owns it, group is developers
sudo chown -R bob:developers project/   # recursively, every file inside

Change just the group

sudo chgrp developers notes.txt

chmod: changing permissions

Two notations — pick whichever you prefer.

Symbolic ("words")

chmod u+x script.sh        # add execute for user (owner)
chmod g+w notes.txt        # add write for group
chmod o-r secret.txt       # remove read for others
chmod a+r everyone.txt     # add read for all (user, group, other)
chmod u=rw,g=r,o= notes.txt   # set exactly: owner rw, group r, other nothing

Who: u user (owner), g group, o other, a all. Verb: + add, - remove, = set exactly.

Numeric (octal)

Each three-letter cluster is a number from 0 to 7. Compute it by adding: read = 4, write = 2, execute = 1.

chmod 644 notes.txt        # rw- r-- r--  (the standard file)
chmod 755 script.sh        # rwx r-x r-x  (the standard executable)
chmod 600 ~/.ssh/id_ed25519  # rw- --- ---  (your private key, locked down)
chmod 700 ~/.ssh           # rwx --- ---  (your ssh directory)
chmod 750 project/         # rwx r-x ---  (owner + group, no one else)

Memorise the three: 644 for normal files, 755 for executables and directories, 600/700 for private things. Most chmods are one of those.

The sticky bit (and friends)

Three more permission bits exist beyond r/w/x. You meet them rarely, but when you do, they're mysterious.

Sticky bit on a directory: chmod +t

On a directory, the sticky bit means "even though anyone can write here, you can only delete your own files." That's how /tmp works — everyone can create files in it, but Alice can't delete Bob's.

ls -ld /tmp
# drwxrwxrwt 18 root root 4096 May 14 09:00 /tmp
#          ^ that t is the sticky bit

setuid and setgid: chmod u+s / g+s

setuid on an executable makes it run as its owner instead of as the user invoking it. That's how passwd can write to /etc/shadow when run by a normal user.

ls -l /usr/bin/passwd
# -rwsr-xr-x  1 root root  ...
#    ^ the s in place of x means setuid

You almost never set this yourself — it's a security minefield. But you'll see it on system binaries.

setgid on a directory makes new files inside inherit the directory's group. Useful for shared project directories.

umask: what new files get by default

umask is the "default permissions" knob, expressed as the bits to subtract from full permissions. Most distros default to 022:

  • New files get 666 - 022 = 644 (rw-r--r--).
  • New directories get 777 - 022 = 755 (rwxr-xr-x).

To make your new files private by default:

umask 077         # files get 600, dirs get 700

Put that in your ~/.bashrc or ~/.zshrc.

ACLs: when the three-tier model isn't enough

If "owner + one group + other" isn't expressive enough — say you want Alice and Bob to both have write, but not the rest of the group — you reach for Access Control Lists:

setfacl -m u:alice:rw notes.txt
setfacl -m u:bob:rw notes.txt
getfacl notes.txt                  # show the full ACL

Files with ACLs show a + at the end of the permission column in ls -l. Most filesystems support them; you almost never need them — but when you do, they're what you're looking for.

Two routines that fix 90% of "permission denied"

# I copied files in as root by mistake — give them back to me
sudo chown -R $USER:$USER ~/folder/

# scripts don't run — they need execute
chmod +x script.sh

← back to index