Skip to content
Kernel Security

eBPF for Security: Listening to Your Kernel in Real Time

11 min read

Most security tools read logs. They wait for sshd to write a "Failed password" line, parse it, and react. By the time the log exists, the event already happened. The attacker already tried the password. The process already ran. The file was already opened.

eBPF changes this. It lets you run small, verified programs inside the Linux kernel itself. You see every syscall, every process, every network connection the moment it happens, before any log is written. Inner Warden uses six eBPF programs to monitor and protect your server at the kernel level, all in about 10KB of bytecode.

What is eBPF

eBPF (extended Berkeley Packet Filter) is a technology that lets you run sandboxed programs inside the Linux kernel without modifying kernel source code or loading kernel modules. Every eBPF program is verified by the BPF verifier before it runs. The verifier checks that the program terminates, does not access invalid memory, and cannot crash the kernel. If verification fails, the program is rejected.

This means eBPF programs are safe by construction. They cannot cause kernel panics. They cannot corrupt memory. They cannot enter infinite loops. The verifier guarantees it. This makes eBPF ideal for production security monitoring: you get kernel-level visibility with kernel-level safety.

Why eBPF beats log parsing

Traditional security tools work by tailing log files. auth.log, syslog, journald, nginx access logs. This approach has three fundamental problems:

  • Timing: logs are written after the event. By the time you parse "Accepted publickey for root," the attacker is already logged in. eBPF sees the syscall before the log line exists.
  • Evasion: attackers can clear logs, redirect output, or kill the logging daemon. You cannot clear a tracepoint. eBPF hooks into the kernel itself, not into userspace log writers.
  • Overhead: log parsing means reading files, applying regex, and maintaining file watchers. eBPF runs in kernel space with near-zero overhead. There is no file I/O, no regex, no polling.

eBPF does not replace logs. Inner Warden still monitors auth.log, journald, nginx, and other sources. But eBPF adds a layer that cannot be evaded by any userspace technique.

The six eBPF programs Inner Warden runs

Inner Warden loads six eBPF programs into the kernel, each attached to a different hook point. Together, they cover process execution, network activity, file access, privilege escalation, execution policy, and network-level blocking.

3 Tracepoints
sys_enter_execve: every process execution

Fires every time a process is created on the system. Captures the binary path, arguments, UID, GID, and parent PID. This is how Inner Warden detects reverse shells, crypto miners, and suspicious binaries running from /tmp. No process can start without this tracepoint seeing it.

sys_enter_connect: every network connection

Fires every time a process opens a network connection. Captures the destination IP, port, protocol, and the PID making the connection. This detects C2 callbacks, data exfiltration, and unexpected outbound connections from server processes that should never initiate network traffic.

sys_enter_openat: every file access

Fires every time a file is opened. Captures the file path, flags (read/write/create), and the process doing the access. This detects attempts to read /etc/shadow, modify SSH authorized_keys, tamper with system binaries, or access sensitive configuration files.

1 Kprobe
commit_creds: privilege escalation detection

This kernel function is called whenever a process changes its credentials. Inner Warden watches for UID transitions to 0 (root) from non-root processes. When a normal user process suddenly becomes root outside of sudo or su, it is almost certainly a privilege escalation exploit: a kernel vulnerability, a SUID binary abuse, or a container escape. This kprobe catches it at the exact moment it happens.

1 LSM Hook
bprm_check_security: execution blocking

This Linux Security Module hook fires before a binary is executed. Inner Warden uses it to block execution from world-writable directories: /tmp, /dev/shm, and /var/tmp. These are the directories attackers use to drop and run payloads because any user can write to them. The LSM hook does not just detect. It prevents. The binary never runs. The exec call returns EPERM.

1 XDP Program
XDP blocklist: wire-speed IP blocking

XDP (eXpress Data Path) runs at the network driver level, before the kernel networking stack even sees the packet. Inner Warden maintains a BPF HashMap of blocked IPs. Every incoming packet is checked against the map. Blocked packets are dropped immediately. No TCP handshake, no SYN-ACK, no response. The attacker gets silence. This handles 10 million+ packets per second on commodity hardware. It is faster than iptables, nftables, or any userspace firewall.

Container awareness through cgroup tracking

Every eBPF event includes the cgroup_id of the process that triggered it. On a container host, each container runs in its own cgroup. This means Inner Warden knows exactly which container each event belongs to: which container spawned the suspicious process, which container opened the network connection, which container tried to escalate privileges.

