This is your one-stop reference for Linux ACL interview preparation. The questions are grouped by topic, progress from basic to advanced, and include code-based questions that often appear in Linux system programming interviews. Each answer is detailed enough to satisfy a senior-level interviewer but clear enough to understand at a glance.
Section 1: Overview & Tag Types
- ACL_USER_OBJ — Permissions for the file owner. Exactly one per ACL.
- ACL_USER — Permissions for a specific user identified by UID. Zero or more per ACL.
- ACL_GROUP_OBJ — Permissions for the file’s owning group. Exactly one per ACL.
- ACL_GROUP — Permissions for a specific group identified by GID. Zero or more per ACL.
- ACL_MASK — Upper bound on permissions granted by ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP entries combined. At most one per ACL.
- ACL_OTHER — Permissions for users matching none of the above. Exactly one per ACL.
system.posix_acl_access extended attribute to be stored.system.posix_acl_access. The default ACL (on directories) is stored in system.posix_acl_default. For a minimal ACL, only the standard inode permission bits are used and no extended attribute is needed. To enable ACLs on ext2/ext3/ext4/Reiserfs, the file system must be mounted with the -o acl mount option.acl_valid().Section 2: Permission-Checking Algorithm
The kernel checks in this fixed order, stopping at the first match:
- Privileged process: All access granted. Exception: execute is granted only if at least one ACL entry grants it.
- ACL_USER_OBJ: If the process’s effective UID matches the file owner, permissions from this entry are used (no mask applied).
- ACL_USER: If the effective UID matches an ACL_USER entry’s qualifier, that entry’s permissions ANDed with ACL_MASK are granted.
- Group class: If any of the process’s group IDs (effective or supplementary) match the file group or any ACL_GROUP qualifier, the matching entry’s permissions ANDed with ACL_MASK are used. If a match is found but denies access, deny (no fallthrough to ACL_OTHER).
- ACL_OTHER: If none of the above matched, permissions from ACL_OTHER are granted.
Section 3: ACL Text Forms
Long text form: one entry per line, supports comments starting with #. Used by getfacl output and setfacl -M file. Example:
user::rw-
user:alice:r--
group::r--
mask::rw-
other::---
Short text form: all entries on one line separated by commas. Used with setfacl -m. Example:
u::rw-,u:alice:r--,g::r--,m::rw-,o::---
u:paulh:r-x,g:teach:-w- (short form) or equivalently:
user:paulh:r-x
group:teach:-w-
Note that you can also abbreviate permissions as rx and w (omitting the dash) in short text form.
u::rwx and u:alice:rwx in ACL text form?u::rwx (no qualifier between the colons) means ACL_USER_OBJ — permissions for the file owner. u:alice:rwx (with qualifier “alice”) means ACL_USER — permissions for the specific user named alice. The presence or absence of the tag qualifier is what distinguishes ACL_USER_OBJ from ACL_USER, and ACL_GROUP_OBJ from ACL_GROUP.Section 4: ACL_MASK
chmod(). It acts as an upper bound on the permissions of the “group class” (ACL_USER, ACL_GROUP_OBJ, ACL_GROUP entries). When an ACL-unaware application calls chmod(file, mode), instead of destroying the fine-grained ACL_USER and ACL_GROUP entries, Linux changes the ACL_MASK entry to reflect the new group permissions. This preserves the individual per-user and per-group ACL entries while still honouring the semantics intended by the chmod() call.chmod() changes ACL_MASK when you modify the group bits — not ACL_GROUP_OBJ. Similarly, the group permission bits returned by stat() in st_mode reflect the ACL_MASK permissions, not ACL_GROUP_OBJ. The owner and other bits still map directly to ACL_USER_OBJ and ACL_OTHER.#effective: comment in getfacl output mean?#effective: comment is shown by getfacl after an ACL entry when the permissions that entry actually grants are less than what is written in the entry, due to masking by ACL_MASK. For example, user:paulh:r-x #effective:--x means the ACL_USER entry for paulh says r-x, but after ANDing with the ACL_MASK (--x), paulh effectively only gets execute permission.setfacl command and acl_calc_mask() both create the ACL_MASK entry automatically when you add ACL_USER or ACL_GROUP entries.Section 5: getfacl & setfacl Commands
ls -l appends a plus sign (+) after the traditional 9-character permission field. For example: -rwxr-x--x+. The + is the signal to use getfacl to see the full permissions.setfacl -m modifies — it adds or updates only the specified entries while leaving all other existing entries intact. setfacl --set replaces the entire ACL with exactly the entries you provide; any entries not specified are removed. Use --set when you want full control over the resulting ACL and don’t want old entries to linger.# Backup ACLs of entire /data tree
getfacl -R /data > acl_backup.txt
# Restore ACLs from backup
setfacl --restore=acl_backup.txt
This preserves all ACL entries including named users, named groups, and default ACLs. It is especially useful before operations like tar or rsync that may not preserve ACLs.
setfacl -n (or --no-mask) prevents setfacl from automatically recalculating and updating the ACL_MASK entry after a modification. Normally, after any -m or -x operation, setfacl adjusts the mask to be the union of all group class entries. If you want precise, manual control over the mask value and don’t want it automatically adjusted, use -n.Section 6: Default ACLs & File Creation
mode argument passed to open(): ACL_USER_OBJ (ANDed with owner bits), ACL_MASK or ACL_GROUP_OBJ if no mask (ANDed with group bits), and ACL_OTHER (ANDed with other bits). All other entries (named ACL_USER, ACL_GROUP) are carried over unchanged. The process umask is completely ignored.mode argument of open() after clearing bits turned off by the process umask. The resulting minimal ACL has only ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER entries.system.posix_acl_default. The access ACL is stored in system.posix_acl_access. You can inspect these with getfattr -d <directory>.Section 7: ACL C API
acl_entry_t entry;
int eid;
for (eid = ACL_FIRST_ENTRY; acl_get_entry(acl, eid, &entry) == 1;
eid = ACL_NEXT_ENTRY) {
/* process entry */
}
Use ACL_FIRST_ENTRY on the first call and ACL_NEXT_ENTRY on all subsequent calls. The function returns 1 for a valid entry, 0 when there are no more entries, and -1 on error.
acl_entry_t entry;
acl_permset_t ps;
uid_t uid = 1005;
acl_create_entry(&acl, &entry);
acl_set_tag_type(entry, ACL_USER);
acl_set_qualifier(entry, &uid);
acl_get_permset(entry, &ps);
acl_clear_perms(ps);
acl_add_perm(ps, ACL_READ);
acl_add_perm(ps, ACL_WRITE);
acl_set_permset(entry, ps);
acl_calc_mask(&acl); /* Update/create ACL_MASK */
acl_calc_mask() recalculates the ACL_MASK entry as the union of all permissions in ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. If you add or modify any of these entries and don’t call acl_calc_mask(), the mask may be stale and no longer reflect the actual group class permissions. It also creates the ACL_MASK entry if one doesn’t exist, which is mandatory for ACLs with ACL_USER or ACL_GROUP entries.All of the following return heap-allocated objects that must be freed with acl_free():
acl_get_file()→ acl_tacl_from_text()→ acl_tacl_init()→ acl_tacl_dup()→ acl_tacl_to_text()→ char*acl_get_qualifier()→ void* (uid_t* or gid_t*)
Using standard free() on these is incorrect; always use acl_free().
acl_get_entry() returns: 1 when it successfully retrieves an ACL entry; 0 when there are no more entries in the ACL (end of list); -1 on error (check errno). This is different from most other ACL functions which return 0 on success and -1 on failure.acl_valid(acl) returns 0 if the ACL is structurally valid. An ACL is valid when: ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER each appear exactly once; an ACL_MASK entry is present if any ACL_USER or ACL_GROUP entries exist; there is at most one ACL_MASK entry; no two ACL_USER entries share the same UID; and no two ACL_GROUP entries share the same GID.acl_dup(acl) creates a deep copy of an in-memory ACL and returns a handle to the new copy. You use it when you want to modify an ACL without affecting the original — for example, when you want to experiment with a modified version of an ACL before deciding whether to apply it to a file, or when you want to keep the original ACL for comparison.Section 8: Implementation Limits
- ext2/ext3/ext4: ~500 entries (block-size limited; ~500 for 4 kB blocks). Kernels before 2.6.11 had a hard limit of 32.
- XFS: 25 entries (hard internal limit).
- Reiserfs/JFS: 8191 entries (limited by the 64 kB VFS xattr value size).
- Btrfs: ~500 entries (same block-based constraint as ext4 at time of writing).
/etc/group and reference those groups in the ACL instead of listing individual users.Section 9: Tricky / Scenario Questions
#effective: r-- comment in getfacl output would indicate this.chmod 700: sets ACL_USER_OBJ to rwx (owner gets full access), sets ACL_MASK to — (the group bits of 700 are 0), and sets ACL_OTHER to — (other bits of 700 are 0). The ACL_GROUP_OBJ, ACL_USER, and ACL_GROUP entries are not deleted but their effective permissions become — because ACL_MASK is now —. This is the intended behaviour — ACL entries are preserved but masked to zero, and can be unmasked again by a later chmod that sets group bits.acl_t object tracking a “current position” cursor. Each successful call to acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) advances this cursor and returns the next entry. This means the iteration state is bound to the specific acl_t handle — if you start iterating a second time, you must restart with ACL_FIRST_ENTRY.system.posix_acl_access and system.posix_acl_default), and you can read and write them with getxattr() and setxattr(). However, it is not recommended because the on-disk encoding of ACL entries is a binary format specific to the Linux ACL implementation. The ACL library API handles all encoding/decoding transparently, correctly, and portably. Direct xattr manipulation would require you to understand and manage the binary layout yourself, which is error-prone and non-portable.setfacl -m u:bob:r-- *.c
Or recursively for a directory tree:
find . -name "*.c" -exec setfacl -m u:bob:r-- {} \;
acl_get_perm(permset, perm) is a Linux extension to the POSIX.1e draft standard (not in the portable API). It returns 1 if the specified permission (ACL_READ, ACL_WRITE, or ACL_EXECUTE) is set in the permission set, 0 if not, or -1 on error. The standard POSIX.1e draft does not include a function to query individual permission bits from a permset — you would have to inspect the permset structure directly in a non-portable way. acl_get_perm() fills this gap cleanly. Requires #include <acl/libacl.h>.Quick Reference — Common Commands
# View ACL of a file
getfacl filename
# View without header comments
getfacl --omit-header filename
# View default ACL of a directory
getfacl -d directory/
# Add/modify entries (leaves others intact)
setfacl -m u:alice:rw,g:devteam:r filename
# Set entire ACL (replaces all existing entries)
setfacl --set u::rwx,u:alice:r--,g::r--,m::rw-,o::--- filename
# Remove a specific entry
setfacl -x u:alice filename
# Remove ALL extended entries (back to minimal)
setfacl -b filename
# Remove default ACL from a directory
setfacl -k directory/
# Set a default ACL on a directory
setfacl -d -m u::rwx,g::rwx,o::rx directory/
# Recursively apply ACL
setfacl -R -m u:bob:r-- directory/
# Backup ACLs
getfacl -R . > acls.bak
# Restore ACLs
setfacl --restore=acls.bak
You have covered the full Linux ACL chapter: overview, algorithm, text forms, mask, shell commands, default ACLs, C API, and interview prep. Share EmbeddedPathashala with fellow embedded & Linux learners.
