Permissions: mode bits vs ownership vs ACLs vs capabilities¶
Mental model¶
Four separate access-control systems, often lumped together as "permissions." Mode bits and ACLs control file access. Ownership determines who matches which mode category. Capabilities control what a process is allowed to do at the kernel level.
What it looks like¶
"Fix the permissions." Could mean: chmod, chown, setfacl, or setcap. People use "permissions" for all four interchangeably.
What it really is¶
- Mode bits (rwx): per-inode, three categories — owner / group / other. 9 permission bits + 3 special bits (setuid, setgid, sticky). Stored in the inode.
- Ownership (uid/gid): determines which mode category applies. A process's effective uid is checked against the file's owner uid; then effective gid against file gid; then "other."
- ACLs (Access Control Lists): extend mode bits with per-user and per-group entries. Checked after ownership matching. Stored as extended attributes (xattr).
- Capabilities: decompose root's powers into ~60+ distinct privileges (CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, etc.). Attached to processes or executable files. Process-level, not file-level access control.
Why it seems confusing¶
"Permission denied" could come from any of these systems (or SELinux/AppArmor on top). Mode bits and ACLs control file access. Capabilities control kernel operations. Ownership is not a permission — it determines which permission set applies.
What actually matters¶
- Kernel checks in order: is process uid 0? → owner match? → group match? → other. ACLs insert between owner and other.
- setuid bit: when set on an executable, the process runs with the file owner's uid as effective uid. setgid: same for gid.
- Capabilities replace the setuid-root pattern. Instead of giving a binary full root, grant only CAP_NET_BIND_SERVICE to bind port 80.
- Sticky bit on directories: only file owner (or dir owner or root) can delete entries. Used on /tmp.
- umask masks bits at file creation time — it doesn't change existing permissions.
Common mistakes¶
- Using
chmod 777to "fix" permission errors. This removes all access control instead of diagnosing the real issue. - Forgetting that ACLs override group/other mode bits. If an ACL exists, the group mode bits become the ACL mask.
- Confusing file capabilities with process capabilities.
getcapreads file capabilities;/proc/PID/statusshows process capabilities. - Setting setuid on scripts. The kernel ignores setuid on interpreted scripts (security measure).
Small examples¶
# Mode bits
chmod 750 app.sh # rwxr-x--- (owner/group/other)
stat -c '%a %U:%G' app.sh # 750 deploy:deploy
# Ownership
chown deploy:deploy app.sh # changes which uid/gid match
# ACLs
setfacl -m u:alice:rx app.sh # alice gets r-x regardless
getfacl app.sh # shows ACL entries
# Note: group mode bits now act as ACL mask
# Capabilities
setcap cap_net_bind_service=+ep /usr/bin/myapp
getcap /usr/bin/myapp
# myapp can bind port 80 without running as root
# setuid
chmod u+s /usr/bin/passwd # runs as root (file owner)
# Replaced by capabilities where possible
One-line summary¶
Mode bits = rwx per owner/group/other; ownership = who matches which category; ACLs = fine-grained file access; capabilities = fine-grained root powers for processes.