18a98ec7cSDarrick J. Wong.. SPDX-License-Identifier: GPL-2.0 28a98ec7cSDarrick J. Wong 38a98ec7cSDarrick J. WongExtended Attributes 48a98ec7cSDarrick J. Wong------------------- 58a98ec7cSDarrick J. Wong 68a98ec7cSDarrick J. WongExtended attributes (xattrs) are typically stored in a separate data 78a98ec7cSDarrick J. Wongblock on the disk and referenced from inodes via ``inode.i_file_acl*``. 88a98ec7cSDarrick J. WongThe first use of extended attributes seems to have been for storing file 98a98ec7cSDarrick J. WongACLs and other security data (selinux). With the ``user_xattr`` mount 108a98ec7cSDarrick J. Wongoption it is possible for users to store extended attributes so long as 118a98ec7cSDarrick J. Wongall attribute names begin with “user”; this restriction seems to have 128a98ec7cSDarrick J. Wongdisappeared as of Linux 3.0. 138a98ec7cSDarrick J. Wong 148a98ec7cSDarrick J. WongThere are two places where extended attributes can be found. The first 158a98ec7cSDarrick J. Wongplace is between the end of each inode entry and the beginning of the 16*3103084aSWang Jianjiannext inode entry. For example, if inode.i_extra_isize = 28 and 17*3103084aSWang Jianjiansb.inode_size = 256, then there are 256 - (128 + 28) = 100 bytes 188a98ec7cSDarrick J. Wongavailable for in-inode extended attribute storage. The second place 198a98ec7cSDarrick J. Wongwhere extended attributes can be found is in the block pointed to by 208a98ec7cSDarrick J. Wong``inode.i_file_acl``. As of Linux 3.11, it is not possible for this 218a98ec7cSDarrick J. Wongblock to contain a pointer to a second extended attribute block (or even 228a98ec7cSDarrick J. Wongthe remaining blocks of a cluster). In theory it is possible for each 238a98ec7cSDarrick J. Wongattribute's value to be stored in a separate data block, though as of 248a98ec7cSDarrick J. WongLinux 3.11 the code does not permit this. 258a98ec7cSDarrick J. Wong 268a98ec7cSDarrick J. WongKeys are generally assumed to be ASCIIZ strings, whereas values can be 278a98ec7cSDarrick J. Wongstrings or binary data. 288a98ec7cSDarrick J. Wong 298a98ec7cSDarrick J. WongExtended attributes, when stored after the inode, have a header 308a98ec7cSDarrick J. Wong``ext4_xattr_ibody_header`` that is 4 bytes long: 318a98ec7cSDarrick J. Wong 328a98ec7cSDarrick J. Wong.. list-table:: 338a98ec7cSDarrick J. Wong :widths: 8 8 24 40 348a98ec7cSDarrick J. Wong :header-rows: 1 358a98ec7cSDarrick J. Wong 368a98ec7cSDarrick J. Wong * - Offset 378a98ec7cSDarrick J. Wong - Type 388a98ec7cSDarrick J. Wong - Name 398a98ec7cSDarrick J. Wong - Description 408a98ec7cSDarrick J. Wong * - 0x0 41*3103084aSWang Jianjian - __le32 42*3103084aSWang Jianjian - h_magic 438a98ec7cSDarrick J. Wong - Magic number for identification, 0xEA020000. This value is set by the 448a98ec7cSDarrick J. Wong Linux driver, though e2fsprogs doesn't seem to check it(?) 458a98ec7cSDarrick J. Wong 468a98ec7cSDarrick J. WongThe beginning of an extended attribute block is in 478a98ec7cSDarrick J. Wong``struct ext4_xattr_header``, which is 32 bytes long: 488a98ec7cSDarrick J. Wong 498a98ec7cSDarrick J. Wong.. list-table:: 508a98ec7cSDarrick J. Wong :widths: 8 8 24 40 518a98ec7cSDarrick J. Wong :header-rows: 1 528a98ec7cSDarrick J. Wong 538a98ec7cSDarrick J. Wong * - Offset 548a98ec7cSDarrick J. Wong - Type 558a98ec7cSDarrick J. Wong - Name 568a98ec7cSDarrick J. Wong - Description 578a98ec7cSDarrick J. Wong * - 0x0 58*3103084aSWang Jianjian - __le32 59*3103084aSWang Jianjian - h_magic 608a98ec7cSDarrick J. Wong - Magic number for identification, 0xEA020000. 618a98ec7cSDarrick J. Wong * - 0x4 62*3103084aSWang Jianjian - __le32 63*3103084aSWang Jianjian - h_refcount 648a98ec7cSDarrick J. Wong - Reference count. 658a98ec7cSDarrick J. Wong * - 0x8 66*3103084aSWang Jianjian - __le32 67*3103084aSWang Jianjian - h_blocks 688a98ec7cSDarrick J. Wong - Number of disk blocks used. 698a98ec7cSDarrick J. Wong * - 0xC 70*3103084aSWang Jianjian - __le32 71*3103084aSWang Jianjian - h_hash 728a98ec7cSDarrick J. Wong - Hash value of all attributes. 738a98ec7cSDarrick J. Wong * - 0x10 74*3103084aSWang Jianjian - __le32 75*3103084aSWang Jianjian - h_checksum 768a98ec7cSDarrick J. Wong - Checksum of the extended attribute block. 778a98ec7cSDarrick J. Wong * - 0x14 78*3103084aSWang Jianjian - __u32 79*3103084aSWang Jianjian - h_reserved[3] 808a98ec7cSDarrick J. Wong - Zero. 818a98ec7cSDarrick J. Wong 828a98ec7cSDarrick J. WongThe checksum is calculated against the FS UUID, the 64-bit block number 838a98ec7cSDarrick J. Wongof the extended attribute block, and the entire block (header + 848a98ec7cSDarrick J. Wongentries). 858a98ec7cSDarrick J. Wong 868a98ec7cSDarrick J. WongFollowing the ``struct ext4_xattr_header`` or 878a98ec7cSDarrick J. Wong``struct ext4_xattr_ibody_header`` is an array of 888a98ec7cSDarrick J. Wong``struct ext4_xattr_entry``; each of these entries is at least 16 bytes 898a98ec7cSDarrick J. Wonglong. When stored in an external block, the ``struct ext4_xattr_entry`` 908a98ec7cSDarrick J. Wongentries must be stored in sorted order. The sort order is 918a98ec7cSDarrick J. Wong``e_name_index``, then ``e_name_len``, and finally ``e_name``. 928a98ec7cSDarrick J. WongAttributes stored inside an inode do not need be stored in sorted order. 938a98ec7cSDarrick J. Wong 948a98ec7cSDarrick J. Wong.. list-table:: 958a98ec7cSDarrick J. Wong :widths: 8 8 24 40 968a98ec7cSDarrick J. Wong :header-rows: 1 978a98ec7cSDarrick J. Wong 988a98ec7cSDarrick J. Wong * - Offset 998a98ec7cSDarrick J. Wong - Type 1008a98ec7cSDarrick J. Wong - Name 1018a98ec7cSDarrick J. Wong - Description 1028a98ec7cSDarrick J. Wong * - 0x0 103*3103084aSWang Jianjian - __u8 104*3103084aSWang Jianjian - e_name_len 1058a98ec7cSDarrick J. Wong - Length of name. 1068a98ec7cSDarrick J. Wong * - 0x1 107*3103084aSWang Jianjian - __u8 108*3103084aSWang Jianjian - e_name_index 1098a98ec7cSDarrick J. Wong - Attribute name index. There is a discussion of this below. 1108a98ec7cSDarrick J. Wong * - 0x2 111*3103084aSWang Jianjian - __le16 112*3103084aSWang Jianjian - e_value_offs 1138a98ec7cSDarrick J. Wong - Location of this attribute's value on the disk block where it is stored. 1148a98ec7cSDarrick J. Wong Multiple attributes can share the same value. For an inode attribute 1158a98ec7cSDarrick J. Wong this value is relative to the start of the first entry; for a block this 1168a98ec7cSDarrick J. Wong value is relative to the start of the block (i.e. the header). 1178a98ec7cSDarrick J. Wong * - 0x4 118*3103084aSWang Jianjian - __le32 119*3103084aSWang Jianjian - e_value_inum 1208a98ec7cSDarrick J. Wong - The inode where the value is stored. Zero indicates the value is in the 1218a98ec7cSDarrick J. Wong same block as this entry. This field is only used if the 122*3103084aSWang Jianjian INCOMPAT_EA_INODE feature is enabled. 1238a98ec7cSDarrick J. Wong * - 0x8 124*3103084aSWang Jianjian - __le32 125*3103084aSWang Jianjian - e_value_size 1268a98ec7cSDarrick J. Wong - Length of attribute value. 1278a98ec7cSDarrick J. Wong * - 0xC 128*3103084aSWang Jianjian - __le32 129*3103084aSWang Jianjian - e_hash 1308a98ec7cSDarrick J. Wong - Hash value of attribute name and attribute value. The kernel doesn't 1318a98ec7cSDarrick J. Wong update the hash for in-inode attributes, so for that case this value 1328a98ec7cSDarrick J. Wong must be zero, because e2fsck validates any non-zero hash regardless of 1338a98ec7cSDarrick J. Wong where the xattr lives. 1348a98ec7cSDarrick J. Wong * - 0x10 1358a98ec7cSDarrick J. Wong - char 136*3103084aSWang Jianjian - e_name[e_name_len] 1378a98ec7cSDarrick J. Wong - Attribute name. Does not include trailing NULL. 1388a98ec7cSDarrick J. Wong 1398a98ec7cSDarrick J. WongAttribute values can follow the end of the entry table. There appears to 1408a98ec7cSDarrick J. Wongbe a requirement that they be aligned to 4-byte boundaries. The values 1418a98ec7cSDarrick J. Wongare stored starting at the end of the block and grow towards the 142*3103084aSWang Jianjianxattr_header/xattr_entry table. When the two collide, the overflow is 1438a98ec7cSDarrick J. Wongput into a separate disk block. If the disk block fills up, the 1448a98ec7cSDarrick J. Wongfilesystem returns -ENOSPC. 1458a98ec7cSDarrick J. Wong 1468a98ec7cSDarrick J. WongThe first four fields of the ``ext4_xattr_entry`` are set to zero to 1478a98ec7cSDarrick J. Wongmark the end of the key list. 1488a98ec7cSDarrick J. Wong 1498a98ec7cSDarrick J. WongAttribute Name Indices 1508a98ec7cSDarrick J. Wong~~~~~~~~~~~~~~~~~~~~~~ 1518a98ec7cSDarrick J. Wong 1528a98ec7cSDarrick J. WongLogically speaking, extended attributes are a series of key=value pairs. 1538a98ec7cSDarrick J. WongThe keys are assumed to be NULL-terminated strings. To reduce the amount 1548a98ec7cSDarrick J. Wongof on-disk space that the keys consume, the beginning of the key string 1558a98ec7cSDarrick J. Wongis matched against the attribute name index. If a match is found, the 1568a98ec7cSDarrick J. Wongattribute name index field is set, and matching string is removed from 1578a98ec7cSDarrick J. Wongthe key name. Here is a map of name index values to key prefixes: 1588a98ec7cSDarrick J. Wong 1598a98ec7cSDarrick J. Wong.. list-table:: 1608a98ec7cSDarrick J. Wong :widths: 16 64 1618a98ec7cSDarrick J. Wong :header-rows: 1 1628a98ec7cSDarrick J. Wong 1638a98ec7cSDarrick J. Wong * - Name Index 1648a98ec7cSDarrick J. Wong - Key Prefix 1658a98ec7cSDarrick J. Wong * - 0 1668a98ec7cSDarrick J. Wong - (no prefix) 1678a98ec7cSDarrick J. Wong * - 1 1688a98ec7cSDarrick J. Wong - “user.” 1698a98ec7cSDarrick J. Wong * - 2 170*3103084aSWang Jianjian - “system.posix_acl_access” 1718a98ec7cSDarrick J. Wong * - 3 172*3103084aSWang Jianjian - “system.posix_acl_default” 1738a98ec7cSDarrick J. Wong * - 4 1748a98ec7cSDarrick J. Wong - “trusted.” 1758a98ec7cSDarrick J. Wong * - 6 1768a98ec7cSDarrick J. Wong - “security.” 1778a98ec7cSDarrick J. Wong * - 7 178*3103084aSWang Jianjian - “system.” (inline_data only?) 1798a98ec7cSDarrick J. Wong * - 8 1808a98ec7cSDarrick J. Wong - “system.richacl” (SuSE kernels only?) 1818a98ec7cSDarrick J. Wong 1828a98ec7cSDarrick J. WongFor example, if the attribute key is “user.fubar”, the attribute name 1838a98ec7cSDarrick J. Wongindex is set to 1 and the “fubar” name is recorded on disk. 1848a98ec7cSDarrick J. Wong 1858a98ec7cSDarrick J. WongPOSIX ACLs 1868a98ec7cSDarrick J. Wong~~~~~~~~~~ 1878a98ec7cSDarrick J. Wong 1888a98ec7cSDarrick J. WongPOSIX ACLs are stored in a reduced version of the Linux kernel (and 1898a98ec7cSDarrick J. Wonglibacl's) internal ACL format. The key difference is that the version 1908a98ec7cSDarrick J. Wongnumber is different (1) and the ``e_id`` field is only stored for named 1918a98ec7cSDarrick J. Wonguser and group ACLs. 192