Introduction
Linux capabilities were introduced in the 2.6 kernel to break the monolithic root privilege into discrete units. They allow a process to perform privileged operations-such as binding to low-numbered ports or modifying system files-without granting it full superuser rights.
Understanding how they work is essential for hardening systems, securing containers, and preventing privilege-escalation attacks.
Prerequisites
Before diving in, you should be comfortable with:
- Basic Linux command line navigation
- Understanding of Unix file permissions and ownership
- Familiarity with systemd, init, and kernel boot parameters
- Knowledge of container runtimes (Docker, Podman, rkt)
Core Concepts
Capabilities are stored in a binary bitmap attached to an executable or a running process. The kernel checks this bitmap whenever a privileged operation is requested. Each capability corresponds to a specific set of privileged actions. The 31 standard capabilities include CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_DAC_OVERRIDE, and many others.
Capabilities interact with several kernel features:
- Namespace isolation: Each namespace can have its own capability set.
- Process bounding set: The set of capabilities a process can ever have.
- Effective set: Capabilities that are currently active for the process.
- Permitted set: Capabilities that the process is allowed to use.
- Inheritable set: Capabilities that can be inherited across execve calls.
Understanding these sets is key to predicting how capabilities are applied and how they can be abused.
Definition and History of Linux Capabilities
Prior to 2.6.24, root was the sole superuser, and any privileged action required full superuser rights. This monolithic model made it difficult to run privileged services safely.
The capabilities subsystem was added to allow a process to retain only the privileges it actually needs.
The concept mirrors the principle of least privilege and is inspired by the Windows Access Control Lists (ACLs) and the POSIX capabilities standard. The first implementation was a proof of concept in 2001, but it wasn’t merged into mainline until 2003. Over the years, the set of capabilities has expanded to cover new privileged operations, such as CAP_IPC_LOCK for memory locking and CAP_SYS_RAWIO for raw I/O.
Key Milestones
- 2003: Capabilities 1.0 merged into kernel 2.6.24.
- 2005: Introduction of the
capshutility for interactive capability manipulation. - 2012: Docker’s default configuration granted containers
CAP_SYS_ADMIN, leading to numerous exploits. - 2019: Kernel 5.0 added new capabilities
CAP_SYS_CHROOTandCAP_SYS_PTRACEto refine sandboxing.
Capability Namespaces and Their Scope
Namespaces provide isolation boundaries for kernel resources. Capabilities can be scoped per namespace, meaning a process in one namespace can have a different set of capabilities than a process in another. The three most relevant namespaces for capabilities are:
- PID namespace: Isolates process IDs.
- Mount namespace: Isolates filesystem mounts.
- Network namespace: Isolates network stacks.
When a process is forked into a new namespace, its capability sets are inherited unless explicitly changed. Containers run in their own PID, Mount, and Network namespaces, and the default Docker configuration often grants them CAP_SYS_ADMIN to allow privileged operations inside the container.
Capabilities can also be limited by the ambient set in user namespaces, a mechanism introduced in kernel 5.3 to improve sandboxing for unprivileged users.
Common Capability Sets
Below are some of the most frequently encountered capabilities and the privileged actions they permit:
CAP_SYS_ADMIN- Broad administrative control: mounting filesystems, creating network interfaces, modifying kernel parameters.CAP_NET_ADMIN- Network configuration: changing routing tables, binding to low-port sockets.CAP_DAC_OVERRIDE- Bypass file read/write restrictions.CAP_SETUID- Set user IDs on files.CAP_SYS_CHROOT- Executechrootsystem call.CAP_SYS_PTRACE- Trace other processes.CAP_SYS_RESOURCE- Set resource limits.
While CAP_SYS_ADMIN is often considered “everything” due to its wide range, many exploits rely on more specific capabilities such as CAP_NET_ADMIN to bind to privileged ports or CAP_SYS_PTRACE to hijack running processes.
Tools for Listing and Modifying Capabilities
Managing capabilities requires a set of utilities that can read, set, and inspect extended attributes. The most common tools are:
- getcap - Display capabilities on a file.
- setcap - Assign capabilities to a file.
- capsh - Interactive shell with capability manipulation.
- lscap - List the current capability sets of a running process.
Listing File Capabilities
$ sudo getcap /usr/bin/passwd
/usr/bin/passwd = cap_setuid,cap_setgid+ep
The output shows the permitted and effective bits (+ep) for the binary.
Setting Capabilities on a Binary
$ sudo setcap cap_net_bind_service=+ep /usr/bin/myapp
This command grants CAP_NET_BIND_SERVICE so myapp can bind to ports below 1024 without running as root.
Inspecting a Running Process
$ lscap $(pidof myapp)
Effective: cap_net_bind_service
Permitted: cap_net_bind_service
Inheritable:
Bounding: cap_net_bind_service
Ambient:
Interactive Capability Shell
$ sudo capsh --print
Current: (unconfined)
Permitted: (unconfined)
Effective: (unconfined)
Inheritable: (unconfined)
Bounding: (unconfined)
Ambient: (unconfined)
Use capsh --caps="cap_net_bind_service+e" --user=root --keep=1 --exec /bin/bash to spawn a shell with a specific capability.
Typical Misconfigurations That Expose Capabilities to Unprivileged Users
Even small configuration errors can grant unnecessary privileges. Some common pitfalls include:
- Unrestricted
setcapusage - Allowing developers to set capabilities on binaries without review. - Docker
--privilegedflag - This flag mounts all devices and grants the containerCAP_SYS_ADMINby default. - Misplaced
chrootbinaries - Placingchrootin a world-writable directory withCAP_SYS_CHROOTcan let attackers escape sandboxes. - Legacy services running as root - Services that unnecessarily run as root expose all capabilities to any process they spawn.
- Inadequate
ambientset configuration - Some containers inherit ambient capabilities that should have been cleared.
Security audits should verify that only the capabilities required by a binary are present, and that containers do not run with --privileged unless absolutely necessary.
Practical Exercises: Enumerating Capabilities on a VM and a Docker Container
These exercises walk you through inspecting capabilities on a host VM and a Docker container, highlighting typical gaps.
Exercise 1 - Host VM
- Log into a test VM with sudo privileges.
- Run
sudo getcap /bin/sudoto see which capabilitiessudohas. - Use
sudo capsh --printto view the effective set for your shell. - Identify any capabilities that are unnecessary for your workflow.
Exercise 2 - Docker Container
- Create a minimal Dockerfile that copies
/usr/bin/sshinto the image. - Build the image and run it without any capability flags.
- Inside the container, run
getcap /usr/bin/sshandlscap $$to list capabilities. - Re-run the container with
--cap-drop=ALLand--cap-add=NET_BIND_SERVICEto demonstrate fine-grained control.
These steps illustrate how to control capability exposure in containers.
Practical Examples
Below are real-world scenarios where capability manipulation changed the security posture.
Scenario 1 - Binding to Privileged Ports Without Root
# Install a simple HTTP server binary
$ sudo setcap cap_net_bind_service=+ep /usr/bin/simplehttpd
# Run the server as a non-root user
$ ./simplehttpd 80
The server can listen on port 80 without requiring root privileges, reducing the blast radius if compromised.
Scenario 2 - Escaping a Container via CAP_SYS_ADMIN
In 2019, a misconfigured Docker container with
--privilegedflag allowed attackers to mount the host filesystem, read secrets, and modify kernel modules. The attack leveragedCAP_SYS_ADMINto executechrootinto the host root directory.
Mitigation: Avoid --privileged unless necessary. Use --cap-drop=ALL and explicitly add only required capabilities.
Tools & Commands
Below is a quick reference table of key commands.
| Command | Purpose |
|---|---|
getcap | Show capabilities on a file |
setcap | Assign capabilities to a file |
capsh | Interactive capability shell |
lscap | List capabilities of a process |
docker run --cap-add=CAP_NET_ADMIN | Add capability to container |
docker run --cap-drop=ALL | Remove all capabilities from container |
Defense & Mitigation
Security hardening around capabilities involves multiple layers:
- Principle of Least Privilege - Grant only the capabilities a process needs.
- Capability Bounding Files - Use
/etc/sudoers.dand/etc/ld.so.preloadrestrictions. - Container Runtime Policies - Enforce
--cap-drop=ALLby default in Docker Compose or Kubernetes PodSecurityPolicies. - Audit Logs - Enable
auditdrules to logcapsetsyscalls andexecvewith capabilities. - Immutable Filesystems - Mount binaries on read-only filesystems to prevent attackers from adding capabilities.
Example auditd rule:
# /etc/audit/rules.d/capset.rules
-a always,exit -F arch=b64 -S capset -k capset
Common Mistakes
Even experienced admins fall into these traps:
- Assuming
CAP_SYS_ADMINis safe because it’s “just one capability.” - Granting capabilities to binaries that are rarely executed.
- Leaving
capabilitieson executables in world-writeable directories. - Using
--privilegedflag in production containers without evaluating the risk. - Ignoring the
ambientset, which can leak capabilities across namespace boundaries.
Regular audits and automated scanning tools can help catch these issues early.
Real-World Impact
Capabilities influence a wide range of security incidents:
- Container Breakouts - Attackers exploited
CAP_SYS_ADMINin Docker to mount the host filesystem, leading to data exfiltration in several high-profile breaches. - Privilege Escalation in Linux Distros - details
- IoT Device Attacks - Many embedded devices ship with binaries granted
CAP_SYS_ADMINto support OTA updates, creating a vector for attackers to modify firmware.
Trend: Modern cloud platforms are moving toward unprivileged containers by default, stripping all capabilities except those explicitly required. This shift is driven by the high cost of container breakout incidents.
Practice Exercises
After studying this guide, try the following labs:
- Capability Audit - Scan all binaries in
/usr/binand list those with non-default capabilities. - Container Hardening - Build a Docker image for
nginxthat drops all capabilities and then selectively adds onlyNET_BIND_SERVICE. - Exploit Simulation - Use
setcap cap_net_bind_service=+epto bind a listening service to port 80, then verify that the process can’t read/etc/shadow. - Audit Log Review - Configure
auditdto monitorcapsetsyscalls, generate a capability change, and parse the log to confirm detection.
Document your findings and compare the security posture before and after mitigation.
Further Reading
- “Linux Capabilities: An Overview” - Kernel documentation
- “Security Hardening for Docker” - Docker Docs
- “Linux Security Hardening” - CIS Benchmarks
- “Privilege Escalation in Linux” - SANS White Papers
Summary
Linux capabilities provide a granular approach to privilege management, essential for secure system design and container isolation. By mastering the tools to list, set, and audit capabilities, you can mitigate privilege-escalation risks and harden your environment against modern attack vectors.
Key takeaways:
- Capabilities replace monolithic root privileges with fine-grained permissions.
- Use
getcap,setcap,capsh, andlscapto inspect and modify capabilities. - Always follow the principle of least privilege, especially in container runtimes.
- Regularly audit binaries and container configurations for unnecessary capabilities.
- Leverage
auditdand immutable filesystems for additional protection.