Linux capabilities

On this page 7

Linux capabilities are a kernel mechanism that divides the all-or-nothing power of root into distinct privileges, each of which can be granted to or removed from a process independently. In Linux security, they let a program bind a low network port or change file ownership without receiving full superuser rights, which directly applies the principle of least privilege.

Traditional UNIX checks asked only one question: is the effective user ID zero. Capabilities replace that single test with about forty separate checks, such as CAP_NET_BIND_SERVICE or CAP_SYS_ADMIN, so the kernel verifies the specific privilege an operation needs.

How Linux capabilities work in the kernel

Each thread carries several capability sets, which are bit masks of privileges. When a thread attempts a privileged operation, such as loading a kernel module, the kernel checks whether the corresponding capability is present in the thread’s effective set. The user ID is no longer the deciding factor for these operations.

The sets interact through precise rules, especially when a program is started with execve. The table describes each per-thread set and its role.

SetMeaningPractical effect
PermittedUpper bound of usable capabilitiesCan be raised into effective
EffectiveCapabilities checked by the kernel nowDetermines what succeeds
InheritablePreserved across execve under conditionsRarely sufficient alone
BoundingLimit on what can ever be gainedDropped entries are gone for good
AmbientKept across execve of unprivileged programsLets services pass capabilities on
Per-thread capability sets

Executable files can also carry file capabilities, stored in the security.capability extended attribute. When such a file runs, the kernel combines the file sets with the thread sets, so a binary can gain one specific privilege without the setuid-root bit.

Important capabilities and their risk

Capabilities are not equally dangerous. Some grant a narrow right, while others are close to full root because they allow changes that can be turned into arbitrary code execution in the kernel or control over other processes.

CapabilityWhat it permitsRisk level
CAP_NET_BIND_SERVICEBind to ports below 1024Low
CAP_NET_RAWRaw and packet sockets, as used by pingModerate
CAP_CHOWNChange file owners arbitrarilyModerate
CAP_DAC_OVERRIDEBypass file permission checksHigh
CAP_NET_ADMINConfigure interfaces, routes and firewallsHigh
CAP_SYS_PTRACETrace and inspect other processesHigh
CAP_SYS_ADMINMounts, namespaces and many other operationsNear root
Frequently used capabilities

CAP_SYS_ADMIN is often called the new root because it covers dozens of unrelated operations. Granting it to a container or service removes most of the benefit of using capabilities, so it should be treated as a last resort.

Managing capabilities in practice

Administrators manage capabilities through file attributes, service units and container settings. The table summarizes the main tools and their typical use.

Tool or settingPurposeExample
setcapAssign file capabilitiessetcap cap_net_bind_service=+ep /usr/bin/app
getcapShow file capabilitiesgetcap -r /usr/bin
capshInspect or launch with given setscapsh --print
/proc/PID/statusShow sets of a running processCapEff and CapBnd fields
CapabilityBoundingSetsystemd limit for a serviceCapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilitiessystemd grant to a non-root serviceAmbientCapabilities=CAP_NET_BIND_SERVICE
Tools for working with capabilities

A common pattern is to run a service as an unprivileged user with one ambient capability, combined with NoNewPrivileges=yes. Container runtimes apply a similar approach: they start with a reduced default set and allow options such as --cap-drop=ALL with selected additions.

Capabilities compared with other Linux security controls

Capabilities answer which privileged operations a process may perform, but they do not restrict which files it may read as an ordinary user or which system calls it may make. Other controls in Linux security fill those gaps.

ControlQuestion it answersGranularity
Linux capabilitiesWhich root privileges are heldAbout forty privilege bits
SeccompWhich system calls are allowedPer system call and argument
SELinuxWhat labeled subjects may do to objectsType enforcement policy
AppArmorWhich paths and resources a program may usePath-based profiles
PAMHow users authenticate and start sessionsPer service login stack
Capabilities and neighboring controls

These controls are complementary. A hardened service typically drops capabilities, applies a seccomp filter and runs under a mandatory access control profile, so a single weakness does not give an attacker unrestricted control.

Pitfalls and misconceptions

Capabilities are easy to misuse because their semantics across execve are subtle. The following points summarize the errors that appear most often in audits.

  • Root is still powerful without capabilities, because it owns many files and configuration paths that matter to security.
  • File capabilities are lost when a binary is replaced by a package update or copied without extended attributes.
  • Interpreted scripts cannot hold file capabilities effectively; setting them on the interpreter grants them to every script.
  • Several capabilities allow escalation to full root, including CAP_SYS_ADMIN, CAP_SYS_MODULE and CAP_DAC_OVERRIDE.
  • Inheritable alone does not pass capabilities to unprivileged child programs; ambient capabilities exist for that purpose.

A plain-language summary

On a traditional Linux system, the administrator account holds a single master key that opens every door. Linux capabilities cut that master key into many small keys. One key opens only the network door, another only the clock, another only the file ownership office.

A program receives only the keys it actually needs. If someone takes over that program, they get those few keys rather than the whole building. That simple idea greatly limits the damage of a security mistake.

An example from practice

A team deploys a small web service that must listen on port 443, which is below 1024 and normally requires root. Running the whole service as root would expose the system if the application had a vulnerability.

The team creates a dedicated service account and writes a systemd unit with User=webapp, AmbientCapabilities=CAP_NET_BIND_SERVICE, CapabilityBoundingSet=CAP_NET_BIND_SERVICE and NoNewPrivileges=yes. Checking /proc/PID/status confirms that only one capability bit is set.

The service binds port 443 normally, but it cannot change file ownership, load modules or reconfigure the network. A later penetration test finds a file upload flaw, yet the attacker gains only an unprivileged account with one narrow right.