How to Detect eBPF Rootkits Before They Can Hide

Summary
Datadog Security Labs explains how VoidLink, LinkPro, and Atomic Arch use eBPF helpers to hide activity or disrupt analysis, and shows how defenders can detect suspicious programs during BPF_PROG_LOAD.
Key points
- VoidLink tampers with Netlink response buffers using bpf_probe_write_user() to make ss skip selected connections.
- LinkPro uses bpf_override_return() to make eBPF program enumeration stop early, hiding programs from tools such as bpftool.
- Atomic Arch uses bpf_send_signal() to kill processes attempting to attach to protected processes with ptrace.
- The article recommends capturing eBPF program type, attach type, identity, maps, and helper IDs while programs are loaded, before they can interfere with monitoring.
- Datadog's described sensor captures helper IDs during verifier processing and combines them with program metadata.
- Detection rules can flag BPF_PROG_LOAD events using BPF_PROBE_WRITE_USER, BPF_OVERRIDE_RETURN, or BPF_SEND_SIGNAL; correlating multiple helper signals can increase confidence.
Article Details
- Defense Focus
- Detect eBPF rootkits at BPF_PROG_LOAD by capturing each program's helper usage and other load-time metadata before it can attach or tamper with host observations.
- Detection Methods
- Capture a load-time fingerprint containing program type, expected attach type, name, tag, ID, map metadata, and the exact helper set.
- Use a kprobe on check_helper_call to record raw helper IDs before verifier rewriting, and use the security_bpf_prog LSM hook to collect program metadata.
- Alert on BPF_PROG_LOAD events that include BPF_PROBE_WRITE_USER, BPF_OVERRIDE_RETURN, BPF_SEND_SIGNAL, or BPF_SEND_SIGNAL_THREAD.
- Correlate two or more of these helper signals within a one-hour window; the article says signals from an interactive shell or a binary in a world-writable directory increase confidence.
- Compare BPF program enumeration results with bpftool prog show id N to identify discrepancies caused by LinkPro's enumeration hook.
- Inspect /sys/kernel/debug/tracing/trace_pipe for LinkPro debug output, but do not rely on it as the primary detection.
- Data Sources
- BPF_PROG_LOAD syscall events
- Raw eBPF helper IDs observed during check_helper_call
- Linux Security Module security_bpf_prog hook
- eBPF program metadata and map references
- bpftool program enumeration and individual program lookup results
- /sys/kernel/debug/tracing/trace_pipe
- Rule Types
- BPF_PROG_LOAD helper-presence rules
- One-hour multi-helper correlation rule
- Platforms
- Linux
- Defensive Actions
- Capture the complete eBPF program fingerprint at load time, before the program can attach or interfere with monitoring.
- Treat the listed uncommon helpers with caution, especially when multiple appear together or are loaded by suspicious processes.
- Where legitimate software uses these helpers, scope rules by excluding known tracing frameworks using process path or name.
- Investigate discrepancies between enumerated BPF programs and direct lookup by program ID.
MITRE ATT&CK
T1014 · RootkitThe eBPF rootkits hide processes, connections, or their own eBPF programs by manipulating kernel-mediated syscall responses and enumeration.T1562.001 · Disable or Modify ToolsThe rootkits evade defenses by concealing kernel-level activity and, in the Atomic Arch example, killing processes that attempt to attach to protected processes.
Malware
Vendors
Products
bpftoolSamples found in the wild bypass tools that have long been considered hard to evade, such as ss, as well as tools that assume attackers can't touch kernel-level introspection, such as bpftool.Datadog AgentTo see how the Datadog Agent's Workload Protection (WP) sensor captures this fingerprint, we need to understand how the kernel encodes helper calls and when that encoding is visible.libbpfThe caller (bpftool, libbpf, or anything else walking the program list) sees -ENOENT and concludes there are no more entries.Workload ProtectionTo see how the Datadog Agent's Workload Protection (WP) sensor captures this fingerprint, we need to understand how the kernel encodes helper calls and when that encoding is visible.