Read Process Capability Trees Safely with captree
captree shows the Linux capabilities attached to a process tree without ever touching them. The examples follow captree(8) as installed with libcap2-bin version 1:2.66-5ubuntu2.4. Allow about ten minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell and a libcap build that includes the captree executable. The command only inspects process state in this workflow, so elevated privileges are not a normal prerequisite. Processes owned by another account may still be less visible, or may change while you inspect them.
1. Check that the executable is really installed
Start by checking the command and the package version. Ordinary, read-only:
$ command -v captree
$ dpkg-query -W -f='${Package} ${Version}\n' libcap2-bin
libcap2-bin 1:2.66-5ubuntu2.4
The first line should print a path before you continue. On the reference machine used for this guide it prints nothing: the package ships the manual page, but dpkg -L libcap2-bin lists capsh, getcap, getpcaps and setcap, not captree. That is a packaging fact, not a reason to pretend it ran. If your host has the same layout, stop here and get a matching libcap build through your normal package or build process. Do not replace system files by hand.
Checkpoint
This must succeed before any later example can work:
$ captree --help
captree [OPTIONS] [(pid|glob-name) ...]
The exact help text can differ between Go runtime versions. The installed manual records exit status 0 for modern runtimes and status 2 for older ones on --help.
2. Inspect the default target
With no target argument, captree uses PID 1. Run it without sudo first:
$ captree
host-specific capability tree for PID 1
The real output is host-specific. Capabilities use the quoted text form from cap_from_text(3), and an IAB tuple, when useful, appears in square brackets using the cap_iab(3) text form. Never copy a capability list from one machine to another and treat it as a baseline: the process, kernel, service manager and launch configuration all shape it.
To make the target explicit, pass a numeric PID:
$ TARGET_PID=1234
$ captree "$TARGET_PID"
capability tree rooted at PID 1234, if it exists
Replace 1234 with a PID that actually exists on your host. Discover one without changing state if you need to:
$ pgrep -xo systemd
1
A target that cannot be found gives exit status 1. Check the status immediately if a script depends on the result:
$ captree "$TARGET_PID" > /tmp/captree.txt
$ status=$?
$ printf 'captree status: %s\n' "$status"
captree status: 0
Status 0 means captree completed its documented target lookup and traversal, not that every process in a changing tree was examined without interruption.
3. View all kernel-known processes carefully
PID 0 is special to captree: it requests every process the kernel knows about, which can be far more output than the default. Write it to a new file if you need to review it properly:
$ captree 0 > /tmp/captree-all.txt
$ printf 'captree status: %s\n' "$?"
captree status: 0
That creates or truncates /tmp/captree-all.txt, so never point it at a valuable path without checking first. The command itself does not modify processes, capabilities or service configuration.
A PID is not the only target form: the manual also permits a glob-name value, so a process name pattern can select matching processes. Quote the pattern so the shell does not expand it before captree sees it:
$ captree 'sshd*'
capability trees for matching process names, if any
Keep the pattern narrow. A broad one can select more than you meant, and a name can change between discovery and inspection. For a stable audit target, prefer a numeric PID and record when it was checked.
4. Limit tree depth for a focused check
Use --depth=n to limit how far captree descends from the selected process. The default is 0, which means unlimited depth, not zero displayed levels:
$ captree --depth=1 "$TARGET_PID"
the target and its first level of descendants
Start small and increase --depth when you need more context; PID 1 or PID 0 can otherwise produce a very long tree. Options must come before the list of PID or name targets.
For a repeatable text report, redirect standard output and check the status before trusting the file:
$ captree --depth=2 "$TARGET_PID" > /tmp/captree-depth-2.txt
$ test "$?" -eq 0 && wc -l /tmp/captree-depth-2.txt
5. Show empty and redundant capability fields
By default, captree omits the IAB tuple when its inheritable and ambient components are empty or redundant with the regular capability text. That is a presentation choice, not evidence the process has no capability state. Add --verbose when an empty field matters to your investigation:
$ captree --verbose "$TARGET_PID"
capability sets and IAB tuples, including empty or redundant values
Compare like with like: a report made with --verbose has more fields than one without it, so record the option alongside any saved evidence. The capability text is descriptive; changing capabilities needs other tools and its own security review.
6. Control colour and diagnose failures
When standard output is a terminal, targeted PIDs are coloured red by default. Piping normally suppresses colour, but use --colour=false when you need a guaranteed plain report:
$ captree --colour=false --depth=1 "$TARGET_PID" > /tmp/captree-plain.txt
The manual also accepts a US spelling variant for the same option. Keep that literal spelling in scripts only if you need compatibility with it:
$ captree --color=false --depth=1 "$TARGET_PID" > /tmp/captree-plain.txt
That option only changes presentation. It does not hide capabilities or alter process state.
- Status 1? Check that the PID or name still exists.
- Status 2? Check option spelling and placement.
For a safe target check:
$ test -d "/proc/$TARGET_PID" && echo 'PID still exists'
PID still exists
A process can exit right after that test, so treat it as a diagnostic, not a lock. Do not reach for sudo as the first response to a lookup failure: it cannot make a nonexistent target reappear, and this command does not need a state-changing privileged operation.
Done means
- Executable confirmed.
captreeis present and its package or build provenance is known. - Target forms understood. You can inspect PID 1, an explicit PID, a name glob, or every kernel-known process.
- Depth used deliberately.
--depthcontrols large trees, and depth 0 is understood as unlimited, not empty. - Verbose used when it matters.
--verbosesurfaces omitted empty or redundant IAB fields. - Reports are traceable. Saved output records the target, options, time and exit status.
- Nothing changed. No process, capability, service or persistent configuration was touched.