How Access Control Lists encode permissions as binary flags — covering Linux ACL entries, mask operations, effective permission computation, and real-world usage.
In my work managing shared development servers, I have found that the standard chmod permission model — owner, group, others — breaks down fast when you have more than one group or more than one special user who needs access. This is where ACLs (Access Control Lists) come in. ACLs extend the traditional 9-bit permission model by allowing multiple independent 3-bit permission entries for different users and groups.
Fundamentally, ACLs still use the same 3-bit binary structure we saw with chmod:
I once had to audit a NAS with hundreds of ACL entries. Recognizing the bit patterns in the access mask let me spot a misconfigured deny entry that was blocking backups for months.
| Bit | Permission | Octal | Binary |
|---|---|---|---|
| 2 | Read (r) | 4 | 100 |
| 1 | Write (w) | 2 | 010 |
| 0 | Execute (x) | 1 | 001 |
Each ACL entry stores exactly these 3 bits. The key difference is that instead of having only three slots (owner, group, others), an ACL can have dozens of entries, each with its own 3-bit permission flag. Each entry is associated with a specific user or group on the system.
When you run getfacl on a file that has ACL entries, you will see output like this:
The critical thing I want you to notice is that each entry — user:alice, user:bob, group:ops — has its own 3-bit rwx value, stored as a 3-bit binary number in the filesystem metadata. This is fundamentally different from traditional Unix permissions, where there is exactly one 3-bit group entry.
Linux ACLs define several entry types, each serving a specific role in the permission resolution logic. Understanding these types is essential for correctly configuring ACLs at the binary level.
This is the file owner's permission entry. It uses a standard 3-bit rwx flag. In the ACL system, this is the same as the traditional owner triple. The binary value is exactly what you would set with chmod's first octal digit.
These are additional users who receive specific permissions. Each named user gets its own 3-bit entry. In my deployment scripts, I frequently add ACL_USER entries for service accounts that need limited access to shared directories.
ACL_GROUP_OBJ is the file's owning group entry. ACL_GROUP entries are named groups with their own 3-bit permissions. A file can have multiple ACL_GROUP entries, each granting different permissions to different groups.
This is a critical entry that I will cover in detail in the next section. The mask is a 3-bit value that caps the maximum permissions that ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries can grant. It does not affect ACL_USER_OBJ (the owner) or ACL_OTHER.
This is the traditional "others" permission triple. It applies to anyone who does not match any user or group entry. It remains a 3-bit value and is never affected by the mask.
| Tag Type | Purpose | Bits | Mask-affected? |
|---|---|---|---|
| ACL_USER_OBJ | File owner | 3 (rwx) | No |
| ACL_USER | Named users | 3 each | Yes |
| ACL_GROUP_OBJ | Owning group | 3 | Yes |
| ACL_GROUP | Named groups | 3 each | Yes |
| ACL_MASK | Permission cap | 3 | N/A |
| ACL_OTHER | Everyone else | 3 | No |
The ACL mask is one of the most misunderstood parts of the ACL system. I have seen many engineers spend hours debugging why ACL entries seem to not work, only to discover the mask was restricting their permissions. The mask is a 3-bit binary value that acts as a permission ceiling.
Here is the critical rule: the effective permission for any ACL_USER, ACL_GROUP_OBJ, or ACL_GROUP entry is computed as entry & mask (bitwise AND). Even if an entry has rwx (111), if the mask is r-- (100), the effective permission is r-- (100).
In my experience, the mask gets set automatically when you use setfacl. If you add an ACL_USER entry with rwx, the mask is often updated to rwx as well — but not always. If you later modify the mask to something more restrictive with setfacl -m m::r-x, all existing named user and group entries become restricted.
Here is a practical example from a server I manage. We have a shared deployment directory where the ops team needs full access but contractors should only read:
If an ACL entry seems wrong, always check the mask: getfacl file | grep mask. The mask is the most common source of ACL bugs I encounter. A mask of r-- will neuter every named user or group entry regardless of what they are set to. Use the bitwise calculator to compute effective = entry & mask.
The entire ACL permission resolution system relies on bitwise AND to compute effective permissions. This is not an analogy — the kernel literally does a bitwise AND operation between the ACL entry and the ACL mask. Understanding this bitwise computation is essential for debugging ACL issues.
Here is how the kernel resolves permissions for a user trying to access a file with ACLs:
Steps 2, 3, and 4 involve the bitwise AND with the mask. Let me show you several examples of how this works in practice.
In example 3, the mask of 100 (read-only) effectively neuters every named user and group. Only the owner (ACL_USER_OBJ) and others (ACL_OTHER) are unaffected. This is a common configuration for a read-only maintenance window, but it can be very confusing if you are not expecting it.
The two commands for working with Linux ACLs are getfacl (view) and setfacl (modify). When you use these commands, you are directly manipulating the 3-bit permission bitfields stored in each ACL entry.
The getfacl command shows the binary permission flags for each entry. While it displays them symbolically (rwx), you should train yourself to see them as the 3-bit binary values they represent.
The setfacl -m command accepts permission values in symbolic (u:alice:rwx) or octal (u:alice:7) form. Under the hood, both set the same 3-bit binary flag.
Removing an ACL entry with setfacl -x deletes that entry entirely. The remaining entries are unaffected. This is different from setting an entry to --- (000), which keeps the entry but grants no permissions.
I prefer removing entries over setting them to zero. If an ACL_USER entry exists but has 000 permissions, that user is explicitly denied access even if a group entry would otherwise grant them access. This is because ACL resolution stops at the first match — a user entry with 000 still matches the user, and no further lookups occur.
Use the bitwise calculator to compute effective permissions by ANDing ACL entry values with the mask. See how different mask values restrict access.
An ACL (Access Control List) in Linux extends the traditional Unix permission model beyond owner/group/others. ACLs allow you to assign permissions to multiple specific users and groups independently. Each ACL entry uses the same rwx bit flags as traditional permissions but can be associated with any user or group on the system.
ACL permissions use the same 3-bit binary encoding as traditional Unix permissions. Read (r) is bit 2 (value 4), write (w) is bit 1 (value 2), and execute (x) is bit 0 (value 1). Each ACL entry stores these 3 bits independently. For example, rwx = 111 (7) and r-x = 101 (5). The advantage of ACLs is that this 3-bit structure is replicated for each user or group entry in the list.
The ACL mask entry is a 3-bit value that caps the maximum permissions that named users, named groups, and the group owner class can receive. Even if a specific ACL entry grants rwx, the mask can restrict effective permissions. For example, if the mask is r-- (100, binary 100), then an ACL_USER entry with rwx permissions is effectively reduced to r--. The mask uses bitwise AND to compute effective permissions.
The ACL mask uses a bitwise AND operation to determine effective permissions. Effective = ACL_entry & mask. If a user's ACL entry has rwx (binary 111) and the mask is r-x (binary 101), the effective permission is 111 & 101 = 101 (r-x). The write bit is cleared because the mask has write set to 0.
ACL_USER_OBJ is the file owner's permissions, equivalent to the standard owner triple (bits 8-6 in the 9-bit mask). ACL_USER entries are additional named users with their own 3-bit permission flags. Multiple ACL_USER entries can exist, each for a different user. ACL_USER_OBJ is always present, while ACL_USER entries are optional and defined by setfacl.
Run tune2fs -l /dev/sda1 | grep "Default mount options" or check mount | grep acl. Most modern Linux filesystems (ext4, XFS, Btrfs) have ACL support enabled by default. Use getfacl file to see if ACL entries exist on a specific file.
When you run chmod on a file with ACL entries, the behavior depends on the permission class being modified. Chmod affects ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER. It can also update the ACL_MASK to reflect the group class permissions. The individual ACL_USER and ACL_GROUP entries are not directly modified by chmod, though their effective permissions may change if the mask is updated.