18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ciExtended Attributes 48c2ecf20Sopenharmony_ci------------------- 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ciExtended attributes (xattrs) are typically stored in a separate data 78c2ecf20Sopenharmony_ciblock on the disk and referenced from inodes via ``inode.i_file_acl*``. 88c2ecf20Sopenharmony_ciThe first use of extended attributes seems to have been for storing file 98c2ecf20Sopenharmony_ciACLs and other security data (selinux). With the ``user_xattr`` mount 108c2ecf20Sopenharmony_cioption it is possible for users to store extended attributes so long as 118c2ecf20Sopenharmony_ciall attribute names begin with “user”; this restriction seems to have 128c2ecf20Sopenharmony_cidisappeared as of Linux 3.0. 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciThere are two places where extended attributes can be found. The first 158c2ecf20Sopenharmony_ciplace is between the end of each inode entry and the beginning of the 168c2ecf20Sopenharmony_cinext inode entry. For example, if inode.i\_extra\_isize = 28 and 178c2ecf20Sopenharmony_cisb.inode\_size = 256, then there are 256 - (128 + 28) = 100 bytes 188c2ecf20Sopenharmony_ciavailable for in-inode extended attribute storage. The second place 198c2ecf20Sopenharmony_ciwhere extended attributes can be found is in the block pointed to by 208c2ecf20Sopenharmony_ci``inode.i_file_acl``. As of Linux 3.11, it is not possible for this 218c2ecf20Sopenharmony_ciblock to contain a pointer to a second extended attribute block (or even 228c2ecf20Sopenharmony_cithe remaining blocks of a cluster). In theory it is possible for each 238c2ecf20Sopenharmony_ciattribute's value to be stored in a separate data block, though as of 248c2ecf20Sopenharmony_ciLinux 3.11 the code does not permit this. 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciKeys are generally assumed to be ASCIIZ strings, whereas values can be 278c2ecf20Sopenharmony_cistrings or binary data. 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciExtended attributes, when stored after the inode, have a header 308c2ecf20Sopenharmony_ci``ext4_xattr_ibody_header`` that is 4 bytes long: 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci.. list-table:: 338c2ecf20Sopenharmony_ci :widths: 8 8 24 40 348c2ecf20Sopenharmony_ci :header-rows: 1 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci * - Offset 378c2ecf20Sopenharmony_ci - Type 388c2ecf20Sopenharmony_ci - Name 398c2ecf20Sopenharmony_ci - Description 408c2ecf20Sopenharmony_ci * - 0x0 418c2ecf20Sopenharmony_ci - \_\_le32 428c2ecf20Sopenharmony_ci - h\_magic 438c2ecf20Sopenharmony_ci - Magic number for identification, 0xEA020000. This value is set by the 448c2ecf20Sopenharmony_ci Linux driver, though e2fsprogs doesn't seem to check it(?) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciThe beginning of an extended attribute block is in 478c2ecf20Sopenharmony_ci``struct ext4_xattr_header``, which is 32 bytes long: 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci.. list-table:: 508c2ecf20Sopenharmony_ci :widths: 8 8 24 40 518c2ecf20Sopenharmony_ci :header-rows: 1 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci * - Offset 548c2ecf20Sopenharmony_ci - Type 558c2ecf20Sopenharmony_ci - Name 568c2ecf20Sopenharmony_ci - Description 578c2ecf20Sopenharmony_ci * - 0x0 588c2ecf20Sopenharmony_ci - \_\_le32 598c2ecf20Sopenharmony_ci - h\_magic 608c2ecf20Sopenharmony_ci - Magic number for identification, 0xEA020000. 618c2ecf20Sopenharmony_ci * - 0x4 628c2ecf20Sopenharmony_ci - \_\_le32 638c2ecf20Sopenharmony_ci - h\_refcount 648c2ecf20Sopenharmony_ci - Reference count. 658c2ecf20Sopenharmony_ci * - 0x8 668c2ecf20Sopenharmony_ci - \_\_le32 678c2ecf20Sopenharmony_ci - h\_blocks 688c2ecf20Sopenharmony_ci - Number of disk blocks used. 698c2ecf20Sopenharmony_ci * - 0xC 708c2ecf20Sopenharmony_ci - \_\_le32 718c2ecf20Sopenharmony_ci - h\_hash 728c2ecf20Sopenharmony_ci - Hash value of all attributes. 738c2ecf20Sopenharmony_ci * - 0x10 748c2ecf20Sopenharmony_ci - \_\_le32 758c2ecf20Sopenharmony_ci - h\_checksum 768c2ecf20Sopenharmony_ci - Checksum of the extended attribute block. 778c2ecf20Sopenharmony_ci * - 0x14 788c2ecf20Sopenharmony_ci - \_\_u32 798c2ecf20Sopenharmony_ci - h\_reserved[3] 808c2ecf20Sopenharmony_ci - Zero. 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciThe checksum is calculated against the FS UUID, the 64-bit block number 838c2ecf20Sopenharmony_ciof the extended attribute block, and the entire block (header + 848c2ecf20Sopenharmony_cientries). 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciFollowing the ``struct ext4_xattr_header`` or 878c2ecf20Sopenharmony_ci``struct ext4_xattr_ibody_header`` is an array of 888c2ecf20Sopenharmony_ci``struct ext4_xattr_entry``; each of these entries is at least 16 bytes 898c2ecf20Sopenharmony_cilong. When stored in an external block, the ``struct ext4_xattr_entry`` 908c2ecf20Sopenharmony_cientries must be stored in sorted order. The sort order is 918c2ecf20Sopenharmony_ci``e_name_index``, then ``e_name_len``, and finally ``e_name``. 928c2ecf20Sopenharmony_ciAttributes stored inside an inode do not need be stored in sorted order. 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci.. list-table:: 958c2ecf20Sopenharmony_ci :widths: 8 8 24 40 968c2ecf20Sopenharmony_ci :header-rows: 1 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci * - Offset 998c2ecf20Sopenharmony_ci - Type 1008c2ecf20Sopenharmony_ci - Name 1018c2ecf20Sopenharmony_ci - Description 1028c2ecf20Sopenharmony_ci * - 0x0 1038c2ecf20Sopenharmony_ci - \_\_u8 1048c2ecf20Sopenharmony_ci - e\_name\_len 1058c2ecf20Sopenharmony_ci - Length of name. 1068c2ecf20Sopenharmony_ci * - 0x1 1078c2ecf20Sopenharmony_ci - \_\_u8 1088c2ecf20Sopenharmony_ci - e\_name\_index 1098c2ecf20Sopenharmony_ci - Attribute name index. There is a discussion of this below. 1108c2ecf20Sopenharmony_ci * - 0x2 1118c2ecf20Sopenharmony_ci - \_\_le16 1128c2ecf20Sopenharmony_ci - e\_value\_offs 1138c2ecf20Sopenharmony_ci - Location of this attribute's value on the disk block where it is stored. 1148c2ecf20Sopenharmony_ci Multiple attributes can share the same value. For an inode attribute 1158c2ecf20Sopenharmony_ci this value is relative to the start of the first entry; for a block this 1168c2ecf20Sopenharmony_ci value is relative to the start of the block (i.e. the header). 1178c2ecf20Sopenharmony_ci * - 0x4 1188c2ecf20Sopenharmony_ci - \_\_le32 1198c2ecf20Sopenharmony_ci - e\_value\_inum 1208c2ecf20Sopenharmony_ci - The inode where the value is stored. Zero indicates the value is in the 1218c2ecf20Sopenharmony_ci same block as this entry. This field is only used if the 1228c2ecf20Sopenharmony_ci INCOMPAT\_EA\_INODE feature is enabled. 1238c2ecf20Sopenharmony_ci * - 0x8 1248c2ecf20Sopenharmony_ci - \_\_le32 1258c2ecf20Sopenharmony_ci - e\_value\_size 1268c2ecf20Sopenharmony_ci - Length of attribute value. 1278c2ecf20Sopenharmony_ci * - 0xC 1288c2ecf20Sopenharmony_ci - \_\_le32 1298c2ecf20Sopenharmony_ci - e\_hash 1308c2ecf20Sopenharmony_ci - Hash value of attribute name and attribute value. The kernel doesn't 1318c2ecf20Sopenharmony_ci update the hash for in-inode attributes, so for that case this value 1328c2ecf20Sopenharmony_ci must be zero, because e2fsck validates any non-zero hash regardless of 1338c2ecf20Sopenharmony_ci where the xattr lives. 1348c2ecf20Sopenharmony_ci * - 0x10 1358c2ecf20Sopenharmony_ci - char 1368c2ecf20Sopenharmony_ci - e\_name[e\_name\_len] 1378c2ecf20Sopenharmony_ci - Attribute name. Does not include trailing NULL. 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciAttribute values can follow the end of the entry table. There appears to 1408c2ecf20Sopenharmony_cibe a requirement that they be aligned to 4-byte boundaries. The values 1418c2ecf20Sopenharmony_ciare stored starting at the end of the block and grow towards the 1428c2ecf20Sopenharmony_cixattr\_header/xattr\_entry table. When the two collide, the overflow is 1438c2ecf20Sopenharmony_ciput into a separate disk block. If the disk block fills up, the 1448c2ecf20Sopenharmony_cifilesystem returns -ENOSPC. 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciThe first four fields of the ``ext4_xattr_entry`` are set to zero to 1478c2ecf20Sopenharmony_cimark the end of the key list. 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciAttribute Name Indices 1508c2ecf20Sopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~ 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciLogically speaking, extended attributes are a series of key=value pairs. 1538c2ecf20Sopenharmony_ciThe keys are assumed to be NULL-terminated strings. To reduce the amount 1548c2ecf20Sopenharmony_ciof on-disk space that the keys consume, the beginning of the key string 1558c2ecf20Sopenharmony_ciis matched against the attribute name index. If a match is found, the 1568c2ecf20Sopenharmony_ciattribute name index field is set, and matching string is removed from 1578c2ecf20Sopenharmony_cithe key name. Here is a map of name index values to key prefixes: 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci.. list-table:: 1608c2ecf20Sopenharmony_ci :widths: 16 64 1618c2ecf20Sopenharmony_ci :header-rows: 1 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci * - Name Index 1648c2ecf20Sopenharmony_ci - Key Prefix 1658c2ecf20Sopenharmony_ci * - 0 1668c2ecf20Sopenharmony_ci - (no prefix) 1678c2ecf20Sopenharmony_ci * - 1 1688c2ecf20Sopenharmony_ci - “user.” 1698c2ecf20Sopenharmony_ci * - 2 1708c2ecf20Sopenharmony_ci - “system.posix\_acl\_access” 1718c2ecf20Sopenharmony_ci * - 3 1728c2ecf20Sopenharmony_ci - “system.posix\_acl\_default” 1738c2ecf20Sopenharmony_ci * - 4 1748c2ecf20Sopenharmony_ci - “trusted.” 1758c2ecf20Sopenharmony_ci * - 6 1768c2ecf20Sopenharmony_ci - “security.” 1778c2ecf20Sopenharmony_ci * - 7 1788c2ecf20Sopenharmony_ci - “system.” (inline\_data only?) 1798c2ecf20Sopenharmony_ci * - 8 1808c2ecf20Sopenharmony_ci - “system.richacl” (SuSE kernels only?) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciFor example, if the attribute key is “user.fubar”, the attribute name 1838c2ecf20Sopenharmony_ciindex is set to 1 and the “fubar” name is recorded on disk. 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciPOSIX ACLs 1868c2ecf20Sopenharmony_ci~~~~~~~~~~ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciPOSIX ACLs are stored in a reduced version of the Linux kernel (and 1898c2ecf20Sopenharmony_cilibacl's) internal ACL format. The key difference is that the version 1908c2ecf20Sopenharmony_cinumber is different (1) and the ``e_id`` field is only stored for named 1918c2ecf20Sopenharmony_ciuser and group ACLs. 192