LinuxXXX · Linux Capabilities and PrivilegeCapability debug
capsh and capability debugging - inspecting and dropping capabilities
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
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
Q1. Which command decodes a capability mask to a readable list?
Q2. A capability dropped with `capsh --drop=` cannot be regained by anything capsh subsequently starts with `--`.
Q3. Which of the following are valid capability debugging tools? Select all that apply.
Passing score: 75%. Answers are checked in this browser.