Skip to main content
RunBook Academy

LinuxXXX · Linux Capabilities and PrivilegeCapability debug

capsh and capability debugging - inspecting and dropping capabilities

Intermediate⏱ ~10 mincapshgetpcaps

What you'll learn

  • Decode a capability mask
  • Drop capabilities for a process
  • Use prctl to inspect capabilities
  • Recognise when capabilities are missing

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

When a capability is missing or extra, debugging starts with inspecting what’s actually set. This lesson covers the tools and the prctl interface.

Inspect capabilities

# From /proc
grep Cap /proc/$$/status
# CapInh: 0000000000000000
# CapPrm: 0000000000000000
# CapEff: 0000000000000000
# CapBnd: 0000003fffffffff

# Decode the mask
capsh --decode=0000003fffffffff
# Current: = cap_chown,cap_dac_override,...

capsh

capsh is the canonical tool:

# Show current
capsh --print

# Decode a mask
capsh --decode=0000003fffffffff

# Drop from the BOUNDING set of a NEW process that capsh execs.
# Your shell is unaffected - see the callout below.
sudo capsh --drop=cap_net_bind_service --print | grep -i bounding

# Drop multiple
sudo capsh --drop='cap_net_bind_service,cap_sys_admin' --print

# Run a program without a capability, as an unprivileged user:
# everything after -- is passed to the shell capsh execs.
sudo capsh --drop=cap_net_bind_service --user=nobody -- \
    -c 'python3 -m http.server 80'

getpcaps

For an arbitrary process:

PID=$(pgrep -o nginx)       # or any PID you already have
sudo getpcaps "$PID"
1234: cap_chown,cap_dac_override,...

getpcaps takes PIDs only — it does not resolve process names. Given one it fails with Cannot parse pid nginx: (Invalid argument). Expand the name yourself:

# Every process of that name, all at once
sudo getpcaps $(pgrep nginx)

# Or the main PID of the unit, which is usually the one you want
sudo getpcaps "$(systemctl show -p MainPID --value nginx)"

Prefer the MainPID form for a service: pgrep nginx also matches workers, and on a busy host it can match an unrelated process whose command line happens to contain the string.

Decoding a mask

The mask is a 64-bit value. Each bit represents one capability (CAP_CHOWN is bit 0, CAP_DAC_OVERRIDE is bit 1, etc.). The mask is shown as a hex value where each bit set means the capability is present.

capsh --decode=<mask> translates the mask to a readable list.

prctl

The prctl interface exposes capabilities at the system call level. From C or Python:

// Drop CAP_NET_BIND_SERVICE
prctl(PR_CAPBSET_DROP, CAP_NET_BIND_SERVICE, 0, 0, 0);

From the shell (via capsh):

sudo capsh --drop=cap_net_bind_service --user=nginx -- -c 'python3 -m http.server 80'

This drops the capability and runs the command as the nginx user. The server cannot bind to port 80.

Common diagnostic patterns

“Why is ping failing?”

getcap /bin/ping
# If empty, the capability was not set
sudo setcap cap_net_raw+ep /bin/ping

Grant cap_net_raw and nothing else. ping needs a raw socket; that is the whole requirement. Adding cap_net_admin - as older guidance did - also hands the binary interface reconfiguration, routing-table changes, firewall administration and promiscuous mode. On a world-executable file that turns any ping bug into control of the host’s networking. If a capability can be removed and the program still works, it was never needed.

“Why is my service denied?”

# Substitute your own values before running:
PID=1234

# Check the service's bounding set
grep Cap /proc/"$PID"/status

# Decode the hex mask that CapBnd reports. Read it out of /proc rather than
# retyping it - the masks are 16 hex digits and a transposed pair decodes to
# a completely different capability set.
CAPBND=$(awk '/^CapBnd:/ { print $2 }' /proc/"$PID"/status)
capsh --decode="$CAPBND"

If a capability is missing from the bounding set, the process can never acquire it.

“Why can the service do more than expected?”

PID=$(pgrep -o nginx)
sudo getpcaps "$PID"

If unexpected capabilities are effective, audit the file’s xattrs and the parent’s capabilities.

When to drop capabilities

  • Before exec: file capabilities + inheritable.
  • After exec: prctl(PR_CAPBSET_DROP).
  • In containers: explicitly drop everything not needed.

For a service, the goal is “minimal capabilities needed”: the service cannot do what it does not need to do. This is defence in depth at the capability layer.

Knowledge check

Knowledge check · 3 questions

  1. Q1. Which command decodes a capability mask to a readable list?

  2. Q2. A capability dropped with `capsh --drop=` cannot be regained by anything capsh subsequently starts with `--`.

  3. Q3. Which of the following are valid capability debugging tools? Select all that apply.

Passing score: 75%. Answers are checked in this browser.