Linux Error: Operation not permitted — Cause, Fix, and Troubleshooting Guide
How to fix the Linux 'Operation not permitted' error (EPERM): missing capabilities, the immutable bit, seccomp, user namespaces, SELinux and AppArmor denials explained.
- #linux
- #troubleshooting
- #permissions
- #security
Summary
Operation not permitted is the kernel’s EPERM (errno 1), and it is subtly different from Permission denied (EACCES). EACCES means “you failed a file-permission check”; EPERM means “even with the right file permissions, you lack the privilege to perform this operation.” It shows up when a process needs a Linux capability it does not hold, tries to modify an immutable file, is blocked by seccomp, hits a user-namespace boundary in a container, or is stopped by SELinux/AppArmor policy.
Common Symptoms
chown: changing ownership of 'file': Operation not permittedmount: Operation not permittedinside a non-privileged container.kill: (1234) - Operation not permittedwhen signalling another user’s process.rm: cannot remove 'file': Operation not permittedon a file that looks writable.bind: Operation not permittedbinding to a port below 1024 without privilege.ping: socket: Operation not permittedfor a non-root user withoutcap_net_raw.
Most Likely Causes of the ‘Operation not permitted’ Error
Production causes, most common first:
- Missing Linux capability. The operation requires a capability the process dropped or never had —
CAP_NET_BIND_SERVICE(low ports),CAP_NET_RAW(raw sockets/ping),CAP_CHOWN,CAP_SYS_ADMIN(mount, many syscalls). Common in hardened containers that drop capabilities. - Immutable / append-only attribute. A file has
chattr +i(immutable) or+a(append-only); even root getsEPERMon delete/modify until the attribute is cleared. - Container capability drop / user namespace. Docker/Kubernetes containers run with a reduced capability set and a non-root UID; privileged operations (mount, ptrace, changing another UID’s files) return
EPERM. - seccomp filter blocking a syscall. The runtime’s seccomp profile denies the syscall, surfacing as
EPERM(orEACCES) to the program. - Signalling / ptracing another user’s process without
CAP_KILL/ matching UID (or blocked byyamaptrace_scope). - SELinux (RHEL/Rocky) or AppArmor (Ubuntu/Debian) policy denying a privileged operation.
- Read-only or protected sysctl/procfs writes (e.g.
kernel.*under a restricted namespace).
Quick Triage
# Am I root? What capabilities do I actually hold?
id
capsh --print
# Does the file carry an immutable/append-only attribute?
lsattr ./file
# Recent kernel denials?
sudo dmesg | tail -30
Diagnostic Commands
capsh --print
Prints the current and bounding capability sets. If cap_net_bind_service (or whatever the operation needs) is absent from the effective/permitted set, that is the cause.
getcap /usr/bin/ping /usr/local/bin/app
Shows file capabilities set on a binary. A missing cap_net_raw+ep on ping, for example, forces it to need root.
lsattr ./file
Reveals the immutable (i) and append-only (a) attributes. Either one causes EPERM on modify/delete for everyone, including root.
id
ls -l ./file
Confirms your UID and the file’s owner. Changing ownership of a file you do not own (without CAP_CHOWN) returns EPERM, not EACCES.
grep -i seccomp /proc/self/status
grep Cap /proc/self/status
Seccomp: 2 means a filter is active on the process. The CapEff/CapBnd bitmasks (decode with capsh --decode=<hex>) show effective and bounding capabilities.
sudo dmesg | grep -iE 'seccomp|SIGSYS|apparmor.*DENIED'
sudo ausearch -m AVC -ts recent # SELinux (RHEL/Rocky)
Kernel logs pinpoint a seccomp kill (SIGSYS), an AppArmor DENIED line, or a SELinux AVC that translated into EPERM.
# In a container: what capabilities does it actually have?
docker inspect --format '{{.HostConfig.CapAdd}} {{.HostConfig.CapDrop}}' <ctr>
cat /proc/1/status | grep Cap
Confirms which capabilities the container runtime granted or dropped.
Fix / Remediation
-
Grant the specific capability to a binary (least privilege — do not run as root):
sudo setcap cap_net_bind_service=+ep /usr/local/bin/app # bind low ports sudo setcap cap_net_raw+ep /usr/bin/ping # raw sockets -
Add the capability to a container instead of
--privileged:docker run --cap-add=NET_BIND_SERVICE myappIn Kubernetes, set
securityContext.capabilities.add: ["NET_BIND_SERVICE"]. -
Clear an immutable / append-only attribute when a file must be modified:
Warning: These attributes are deliberate protection (often on
/etc/resolv.conf, audit logs, or hardened configs). Confirm intent before clearing.sudo chattr -i ./file # remove immutable sudo chattr -a ./file # remove append-only -
Relax or fix the seccomp profile if the runtime blocks a required syscall — supply a corrected profile rather than
--security-opt seccomp=unconfined, which disables all filtering. -
Adjust ptrace scope for debuggers only when needed:
sudo sysctl -w kernel.yama.ptrace_scope=0 # dev/debug hosts only -
Address MAC denials in the dedicated guides. For SELinux, create a targeted policy module from the AVC; for AppArmor, update the profile. See the links below — do not disable enforcement wholesale.
Warning: Prefer
setcap/--cap-addover running the whole process as root or--privileged. Granting a single capability is far safer than dropping all confinement.
Validation
getcap /usr/local/bin/app # capability now present
capsh --print | grep cap_net # effective set includes it
lsattr ./file # no i/a attribute
sudo -u appuser /usr/local/bin/app # privileged op now succeeds
Prevention
- Grant precise file capabilities with
setcapinstead of the setuid bit or running as root. - In containers, drop all capabilities and add back only what the workload needs (
--cap-drop=ALL --cap-add=NET_BIND_SERVICE). - Document deliberate
chattr +i/+aprotections so operators know why writes fail. - Keep seccomp profiles in version control and test workloads against them in CI.
- Keep SELinux
Enforcing/ AppArmor enabled and write proper policy rather than disabling it.
Related Errors
- Linux Error: Permission denied
- Linux Error: Text file busy
- Linux Error: Device or resource busy
- SELinux AVC denial
- AppArmor “DENIED” operation
Final Notes
The key distinction: EACCES (“Permission denied”) is a file-permission failure, while EPERM (“Operation not permitted”) is a privilege failure — you lack a capability, the file is immutable, or a security layer (seccomp, user namespaces, SELinux, AppArmor) blocked the operation. Check capsh --print, getcap, and lsattr first, then the kernel log for MAC or seccomp denials, and grant the single missing privilege rather than removing all confinement.
Want faster Linux incident response? Use DevOps AI Toolkit to turn production errors into clear diagnostics, remediation steps, and reusable runbooks.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.