Operations 14 min read

Tracing Linux Process Capability Changes with eBPF

The article explains how to use eBPF tracepoints to monitor and record changes in Linux process capabilities, detailing the kernel data structures, BPF program logic, and user‑space handling needed to debug real‑world capability issues such as tcpdump failures and systemd service launches.

Linux Kernel Journey
Linux Kernel Journey
Linux Kernel Journey
Tracing Linux Process Capability Changes with eBPF

Linux capabilities provide fine‑grained privilege control through several sets (Inheritable, Permitted, Effective, Bounding, Ambient). The author encountered a real problem where tcpdump failed with Couldn't change ownership of savefile because the process lacked the cap_chown capability, as shown by strace and capsh --print.

Traditional debugging tools like ptrace are too slow and cannot access certain process attributes (e.g., securebits) from /proc/pid/status. The author therefore turned to eBPF, which can attach to the raw syscall entry and exit tracepoints ( tracepoint/raw_syscalls/sys_enter and tracepoint/raw_syscalls/sys_exit) with minimal overhead.

The BPF header cap.bpf.h defines structures for filtering ( s_filter), event data ( s_event), and capability snapshots ( s_cap). The program uses two BPF maps: a BPF_MAP_TYPE_PERF_EVENT_ARRAY named events to send data to user space, and a BPF_MAP_TYPE_HASH named rsyscall_enter (max 10000 entries) to store the capability state captured at syscall entry.

struct s_filter { pid_t pid; __s64 uid; };
struct s_cap { unsigned int securebits; __u64 cap_inheritable; __u64 cap_permitted; __u64 cap_effective; __u64 cap_bset; __u64 cap_ambient; };
struct s_event { __u64 nsec; int nr; int retvel; pid_t pid; pid_t tgid; pid_t ppid; uid_t uid; char comm[20]; __u64 ustack_sz; __u64 ustack[20]; struct s_cap cap_before; struct s_cap cap_after; union { /* various syscall‑specific structs */ } data; };

On syscall entry, the BPF program reads the current task_struct, filters by PID/UID if requested, records timestamps, PID/TGID/PPID, UID, command name, and the user‑mode stack. It then calls save_cred() to copy the current capability sets into event.cap_before. Depending on the syscall number, it extracts additional arguments (e.g., capset, execve, setuid, prctl) and stores them in the union.

On syscall exit, the program looks up the stored entry, reads the new capability state into a temporary s_cap, and compares each field with the previously saved values. If any field differs, it updates event.cap_after, records the exit timestamp, and emits the event via the perf buffer.

The user‑space component registers a perf buffer callback that formats the event: it prints the time, UID, PID, TGID, PPID, command, and both capability snapshots. It also resolves the user‑mode stack using BCC's BCCUstackResolver to show the code path that triggered the change.

Time: 01:39:16.317241701, uid = 0, pid: 3136, tgid: 3136, ppid: 824, comm: sshd
syscall: prctl
option: PR_SET_KEEPCAPS
arg2: 1
retval: 0
securebits: 0x00000000
cap_inheritable: 0x0000000000000000
cap_permitted: 0x000001ffffffffff
cap_effective: 0x000001ffffffffff
... (diff output) ...

Using this tool, the author debugged a mismatch between the capabilities of a desktop terminal process and the sshd process. The logs revealed that systemd set capabilities via PR_SET_SECUREBITS and execve during service startup, and the subsequent stack traces pinpointed the exact code paths in systemd responsible for the changes.

Overall, the article demonstrates a complete workflow: from understanding Linux capability mechanics, through reproducing a real failure, to building an eBPF tracer that captures, filters, and reports capability transitions with low overhead, enabling precise kernel‑level debugging.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

eBPFkernel debuggingBPF mapsLinux capabilitiestracepointsprocess tracing
Linux Kernel Journey
Written by

Linux Kernel Journey

Linux Kernel Journey

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.