Linux Capabilities

Linux capabilities subdivide root privileges — getcap, setcap, capsh, and Docker cap-drop patterns.

Overview

Traditionally, Linux privilege was binary: you either had root (UID 0) and could do anything, or you were an unprivileged user. Linux capabilities break this model by dividing root's omnipotent authority into ~40 distinct privilege units that can be independently granted or revoked.

Why Capabilities Matter

Running a process as root to bind port 80 is a massive security over-grant. With capabilities, you grant only CAP_NET_BIND_SERVICE and nothing else. A vulnerability in the service cannot be exploited to write to /etc/passwd or load kernel modules.

Key Capabilities

  • CAP_NET_BIND_SERVICE — Bind to ports below 1024
  • CAP_NET_RAW — Raw socket access (ping, tcpdump)
  • CAP_SYS_PTRACE — Trace other processes (strace, gdb)
  • CAP_SYS_ADMIN — Broad system administration — mount, namespace creation. Often called "almost root".
  • CAP_CHOWN — Change file ownership
  • CAP_SETUID / CAP_SETGID — Change process UID/GID
  • CAP_DAC_OVERRIDE — Bypass DAC permission checks
  • CAP_KILL — Send signals to any process

Capability Sets

Each thread has five capability sets: - Permitted — the maximum set a thread can ever have - Effective — the capabilities currently active for privilege checks - Inheritable — capabilities inherited across execve() - Ambient — inheritable even by unprivileged executables (Linux 4.3+) - Bounding — an upper bound; capabilities in permitted cannot exceed bounding

File Capabilities

Executable files can have capabilities attached, replacing setuid root: - Permitted — added to thread's permitted set on exec - Inheritable — ANDed with thread's inheritable - Effective bit — if set, permitted file capabilities are also effective

Key concepts

CAP_NET_BIND_SERVICE
Allows binding to privileged ports (<1024) without root. The canonical replacement for running web servers as root.
CAP_SYS_ADMIN
The broadest capability — covers mount/unmount, namespace manipulation, kernel keyring access, device I/O, and more. Granting this is nearly equivalent to root. Avoid.
setcap
Set capabilities on an executable file. setcap cap_net_bind_service+ep /usr/bin/nginx — +e adds to effective set, +p to permitted. Use getcap to read.
getcap
Read capabilities from a file. getcap /usr/bin/ping returns cap_net_raw=ep. getcap -r /usr/bin/ recursively scans a directory.
capsh
Capability shell — inspects and modifies capability state. capsh --print shows all five sets for the current process. capsh --decode=0000003fffffffff decodes a hex capability bitmask.
Docker --cap-drop/--cap-add
Docker containers start with a restricted capability set (not full root). --cap-drop ALL removes all capabilities; --cap-add NET_BIND_SERVICE adds back only what is needed. Far safer than --privileged.

When to use it

  • Allowing a non-root service to bind to port 443 — setcap cap_net_bind_service+ep /usr/bin/myapp
  • Hardening Docker containers — --cap-drop ALL --cap-add NET_BIND_SERVICE instead of --privileged
  • Replacing a setuid-root binary with a capability-based equivalent
  • Auditing what capabilities a running process has — cat /proc/PID/status | grep Cap, decode with capsh
  • Designing least-privilege container security in Kubernetes securityContext

Interview questions

  • How do you allow a non-root application to bind to port 80 using capabilities instead of running as root?
  • Walk through capability sets — permitted, effective, inheritable, ambient, and bounding. How do they interact?

Sign up free to read the full topic

More Linux topics

Start free on Cariara · Coding problems · System design studio