How to remove stubborn immutable Linux file when rm -f fails with Operation not permitted

Root Cause Diagnosis

rm: cannot remove 'file': Operation not permitted (errno EPERM) appearing even for root means the inode carries a protection that overrides normal permission checks, most commonly the ext2/3/4 immutable attribute (i) or append-only attribute (a). With either flag set, the kernel refuses unlink, rename, truncate, write, and hard-link operations until the flag is cleared, regardless of UID or mode bits. Other sources of the same error are filesystem-level read-only or special flags on XFS, Btrfs, and NFS, SELinux or AppArmor policy, a non-root user lacking ownership of a sticky directory, and the CAP_LINUX_IMMUTABLE capability being dropped.

Quick Fix

Inspect the attributes, clear the flag, and delete:

lsattr /path/to/file
sudo chattr -i -a /path/to/file
sudo rm -f /path/to/file

For a directory tree:

sudo chattr -R -i -a /path/to/dir
sudo rm -rf /path/to/dir

If chattr itself returns Operation not permitted, continue with the steps below.

Step-by-Step Resolution

1. Identify the attribute blocking the operation.

lsattr -d /path/to/file          # file or directory itself
lsattr /path/to/parent/          # parent directory contents

Sample output and meaning:

FlagMeaningBlocks
iImmutableDelete, rename, write, link, truncate
aAppend-onlyDelete, rename, overwrite (appends allowed)
sSecure deletion (ignored on most kernels)Nothing in practice
eExtent format (ext4 default)Nothing; informational

Check the parent directory as well. A directory with i or a prevents deleting any entry inside it, even when the file itself has no flags.

2. Remove the flags.

sudo chattr -i /path/to/file
sudo chattr -a /path/to/file
lsattr /path/to/file             # verify the flags are gone

Apply the same commands to the parent directory if it carries a flag. Use -R for recursive removal, but note that chattr -R does not follow symlinks.

See also  How to clear dead Docker overlay2 storage directory safely without breaking daemon

3. Delete the file.

sudo rm -f /path/to/file
sudo rm -rf /path/to/dir         # directories

4. If chattr fails with Operation not permitted, check the capability bound.

Changing i and a requires CAP_LINUX_IMMUTABLE. Containers and hardened systems often drop it.

capsh --print | grep -i linux_immutable
grep CapBnd /proc/self/status
capsh --decode=$(awk '/CapBnd/{print $2}' /proc/self/status) | tr ',' '\n' | grep -i immutable

