Skip to content

eBPF Runtime Enforcement

The cloudtaser eBPF agent is a daemonset that deploys kernel-level enforcement programs on every node. It monitors and blocks attack vectors that could be used to extract secrets from protected processes. cloudtaser-ebpf v0.4.8 ships 27 vectors across two enforcement phases.

Phase 2 enforcement (v0.4.8)

Four new vectors shipped in v0.4.8 extend coverage to pidfd_getfd FD theft, namespace escape via setns and the new mount API, coredump redirect via core_pattern, and BPF program detach. See Phase 2 Enforcement Vectors for the full write-up including verification commands and kernel requirements.

Compliance and Business Summary

The eBPF agent blocks 27 attack vectors in real time (as of v0.4.8), providing continuous runtime enforcement that satisfies NIS2 Article 21(b) incident handling and DORA Article 10 detection requirements. Every blocked attempt is logged with full audit trail (source process, target process, syscall, timestamp), enabling demonstrable compliance with regulatory monitoring obligations.


Architecture

┌──────────────────────────────────────────────────────────┐
│  Kubernetes Node                                         │
│                                                          │
│  ┌─────────────────────┐    ┌─────────────────────────┐  │
│  │ cloudtaser eBPF Pod │    │ Protected Application   │  │
│  │                     │    │ Pod                      │  │
│  │  Agent (user-space) │    │  ┌───────────────────┐  │  │
│  │  - Cgroup tracking  │    │  │ wrapper (PID 1)   │  │  │
│  │  - Event logging    │    │  │ secrets in memfd  │  │  │
│  │  - Policy decisions │    │  └───────┬───────────┘  │  │
│  │         ▲           │    │          │              │  │
│  └─────────┼───────────┘    │  ┌───────▼───────────┐  │  │
│            │                │  │ application       │  │  │
│            │                │  └───────────────────┘  │  │
│  ──────────┼────────────────┼─────────────────────────┼──│
│  Kernel    │                                          │  │
│  ┌─────────▼──────────────────────────────────────────┐  │
│  │ eBPF Programs                                      │  │
│  │  - kprobe/openat2 (file access control)            │  │
│  │  - kprobe/write, writev (exfiltration block)       │  │
│  │  - kprobe/sendto, sendmsg (network block)          │  │
│  │  - kprobe/ptrace (debug prevention)                │  │
│  │  - kprobe/process_vm_readv (cross-process block)   │  │
│  │  - kprobe/init_module (privesc detection)          │  │
│  │  - ...27 attachment points (v0.4.8)                        │  │
│  └────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────┘

The agent operates in two modes:

  • Pod-cgroup enforcement (v0.1.59+) -- blocks syscalls from/targeting tasks running inside protected pod cgroups, identified via BPF_MAP_TYPE_CGROUP_ARRAY and bpf_current_task_under_cgroup. This replaces the earlier PID-set model and correctly handles kernel-namespace ID mismatches seen on kernel 6.17+ with cgroupns tasks.
  • Global privilege escalation detection -- detects dangerous operations from any process on the node

Cgroup-array enforcement model (v0.1.59+)

Starting with cloudtaser-ebpf v0.1.59 (helm 1.0.61), the agent switched from an inode-based monitored_cgroups HASH map to BPF_MAP_TYPE_CGROUP_ARRAY with bpf_current_task_under_cgroup. This is architecturally cleaner and fixes the kernel-namespace ID mismatch that affected cgroupns-isolated tasks on kernel 6.17+. The user-visible change: cgroup membership is now checked by array lookup rather than inode comparison. The enforcement outcome (block or kill) is identical.


Enforcement Modes

Synchronous Block (kprobe override)

Kernel requirement: CONFIG_BPF_KPROBE_OVERRIDE=y

The eBPF program attaches to the kernel function entry point via kprobe. When a monitored syscall is invoked, the program inspects the arguments and can override the return value before the syscall executes. The calling process receives -EACCES and the syscall never runs.

Attacker calls openat("/proc/PID/mem")
  → kprobe fires BEFORE syscall executes
  → eBPF program checks caller's task against cgroup-array (bpf_current_task_under_cgroup)
  → Returns -EACCES to caller
  → File is never opened
  → Event logged: PROCMEM_READ

This is the preferred enforcement mode

Synchronous blocking means the attack is stopped before any data is accessed. There is no race condition and no window of exposure.

