Chapter 8: Extended Attributes, ACLs and Quotas
Chapter 8: Extended Attributes, ACLs and Quotas
Standard Unix file metadata is confined to fixed attributes: ownership, file size, timestamps, and 12-bit permission modes. Modern operating systems, security subsystems, and storage managers, however, require associating arbitrary key-value metadata with files: Mandatory Access Control labels (SELinux contexts), capability bounding masks, granular POSIX Access Control Lists (ACLs), cryptographic checksums, and storage accounting identifiers.
In ext4, these capabilities are provided by the Extended Attribute (xattr) subsystem and the quota management framework. This chapter explores how ext4 stores and deduplicates extended attributes, formats POSIX ACLs, manages security namespaces, and enforces hierarchical project quotas.
Extended Attribute Storage (Inline vs. EA Blocks)
Extended attributes in ext4 associate name-value pairs with an inode. Because storage space is at a premium, ext4 employs a two-tier storage model:
┌────────────────────────────────────────────────────────────────────────┐
│ XATTR TWO-TIER STORAGE MODEL │
│ │
│ Tier 1: Inline Storage (Inside Inode) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 256-Byte Inode: Extra space after i_extra_isize (e.g. 96 B) │ │
│ │ [Header Magic: 0xEA020000] [Small xattrs (SELinux, Caps)] │ │
│ │ Benefit: Zero extra disk I/O; fetched in same read as inode │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ Tier 2: External EA Block (i_file_acl > 0) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Dedicated 4 KiB Block allocated on physical disk │ │
│ │ [ext4_xattr_header] [Large xattrs / multiple POSIX ACLs] │ │
│ │ Deduplication: Identical EA blocks shared across files (ref) │ │
│ └──────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
- Inline xattrs: Stored in the trailing portion of the 256-byte inode. Small, frequently queried attributes—such as an SELinux label (
system_u:object_r:httpd_sys_content_t:s0) or Linux capability mask—are embedded directly inside the inode. The kernel fetches both the file’s basic metadata and its security labels in a single physical block read. - External Extended Attribute Block: If an inode’s attributes exceed available inline space, ext4 allocates an external \(4\text{ KiB}\) data block pointed to by
i_file_acl. - Deduplication and Reference Counting: External EA blocks maintain an
h_refcount. If 10,000 files in a directory share an identical, complex POSIX ACL ruleset, ext4 does not allocate 10,000 separate blocks; it points all 10,000 inodes to a single shared EA block, incrementing its reference counter.
The xattr Header and Entry Formats
Both inline and external extended attribute regions begin with the ext4_xattr_header:
struct ext4_xattr_header {
__le32 h_magic; /* Magic number: 0xEA020000 */
__le32 h_refcount; /* Reference count (number of inodes sharing this block) */
__le32 h_blocks; /* Number of disk blocks used (always 1) */
__le32 h_hash; /* Hash value of all attribute names and values */
__le32 h_checksum; /* CRC32c checksum of EA block */
__u32 h_reserved[3];
};The header is followed by an array of ext4_xattr_entry structures, each describing one key-value attribute:
struct ext4_xattr_entry {
__u8 e_name_len; /* Length of attribute name */
__u8 e_name_index; /* Namespace prefix index (1=user, 2=posix_acl, 4=trusted, 6=security) */
__le16 e_value_offs; /* Byte offset to value within the block */
__le32 e_value_inum; /* Inode number (if value is stored in an external inode) */
__le32 e_value_size; /* Byte length of attribute value */
__le32 e_hash; /* Checksum hash of name and value */
char e_name[0]; /* Attribute name string (e.g., "selinux") */
};Entries grow forward from the top of the block, while attribute values are packed backward from the bottom of the block.
POSIX ACLs and the acl_mode Hook
Standard Discretionary Access Control (DAC) limits file permissions to a single user, single group, and others. POSIX Access Control Lists (ACLs) allow attaching multi-user, multi-group access matrices to an inode.
In ext4, POSIX ACLs are not a separate on-disk database; they are stored as extended attributes in the System namespace: - Access ACL: system.posix_acl_access - Default Directory ACL: system.posix_acl_default
┌────────────────────────────────────────────────────────────────────────┐
│ POSIX ACL BINARY HEADER (VFS) │
│ │
│ posix_acl_xattr_header (version: 0x0002) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Entry 0: ACL_USER_OBJ (Permissions for file owner) │ │
│ │ Entry 1: ACL_USER (Specific UID: permissions) │ │
│ │ Entry 2: ACL_GROUP_OBJ (Permissions for file group) │ │
│ │ Entry 3: ACL_GROUP (Specific GID: permissions) │ │
│ │ Entry 4: ACL_MASK (Maximum permissible permissions) │ │
│ │ Entry 5: ACL_OTHER (Permissions for others) │ │
└────────────────────────────────────────────────────────────────────────┘
When an application invokes chmod(), the ext4 VFS hook automatically updates the standard inode i_mode bits and synchronizes the corresponding ACL_USER_OBJ and ACL_OTHER entries in the xattr block.
Project Quotas and User/Group Quotas
Quota systems prevent individual tenants or rogue processes from consuming all available disk space:
- User and Group Quotas: Track disk blocks and inodes owned by specific UIDs or GIDs. In modern ext4, quota tracking is maintained by internal hidden quota inodes (Inode 3 for user quota, Inode 4 for group quota), eliminating the legacy requirement for external
aquota.userfiles. - Project Quotas (
i_projid): While user and group quotas bind to process credentials, Project Quotas bind directly to directory hierarchies regardless of which user writes into them.- Ideal for container runtimes (Docker, Podman, containerd) and multi-tenant web hosting:
# Assign Project ID 1001 to a container storage directory sudo chattr -p 1001 /var/lib/containers/storage/overlay/node-1/ # Enforce a 10 GiB hard limit on Project ID 1001 sudo setquota -P 1001 8G 10G 0 0 /var
Security xattrs: Trusted, User and System Namespaces
Extended attributes are strictly compartmentalized into distinct namespaces defined by e_name_index:
| Namespace Index | Prefix | Access Restriction & Usage |
|---|---|---|
1 |
user.* |
Accessible by unprivileged users subject to standard file permissions. |
2 |
system.posix_acl_access |
Managed by kernel VFS for file POSIX ACL evaluation. |
3 |
system.posix_acl_default |
Default ACLs inherited by newly created child files. |
4 |
trusted.* |
Restricted to processes with CAP_SYS_ADMIN; invisible to normal users. |
6 |
security.* |
Managed by Linux Security Modules: security.selinux, security.apparmor, security.capability (file capabilities). |
This namespace separation prevents unprivileged users from modifying their own process capabilities or altering Mandatory Access Control labels.