rand-guard

rand-guard is a small eBPF EDR project built with Rust and Aya. The goal is not to imitate a commercial EDR product, but to implement the full pipeline myself: collect process, file, and network telemetry from a Linux endpoint with eBPF, normalize and enrich it in userspace, evaluate detections, and write structured output.

This project prioritizes a small, explainable end-to-end flow over a broad feature list. The kernel side only collects a limited set of events through tracepoints, while policy decisions and output handling live in userspace. Events cross a fixed-layout ABI in crates/common, are delivered through the EVENTS ring buffer, and are emitted by the userspace runtime as NDJSON.

The current implementation covers process lifecycle events, file events, opt-in network syscall telemetry, built-in detections, an MVP rule engine, alert records, packaging, and demo workflows. DNS collection, payload collection, accept/accept4, socket lifecycle correlation, and multi-event time-window rule correlation are not implemented yet.

The project code is available at https://github.com/random6-xyz/rand-guard.

Posts

  1. Building a Small Rust eBPF EDR 1: MVP Architecture

    The first post explains the overall structure of rand-guard. It follows an event from a Linux tracepoint through an eBPF program, the EVENTS ring buffer, userspace normalization, detection/rule evaluation, and NDJSON output.

  2. Building a Small Rust eBPF EDR 2: Stable Event ABI

    This post covers the ABI design used to pass events safely between eBPF and userspace. It focuses on #[repr(C)] structs in crates/common, EventHeader, schema versioning, event kinds, fixed-size string fields, and truncation flags.

  3. Building a Small Rust eBPF EDR 3: Process Lifecycle Telemetry

    This post explains how execve, execveat, fork, and exit events are collected and enriched through a userspace process table. It covers why sched_process_exec and syscall tracepoints are used together, plus ppid, comm, exe_path enrichment and cache eviction limits.

  4. Building a Small Rust eBPF EDR 4: File Telemetry and Persistence Detection

    This post describes file event collection for open, write, rename, and unlink syscall families, along with persistence-sensitive path detection. It explains watch_paths, watch_patterns, exclude_paths, systemd service and cron path detections, source event annotations, and separate alert records.

  5. Building a Small Rust eBPF EDR 5: Optional Network Telemetry

    This post explains why network telemetry is opt-in by default. It covers the currently supported connect, bind, and listen tracepoints, IPv4/IPv6 sockaddr parsing, suspicious port detection, process name filtering, and why DNS, payload, and socket correlation are intentionally not implemented yet.

  6. Building a Small Rust eBPF EDR 6: MVP Rule Engine and Alert Records

    This post explains the current userspace rule engine. It covers single-event matchers for process, file, and network events, built-in rules and config [[rules]], stable event_type = "alert" records, and why regex and multi-event correlation are not part of the MVP.

  7. Building a Small Rust eBPF EDR 7: Running, Packaging, Health, and Roadmap

    This post summarizes how to build, run, and package the project. It covers xtask, systemd packaging, quickstart demos, health records, local throughput benchmarks, the threat model, and the roadmap.

Current Scope

  • Process lifecycle collection: execve, execveat, fork, exit.
  • File telemetry: open, write, rename, unlink syscall families.
  • Optional network telemetry: connect, bind, listen.
  • Shared fixed-layout event ABI in crates/common.
  • Ring-buffer delivery through the EVENTS map.
  • Userspace normalization and process context enrichment.
  • Built-in persistence-sensitive file detections.
  • Built-in suspicious network port detections.
  • MVP single-event [[rules]] evaluation.
  • Stable event_type = "alert" records.
  • Stdout newline-delimited JSON output.
  • xtask workflows for build, test, package, smoke, and throughput.

Current Limits

  • This project does not aim for production EDR parity.
  • The rule engine is a single-event matcher MVP; it has no expression DSL, regex, time windows, or multi-event correlation.
  • Network collection is limited to connect, bind, and listen syscall tracepoints.
  • DNS collection and payload collection are not implemented.
  • accept/accept4 telemetry and full socket lifecycle correlation are not implemented.
  • Runtime output is currently centered on stdout NDJSON.
  • Loading eBPF programs requires root or suitable Linux capabilities.

Code

  • crates/common: event ABI shared by eBPF and userspace.
  • crates/ebpf: no_std, no_main Aya eBPF tracepoint programs.
  • crates/user: loader, config, ring-buffer consumer, normalization, enrichment, detections, rule engine, and output.
  • xtask: format, check, clippy, test, build, package, run, ci-smoke, and throughput workflows.
  • docs: architecture, quickstart, threat model, roadmap, benchmark, and demo scenarios.