Linux Basics 04: Permissions And Ownership — rwx Is Not The Same On Files And Directories

Published 2022-04-12 20:30 Updated 2022-04-12 22:10 1371 words 7 min read ... Page views Handwritten Every word here was typed by me.

Linux Basics 25: Wrapping Up — Self-Audit Checklists And Where To Go DeeperLinux Basics 24: Boot And Rescue — UEFI, GRUB, initramfs And Emergency ModeLinux Basics 23: Containers And Kernel Boundaries — Namespaces, Cgroups And What docker exec DoesLinux Basics 22: Logs And A Debugging Method — Six Steps From Symptom To Root CauseLinux Basics 21: Scheduled Tasks — The Traps Of crontab And systemd TimersLinux Basics 20: Shell Scripting, Part Two — trap, Logging, Idempotence And LockingLinux Basics 19: Shell Scripting, Part One — Quoting, Tests And Exit CodesLinux Basics 18: Performance And Tracing — Where Is The Machine Actually StuckLinux Basics 17: Firewalls — How iptables, nftables, firewalld And ufw RelateLinux Basics 16: SELinux — When Every Permission Is Correct And The Service Is Still DeniedLinux Basics 15: Advanced Permissions — sudoers Wildcards, ACLs And CapabilitiesLinux Basics 14: SSH And Remote Operations — Keys, Permissions And Three Kinds Of TunnelLinux Basics 13: Networking Fundamentals — Troubleshoot From The Bottom UpLinux Basics 12: Disks And Filesystems — From Block Device To Mount PointLinux Basics 11: systemd — units, systemctl And journalctl Done ProperlyLinux Basics 10: Package Management — What apt Actually Does, And The Four Common ErrorsLinux Basics 09: Users And Groups — passwd, shadow And sudoersLinux Basics 08: Environment Variables And Shell Startup Files — Why ssh Cannot Find Your PATHLinux Basics 07: Processes And Signals — The Real Difference Between TERM And KILLLinux Basics 06: Pipelines And Redirection — Three Streams, One Ordering TrapLinux Basics 05: Text Processing — Turning grep/sort/uniq Into Your Analysis ToolkitLinux Basics 04: Permissions And Ownership — rwx Is Not The Same On Files And DirectoriesLinux Basics 03: The Real Semantics Of ls, cp, mv, rm — And The * That The Shell ExpandsLinux Basics 02: Why / Looks Like This, and What An Inode Really StoresLinux Basics 01: Terminals, Shells, and How Commands Are Actually Found
What the nine bits really mean, why you can delete a file you cannot write, why ls shows a name you cannot read, how umask computes, what the sticky bit protects, and how setuid turns passwd into a privilege entry point.

What This Chapter Solves

For most people permissions stop at “just chmod 777 it”. In real incidents the usual 403 is not a lack of permission on the file at all — it is a missing x on one directory along the path. And the usual misunderstanding is “I can’t write this file, so how did I just delete it?”. Both have one explanation: rwx means one thing on files and another thing on directories.

1. Nine Bits: Three Identities × Three Permissions

ls -l /etc/passwd /tmp /usr/bin/passwd; stat -c '%a %A %U:%G %n' /etc/passwd /tmp
-rw-r--r--  1 root root 2612 ... /etc/passwd
drwxrwxrwx   9 root root 4096 ... /tmp        ← really 777? read on for the sticky bit
BitMeaningValue
rread4
wwrite2
xexecute / traverse1

The three groups are owner (u) / group (g) / others (o). Two ways to change them: numeric (chmod 644 f) or symbolic (chmod u+x,g-w,o=r f). I read results in numeric form and make incremental changes symbolically:

chmod 640 secret.txt            # owner rw, group r, others nothing
chmod u+x script.sh             # add execute for the owner only
chmod -R o-rwx /srv/private     # strip everything from others, recursively
chmod --reference=a.txt b.txt   # copy a's permissions onto b
umask -S                        # show the current umask symbolically

2. The Core Idea: rwx On A Directory Is A Different Language

On files: r read content, w change content, x executable. On directories: r list entries (ls), w add/remove/rename entries, x traverse (enter, cd, reach children).

Because the three are independent, two classic situations appear:

mkdir -p t/sub; echo hi > t/sub/f
chmod 400 t        # directory: r--
ls t               # ✅ names are listed (r is enough)
cat t/sub/f        # ❌ Permission denied (no x, cannot traverse)
chmod 100 t        # directory: --x
ls t               # ❌ cannot list (no r)
cat t/sub/f        # ✅ readable if you know the exact path (x is enough)

My note: the first case is the key to debugging. Most “web 403” and “Permission denied opening a folder” reports are a directory missing x somewhere up the path — even when the target file is 644. Walk the path level by level:

namei -l /srv/www/site/public/index.html

