Users & Permissions

File Permissions

Read, write, execute, ownership, and umask: the core permission model.

The rwx permission bits are the control the kernel checks on almost every file access, millions of times a second. They are simple enough to reason about at a glance, which is exactly why mistakes are so common and so consequential: a config file that is world-writable, a private key that is world-readable, or a directory anyone can traverse. This page makes the model precise so you can read any ls -l line correctly and set safe defaults. Practice on the lab VM.

The rwx Bits: Owner, Group, Other

Every file has an owner (a user) and a group, plus three permission triples: what the owner may do, what members of the group may do, and what everyone else (“other”) may do. Each triple is read (r), write (w), execute (x). ls -l shows all of it.

ls -l /etc/hosts /usr/bin/passwd

Expected output:

-rw-r--r-- 1 root root   221 Jul  6 09:10 /etc/hosts
-rwsr-xr-x 1 root root 59976 Apr  8  2024 /usr/bin/passwd

Read the first field left to right. The leading character is the type (- file, d directory, l symlink). The next nine are owner, group, other triples. For /etc/hosts: owner root may read and write (rw-), group may read (r--), other may read (r--). The kernel checks these in order: if you are the owner, only the owner triple applies; else if you are in the group, only the group triple; else the other triple. You do not accumulate permissions across triples, which surprises people. The s in the passwd line is setuid, covered in Setuid & Setgid.

Octal Notation

The same bits are commonly written as three octal digits, one per triple, where r=4, w=2, x=1 summed. rw-r--r-- is 6-4-4, or 644. rwxr-xr-x is 7-5-5, or 755. This is the notation chmod usually takes.

SymbolicOctalTypical use
rw-r--r--644Regular file, world-readable
rw-------600Private file (SSH key, secret)
rwxr-xr-x755Executable or public directory
rwx------700Private directory
rw-rw-r--664Group-writable file

Set permissions with chmod, and ownership with chown. Create a file and lock it down:

echo "secret" > /tmp/key
chmod 600 /tmp/key
ls -l /tmp/key

Expected output:

-rw------- 1 ubuntu ubuntu 7 Jul  6 09:22 /tmp/key

chmod also accepts symbolic edits, which are safer for tweaking one bit without restating the rest: chmod o-r /tmp/key removes read for other, chmod g+w file adds group write. Use octal to set an absolute mode, symbolic to adjust one.

Directory Semantics: Execute Means Traverse

On a directory the bits mean something different, and this trips up almost everyone. Read lets you list the names inside. Write lets you create, rename, and delete entries (note: delete depends on the directory, not the file). Execute lets you enter the directory and access items by name, that is, traverse into it. Read without execute is nearly useless; execute without read lets you reach a known filename but not list what is there.

mkdir /tmp/vault
echo data > /tmp/vault/inside
chmod 711 /tmp/vault        # rwx for owner, execute-only for group/other
ls -ld /tmp/vault
sudo -u nobody cat /tmp/vault/inside     # knows the name: works
sudo -u nobody ls /tmp/vault             # tries to list: fails

Expected output:

drwx--x--x 2 ubuntu ubuntu 4096 Jul  6 09:25 /tmp/vault
data
ls: cannot open directory '/tmp/vault': Permission denied

The 711 directory is a classic pattern: others can reach files they already know the path to, but cannot enumerate the contents. Home directories often use 700 or 711 for exactly this reason. To delete a file you need write and execute on its parent directory, not on the file itself, which is why the sticky bit exists (see Setuid & Setgid).

umask And Default Permissions

New files do not get 777; the shell masks off bits according to umask. The umask is subtracted (bitwise) from a base mode of 666 for files and 777 for directories. Ubuntu’s default umask is 022, so new files come out 644 and new directories 755.

umask
touch /tmp/newfile
mkdir /tmp/newdir
ls -ld /tmp/newfile /tmp/newdir

Expected output:

0022
-rw-r--r-- 1 ubuntu ubuntu    0 Jul  6 09:28 /tmp/newfile
drwxr-xr-x 2 ubuntu ubuntu 4096 Jul  6 09:28 /tmp/newdir

A tighter umask denies “other” by default, which is good practice for anything touching sensitive data. Setting umask 077 makes new files 600 and directories 700, so nothing is readable outside the owner unless you widen it deliberately:

umask 077
touch /tmp/private
ls -l /tmp/private

Expected output:

-rw------- 1 ubuntu ubuntu 0 Jul  6 09:30 /tmp/private

A umask set at the shell lasts only for that session; put it in a login profile or a service unit to make it persistent. Defaults matter because most files are created, not chmod’d afterward, so a safe umask prevents whole classes of accidental exposure.

The classic bits handle owner/group/other and no more. When you need more than one group or user with distinct access, or protection the owner cannot undo, continue to ACLs & Attributes. For programs that change identity as they run, see Setuid & Setgid.

Practical Guidance

  1. Read ls -l from the left: type, then owner/group/other triples; remember only the first matching triple applies.
  2. Use octal for absolute modes and symbolic (g+w, o-r) for adjusting a single bit without disturbing the rest.
  3. Keep secrets at 600 and private directories at 700; never leave keys or credentials group- or world-readable.
  4. Remember execute on a directory means traverse; 711 hides the listing while still allowing known-path access.
  5. Set a 077 umask for any account or service that handles sensitive data, and make it persistent in a profile or unit.
  6. Audit for over-broad permissions with find / -perm -o+w -type f 2>/dev/null and fix anything unexpected.