NERRF
Tracker

Tracker Component

Real-time eBPF-based system call tracing for ransomware detection

Overview

The NERRF Tracker is a high-performance, kernel-space eBPF instrumentation layer that captures fine-grained file system operations in real-time. It forms the sensory foundation of the NERRF framework, streaming structured syscall events via gRPC to AI models for attack detection and recovery planning.

Key Capabilities

  • Real-time syscall capture (≥1k events/sec sustained on 4-core VM)
  • Sub-microsecond latency from kernel to userspace via ring buffers
  • Zero-copy event passing using BPF ring buffers (vs. perf events)
  • Efficient gRPC streaming with per-client buffering
  • Protobuf-structured data for seamless ML pipeline integration
  • Minimal kernel overhead (<5% CPU for production workloads)

Architecture Stack

┌─────────────────────────────────────────────────────────────┐
│                    gRPC Clients (AI/ML)                     │
└────────────────────┬────────────────────────────────────────┘
                     │ gRPC Streaming

┌─────────────────────────────────────────────────────────────┐
│           Go Userspace (tracker binary, port 50051)         │
│  ┌─────────────────────────────────────────────────────────┤
│  │ Ring Buffer Reader  │ Event Parser  │ gRPC Server        │
│  └──────────┬──────────────────────────────────────────────┘
│             │ ring-buffer-read (mmap'd)
└─────────────┼────────────────────────────────────────────────┘

┌─────────────▼────────────────────────────────────────────────┐
│           Linux Kernel eBPF Programs (tracepoints.o)         │
│  ┌─────────────────────────────────────────────────────────┤
│  │ sys_enter_openat  │ sys_enter_write  │ sys_enter_rename  │
│  │ (tracepoints.c)   │ (tracepoints.c)  │ (tracepoints.c)   │
│  └─────────────────────────────────────────────────────────┘
└────────────────────────────────────────────────────────────┘

┌─────────────▼────────────────────────────────────────────────┐
│         Linux VFS & Syscall Layer (kernel 4.18+)            │
└────────────────────────────────────────────────────────────┘

Event Flow

  1. Syscall Tracepoint → Kernel triggers eBPF program
  2. Event Serialization → eBPF reserves space in ring buffer
  3. Atomic Submission → eBPF submits event without copying
  4. Userspace Read → Go program reads mmap'd ring buffer
  5. Event Parsing → Binary data → Go struct → Protobuf
  6. gRPC Broadcast → Event sent to all connected clients

Supported Syscalls

SyscallIDPurposeCaptured Fields
openat()1File open/create operationspath, flags, mode
write()2File write operations (LockBit key)fd, bytes, offset
rename()3File rename/move (LockBit indicator)old path, new path

Future Extensions:

  • unlink() – File deletion patterns
  • chmod() – Permission changes
  • setxattr() – Metadata modifications

Technology Choices

Why eBPF?

AspecteBPFAlternatives
Kernel-spacePrograms run in kernelstrace, auditd (slower)
Zero-copyRing buffers (mmap'd)perf events (copying)
SafetyKernel verifierKernel modules (unsafe)
PerformanceJIT-compiled, fast pathuserspace hooks (slow)
CompatibilityKernel 4.18+, no recompilesystemtap (setup-heavy)

Ring Buffer vs. Perf Events

Ring Buffer (tracepoints.c):              Perf Events (legacy):
├─ mmap'd shared memory                   ├─ per-CPU buffers
├─ atomic reservation (no locks)          ├─ spinlock protection
├─ single-reader model                    ├─ complex consumer sync
├─ minimal CPU overhead                   ├─ higher CPU usage
└─ efficient GC (auto-wrap)               └─ manual buffer management

Why gRPC + Protobuf?

  • Language-agnostic streaming to Python (AI), Rust (sandbox), etc.
  • Structured schema prevents field mismatches between components
  • Built-in compression for large trace uploads
  • Reflection API for debugging with grpcurl

Core Components

1. eBPF Programs (tracepoints.c)

Located at tracker/bpf/tracepoints.c (81 lines of kernel code):

Key Features:

  • GPL License required for BPF helpers
  • Ring buffer map (256 KB capacity, auto-wrap)
  • Inline common fields via fill_common() macro
  • String sanitization for paths (null-terminated, UTF-8)
  • Zero-allocation event handling (pre-reserved slots)

Tracepoint Hook:

SEC("tracepoint/syscalls/sys_enter_openat")
int trace_openat(struct trace_event_raw_sys_enter *ctx)

This hooks the sys_enter_openat tracepoint provided by the kernel, fired immediately when openat() syscall is invoked.

2. Go Userspace (cmd/tracker/main.go)

Located at tracker/cmd/tracker/main.go (331 lines):

Startup Sequence:

  1. Set RLIMIT_MEMLOCK (unbounded) for eBPF memory
  2. Load tracepoints.o via libbpf Go wrapper
  3. Attach tracepoints to kernel hooks
  4. Create ring buffer reader (mmap'd interface)
  5. Launch gRPC server on :50051
  6. Begin event broadcast loop

gRPC Server:

  • Implements TrackerServer interface
  • Streams EventBatch to clients
  • Per-client buffered channels (100-event buffer)
  • Graceful client disconnect handling

Event Processing:

// Binary → Go struct
binary.Read(buffer, binary.LittleEndian, &event)

// Monotonic → Wall-clock timestamp
eventTime := bootTime.Add(time.Duration(e.Ts) * time.Nanosecond)

// Go struct → Protobuf
pbEvent := &pb.Event{Ts, Pid, Tid, Comm, Syscall, Path, ...}

3. Protocol Buffers (proto/trace.proto)

Defines the gRPC contract:

message Event {
  google.protobuf.Timestamp ts = 1;    // Wall-clock time
  uint32 pid = 2;                      // Process ID
  uint32 tid = 3;                      // Thread ID
  string comm = 4;                     // Executable name
  string syscall = 5;                  // "openat" | "write" | "rename"
  string path = 6;                     // File path
  string new_path = 7;                 // Destination (rename only)
  int64 ret_val = 8;                   // Return value (fd or error)
  uint64 bytes = 9;                    // Bytes written
  OpenFlags flags = 10;                // File open flags
}

message EventBatch {
  repeated Event events = 1;           // Batch of 1+ events
}

service Tracker {
  rpc StreamEvents(Empty) returns (stream EventBatch);
}

Performance Characteristics

Benchmark Results (M1 Milestone)

Environment: 4-core cloud VM, 8 GB RAM, Ubuntu 22.04

MetricResultTargetStatus
Peak throughput1,250 evt/s≥1k evt/s
P99 latency240 µs<1 ms
CPU overhead3.8%<5%
Memory footprint12 MB<50 MB
Sustained (10 min)1,100 evt/s≥1k evt/s

Scalability Notes

  • Ring buffer capacity (256 KB) handles ~50 ms of events at 1k evt/sec
  • Userspace loop processes events in batches (adaptive)
  • Per-client buffering (100 events) prevents gRPC backpressure
  • Slow client handling via non-blocking channel send (drop overflow)

Deployment Options

1. Local Development (Host eBPF)

# Build tracker binary
cd tracker
make tracker

# Run with root
sudo ./bin/tracker

# Query events (in another terminal)
grpcurl -plaintext -d '{}' localhost:50051 nerrf.trace.Tracker/StreamEvents

Requirements: Linux kernel 4.18+, root/CAP_SYS_ADMIN, libbpf

2. Container (Privileged)

# Build image
docker build -f tracker/Dockerfile.minimal -t nerrf/tracker:m1 .

# Run with host network & privileged (required for eBPF)
docker run --privileged --network host nerrf/tracker:m1

3. Kubernetes (DaemonSet)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: tracker
spec:
  template:
    spec:
      hostNetwork: true
      privileged: true
      containers:
        - name: tracker
          image: nerrf/tracker:m1
          env:
            - name: TRACKER_LISTEN_ADDR
              value: "0.0.0.0:50051"  # Listen on all interfaces

Considerations:

  • One pod per node (DaemonSet)
  • Host network & privileged mode (eBPF requirement)
  • Service discovery for AI components

Development Roadmap

M2 & Beyond

  • kprobe-based FD resolution: Current write() syscall lacks path info; kprobes can resolve fd → inode → path
  • Context aggregation: Thread-local storage for multi-syscall events (e.g., open → write → close)
  • Histograms & metrics: Prometheus integration for latency/throughput dashboards
  • Filtering: User-space filter programs to reduce event volume pre-gRPC
  • Compression: gRPC message compression for bandwidth optimization

Troubleshooting

"BPF object not found"

  • Ensure make completed: ls tracker/bpf/tracepoints.o
  • Check executable path detection logic

"Permission denied (eBPF attach)"

  • Must run as root: sudo ./bin/tracker
  • Or grant CAP_SYS_ADMIN: setcap cap_sys_admin=ep ./bin/tracker

"ringbuf read error: resource temporarily unavailable"

  • Normal when no events occur; logs retry automatically

gRPC connection refused

  • Check listener: ss -tlnp | grep 50051
  • Verify address env var: echo $TRACKER_LISTEN_ADDR

Next Steps