Inspect BPF perf Attachments with bpftool perf
Something is hooked into your kernel via perf and you want to know who, so run bpftool perf. It lists the BPF programs attached through perf events, and you can turn the same inventory into JSON for scripts or incident notes. The command is read-only: it does not detach programs, unload BPF objects or change a service. Allow about ten minutes, or longer if the matching kernel-tools package is missing.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide follows the installed bpftool-perf(8) manual from linux-tools-common version 6.8.0-139.139. The local package supplies a wrapper, but this machine lacks the kernel-specific executable for kernel 6.8.0-139. That is a packaging problem, not evidence that the host has no BPF attachments.
1. Check the binary first
Start with ordinary, read-only checks, and do not add sudo yet. The first command identifies the program your shell selects. The second asks the wrapper for its version:
$ command -v bpftool
/usr/sbin/bpftool
$ bpftool -V
WARNING: bpftool not found for kernel 6.8.0-139
You may need to install the following packages for this specific kernel:
linux-tools-6.8.0-139-generic
linux-cloud-tools-6.8.0-139-generic
Exact wording varies with the distribution and running kernel. On the machine used for this guide, the wrapper exits after this warning because the matching tool is absent. Check the package version separately when you need an audit trail:
$ dpkg-query -W -f='${Package}\t${Version}\n' linux-tools-common
linux-tools-common 6.8.0-139.139
Checkpoint
If bpftool -V names a missing kernel-specific package, stop here and install it through your normal change process. Do not work around the mismatch by copying a binary from another host.
2. Confirm the perf subcommand syntax
Once a working bpftool binary is present, the perf family accepts show and list as equivalent inventory commands. The default invocation is:
$ bpftool perf
pid 21711 fd 5: prog_id 5 kprobe func __x64_sys_write offset 0
pid 21767 fd 5: prog_id 8 tracepoint sys_enter_nanosleep
The process ID and file descriptor identify the process holding the perf event. prog_id identifies the BPF program. The remaining fields describe the attachment type and point. The sample values are illustrative: your host can legitimately print no records, or a completely different set.
Use the explicit spelling in scripts when clarity matters:
$ bpftool perf show
$ bpftool perf list
Tip
Both commands list raw tracepoint, tracepoint and probe attachments known to the running system. They do not list every kind of BPF link, so an empty perf inventory does not prove the kernel has no BPF programs.
3. Read the attachment point
Tracepoint records use a probe name, such as sys_enter_nanosleep. Kernel probes use a function and offset, or a kernel virtual address. User probes use a file name and file offset:
$ bpftool perf show
pid 21765 fd 5: prog_id 7 kretprobe func __x64_sys_nanosleep offset 0
pid 21767 fd 5: prog_id 8 tracepoint sys_enter_nanosleep
pid 21800 fd 5: prog_id 9 uprobe filename /home/yhs/a.out offset 1159
- The PID is not the target. Do not confuse the process ID with the target function's ID.
- An offset is not a line number. Do not read a uprobe file offset as a source line.
- Records vanish with their holder. If the process holding an attachment exits, the record can disappear with it. Capture the inventory close to the event you are investigating.
4. Produce machine-readable output
Use -j or --json when another tool will consume the result. The output is an array of objects, with field names that match the attachment kind:
$ bpftool -j perf
[{"pid":21711,"fd":5,"prog_id":5,"fd_type":"kprobe","func":"__x64_sys_write","offset":0},
{"pid":21767,"fd":5,"prog_id":8,"fd_type":"tracepoint","tracepoint":"sys_enter_nanosleep"},
{"pid":21800,"fd":5,"prog_id":9,"fd_type":"uprobe","filename":"/home/yhs/a.out","offset":1159}]
For readable JSON during a manual review, add -p. It implies JSON:
$ bpftool -p perf
Prefer JSON for scripts over parsing the human-readable spacing. Test for a field such as func, tracepoint or filename according to fd_type, and do not assume every object has all three.
5. Handle access and missing-tool failures
The perf subsystem is subject to the host's security policy. Run the inventory as the account that will normally use it. If it reports a permission error, inspect the error and your organisation's perf policy before trying elevation:
$ bpftool perf show
[permission diagnostic from this host]
$ printf 'exit status: %s\n' "$?"
exit status: 1
- Do not hard-code the status. The exact message and exit status depend on the binary and kernel, so do not build monitoring around the sample.
- Elevation is optional and limited. If your approved procedure permits it, repeat the same read-only command with
sudo. Elevated access may reveal more system information, but it does not repair a missing kernel-specific bpftool binary and it does not detach anything. - Missing tool means a package change. Use the package name the wrapper prints as your lead. Do not install packages as part of an incident command unless that change is authorised. Then repeat Step 1 and run
bpftool perf show.
6. Keep the inspection reversible
Every command in this workflow reads program and attachment metadata. There is no undo command because nothing was changed.
Warning
Do not follow an unexpected attachment by killing the listed process or deleting a pinned BPF object. Those actions can disrupt tracing or an application, and they need a separate ownership and rollback decision.
For an incident record, save JSON to a new file rather than overwriting an existing report:
$ output_file="bpftool-perf-$(date +%Y%m%d-%H%M%S).json"
$ bpftool -j perf > "$output_file"
$ test -s "$output_file" && echo 'inventory saved'
Shell globbing can match several old reports, so use a dedicated empty directory or an explicit destination when automating this. Keep the file access-controlled if attachment names or process IDs are sensitive in your environment.
Done means
- Binary verified. You confirmed bpftool matches the running kernel instead of trusting the wrapper alone.
- Inventory taken.
bpftool perf showorbpftool perf listproduced the current perf attachment list. - IDs told apart. You can distinguish process and program IDs from tracepoint names, symbols and file offsets.
- Scripts use JSON. They consume
-joutput and handle attachment-specific fields. - Failures separated. Permission errors and missing packages are different diagnoses.
- Nothing changed. No process, BPF program, attachment or persistent configuration was modified.