Skip to content

Commit 10db79b

Browse files
committed
Split detection from transport behind a Backend trait
Wraith's detection model — provenance, W^X, stack-integrity, and the exploitation-chain correlator — was interleaved with the ptrace reap loop in tracer.rs, so the eBPF backend the README already names as the near-zero-overhead production path had nowhere to attach. Extract the transport-agnostic detection core into src/engine.rs: - Engine owns the per-address-space cached memory map, the per-process live stats, the Detector, the run Summary, and the enforce-on-CRITICAL policy. It captures a neutral SyscallEntry register snapshot and, in inspect(), refreshes the map, runs detection, and returns the enforcement Action to carry out — without ever issuing a ptrace call. - Backend is the trait a transport implements (drive()). Tracer becomes the first Backend: it keeps only what is ptrace-specific — the waitpid loop, register reads, thread entry/exit phase, and the enforcement *mechanism* (rewriting the syscall number, SIGKILLing the tree). - Summary, ProcStat, and Reporter move to engine.rs and are re-exported from tracer.rs, so wraith::tracer::{...} paths stay source-compatible. Behavior is unchanged: the map dirty/refresh timing, syscall counting on a lost getregs, the CRITICAL-only enforcement gate, and the fatal-fault signal path are all preserved. Full suite (37 unit + 5 bin + 10 integration) passes and clippy is clean; a live run still reports benign as clean and shellcode-sim as an EXPLOITATION CHAIN. An eBPF backend can now implement Backend and reuse the entire Engine, swapping only how a syscall stop is obtained. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FiEuoW9Kpfw6Gv1d3pCXgs
1 parent f26f152 commit 10db79b

4 files changed

Lines changed: 566 additions & 412 deletions

File tree

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ carry the smallest supply chain you can manage. The engine links only `nix` and
237237
├─ syscalls.rs the syscall table Wraith cares about
238238
├─ detect.rs the invariants + the exploitation-chain correlator
239239
├─ event.rs detection events + their JSONL form
240-
├─ tracer.rs the ptrace engine (spawn/attach/scan, thread-following, enforcement)
240+
├─ engine.rs the transport-agnostic detection core (Backend trait, Engine)
241+
├─ tracer.rs the ptrace Backend (spawn/attach/scan, thread-following, enforcement)
241242
├─ ui.rs the live terminal dashboard (--ui), hand-rolled ANSI
242243
└─ bin/
243244
├─ wraith.rs the CLI sensor
@@ -251,6 +252,15 @@ The tracer adds no syscall of its own on the hot path beyond the unavoidable
251252
`getregs`, and re-reads `/proc/<pid>/maps` only when a memory operation could
252253
have changed it.
253254

255+
**Transport-agnostic core.** Detection is split from transport behind a
256+
`Backend` trait. The `ptrace` tracer is the first backend: it captures each
257+
syscall-entry into a neutral register snapshot and hands it to the shared
258+
`Engine`, which owns the cached memory map, the per-process stats, the detector,
259+
and the enforce-on-CRITICAL policy — and never issues a `ptrace` call itself.
260+
The same `Engine` drives any transport unchanged, so the planned eBPF backend
261+
(below) reuses the entire detection model and only swaps how a syscall stop is
262+
obtained.
263+
254264
**Thread-following.** Real targets — network daemons, request handlers, fuzz
255265
harnesses — are multithreaded, and an exploit can fire from any thread. Wraith
256266
follows every `clone`/`fork`/`vfork` the target makes and inspects syscalls
@@ -270,7 +280,11 @@ claim to be a finished EDR.
270280
(network daemons, parsers, fuzz targets), not the whole system. The
271281
production path is the same logic on **eBPF** (`tracepoint/raw_syscalls` +
272282
a page-provenance map) for near-zero overhead — the detection model is
273-
transport-agnostic by design.
283+
transport-agnostic by design, and now lives behind a `Backend` trait
284+
(`src/engine.rs`) so that eBPF backend slots in beside the `ptrace` one
285+
without touching detection. (eBPF observes rather than stops, so it would be
286+
the low-overhead *observe* backend; `ptrace` stays for lossless capture and
287+
`--block`/`--kill`, which need the tracee held at syscall entry.)
274288
- **Attach vs. pre-existing threads.** `wraith run` and `wraith attach` follow
275289
every thread and child the target spawns *after* tracing begins (via
276290
`PTRACE_O_TRACECLONE`/`FORK`/`VFORK`). When attaching to an already-running

0 commit comments

Comments
 (0)