This is critical for container security. A process executing /bin/sh inside a production web container is very different from the same command on the host. Inner Warden can correlate eBPF events with Docker container metadata to provide context-aware detection and response, including blocking or isolating specific containers without affecting the rest of the host.

Writing Rust for the BPF verifier

Inner Warden's eBPF programs are written in Rust, compiled as a #![no_std] crate targeting the bpfel-unknown-none architecture. This is not normal Rust. There is no standard library, no heap allocation, no Vec, no String, no println. The BPF verifier enforces a 512-byte stack limit per function. Every variable must be on the stack or in a BPF map.

eBPF Rust constraints
// No heap: no Vec, String, Box, Arc
// No standard library: #![no_std]
// 512-byte stack limit per function
// All loops must have bounded iteration counts
// No function pointers or dynamic dispatch
// No floating point arithmetic
// Every memory access must be bounds-checked

// Shared types live in a separate crate:
// crates/sensor-ebpf-types/
// Used by both the eBPF programs and userspace loader

Inner Warden uses the Aya framework to load and manage eBPF programs from userspace. Aya is a pure-Rust eBPF library with no dependency on libbpf, clang, or BCC. The eBPF programs are compiled at build time and embedded in the sensor binary. Shared types between kernel and userspace live in a dedicated crate (sensor-ebpf-types) to ensure type safety across the boundary.

10KB of bytecode. Smaller than a photo.

All six eBPF programs compile to approximately 10KB of BPF bytecode total. That is smaller than a WhatsApp photo, smaller than most favicons, smaller than this blog post. Yet those 10KB give you kernel-level visibility into every process, every connection, every file access, and every privilege change on your server.

The programs are loaded into the kernel via Aya when the sensor starts. They stay attached until the sensor stops. There is no polling, no file watching, no periodic scans. Events flow from the kernel to userspace through ring buffers with minimal copying. The CPU overhead is effectively zero for normal workloads.

What eBPF catches that logs miss

There is an entire class of attacks designed to evade log-based detection. eBPF catches them because it operates at a layer that attackers cannot manipulate from userspace.

  • Fileless malware: malware that runs entirely in memory, never touching the filesystem. No file means no file-integrity alert. But the execve tracepoint sees the process start.
  • In-memory attacks: an attacker who gains code execution inside an existing process (e.g., through a buffer overflow) never creates a new log entry. But connect and openat tracepoints see the unexpected network connections and file accesses from that process.
  • Log-clearing attackers: the first thing a skilled attacker does after gaining access is clear logs. They truncate auth.log, delete bash_history, and stop syslog. None of this affects eBPF tracepoints. The kernel does not care about your log files.
  • Container escapes: when a process escapes its container namespace, it typically involves credential changes (caught by commit_creds kprobe) and unexpected process execution (caught by execve tracepoint). The cgroup_id tracking reveals that the process originated in a container but is now operating at the host level.
  • Privilege escalation exploits: kernel exploits that escalate privileges do not write log lines. They modify in-kernel credential structures. The commit_creds kprobe fires at the exact moment this happens, before the attacker can take any action with their new privileges.

How it fits into the pipeline

eBPF events flow through the same sensor pipeline as every other collector. The sensor receives events from the kernel via ring buffers, normalizes them into the standard Event format, and passes them through stateful detectors. The detectors correlate eBPF events with other sources. A privilege escalation caught by the kprobe is correlated with the SSH session that preceded it, the docker container that hosted it, and the IP address that initiated it.

Event flow
kernel tracepoint/kprobe/LSM/XDP
  → BPF ring buffer
    → sensor (eBPF collector)
      → detectors (correlation + state)
        → incidents-*.jsonl
          → agent (AI triage + enrichment + response)

The agent then enriches the incident with AbuseIPDB and GeoIP data, runs it through the AI confidence scorer, and executes the appropriate response: block the IP via XDP for wire-speed enforcement, suspend the user, kill the process, or isolate the container.

Enable eBPF monitoring

eBPF monitoring is available on Linux kernels 5.10+ with BTF (BPF Type Format) support. Most modern distributions ship with BTF enabled by default.

Install and enable
curl -fsSL https://innerwarden.com/install | sudo bash

# Enable eBPF collectors
innerwarden configure capability ebpf

# Verify kernel support
innerwarden preflight

The preflight check verifies BTF support, kernel version, and required capabilities. If your kernel supports eBPF, the six programs are loaded automatically when the sensor starts. If not, the sensor continues with its other collectors. eBPF is additive, not required.

What to do next