~/home/study/linux-capabilities-overview

Linux Capabilities Overview: A Beginner’s Guide

Learn what Linux capabilities are, how they differ from root, and how to audit and harden them on VMs and Docker containers.

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

  1. 2003: Capabilities 1.0 merged into kernel 2.6.24.
  2. 2005: Introduction of the capsh utility for interactive capability manipulation.
  3. 2012: Docker’s default configuration granted containers CAP_SYS_ADMIN, leading to numerous exploits.
  4. 2019: Kernel 5.0 added new capabilities CAP_SYS_CHROOT and CAP_SYS_PTRACE to 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 - Execute chroot system 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:

  1. getcap - Display capabilities on a file.
  2. setcap - Assign capabilities to a file.
  3. capsh - Interactive shell with capability manipulation.
  4. 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 setcap usage - Allowing developers to set capabilities on binaries without review.
  • Docker --privileged flag - This flag mounts all devices and grants the container CAP_SYS_ADMIN by default.
  • Misplaced chroot binaries - Placing chroot in a world-writable directory with CAP_SYS_CHROOT can let attackers escape sandboxes.
  • Legacy services running as root - Services that unnecessarily run as root expose all capabilities to any process they spawn.
  • Inadequate ambient set 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

  1. Log into a test VM with sudo privileges.
  2. Run sudo getcap /bin/sudo to see which capabilities sudo has.
  3. Use sudo capsh --print to view the effective set for your shell.
  4. Identify any capabilities that are unnecessary for your workflow.

Exercise 2 - Docker Container

  1. Create a minimal Dockerfile that copies /usr/bin/ssh into the image.
  2. Build the image and run it without any capability flags.
  3. Inside the container, run getcap /usr/bin/ssh and lscap $$ to list capabilities.
  4. Re-run the container with --cap-drop=ALL and --cap-add=NET_BIND_SERVICE to 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 --privileged flag allowed attackers to mount the host filesystem, read secrets, and modify kernel modules. The attack leveraged CAP_SYS_ADMIN to execute chroot into 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.

CommandPurpose
getcapShow capabilities on a file
setcapAssign capabilities to a file
capshInteractive capability shell
lscapList capabilities of a process
docker run --cap-add=CAP_NET_ADMINAdd capability to container
docker run --cap-drop=ALLRemove 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.d and /etc/ld.so.preload restrictions.
  • Container Runtime Policies - Enforce --cap-drop=ALL by default in Docker Compose or Kubernetes PodSecurityPolicies.
  • Audit Logs - Enable auditd rules to log capset syscalls and execve with 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_ADMIN is safe because it’s “just one capability.”
  • Granting capabilities to binaries that are rarely executed.
  • Leaving capabilities on executables in world-writeable directories.
  • Using --privileged flag in production containers without evaluating the risk.
  • Ignoring the ambient set, 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_ADMIN in 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_ADMIN to 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:

  1. Capability Audit - Scan all binaries in /usr/bin and list those with non-default capabilities.
  2. Container Hardening - Build a Docker image for nginx that drops all capabilities and then selectively adds only NET_BIND_SERVICE.
  3. Exploit Simulation - Use setcap cap_net_bind_service=+ep to bind a listening service to port 80, then verify that the process can’t read /etc/shadow.
  4. Audit Log Review - Configure auditd to monitor capset syscalls, 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, and lscap to 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 auditd and immutable filesystems for additional protection.