chattr and Extended Attributes: File Properties Beyond Permissions
ls -l shows you permissions. It does not show you that a file is immutable, that a directory can only be appended to, or that there is an SELinux label attached. Two separate mechanisms hold that information, and their names are similar enough that people mix them up constantly.
Two different things
chattr flags are a fixed set of filesystem-level flags stored in the inode. The filesystem itself understands them and enforces them.
Extended attributes are arbitrary name and value pairs stored alongside the file. The filesystem stores them without caring what they mean; other subsystems attach meaning.
Different commands, different storage, different purposes.
lsattr file # chattr flags
getfattr -d file # extended attributes
chattr flags
lsattr myfile
# --------------e------- myfile
lsattr -d /var/log
lsattr -R /etc | grep -v '^-\{20\}'
That string of dashes is the flag field, with a letter in each position where a flag is set. e means extents, which ext4 sets on everything and which you can ignore.
Immutable
sudo chattr +i important.conf
# now nothing works
sudo rm important.conf # Operation not permitted
sudo mv important.conf x # Operation not permitted
echo x | sudo tee -a important.conf # Operation not permitted
sudo chattr -i important.conf
+i blocks writes, renames, deletion and hard links, for everyone including root. The only way past it is clearing the flag, which requires CAP_LINUX_IMMUTABLE.
Legitimate uses:
- A config file a misbehaving installer keeps overwriting
/etc/resolv.confwhen something insists on rewriting it, though our systemd-resolved guide covers doing that properly instead- Protecting a file during an operation you do not entirely trust
The honest caveat: it is not a security boundary. Anyone with root can clear it in one command. What it defends against is accident and automation, not an attacker.
It is also a favourite trick for making a file appear undeletable to someone who does not know the flag exists. If a file refuses to be removed and the permissions look fine, lsattr is the first thing to check.
Append only
sudo chattr +a /var/log/audit.log
echo "new entry" | sudo tee -a /var/log/audit.log # works
echo "replace" | sudo tee /var/log/audit.log # fails
sudo truncate -s 0 /var/log/audit.log # fails
+a permits appends and nothing else. No truncation, no overwriting, no deletion.
The obvious use is audit logs, where the point is that an intruder cannot erase evidence of what they did. The same caveat applies: root can clear the flag. The real answer for tamper-evident logs is shipping them off the host as they are written, and +a is a useful supplement to that rather than a substitute.
It also interacts badly with logrotate, which needs to rename or truncate. Use copytruncate and expect to clear the flag around rotation, or exclude the file.
The rest worth knowing
| Flag | Effect |
|---|---|
i | Immutable |
a | Append only |
A | Do not update atime |
d | Skip in dump backups |
j | Journal data as well as metadata, ext4 |
C | No copy on write, Btrfs |
c | Transparent compression, Btrfs |
m | No compression, Btrfs |
s | Secure deletion, mostly unimplemented |
u | Undeletable, mostly unimplemented |
e | Extents, informational |
s and u do not do what their names suggest. Secure deletion is not implemented by the major filesystems, and relying on it to overwrite data is a mistake. Full disk encryption is the answer to that problem, as our LUKS guide covers.
The Btrfs ones are genuinely useful
# a new file that should not be copy on write
touch /var/lib/mysql/ibdata1
sudo chattr +C /var/lib/mysql/ibdata1
# a directory, so new files inherit it
sudo mkdir /var/lib/vms
sudo chattr +C /var/lib/vms
Copy on write causes heavy fragmentation in files that are rewritten in place: database files, virtual machine images, large log files. +C disables it per file or per directory.
It must be set on an empty file or an empty directory. It cannot be applied retroactively to a file that already has data, and setting it on a populated directory affects only files created afterwards. The usual pattern is create the directory, set the flag, then move data in.
Note that +C also disables checksumming for that file, and it means snapshots of it cost full space rather than sharing blocks. Our Btrfs comparison covers the trade-off.
Filesystem support varies
# find out by trying
sudo chattr +i testfile && echo supported
ext4 supports the traditional set. XFS and Btrfs support subsets, each with their own additions. Many flags are silently ignored elsewhere, and +i and +a do not work on network filesystems at all, which matters if you were planning to protect something on an NFS mount.
Extended attributes
sudo apt install attr # Debian and Ubuntu
sudo dnf install attr # Fedora
# all attributes, all namespaces
getfattr -d -m - /etc/passwd
# set one
setfattr -n user.comment -v "reviewed 2026-09" report.pdf
getfattr -n user.comment report.pdf
# remove
setfattr -x user.comment report.pdf
Attributes live in namespaces, and the namespace determines who can set them and what reads them.
| Namespace | Purpose |
|---|---|
user.* | Anything you like, needs write permission on the file |
trusted.* | Root only |
security.* | SELinux, capabilities, IMA |
system.* | POSIX ACLs |
Where several familiar things actually live
# SELinux labels
getfattr -n security.selinux -d /usr/sbin/sshd
ls -Z /usr/sbin/sshd
# file capabilities
getfattr -n security.capability -d /usr/bin/ping
getcap /usr/bin/ping
# POSIX ACLs
getfattr -n system.posix_acl_access -d somefile
getfacl somefile
This is the practically important part of the whole topic. SELinux labels, file capabilities and ACLs are all extended attributes. ls -Z, getcap and getfacl are friendly front ends onto the same storage.
Which explains a class of bug that is otherwise baffling: copy a binary with plain cp and its capabilities are gone, so ping stops working for unprivileged users. Restore a file from a backup that did not preserve xattrs and SELinux denies access to it. Our SELinux guide and ACL guide cover each front end.
Preserving them through copies and backups
This is where the topic stops being trivia.
# cp: -a includes xattrs, plain cp does not
cp -a source dest
cp --preserve=all source dest
# rsync: -X for xattrs, -A for ACLs
rsync -aAX /src/ /dst/
# tar
tar --xattrs --xattrs-include='*' -cf backup.tar /etc
tar --xattrs -xf backup.tar
# check what survived
getfattr -d -m - original copy
rsync -a alone does not preserve extended attributes. It preserves permissions, times, ownership and symlinks, and neither -X nor -A is included in -a. Plenty of backup scripts have this gap, and it surfaces only on restore, when SELinux blocks a service from reading its own files.
If you use SELinux or ACLs, rsync -aAX is the correct baseline. Our rsync guide and restic versus borg comparison cover the wider backup picture, and both of those tools handle xattrs when told to.
Filesystem support and limits
# is user_xattr enabled
mount | grep -E 'ext4|xfs|btrfs'
# how much space is available for attributes
tune2fs -l /dev/sda1 | grep -i 'block size'
ext4 stores attributes in spare inode space, falling back to a separate block, with a total size limit of one block per file. XFS and Btrfs have more generous limits. FAT and exFAT support none, which is why copying a labelled file to a USB stick and back loses everything.
Trying to store a lot of data in extended attributes is a mistake. They are for metadata.
Practical uses
Find out why a file will not budge:
lsattr thatfile
getfacl thatfile
ls -Z thatfile
Three commands that cover the reasons beyond ordinary permissions. Worth running before concluding that a filesystem is corrupt.
Protect a config from an installer:
sudo chattr +i /etc/something.conf
# run the installer
sudo chattr -i /etc/something.conf
Stop copy on write fragmentation before it starts:
sudo mkdir /var/lib/libvirt/images
sudo chattr +C /var/lib/libvirt/images
# then create the images
Tag files with metadata a script can read:
setfattr -n user.checked -v "$(date -I)" report.pdf
getfattr --only-values -n user.checked report.pdf
Useful, and remember it does not survive a copy without -a, nor a trip through a filesystem that does not support attributes.
Audit for immutable files you did not set:
sudo lsattr -R / 2>/dev/null | grep -E '^....i|^-a'
Slow, and a reasonable thing to check on a machine whose behaviour you are suspicious of, alongside the wider checks in our security practices guide.
Frequently Asked Questions
What is the difference between chattr and extended attributes?
chattr sets filesystem specific flags stored in the inode, a fixed list the filesystem itself understands, such as immutable and append only. Extended attributes are arbitrary name and value pairs stored alongside the file, which is where SELinux labels, POSIX ACLs and file capabilities live. Different mechanisms with confusingly similar names.
Why can root not delete a file?
It probably has the immutable flag set with chattr +i, which blocks writes, renames, deletion and link creation regardless of ownership or privilege. Check with lsattr and clear it with chattr -i. This is also a known way to hide files from people who do not know the flag exists.
Does chattr work on every filesystem?
No. The flags are filesystem specific. ext4 supports the full traditional set, XFS and Btrfs support a subset, and many flags are silently ignored or rejected elsewhere. Notably the append only and immutable flags do not work on network filesystems at all.
What is the difference between the copy on write flag and normal Btrfs behaviour?
chattr +C disables copy on write for a file or for new files in a directory. It is useful for database files and virtual machine images where copy on write causes heavy fragmentation, and it must be set on an empty file or an empty directory because it cannot be applied retroactively.
Where are SELinux labels and file capabilities stored?
In extended attributes, in the security namespace: security.selinux for labels and security.capability for capabilities. This is why copying a file with plain cp loses them, and why cp needs the archive or preserve xattr option when labels matter.
Do extended attributes survive a copy or a backup?
Only if the tool is asked to preserve them. cp needs -a or —preserve=xattr, rsync needs -X for xattrs and -A for ACLs, and tar needs —xattrs. Plenty of backup setups silently drop SELinux labels and ACLs, and the problem only surfaces on restore.