Linux Permissions and ACLs, Properly
Introduction¶
The classic owner/group/other model handles most cases. When it doesn't — "this one service account also needs read access" — the answer is ACLs, not a tangle of supplementary groups. This covers both.
The mode bits¶
ls -l file
# -rwxr-x--- 1 alice devs ...
# |L-+-L-+-L-+
# | | | L other: ---
# | | L group devs: r-x
# | L owner alice: rwx
# L type: - file, d dir, l symlink
Octal: r=4 w=2 x=1, per class. 750 = rwxr-x---. chmod 640 file,
chmod u+x,g-w file.
On directories, x means "can traverse into / access entries by name",
r means "can ls the contents", w means "can create/delete entries" (note:
deleting a file needs w on the directory, not the file).
Special bits¶
| Bit | Octal | On a file | On a directory |
|---|---|---|---|
| setuid | 4000 | Runs as the file's owner (passwd, sudo) |
(ignored) |
| setgid | 2000 | Runs as the file's group | New files inherit the dir's group |
| sticky | 1000 | (ignored) | Only the owner can delete their own files (/tmp) |
chmod 2775 /srv/shared # setgid dir: everything created here is group 'devs'
find / -perm -4000 -type f 2>/dev/null # audit: all setuid binaries
setgid on a shared directory is the standard fix for "files created by different people end up with the wrong group".
umask¶
New files are created with 0666 & ~umask, directories 0777 & ~umask. A
umask of 022 (the common default) gives files 644, dirs 755. For a
locked-down service, set UMask=0027 in the systemd unit's [Service]
section rather than wrapping the command in a shell that runs umask.
POSIX ACLs¶
When you need "group devs has rwx, and also user backup has r-x,
and everyone else nothing" — that's more than three classes. ACLs add
named-user and named-group entries.
# Requires the filesystem mounted with 'acl' (default on ext4/xfs for years)
getfacl /srv/app # show all ACL entries
setfacl -m u:backup:rx /srv/app # grant user backup read+execute
setfacl -m g:auditors:r /srv/app/logs # grant group auditors read
setfacl -x u:backup /srv/app # remove that entry
setfacl -b /srv/app # strip all ACLs
Default ACLs (inheritance)¶
A default ACL on a directory is the template new entries inherit:
# Every new file/dir under /srv/app gets user backup:rx automatically
setfacl -d -m u:backup:rx /srv/app
setfacl -R -m u:backup:rx /srv/app # also apply to existing contents
The mask¶
getfacl shows a mask:: line — it's the ceiling on all named entries and the
owning group. If you setfacl -m u:backup:rwx but the mask is r--, backup
effectively gets r--. setfacl recalculates the mask automatically unless you
pass -n. A + at the end of ls -l mode means ACLs are present.
Verification and troubleshooting¶
# What can user 'backup' actually do with this path?
sudo -u backup test -r /srv/app/config && echo readable
namei -l /srv/app/config/db.yaml # permission of every path component
- "Permission denied" despite correct file mode — a parent directory lacks
xfor that user.namei -lwalks the whole path and shows where it breaks. - ACL set but no effect — the
maskis clamping it.getfacland look at the#effective:comments;setfacl -m m::rwxto widen the mask. - New files don't inherit the ACL — you set an access ACL, not a
default one. Use
setfacl -d -m ...on the directory. - setgid dir but files still wrong group — the process is calling
chown/chmodafter creating, or the mount lost the bit. Re-chmod g+s. Operation not supported— filesystem mounted withoutacl(rare now), or a filesystem that doesn't support them (some FUSE, older NFS withoutnfs4_acl).- SELinux blocks it even though the permissions allow it —
ls -Z,ausearch -m avc -ts recent. Discretionary permissions and SELinux are both checked; both must pass.
Related tools and reading¶
- On-site: Linux commands reference, .htpasswd Generator.
- Related posts: SELinux without setenforce 0, How systemd unit files work.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Linux & Sysadmin
resolv.conf and systemd-resolved
On modern distros /etc/resolv.conf points at a stub resolver managed by systemd-resolved. Editing it directly usually does nothing — here's the real model.
October 24, 2026Tuning Open File Limits on Linux
Four different limits control how many files a process can open. 'Too many open files' means you're hitting one specific one — here's how to find and raise it.
October 24, 2026ss and conntrack for Connection Debugging
ss shows you every socket and its send/receive queues; conntrack shows what the firewall is tracking. Together they explain most 'connection refused' and 'no buffer space' problems.
October 24, 2026