Reactive Kill (fallback)

Kernel requirement: Any Linux with eBPF support (4.18+)

When kprobe override is unavailable, the agent attaches via tracepoints and sends SIGKILL to the offending process immediately after detection.

Attacker calls openat("/proc/PID/mem")
  → Syscall executes (file descriptor returned)
  → Tracepoint fires on syscall exit
  → eBPF program detects violation
  → SIGKILL sent to attacker process
  → Process terminated before read() can follow

Reactive kill has a theoretical gap

Between syscall completion and SIGKILL delivery, the attacker technically holds an open file descriptor. In practice, the kill is delivered before a subsequent read() can execute, but this is a weaker guarantee than synchronous blocking.

Detection + Audit

For operations that cannot be blocked without breaking system functionality (e.g., kernel module loading from system PIDs), the agent logs detailed audit events without taking enforcement action.


Enforcement Vectors by Category

Memory Access

These vectors prevent direct reading of protected process memory.

# Attack Vector Syscall / Path Enforcement Event Type
1 Read /proc/PID/environ openat("/proc/PID/environ") kprobe block (all monitored PIDs in protected cgroup-array, including app child PIDs in sibling cgroups -- broadened in cloudtaser-ebpf#168) ENVIRON_READ
2 Read /proc/PID/mem openat("/proc/PID/mem") kprobe block PROCMEM_READ
3 Read /proc/PID/maps openat("/proc/PID/maps") kprobe block PROCINFO_READ
4 Read /proc/PID/pagemap openat("/proc/PID/pagemap") kprobe block PROCINFO_READ
5 Read /proc/PID/smaps openat("/proc/PID/smaps") kprobe block PROCINFO_READ
6 Cross-process memory read process_vm_readv() kprobe block VMREADV_DENIED
7 Cross-process memory write process_vm_writev() kprobe block VMREADV_DENIED
8 Debug attach ptrace(PTRACE_ATTACH) / ptrace(PTRACE_SEIZE) kprobe block PTRACE_DENIED

Why block /proc/PID/maps?

Memory maps reveal the layout of the process address space, including where memfd_secret regions are allocated. While memfd_secret pages cannot be read through /proc/PID/mem, knowing the layout aids other attack vectors. cloudtaser blocks all /proc information disclosure for monitored processes.

Exfiltration

These vectors prevent secrets from being written to persistent storage or sent over the network.

# Attack Vector Syscall Enforcement Event Type
9 Write secret to file write(), writev() kprobe block (content match) SECRET_LEAK
10 Send secret over network sendto(), sendmsg() kprobe block (content match) SECRET_LEAK
11 Zero-copy file transfer sendfile() kprobe block ZEROCOPY_EXFIL
12 Zero-copy pipe splice splice(), tee() kprobe block ZEROCOPY_EXFIL
13 Zero-copy VM splice vmsplice() kprobe block ZEROCOPY_EXFIL
14 DNS exfiltration DNS query with encoded secret data Content matching on sendto/sendmsg SECRET_LEAK

Content-based matching

For write() and sendto()/sendmsg(), the eBPF program performs content matching against known secret values. This catches cases where the application itself (not an attacker) inadvertently logs or transmits a secret. Zero-copy syscalls are blocked unconditionally for monitored processes because the kernel transfers data without user-space buffer inspection.

Privilege Escalation

These vectors detect or block attempts to gain kernel-level access that could bypass all protections.

# Attack Vector Syscall Enforcement Event Type
15 Load kernel module init_module(), finit_module() Global detection (all PIDs) + kprobe block (protected pod cgroups) MODULE_LOAD
16 Load eBPF program bpf(BPF_PROG_LOAD) Global detection (all PIDs) + kprobe block (protected pod cgroups) BPF_LOAD
17 Performance event sampling perf_event_open() kprobe block PERF_EVENT_DENIED

Why module and eBPF loading are treated specially

Kernel modules and eBPF programs run with full kernel privileges. A malicious module can bypass all user-space protections (except memfd_secret on 5.14+). cloudtaser detects these operations globally -- from any PID on the node, not just monitored processes -- because the threat is node-wide. Blocking is applied only to monitored PIDs to avoid breaking legitimate system operations (e.g., kube-proxy loading eBPF programs).

Evasion

These vectors block techniques that could circumvent the other enforcement categories.

# Attack Vector Syscall / Path Enforcement Event Type
18 Async I/O bypass io_uring_setup() kprobe block IOURING_DENIED
19 Page fault interception userfaultfd() kprobe block USERFAULTFD_DENIED
20 Raw memory device openat("/dev/mem"), /dev/kmem, /proc/kcore kprobe block DEVMEM_DENIED
21 Re-enable core dumps openat("/proc/PID/coredump_filter") for write kprobe block PROC_WRITE_DENIED
22 Read kernel stack openat("/proc/PID/stack") kprobe block PROCINFO_READ
23 Read registers openat("/proc/PID/syscall") kprobe block PROCINFO_READ

io_uring is blocked entirely for monitored processes

io_uring provides a submission queue that bypasses per-syscall eBPF hooks. An attacker could use io_uring to perform file writes or network sends that the eBPF agent cannot inspect. cloudtaser blocks io_uring_setup() for monitored processes. Applications that rely on io_uring for performance must use standard syscalls instead. This is an intentional security trade-off.


Event Format

All enforcement events are logged by the user-space agent in structured format:

{
  "timestamp": "2026-03-21T14:32:01.847Z",
  "event": "PROCMEM_READ",
  "action": "blocked",
  "source_pid": 4821,
  "source_comm": "attacker",
  "target_pid": 1234,
  "target_comm": "wrapper",
  "syscall": "openat",
  "path": "/proc/1234/mem",
  "node": "gke-prod-pool-abc123"
}

Events are emitted to:

  • Container stdout (collected by standard log pipelines)
  • cloudtaser Platform (if connected) for centralized audit
  • Kubernetes events on the protected pod

Configuration

Enforcement Mode

env:
  - name: ENFORCE_MODE
    value: "true"              # Block violations (not just detect)
  - name: GLOBAL_PRIVESC_DETECT
    value: "true"              # Detect module/BPF loads from ANY process

Per-Vector Control

Individual vectors can be toggled for debugging or compatibility:

env:
  - name: CLOUDTASER_EBPF_ALLOW_IOURING
    value: "false"             # Default: false (blocked)
  - name: CLOUDTASER_EBPF_ALLOW_PERF
    value: "false"             # Default: false (blocked)

Disabling enforcement vectors weakens protection

Every disabled vector is an open attack path. Disable individual vectors only for debugging, never in production.


Kernel Compatibility

Feature Minimum Kernel Distribution Examples
eBPF basic (tracepoints) 4.18 RHEL 8, Ubuntu 18.04
kprobe override (synchronous block) 4.18 + CONFIG_BPF_KPROBE_OVERRIDE=y Most cloud provider kernels
BTF (CO-RE, no per-kernel compilation) 5.2 Ubuntu 20.04+, RHEL 8.4+
memfd_secret 5.14 Ubuntu 22.04+, Bottlerocket, Flatcar

Check your kernel configuration

# Verify kprobe override support
zcat /proc/config.gz | grep CONFIG_BPF_KPROBE_OVERRIDE

# Verify BTF support
ls /sys/kernel/btf/vmlinux

# Verify memfd_secret support
uname -r  # Must be >= 5.14

Vector Summary

Phase 1 (v0.1.x – v0.4.7)

Category Vectors Enforcement Scope
Memory Access 8 vectors kprobe block / reactive kill Protected pod cgroups
Exfiltration 6 vectors kprobe block (content match) / reactive kill Protected pod cgroups
Privilege Escalation 3 vectors Global detection + protected pod block All PIDs (detect) / Protected pod cgroups (block)
Evasion 6 vectors kprobe block / reactive kill Protected pod cgroups
Phase 1 Total 23 vectors

Phase 2 (v0.4.8)

Vector Attack Enforcement Scope
V1 — pidfd_getfd Cross-process FD theft via pidfd_getfd(2) BPF LSM block Target-anchored
V2 — setns / mount API Namespace escape + new mount API abuse kprobe + BPF LSM block Caller-anchored
V3 — core_pattern Coredump redirect to attacker handler BPF LSM + kprobe block Caller-anchored
V4 — bpf() tamper BPF detach + program enumeration BPF LSM + kprobe block Caller-anchored
Phase 2 Total +4 vectors

Combined total: 27 enforcement vectors as of v0.4.8.

Phase 2 enforcement detail | Memory Protection | Root Attack Surface