Watch at EaseHistorias. Respuestas. Perspectiva.

Tecnología · GUÍA PRÁCTICA

¿rm dice “Operation not permitted”? Demuestra el límite de unlink antes de chmod o chattr

Conserva el errno, revisa parent e inode flags, separa sticky, mount, namespace y policy, y valida una reparación estrecha con un sibling desechable.

Diagrama original que recorre pathname, parent, atributos, sticky ownership, mount, capacidades y política para diagnosticar EPERM.
Ilustración original: demuestra el límite de unlink antes de cambiar privilegios o permisos. Watch at Ease

“Operation not permitted” es evidencia de un límite de unlink, no prueba de que rm necesite más force. Puede controlar la operación el parent directory, un flag immutable/append-only, sticky ownership, una regla del filesystem, una capability de namespace o una policy de seguridad.

Conserva pathname y errno. Prueba cada frontera sin cambiarla, repara una causa demostrada y valida el parent con un sibling desechable. Borra el target exacto y respaldado solo con autorización explícita.

1. Fija el pathname y el errno real

Guarda command completo, stderr exacto, effective user, working directory y namespace. Si el target debe existir, resuélvelo con realpath -e y registra stat del target y de su parent. Conserva también el pathname original: unlink actúa sobre una directory entry, y un symlink, bind mount o parent renombrado puede cambiar el objeto.

No llames EPERM a todo “cannot remove”. Linux usa EACCES por falta de write/search en el parent, EROFS para filesystem de solo lectura y EBUSY para mount points o algunos casos NFS. Si necesitas strace, úsalo en un fixture desechable o solo cuando el borrado ya esté autorizado y respaldado: una traza que funciona puede borrar el nombre de verdad.

2. Inspecciona el parent antes del mode del file

Recorre componentes con namei -l y aplica stat al parent inmediato y al target. Borrar un nombre modifica el parent directory; hacer writable el file no concede esa operación. Registra owner, group, mode y ACL sin cambiarlos.

Con sticky bit en el parent, Linux puede rechazar unlink salvo que el effective user posea el file, posea el directory o tenga la capability aplicable. Conserva la protección compartida. Demuestra actor u ownership correctos en lugar de retirar sticky de /tmp u otro workspace común.

3. Lee los inode flags del target y del parent

Ejecuta lsattr -d -- sobre target y parent. Immutable impide borrar o renombrar; append-only también puede hacer que unlink devuelva EPERM. No todos los filesystems admiten todos los flags: unsupported es evidencia para seguir, no permiso para descartar otras fronteras.

Si el flag es la causa demostrada, registra owner y propósito. Limpia solo i o a necesarios en el objeto exacto y desde el host o namespace que tenga CAP_LINUX_IMMUTABLE. No uses chattr recursivo ni concedas privilegios amplios a un container para saltarte el diagnóstico.

4. Clasifica límites de mount, filesystem y policy

Usa findmnt -T sobre el target exacto y registra source, filesystem type y options. Un mount de solo lectura es EROFS, no EPERM; un mount point o NFS silly rename puede ser EBUSY. Overlay, network y container filesystems añaden ownership y namespace, así que un workaround antiguo de producto no es una solución universal actual.

Si mode, sticky ownership e inode flags no explican la denegación, reúne evidencia de policy: ls -lZ, logs AVC o kernel recientes, effective capabilities y el container o user namespace pertinente. Repara la regla o capa concreta. No desactives SELinux/AppArmor globalmente ni cambies a blanket privileged.

5. Repara una causa y demuestra acceptance

Haz un cambio reversible vinculado a la evidencia: corrige owner/access del parent previsto, limpia un flag demostrado, actúa como owner válido de sticky, repara la capa mount/storage o actualiza una regla específica. Después vuelve a leer stat, lsattr y findmnt para registrar causalidad.

Antes del target real, crea y elimina un sibling desechable en el mismo parent si la policy lo permite. Eso prueba la operación del parent, no autoriza borrar el target. Confirma pathname, backup y aprobación del owner, y borra una vez. unlink quita un nombre; un file abierto puede conservar inode y data hasta cerrar el último descriptor.

Diagrama original que separa observación, reparación de una causa, prueba sibling y borrado autorizado del target.
Ilustración original: diagnostica, corrige una causa, prueba un sibling y borra una sola vez el target autorizado. Watch at Ease