The second case is more counter-intuitive: whether you can delete a file depends on the w+x of its parent directory, not on the file’s own permissions.

mkdir d; echo secret > d/f; sudo chown root:root d/f; chmod 444 d/f
ls -l d/f              # -r--r--r--  ← you have no write permission
rm d/f                 # ✅ still deleted (d belongs to you and is writable + traversable)

rm operates on the directory entry, not the content — the practical consequence of “the file name belongs to the directory” from chapter 02.

3. umask: The Default Mode Of New Files

The rule is a subtraction by bitwise AND with the complement:

file:      666 & ~umask
directory: 777 & ~umask
umask            # commonly 0022
umask 027 ; touch f ; mkdir d ; stat -c '%a %n' f d      # file 640, directory 750
umask 077 ; touch f2 ; mkdir d2 ; stat -c '%a %n' f2 d2  # file 600, directory 700

Two exceptions to remember: cp -p, cp -a and mv carry the source permissions and ignore umask; chmod overrides everything.

A real consequence: ssh private keys must be tight, or the connection is refused.

chmod 600 ~/.ssh/id_rsa
ssh -i ~/.ssh/id_rsa host   # the WARNING: UNPROTECTED PRIVATE KEY FILE! goes away

4. Three Special Bits: setuid, setgid, sticky

ls -l /usr/bin/passwd   # -rwsr-xr-x  ← the owner's x became s
stat -c '%a %n' /tmp    # 1777 → the leading 1 is the sticky bit
BitValueEffectTypical user
setuid4On exec, the effective UID becomes the file owner/usr/bin/passwd must edit /etc/shadow, which ordinary users cannot touch — setuid root does it
setgid2File: effective GID becomes the file group. Directory: new files inherit the directory’s groupshared team directory: chmod g+s /srv/team
sticky1Files inside may only be deleted by their owner, the directory owner, or root/tmp is 1777: anyone can write, nobody can delete your file
sudo find / -xdev -perm -4000 -type f 2>/dev/null | sort

Two traps worth knowing

  1. The kernel ignores the setuid bit on shell scripts. “Put setuid on a script to escalate privileges” simply does not work on Linux (a #!/bin/sh script with setuid is a no-op). Use a binary or a sudo rule instead.
  2. A custom setuid program is a privilege entry point. The list produced by the find -perm -4000 line above is worth reviewing now and then: one unexpected entry usually means something was installed.

5. Ownership And Group

sudo chown alice file                  # new owner
sudo chown alice:devs file             # owner and group at once
sudo chown -R alice:devs /srv/app      # recursive (⚠️ walk down the tree; check the scope first)
sudo chown --reference=/srv/app /srv/app2

Note: chown -R is one of the easiest ways to cause an incident — if another user’s data is mounted inside /srv/app, or you mistype the path, the damage spreads instantly. I now always look first:

find /srv/app -maxdepth 1 -printf '%u:%g %p\n'

6. Three Real Failures And Where To Look

SymptomReal causeCommand
Web 403 while the file is 644a directory on the path lacks xnamei -l /srv/www/.../index.html
ssh: UNPROTECTED PRIVATE KEY FILE / bad permissionskey too open; or the home dir / .ssh writable by others (StrictModes)chmod 700 ~ ~/.ssh; chmod 600 ~/.ssh/id_*
“I can’t change files in this directory”you have x but not w: traverse yes, modify entries nols -ld .

7. Hands-On Checklist

mkdir -p t/sub; echo hi > t/sub/f
chmod 400 t; ls t; cat t/sub/f                    # 1. r lists, no x means no traversal
chmod 100 t; ls t 2>&1 | head -1; cat t/sub/f     # 2. x traverses, no r means no listing
chmod 755 t; namei -l t/sub/f                     # 3. permissions level by level
mkdir d; echo x > d/f; chmod 444 d/f; rm d/f      # 4. deletion follows the parent directory
umask; umask -S                                   # 5. where default modes come from
ls -l /usr/bin/passwd; stat -c '%a %n' /tmp       # 6. the s bit and sticky
sudo find / -xdev -perm -4000 -type f 2>/dev/null | sort   # 7. setuid audit

Summary

  • Directory r/w/x = list / modify entries / traverse. Deletion depends on the parent directory, not the file.
  • namei -l is the tool for “permission denied along a path”.
  • umask subtracts from 666/777; cp -p and mv ignore it.
  • setuid swaps the effective UID, setgid makes new files inherit the group, sticky protects /tmp; setuid on scripts does nothing.
  • Debug order: x on every directory along the path → the target file’s mode → whether owner/group match the identity actually running.

Next Up

Text processing: grep, sort, uniq, cut, tr — why their combination replaces most hand-written helper scripts, and the streaming mindset: one pipe, no intermediate files.

Written by Handwritten

If you enjoyed this, leave a comment~

Loading...