ACL Bit Operations

How Access Control Lists encode permissions as binary flags — covering Linux ACL entries, mask operations, effective permission computation, and real-world usage.

Data center server rack with blinking LEDs representing ACL bit-level access control operations
ACL and the 3-Bit Permission Flag ACL Entry Types The Mask Entry Effective Permission Computation getfacl and setfacl in Practice FAQ

ACL and the 3-Bit Permission Flag

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.

BitPermissionOctalBinary
2Read (r)4100
1Write (w)2010
0Execute (x)1001

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:

Sample getfacl Output with Binary Annotations
# file: shared_project/
# owner: jake
# group: devteam
user::rwx   // owner   =  111  (7)
user:alice:rwx   // ACL_USER  =  111  (7)
user:bob:r-x   // ACL_USER  =  101  (5)
group::r-x   // group    =  101  (5)
group:ops:rwx   // ACL_GROUP =  111  (7)
mask::rwx     // mask      =  111  (7)
other::---   // others    =  000  (0)
Each ACL entry stores an independent 3-bit binary permission flag

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.

ACL Entry Types and Their Bit Positions

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.

ACL_USER_OBJ (Owner)

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.

ACL_USER (Named Users)

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.

Setting Alice's Permissions with Bit Flags
# Give alice read+write (but not execute):
setfacl -m u:alice:6 /shared/data  // 6 = 110 = rw-

# Binary representation of Alice's entry:
ACL_USER(alice) = 110 = read(1) + write(1) + execute(0)

ACL_GROUP_OBJ and ACL_GROUP

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.

ACL_MASK

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.

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 TypePurposeBitsMask-affected?
ACL_USER_OBJFile owner3 (rwx)No
ACL_USERNamed users3 eachYes
ACL_GROUP_OBJOwning group3Yes
ACL_GROUPNamed groups3 eachYes
ACL_MASKPermission cap3N/A
ACL_OTHEREveryone else3No

The ACL Mask Entry — Binary Cap

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).

Mask Restricting Effective Permissions
ACL_USER(bob) = 111 (rwx, octal 7)
ACL_MASK       = 101 (r-x, octal 5)

Effective = 111 & 101 = 101 (r-x)
Bob loses write access even though his entry has it!

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:

ACL Mask in Action: Shared Directory Setup
setfacl -m u:ops-team:rwx /deploy    // ACL_USER = 111
setfacl -m u:contractor:r-x /deploy  // ACL_USER = 101
setfacl -m m:rwx /deploy           // MASK = 111

# Later: restrict mask for maintenance window
setfacl -m m:r-x /deploy           // MASK = 101

# Now ops-team's effective = 111 & 101 = 101 (lost write!)
# Contractor's effective = 101 & 101 = 101 (unchanged)

Check Your Mask First

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.

Effective Permission Computation with Bitwise AND

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:

  1. If the user is the file owner, use ACL_USER_OBJ. Mask does not apply.
  2. If the user matches an ACL_USER entry, use ACL_USER_entry & ACL_MASK.
  3. If the user belongs to the owning group, use ACL_GROUP_OBJ & ACL_MASK.
  4. If the user belongs to a named ACL_GROUP, use ACL_GROUP_entry & ACL_MASK.
  5. If no match found, use ACL_OTHER.

Steps 2, 3, and 4 involve the bitwise AND with the mask. Let me show you several examples of how this works in practice.

Example 1: Full Mask, No Restriction
ACL_USER(deploy) = 111 (rwx)
ACL_MASK          = 111 (rwx)

111 & 111 = 111 (rwx)
Effective = rwx — no restriction
Example 2: Mask Removes Write
ACL_GROUP(devs) = 110 (rw-)
ACL_MASK           = 101 (r-x)

110 & 101 = 100 (r--)
Effective = r-- — write and execute both removed
Example 3: Comprehensive ACL Check
ACL_USER(bob)  = 111 (rwx, 7)
ACL_GROUP(ops)  = 101 (r-x, 5)
ACL_GROUP_OBJ   = 110 (rw-, 6)
ACL_MASK          = 100 (r--, 4)

bob effective:   111 & 100 = 100 (r--)
ops effective:   101 & 100 = 100 (r--)
group_obj eff:  110 & 100 = 100 (r--)

Everyone is restricted to read-only by the mask!

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.

getfacl and setfacl in Practice

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.

Reading ACLs with getfacl

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.

Reading getfacl Output as Binary
$ getfacl project/
# file: project/
user::rwx   111 (owner: full access)
user:jenny:rw- 110 (jenny: read+write)
group::r-x   101 (group: read+execute)
group:ops:rwx 111 (ops team: full access)
mask::rwx    111 (no restriction)
other::---   000 (others: no access)

Setting ACLs with setfacl

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.

Setting ACL Entries with Octal Values
# Both commands do the same thing:
setfacl -m u:alice:rwx /shared  // symbolic: rwx = binary 111
setfacl -m u:alice:7 /shared  // octal: 7 = binary 111

# Read-only for contractor:
setfacl -m u:contractor:4 /shared  // octal: 4 = binary 100
# = r-- (read only)

Removing ACL Entries

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.

Remove vs. Set to Zero
setfacl -x u:alice /shared  // Removes alice's entry entirely
setfacl -m u:alice:0 /shared // Sets alice's entry to 000 (---)

# Difference: removed = no match falls through to group/other
# Set to zero = match found with 000 no access granted

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.

Experiment with ACL Bit Operations

Use the bitwise calculator to compute effective permissions by ANDing ACL entry values with the mask. See how different mask values restrict access.

Frequently Asked Questions About ACL Bit Operations

What is an ACL in Linux?

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.

How are ACL permissions stored as bits?

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.

What is the ACL mask entry?

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.

How does the ACL mask affect bitwise 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.

What is the difference between ACL_USER_OBJ and ACL_USER?

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.

How do I check if a filesystem supports ACLs?

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.

What happens to ACLs when you run chmod on a file with ACL entries?

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.

Related Tools

Bitwise Calculator →

AND, OR, XOR, NOT, shifts

Bitwise Guide →

Complete operations reference

Hex to ASCII →

Decode hex strings

SHA256 Generator →

Compute hashes