This error occurs when a process inside a Docker container attempts an operation that is blocked by Linux security features like seccomp, AppArmor, or missing Linux capabilities. The fix involves identifying the blocked syscall and granting appropriate permissions through capabilities, custom seccomp profiles, or SELinux configuration.
The "operation not permitted" error (EPERM) in Docker indicates that a process inside your container tried to perform an action that the Linux kernel denied. Unlike "permission denied" (EACCES) which relates to file ownership and permissions, EPERM means the operation itself is not allowed for security reasons. Docker applies multiple layers of security restrictions to containers by default: 1. **Seccomp (Secure Computing Mode)**: Docker's default seccomp profile blocks approximately 44 of the 300+ Linux system calls. This prevents containers from performing potentially dangerous operations like loading kernel modules or rebooting the system. 2. **Linux Capabilities**: Docker drops most Linux capabilities from containers, keeping only a minimal set needed for normal operation. Operations like changing network settings, binding to privileged ports, or creating device nodes require specific capabilities. 3. **AppArmor/SELinux**: On systems with mandatory access control, additional restrictions may apply to container processes and file access. When any of these security layers blocks an operation, the kernel returns EPERM, which applications typically report as "operation not permitted."
First, determine exactly which operation is being blocked. Check the full error message and context:
# Run the failing command with verbose output
docker run --rm your-image sh -c "your-command 2>&1"
# Or attach to a running container to debug
docker exec -it container_name shCommon patterns:
- chmod/chown failing: Usually capability or volume mount issue
- Network commands failing: Missing NET_ADMIN or NET_RAW capability
- mknod failing: Missing MKNOD capability or seccomp block
- mount failing: Missing SYS_ADMIN capability
For detailed syscall information, use strace (if available in your container):
docker run --rm --cap-add SYS_PTRACE your-image strace your-command 2>&1 | grep EPERMTemporarily disable seccomp to verify it's the source of the problem:
docker run --security-opt seccomp=unconfined --rm your-image your-commandImportant: Only use seccomp=unconfined for testing. If this solves the issue, your next step is to create a custom seccomp profile that allows only the specific syscalls needed.
To identify which syscall is blocked, you can use:
# Generate a log of blocked syscalls
docker run --security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
--cap-add ALL \
your-image your-commandIf the command works with seccomp disabled, the default profile is blocking a required syscall.
Docker drops most capabilities by default. Add specific capabilities your application needs:
# Add a single capability
docker run --cap-add NET_ADMIN your-image
# Add multiple capabilities
docker run --cap-add NET_ADMIN --cap-add NET_RAW your-image
# Common capabilities for specific operations:
# - NET_ADMIN: Network configuration (ifconfig, ip, iptables)
# - NET_RAW: Raw sockets (ping, some network tools)
# - SYS_ADMIN: Mount, some cgroup operations (use sparingly)
# - MKNOD: Create device nodes
# - SYS_PTRACE: Debug/trace processes (strace, gdb)
# - IPC_LOCK: Lock memory (databases, real-time apps)For Docker Compose:
services:
myapp:
image: your-image
cap_add:
- NET_ADMIN
- NET_RAWSecurity note: Only add capabilities that are strictly required. Each capability increases the attack surface of your container.
On systems with SELinux (RHEL, CentOS, Fedora), you may need to relabel volumes:
# Add :z for shared volumes (multiple containers)
docker run -v /host/path:/container/path:z your-image
# Add :Z for private volumes (single container)
docker run -v /host/path:/container/path:Z your-imageThe :z and :Z options tell Docker to relabel the volume with appropriate SELinux contexts:
- :z - Shared label, allows multiple containers to access
- :Z - Private label, restricts to a single container (more secure)
For read-only mounts with SELinux:
docker run -v /host/path:/container/path:ro,Z your-imageTo check if SELinux is causing issues:
# Check SELinux status
getenforce
# Temporarily set to permissive (for testing only)
sudo setenforce 0NFS mounts with root_squash (the default) map the root user to nobody, causing permission errors:
Option 1: Use matching UID/GID
Run the container as a user that matches the NFS share owner:
# Find the owner UID/GID on the NFS share
ls -ln /nfs/mount/path
# Run container with matching user
docker run --user 1000:1000 -v /nfs/share:/data your-imageOption 2: Configure NFS server
If you control the NFS server, you can use no_root_squash (not recommended for security) or better, anonuid/anongid:
# /etc/exports
/shared/path *(rw,sync,anonuid=1000,anongid=1000)Option 3: Use named volumes
Named volumes handle permissions better than bind mounts:
docker volume create mydata
docker run -v mydata:/data your-imageDocker Desktop on macOS (Catalina and later) requires explicit permissions for file access:
Step 1: Grant Docker full disk access
1. Open System Preferences (or System Settings on newer macOS)
2. Go to Privacy & Security > Full Disk Access
3. Click the lock to make changes
4. Add Docker (or Docker Desktop) to the list
5. Toggle it ON
6. Restart Docker Desktop
Step 2: If using specific directories, ensure they're in Docker's file sharing settings:
1. Open Docker Desktop
2. Go to Settings > Resources > File Sharing
3. Add the directories you need to mount
4. Click Apply & Restart
Step 3: For persistent issues, try copying files instead of mounting:
# In your Dockerfile, copy files instead of relying on mounts
COPY ./local-files /app/filesOr use Docker volumes instead of bind mounts for data that needs write access.
If nothing else works and security is not a primary concern (development only), you can run in privileged mode:
docker run --privileged your-imageWarning: Privileged mode disables nearly all security restrictions. The container has:
- Full access to all devices
- Can load kernel modules
- Can modify the host system
- No seccomp restrictions
- All capabilities granted
Never use privileged mode in production. Instead, identify the specific capability or syscall needed and grant only that.
For Docker Compose:
services:
myapp:
image: your-image
privileged: true # DEVELOPMENT ONLYIf you need privileged mode to work, document which operations require it and work toward a least-privilege solution.
Outdated versions of Docker or libseccomp may not recognize newer system calls, causing false EPERM errors:
# Check current versions
docker version
apt show libseccomp2 2>/dev/null || rpm -q libseccomp
# Update on Ubuntu/Debian
sudo apt update && sudo apt upgrade docker-ce libseccomp2
# Update on RHEL/CentOS
sudo yum update docker-ce libseccomp
# Update on Fedora
sudo dnf update docker-ce libseccompThis is particularly important when running containers based on newer distributions (like Ubuntu 22.04) on older hosts.
After updating, restart Docker:
sudo systemctl restart dockerCreating a custom seccomp profile: Instead of disabling seccomp entirely, create a profile that allows only the syscalls you need:
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["clone", "clone3"],
"action": "SCMP_ACT_ALLOW"
}
]
}Use it with: docker run --security-opt seccomp=/path/to/profile.json your-image
Debugging seccomp blocks: Use the audit log to see blocked syscalls:
# Enable audit logging
sudo auditctl -a always,exit -F arch=b64 -S all -k docker_seccomp
# Run the container
docker run your-image your-command
# Check audit log
sudo ausearch -k docker_seccomp | grep SECCOMPUnderstanding capability inheritance: Capabilities can be inherited, permitted, or effective. Docker primarily deals with the "effective" set. Some applications may need capabilities in specific sets:
# Check capabilities inside container
docker run --rm --cap-add SYS_ADMIN your-image capsh --printRootless Docker considerations: In rootless Docker, even with --privileged, some operations remain restricted because the Docker daemon itself runs without root privileges. Use --userns=host cautiously if needed:
dockerd-rootless-setuptool.sh install
docker context use rootlessKubernetes SecurityContext: When migrating to Kubernetes, use securityContext to manage capabilities:
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
drop: ["ALL"]AppArmor profiles: On Ubuntu and Debian systems, Docker applies AppArmor profiles. To debug:
# Check if AppArmor is blocking
sudo aa-status
dmesg | grep apparmor
# Run without AppArmor (testing only)
docker run --security-opt apparmor=unconfined your-imageimage operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub