Зачем xattr
Стандартный stat() даёт inode'у фиксированный набор: размер, владельцы, mtime, права. Иногда хочется хранить ещё что-то рядом с файлом - подпись, хеш, тег, mime-type, Origin URL загрузки. xattr - стандартный механизм для этого.
Классические users xattr:
user.mime-type- GNOME / KDE для иконокuser.charset- apache mod_mime для статикиuser.com.dropbox.attributes- Dropbox-меткиuser.checksum.md5- кастомные хеши
Системные xattr активно используются ядром:
security.selinux- метка SELinux ("user_u:object_r:..._t")security.capability- file capabilities (cap_net_bind_service)system.posix_acl_access- [[posix-acl|POSIX ACL]] хранятся именно тутsystem.posix_acl_default- default ACL директорий
Namespaces
| Namespace | Кто пишет | Кто читает | Что |
|---|---|---|---|
user.* | любой с правом write на файл | владелец и подобные | свободные данные приложений |
trusted.* | только root (CAP_SYS_ADMIN) | root | системные tools, FUSE-драйверы |
system.* | ядро | ядро | ACL и подобные структуры |
security.* | LSM (SELinux, AppArmor, IMA) | LSM | метки безопасности и capabilities |
Лимиты:
- Имя ≤ 255 байт
- Значение ≤ 64 KiB на одной ext4 без
-O ea_inode(на больших - в отдельном блоке) - Суммарно на ФС - сильно зависит от inode size; на xfs с
-i size=1024помещается больше встраиваемых
getfattr - чтение
$ getfattr -d file.txt # все user.* (по дефолту)
# file: file.txt
user.mime-type="text/plain"
$ getfattr -d -m '.*' file.txt # все namespace (нужен root для security/trusted)
# file: file.txt
user.mime-type="text/plain"
security.selinux="unconfined_u:object_r:user_home_t:s0"
$ getfattr -n user.mime-type file.txt
# file: file.txt
user.mime-type="text/plain"
$ getfattr -n security.capability /usr/bin/ping
# file: /usr/bin/ping
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAAA
Опции:
| Опция | Что |
|---|---|
-d | dump - все атрибуты |
-n NAME | конкретный |
-m PATTERN | regex для имени; default ^user\. |
-h | если symlink - не следовать |
-R | recursive |
--only-values | только значение, без шапки |
setfattr - запись
setfattr -n user.tag -v "important" file.txt
setfattr -x user.tag file.txt # удалить
setfattr -n user.json -v "$(cat data.json)" file
Бинарные значения (hex):
setfattr -n user.bin -v 0xdeadbeef file.txt
Реальные применения
File capabilities
Linux capabilities делят root-привилегии на ~40 битов.
security.capability xattr на бинарнике даёт ему только нужные:
# Дать ping право слать ICMP без setuid
setcap cap_net_raw+ep /usr/bin/ping
getcap /usr/bin/ping # frontend поверх getfattr
# То же напрямую
getfattr -n security.capability /usr/bin/ping
Это безопаснее setuid - подробнее в capabilities.
SELinux метки
$ getfattr -n security.selinux /etc/passwd
# file: etc/passwd
security.selinux="system_u:object_r:passwd_file_t:s0"
При cp без --preserve=context SELinux-метка теряется и
ставится дефолтная для целевой директории. На прод-сервере это
частая причина "файл скопировался, но программа не может прочитать".
ACL
POSIX ACL физически хранятся как xattr:
$ getfattr -m '^system' file.txt
system.posix_acl_access=0sAgAAAAEABwD/...
Не редактируй напрямую - используй [[posix-acl|setfacl]].
IMA / EVM
Integrity Measurement Architecture хранит подписи в
security.ima и security.evm. Используется в
hardened-системах для measured boot и runtime-integrity.
xattr и cp / tar / rsync
По дефолту не переносятся. Это самый частый баг:
cp -a(archive) - переносит xattrcpбез флагов - не переноситtar- нужен--xattrs(и--xattrs-include='*.*'чтобы захватить все namespace, иначе толькоuser.*)rsync- нужен-X(--xattrs); включи также-Aдля ACL
Скопировать SELinux-context при cp:
cp --preserve=context file new
# или для всего дерева
cp -a /src /dst # -a включает -p со всеми атрибутами
Поддержка по ФС
| ФС | xattr |
|---|---|
| ext4 | да; для больших значений -O ea_inode |
| xfs | да; помещаются в крупный inode |
| btrfs | да |
| tmpfs | да (с ядром >= 6.0 для security namespace) |
| nfs | NFSv4 - частично |
| fat/vfat | нет |
| iso9660 | нет (старая RR-extension - частично) |
При mount -o nouser_xattr - user namespace отключён, остальные работают.
Размер и производительность
- В inode-резервированном пространстве - бесплатно (часть RAM/IO для inode)
- Большие values - в отдельном блоке = +1 IO на чтение
- При очень многих xattr на одном файле - заметные тормоза
ls -l, т.к. ядро может проверять каждый
Когда что-то пошло не так
Operation not supported- mount безuser_xattrили ФС не умеет (vfat). На ext'е это default давно, но тонкие FUSE-mount'ы могут не уметь.Permission deniedприsetfattr -n trusted.*илиsecurity.*- нужен root и соответствующая capability (CAP_SYS_ADMINдля trusted).- xattr пропали после cp/tar/rsync - не было соответствующего флага.
- SELinux denied после переноса - метки не скопировались.
restorecon -Rvвернёт дефолтные для целевой директории. No space leftпри свободном диске - ext4 может упереться в лимит на ea-блоки.tune2fs -l | grep -i ea. Возможно нужен-O ea_inode(требует remkfs).Argument list too long- имя или value превысили лимиты.
Альтернативы
- Resource forks (macOS) - схожая идея, не переносится в Linux
- Side-car файл (
file.metadata.json) - простой, переносится через cp/scp без флагов, но риск рассинхрона - БД - если метаданных много и они часто запрашиваются
- xfs project IDs - для квот на поддерево, не для произвольных тегов