If it is missing:

  • Docker: run the container with --cap-add=LINUX_IMMUTABLE, or modify the file from the host.
  • Kubernetes: add LINUX_IMMUTABLE under securityContext.capabilities.add in the pod spec.
  • System-wide bound: sysctl kernel.cap_bound is not exposed on mainline kernels. A lowered bounding set is set at boot by CapabilityBoundingSet= in the systemd unit or by lcap-style tooling. Check /etc/systemd/system/*.service, /etc/security/capability.conf, and the kernel command line.

5. Check for filesystem-level restrictions.

findmnt -T /path/to/file -o TARGET,SOURCE,FSTYPE,OPTIONS
mount | grep -E " on /path/to/mountpoint "

If the options include ro, remount writable (after confirming why it is read-only, since ext4 flips to ro on I/O errors):

dmesg | tail -50                                  # look for EXT4-fs error, remounting read-only
sudo mount -o remount,rw /mountpoint

If the filesystem went read-only due to errors, unmount and run fsck first:

sudo umount /mountpoint
sudo fsck -f /dev/sdXN

6. Handle filesystem-specific flags.

# Btrfs: the file may be in a read-only snapshot or subvolume
sudo btrfs property get -ts /path/to/subvol ro
sudo btrfs property set -ts /path/to/subvol ro false

# XFS: immutable and append-only are set through xfs_io, and lsattr/chattr work on modern kernels
xfs_io -c "lsattr" /path/to/file
sudo xfs_io -c "chattr -i" /path/to/file

7. Check mandatory access control.

# SELinux
getenforce
ls -Z /path/to/file
sudo ausearch -m avc -ts recent | tail
sudo setenforce 0                         # diagnostic only; re-enable with setenforce 1

# AppArmor
sudo aa-status
sudo dmesg | grep -i apparmor | tail

If a denial appears, correct the label or profile rather than leaving enforcement disabled:

sudo restorecon -v /path/to/file

8. Check for processes holding the file and for immutable-setting services.

sudo lsof /path/to/file
sudo fuser -v /path/to/file
sudo systemctl list-units --type=service | grep -Ei 'aide|tripwire|fail2ban|clamav|immutable'

Some security tools, malware, and configuration management agents re-apply chattr +i automatically. If the flag returns after clearing, stop the responsible service first, and search for cron entries, systemd timers, or scripts calling chattr +i:

sudo grep -rI "chattr" /etc/cron* /etc/systemd /var/spool/cron /usr/local 2>/dev/null

9. Use a rescue environment as a last resort.

See also  Resolving Docker DNS lookup failure inside container on custom bridge network

If the root filesystem is read-only, the capability is unavailable, or the system will not boot, boot from a live USB, mount the volume, and clear the flags offline:

sudo mount /dev/sdXN /mnt
sudo chattr -R -i -a /mnt/path/to/file
sudo rm -f /mnt/path/to/file
sudo umount /mnt

Why This Fails for Some Users

  • Parent directory is immutable: The file shows clean flags, but the parent has i or a. Clear the flag on the directory, not the file.
  • Wrong tool for the filesystem: chattr and lsattr only support ext2/3/4 flags and a subset on XFS (kernel 4.x+), Btrfs, and F2FS. On FAT, exFAT, NTFS (ntfs-3g), and most FUSE filesystems, lsattr returns Inappropriate ioctl for device. Use the filesystem’s own tools or check mount options and permissions instead.
  • NFS and network mounts: Immutable flags set on the server cannot be cleared from the client. Run chattr on the NFS server, or on the exported directory. Root squash (root_squash in /etc/exports) also maps client root to nobody, which produces Operation not permitted on files owned by root.
  • Sticky bit on shared directories: In directories such as /tmp with mode 1777, only the file owner, directory owner, or root can delete an entry. Check with ls -ld /tmp and stat.
  • Containers and overlayfs: On overlay filesystems, files from lower image layers cannot be modified in the upper layer when flags are set on the underlying layer. Delete from the host via the container’s MergedDir or rebuild the image.
  • Mounted bind or loop device read-only: A read-only bind mount (mount -o bind,ro) returns Read-only file system, but some tools surface it as Operation not permitted. Verify with findmnt.
  • Kernel lockdown and securelevel-style protections: Hardened kernels and some distributions limit modification of immutable flags on protected paths while a security module is active. Boot parameters such as lockdown=integrity or securelevel (BSD) stop flag changes until reboot.
  • Cannot clear on special files: Some files in /proc, /sys, /dev, and device nodes are not regular inodes. Operation not permitted there indicates kernel-managed objects, not an attribute problem.
  • File is a mount point or in use as one: rm cannot remove a mount point and may report Device or resource busy or Operation not permitted. Check findmnt /path and unmount first.
  • Flag reappears: Configuration management (Ansible attributes: +i, Puppet, Salt), IDS software, or malware re-applies the flag. Inspect cron, timers, and agents (Step 8) before concluding the removal failed.
  • Security note: An unexpected i flag on a system file such as /etc/passwd, /etc/crontab, or a binary in /usr/bin is a common persistence technique used by malware to resist cleanup. Treat unexplained immutable system files as a possible compromise and investigate before removing them.
See also  Linux crontab script running manually via terminal but failing silently on schedule

Leave a Comment