Talus β Architecture
Internal architecture of Talus: the kernel-side eBPF programs, the userspace event pipeline, the sliding-window alerting heuristic,
Talus β Architecture
Internal architecture of Talus: the kernel-side eBPF programs, the userspace event pipeline, the sliding-window alerting heuristic, and the output layer.
1. System overview
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β KERNEL SPACE β
β syscall entry eBPF tracepoint programs map β
β βββββββββββββ ββββββββββββββββββββββββββββββββββββ ββββββββββββββββ β
β β execve ββββΊβ process-monitor-ebpf ββββΊβ EVENTS β β
β β openat β β #[tracepoint] sys_enter_execve β β PerfEventArrayβ β
β βββββββββββββ β #[tracepoint] sys_enter_openat β ββββββββ¬ββββββββ β
β ββββββββββββββββββββββββββββββββββββ β per-CPU β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌββββββββββββ
β USERSPACE β
β reader thread βββΊ MPSC channel βββΊ Monitor (sliding window + alerting) β
β β β
β TUI β JSON β Plain β Diagnose β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββTwo crates form the workspace:
| Crate | Role | Toolchain |
|---|---|---|
process-monitor-ebpf | Kernel-side tracepoint programs, #![no_std], aya-ebpf | Rust nightly (-Z build-std) |
process-monitor | Userspace: loader, reader thread, monitor core, output modes | Rust stable |
2. Kernel side β process-monitor-ebpf
Both programs run in tracepoint context on syscall entry, before the kernel
copies arguments, so all userspace pointers are read with bpf_probe_read_user
β never dereferenced. This keeps the code verifier-safe.
The kernel and userspace agree on a fixed #[repr(C)] layout so records are
memcpy'd across the perf buffer without serialization:
pub struct ProcessEvent {
pub event_type: u8, // 0 = EXEC, 1 = OPEN
pub pid: u32,
pub uid: u32,
pub comm: [u8; 16], // process comm (truncated)
pub filename: [u8; 64], // target path (truncated)
}An 85-byte payload that occupies 92 bytes on the wire β small and fixed-size, which makes per-CPU perf buffering cheap (no allocation, no variable-length encoding in kernel context).
3. Userspace β process-monitor
Startup sequence (Monitor::start)
- Privilege check β bails unless
geteuid() == 0. - Object load β
aya::Ebpf::load_fileparses the compiled eBPF object. - Program load + attach β each
TracePointprogram attaches tosyscalls/sys_enter_execve/sys_enter_openat. - Map hand-off β the
EVENTSPerfEventArraymoves into the reader thread. - Channel β MPSC connects reader thread β monitor.
Reader thread (talus-reader)
- Enumerates online CPUs, opens one
PerfEventArrayBufferper CPU. - Decodes batches into pre-allocated
BytesMutpools (zero per-event allocation in the hot loop). - Counts
events.lost(perf-buffer overruns) and forwardsMsg::Lost. - Idles 1 ms when no buffer has data β ~1 ms latency, near-zero idle CPU.
Monitor core
stats: HashMap<u32, ProcStats> // pid β cumulative stats
windows: HashMap<u32, VecDeque<Instant>> // pid β open timestamps (1 s window)handle_event records stats, pushes Open timestamps onto the PID's sliding
window, evicts entries older than 1 s, and emits an Alert exactly when the
window crosses the configured threshold (--alert-threshold, 0 disables).
Output layer
Monitor::poll returns a Vec<Output> per tick (Event | Alert) routed by
mode: TUI (frankentui: 7-panel cyberpunk interface β events, process tree,
network, top files, extensions, alerts, heatmap) Β· JSON (NDJSON) Β· Plain
Β· Diagnose (verifies tracepoint IDs under /sys/kernel/tracing/events,
loads + attaches, listens 5 s, prints counters).
4. Data flow summary
kernel userspace reader monitor core output
ββββββββββ βββββββββββββββββ βββββββββββββ ββββββ
openat entry βββΊ EVENTS map βββΊ perf buffer βββΊ Msg::Event βββΊ sliding window βββΊ TUI / JSON / plain
(per CPU) β β
ββ Msg::Lost βββββΊ lost counter βββΊ status bar
ββ Alert (threshold) βββΊ alerts panel5. Performance characteristics
| Aspect | Design |
|---|---|
| Kernel overhead | Two tracepoint programs; fixed-size record; no allocation |
| Userspace decode | Pre-allocated BytesMut pools; zero per-event allocation |
| Latency | Events typically visible in < 1 ms |
| Idle CPU | Reader sleeps 1 ms when no buffers have data |
| Memory | Sliding window evicts every poll; maps bounded by live PIDs |
| Binary | Full LTO + strip = "symbols" + panic = "abort" release profile |
6. Licensing subsystem
The commercial licensing layer spans four components (full details in the
repo's ARCHITECTURE.md
Β§8 and SECURITY.md):
talus-keygen issue βββΊ signed key (Ed25519) βββΊ customer
β
talus license activate <KEY>
βΌ
Cloudflare Worker + D1 (free tier) ββ signature check,
expiry, revocation, seat limits βββΊ activation token| Component | Trust anchor |
|---|---|
talus-keygen (owner machine) | Private key at ~/.secrets/talus/license-keys/ β never inside any repository |
Talus binary (license.rs) | Embedded Ed25519 public key; compile-time XOR checksum detects binary tampering |
Activation server (license-server/) | Public key only; signature, expiry, revocation and seat checks in D1; rate limiting 5/5min per machine |
| Local cache | XOR-obfuscated (0600), re-verified against the signed key on every load β local edits to tier/expiry/features fail closed |
Documented limit: an attacker who fully controls the binary can patch out license checks β signed keys protect the vendor's distribution channel, not a modified client (see the repo SECURITY.md for the full trust model and the key-rotation runbook).