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