Watch at Ease세상을 읽고, 일상의 답을 찾다.

기술 · 실용 가이드

rm “Operation not permitted”? chmod·chattr 전에 unlink boundary를 증명하세요

정확한 errno를 보존하고 parent와 inode flag를 확인해 sticky, mount, namespace와 policy 원인을 나눈 뒤 disposable sibling으로 한 원인 수리를 검증합니다.

pathname, parent, inode flag, sticky ownership, mount, capability와 policy 순서로 rm EPERM을 조사하는 원본 도해.
원본 일러스트: 권한이나 특권을 바꾸기 전에 unlink boundary를 증명합니다. Watch at Ease

“Operation not permitted”는 unlink boundary에 관한 증거이지 rm에 더 강한 force가 필요하다는 뜻이 아닙니다. parent directory, immutable/append-only flag, sticky ownership, filesystem rule, namespace capability 또는 security policy가 작업을 통제할 수 있습니다.

정확한 pathname과 errno를 먼저 보존합니다. 각 boundary를 바꾸지 않고 검사해 증명된 원인 하나만 수리하고 disposable sibling으로 parent를 검증합니다. 삭제가 명시 승인되고 backup된 경우에만 정확한 target을 삭제합니다.

1. pathname과 실제 errno를 고정합니다

전체 command, 정확한 stderr, effective user, working directory와 namespace를 저장합니다. 존재해야 하는 target은 realpath -e로 확인하고 target과 parent의 stat을 따로 기록합니다. 원래 pathname도 보존합니다. unlink는 directory entry에 작용하므로 symlink, bind mount, 이름이 바뀐 parent가 대상을 바꿀 수 있습니다.

모든 “cannot remove”를 EPERM으로 가정하지 않습니다. Linux는 parent write/search 부족을 EACCES, read-only filesystem을 EROFS, mount point나 일부 NFS를 EBUSY로 구분합니다. strace가 필요하면 disposable fixture 또는 삭제가 승인되고 backup된 경우에만 사용합니다. 성공하는 trace는 실제로 이름을 삭제할 수 있습니다.

2. file mode보다 parent를 먼저 확인합니다

namei -l로 component를 따라가고 immediate parent와 target을 따로 stat합니다. 이름 삭제는 parent directory를 수정합니다. file 자체를 writable로 만들어도 directory operation 권한은 생기지 않습니다. owner, group, mode와 ACL을 바꾸지 않고 기록합니다.

parent에 sticky bit가 있으면 effective user가 file owner, directory owner이거나 필요한 capability를 갖지 않은 경우 unlink가 거부될 수 있습니다. 공유 directory 보호를 유지하고 /tmp에서 sticky를 제거하지 말고 올바른 actor 또는 ownership을 증명합니다.

3. target과 parent의 inode flag를 읽습니다

target과 parent 모두에서 lsattr -d --를 실행합니다. immutable은 delete와 rename을 막고 append-only도 unlink를 EPERM으로 만들 수 있습니다. 모든 filesystem이 모든 flag를 지원하지 않으므로 unsupported 결과는 다음 경계를 조사할 증거입니다.

flag가 원인임이 증명되면 object owner와 설정 이유를 기록하고 정확한 object의 필요한 i 또는 a만 해제합니다. CAP_LINUX_IMMUTABLE을 가진 host나 namespace에서 수행하며 recursive chattr나 광범위한 privileged container를 쓰지 않습니다.

4. mount, filesystem과 policy 경계를 분류합니다

정확한 target에 findmnt -T를 사용해 source, filesystem type과 options를 기록합니다. read-only mount는 EROFS이며 EPERM과 다릅니다. mount point나 NFS silly rename은 EBUSY일 수 있습니다. overlay, network, container filesystem은 ownership과 namespace 경계도 더하므로 오래된 제품별 workaround를 현재의 보편 해법으로 쓰지 않습니다.

mode, sticky ownership, inode flag가 거부를 설명하지 못하면 ls -lZ, 최근 AVC/kernel log, effective capability와 관련 container/user namespace를 수집합니다. 구체적인 policy나 owning layer만 고치고 SELinux/AppArmor를 전역으로 끄거나 blanket privileged를 쓰지 않습니다.

5. 한 원인만 수리하고 acceptance를 증명합니다

증거와 연결된 가역 변경 하나만 합니다. 의도한 parent owner/access 수정, 증명된 flag 하나 해제, 올바른 sticky owner로 실행, mount/storage layer 수리 또는 특정 security rule 업데이트입니다. 이후 stat, lsattr와 findmnt를 다시 읽어 인과 증거를 남깁니다.

실제 target을 건드리기 전에 policy가 허용하면 같은 parent에 disposable sibling을 만들고 unlink합니다. 이는 parent operation의 증명이지 target 삭제 승인 자체는 아닙니다. 정확한 pathname, backup과 owner approval을 확인한 뒤 한 번만 삭제합니다. unlink 뒤에도 open file은 마지막 descriptor가 닫힐 때까지 inode와 data를 유지할 수 있습니다.

관찰, 한 원인 수리, 일회용 sibling probe와 승인된 target 삭제를 분리한 원본 도해.
원본 일러스트: 진단하고 한 원인만 고친 뒤 sibling을 시험하고 target을 한 번 삭제합니다. Watch at Ease