Why ACL
Classic [[file-permissions|rwx]] lets you set rights for one owner, one group, and everyone else. When you need "Alice read+write, Bob read, everyone else nothing," three sets are not enough.
Your options:
- Create a new group with Alice and Bob, but Bob needs read only; a single group cannot express that
- Use setgid plus a shared group, which still gives everyone in the group the same rights
- POSIX ACL, which grants rights to individual users or groups one at a time
ACL is an extension of rwx, not a replacement. The base owner/group/other stay; ACL is added on top.
Where it works
Supported on ext4, xfs, btrfs, tmpfs (with RAM on kernel 6
and later), and zfs. It does not work on FAT/NTFS or on old vfat. Mount
with acl (often the default on ext); on xfs it is on by default.
Check it:
mount | grep ' / ' # look for acl in the options (or just the absence of noacl)
tune2fs -l /dev/sda1 | grep -i acl
getfacl: reading
$ getfacl /home/shared/report.pdf
# file: home/shared/report.pdf
# owner: alice
# group: team
user::rw-
user:bob:r--
group::r--
group:auditors:r--
mask::r--
other::---
Reading the output:
user::rw-is the owner's rights (alice)user:bob:r--is a named user; the "r" bitgroup::r--is the group's rights (team)group:auditors:r--is a named groupmask::r--is the upper bound for every ACL entry except owner and otherother::---is everyone else
If ls -l shows a + after the permissions:
-rw-r--r--+ 1 alice team 12K May 2 14:00 report.pdf
that means "the file has an ACL."
setfacl: writing
Basic syntax:
setfacl -m u:bob:r-- file
setfacl -m u:bob:rwx,g:auditors:rx file
setfacl -m u:bob:- file # explicitly "nothing"
setfacl -x u:bob file # remove the ACL for bob
setfacl -b file # clear all ACL (keep the base rwx)
setfacl --restore=acl-backup.txt # from a backup
Options:
| Option | What it does |
|---|---|
-m | modify: add or change |
-x | remove specific entries |
-b | clear all |
-k | remove the default ACL |
-R | recursive |
-d | work with the default ACL (not the effective one) |
Who the entry targets
| Prefix | Who |
|---|---|
u:NAME | a specific user |
g:NAME | a specific group |
m:: | mask |
o:: | other |
u:: | owner (same as chmod u) |
g:: | owning group |
Mask: the upper bound
The mask limits the effective rights for every named user/group
and for the owning group:
user::rw-
user:bob:rwx ← declared rwx
group::rwx
mask::r-- ← but the mask is r only
other::r--
Bob effectively has only r--. ls shows effective:r-- to the right of
the entry. This is a feature, not a bug: run chmod g-w and
guarantee that no ACL can grant write.
setfacl recomputes the mask automatically:
setfacl -m u:bob:rwx file # the mask becomes rwx
setfacl -n -m u:bob:rwx file # -n: do NOT recompute the mask
Default ACL: inheritance
Only on directories. A default ACL applies to new files and subdirectories created inside it:
setfacl -d -m u:bob:rx /home/shared
setfacl -d -m g:team:rwx /home/shared
Now any new file in /home/shared is created with these ACL plus the
usual uid/gid logic. Existing files are not touched.
This is the main use case for ACL in production: a shared folder for a team, so you do not have to fight umask, setgid, and chown every time.
To copy the default into the effective ACL for all existing files:
getfacl --default /home/shared > acl.tpl
setfacl --set-file=acl.tpl -R /home/shared
Full example: a shared team folder
# Create it
sudo mkdir /srv/team-share
sudo chgrp team /srv/team-share
sudo chmod g+s /srv/team-share # setgid: inherit the group
# Default ACL: the team gets rwx, auditors get r only
sudo setfacl -d -m g:team:rwx /srv/team-share
sudo setfacl -d -m g:auditors:rx /srv/team-share
sudo setfacl -d -m o::- /srv/team-share
# Bring the existing files in line too
sudo setfacl -R -m g:team:rwx,g:auditors:rx,o::- /srv/team-share
Now any member of team can write to any file, any auditor can read,
and "other" sees nothing.
ACL and cp / tar / rsync
Not every tool carries ACL by default:
cppreserves ACL with-p(preserve mode includes ACL)tarneeds--acls(on older GNU tar,--aclsis supported from 1.27)rsyncneeds-A(--acls); it adds to the standard-afind ... -exec cp: remember-p
Backups:
getfacl -R /srv/team-share > acl-backup.txt
# ...
setfacl --restore=acl-backup.txt
ACL vs SELinux/AppArmor
ACL is DAC (Discretionary Access Control): the owner decides. SELinux/AppArmor is MAC: a system policy layered on top. They do not replace each other. If SELinux denied something, ACL will not help; if ACL denied it, SELinux will not give it back.
More in selinux-apparmor and capabilities.
When something goes wrong
setfacl: Operation not supported: mounted withoutacl(old ext mount), or the filesystem does not support it (vfat, NFSv3 without acl).- chmod "ate" the ACL: old semantics, where
chmod g+wchanged the mask and the ACL along with the group bit. On newer kernelschmodusually touches only the classic bits, but the mask can be recomputed. Smarter:setfacl -m m::rwx. - Default ACL is not inherited over NFS: old NFS clients do not support ACL. NFSv4 ACL (a different standard!) is a separate story.
tarlost the ACL: there was no--acls. Usebsdtar(libarchive) or--acls --xattrs.- You see
+but getfacl is empty: this happens with a corrupted ACL blob; runsetfacl -band start over.
Alternatives
- NFSv4 ACL: a different standard, closer to Windows/Solaris
- Richacl: deprecated, never merged into mainline
- xattr directly through [[extended-attributes|setfattr]]: ACL is
stored exactly as the xattr
system.posix_acl_*