cap-audit - Man Page
discover the minimal capability set for a program
Synopsis
cap-audit [options] -- command [args...]
cap-audit --service file [-- command-or-args...]
Description
cap-audit traces a target process and its descendants to record every kernel capability check it performs. The tool uses eBPF to hook capability verification paths in the kernel and libcap-ng to format the results. Events are filtered to only the traced process tree to reduce overhead.
The auditor fork/execs the requested command, registers its PID for tracing before exec, and automatically tracks child PIDs. At the end of execution it reports which capability checks returned granted or not granted and presents deployment snippets showing how to grant the minimal set.
For syscall-associated checks returning not granted, cap-audit correlates the check with the raw kernel syscall return value when available. A syscall invocation may contain more than one such check, so capability-check and syscall-outcome counts are independent. Successful syscalls show that the not-granted check did not prevent that invocation from completing. EPERM and EACCES results are reported as permission-related failures requiring manual investigation. Other failures are retained as diagnostic evidence. EINTR and kernel restart results are treated as interruption evidence: interruption alone is inconclusive, while a mix of interrupted and successful invocations requires manual investigation because cap-audit cannot distinguish call sites or arguments. Capabilities with only not-granted checks are never added to automatic recommendations; users should add one only after confirming that required functionality fails because it is absent.
The capability masks installed by successful capset(2) calls are also recorded. A capability requested by capset without a confirmed granted check is reported under CAPSET-ONLY CAPABILITIES rather than being classified as required. Deployment snippets retain it as a current-binary compatibility constraint because removing it from the deployment boundary can cause the application's capset to fail. To remove such a capability, first remove it from the application's capability setup, exercise representative code paths in additional runs, and then narrow the deployment boundary. Failed capset calls do not establish this constraint.
The kernel also checks CAP_SETPCAP during capset when the requested change does not require it. Cap-audit excludes that check from capability-use counts only when the kernel's requested inheritable set is contained in the union of the old inheritable and permitted sets. Other CAP_SETPCAP checks are retained, as are explicit successful capset requests and configured service capabilities. This decision does not depend on the executable's file capabilities.
UID/GID and supplementary-group capability checks between successful PR_SET_KEEPCAPS enable and disable calls on the same thread are classified as initialization, even when an intermediate capset has already occurred. This recognizes the temporary identity capabilities used by capng_change_id(3). Checks outside that credential-changing pattern retain their usual phase. If no successful disable is observed before exec, thread exit, or the end of tracing, cap-audit warns and retains the original phase classification. JSON and YAML also report this as keepcaps_transition_incomplete.
Service recommendations identify requested SETUID/SETGID capabilities whose observed use is confined to initialization, including a completed KEEPCAPS transition. These are not needed for observed operation, but remain in the deployment configuration because the unchanged application needs them during startup. Unexercised paths still require review and testing before changing the application's retained capabilities.
Runtime tracing requires root or the CAP_BPF and CAP_PERFMON capabilities, along with kernel BTF data in /sys/kernel/btf/vmlinux.
Options
- -h, --help
Show a help message and exit.
- -v, --verbose
Print each capability check as it occurs.
- -j, --json
Emit the analysis as JSON.
- -y, --yaml
Emit the analysis as YAML.
- -s, --service FILE
Parse a systemd service unit file, simulate the service user, group, supplementary group, capability, and NoNewPrivileges settings in the traced child, and emit service-specific recommendations. Without an explicit command after --, the parsed ExecStart= command is traced. With --, a command can be supplied explicitly; if the first supplied word starts with -, it is treated as replacement arguments for the parsed ExecStart= executable.
Capabilities explicitly configured in the unit but not observed during the trace are retained in a current-service-compatible recommendation. They are also identified as removal candidates because the relevant functionality may not have been exercised. Cap-audit does not generate a configuration that removes them; targeted testing or manual review must first confirm that each configured capability is unnecessary.
The generated service configuration preserves the NoNewPrivileges= setting used for the audit. When the setting is disabled, enabling it has not been validated by the trace and must be tested separately, including service functionality that starts child processes or helper programs.
Cap-audit does not load the environment configured by Environment= or EnvironmentFile=. A standalone $NAME argument in ExecStart= is therefore treated as unset and omitted. Supply an explicit command after -- when a non-empty expansion is needed for the audit.
A single ! prefix on the ExecStart= executable is supported. It leaves the configured user, group, and supplementary group changes to the executed program while continuing to apply the configured capability and NoNewPrivileges= settings. The fully privileged + prefix and the legacy !! prefix are rejected because cap-audit cannot safely simulate their execution semantics. The @ prefix is also rejected because the command model does not support a separate executable path and overridden first argument.
Only one ExecStart= command is supported. Multiple commands, including oneshot sequences, are rejected. An empty assignment resets the command and permits a subsequent replacement. Unit-file line continuations are rejected; place each directive on one line. Command quoting supports single and double quotes, empty quoted arguments, and backslash escapes for literal backslashes and quote characters. Other escape sequences, such as hexadecimal or whitespace escapes, are rejected instead of being passed with a different meaning.
If a capability check targets a user namespace different from the namespace in which cap-audit started, the observation is retained in the diagnostic output but automatic capability recommendations are suppressed. The safe scope of a capability grant cannot be determined from the target namespace alone.
- --
End option parsing and treat the rest of the command line as the program to execute under audit.
Exit Status
The program returns 0 on success. Non-zero values indicate an error occurred while setting up tracing or executing the target command.
Notes
1. This utility observes the application behavior to decide what is needed. If you do not exercise all functionality, it can result in an incomplete inventory of needed capabilities. If it can't see it, cap-audit can't record it.
2. Event collection has fixed memory limits: 8192 traced tasks, 1024 in-flight capability checks, 4096 syscall records, and a 256 KiB event ring buffer. Exhausting a map or the ring buffer can lose observations and produce an incomplete capability inventory. Such losses are not currently reported.
3. When auditing a daemon, pass options to keep it in the foreground. If it forks and exits, that will end the session and you will only get the capabilities traced up to the exit. Here's an example keeping the daemon in the foreground:
cap-audit /usr/sbin/sshd -D
EXPERIMENTAL: cap-audit output is experimental, but very close.
Files
/sys/kernel/btf/vmlinux
See Also
Author
Steve Grubb