facebookexperimental/reverie/syscall-interception
Claude Code and agent skill by facebookexperimental/reverie
- community
Checking that the SKILL.md file is still in the repository.
How a Reverie tool observes and rewrites guest syscalls — declaring subscriptions, the handle_syscall_event hook, inject vs. tail_inject, typed syscalls via reverie-syscalls, reading/writing guest memory, and the per-backend trap mechanisms (ptrace seccomp, DBT, KVM hypercalls). Read when writing or debugging syscall handlers.
Install
npx vskill@latest install facebookexperimental/reverie/syscall-interceptionSKILL.md
Syscall Interception
This is the day-to-day work of a Reverie tool: decide which syscalls to trap, inspect/modify their arguments, and let them proceed, replace them, or inject new ones. Start from the reverie-architecture skill for the big picture; this skill is the how-to for the Tool/Guest syscall path.
1. Declare what you trap: subscriptions
Tool::subscriptions(cfg) -> Subscription (reverie/src/tool.rs:153, reverie/src/subscription.rs) is where you opt into events. Only subscribed syscalls stop in your tool; everything else runs untrapped. This is the ptrace performance model — an unsubscribed syscall costs nothing, an observed one pays the ptrace-stop tax — so subscribe to the smallest set you need.
Subscription::all()— trap every syscall (what a strace-like or Detcore-like
tool wants).
Subscription::none()then add specificSysnos — for sparse tools.- Also gate CPU events (cpuid/rdtsc), signals, and timers here.
2. The main hook: handle_syscall_event
async fn handle_syscall_event<T: Guest<Self>>(&self, guest: &mut T, syscall: Syscall) -> Result<i64, Errno> (reverie/src/tool.rs:234). You are called before the guest's syscall executes and you own the result. Typical shapes:
inject vs. tail_inject (reverie/src/guest.rs:131 / :175):
guest.inject(s).await? -> i64runssand returns to your handler, so
you can post-process the result (edit returned buffers, record it, chain more syscalls). inject_with_retry handles EINTR-style restarts.
guest.tail_inject(s).await -> Neverrunssas the guest's final action
for this event and resumes the guest — control never comes back. It's the low-overhead default when you don't need the result.
- Footgun:
tail_inject(exit)/tail_inject(exit_group)never returns, so a
tool that must record anything at process/thread exit must do it before the tail_inject (the KVM tools codify "record Exit before tail_inject").
3. Typed syscalls & guest memory (reverie-syscalls)
Handlers receive a decoded Syscall (the #[non_exhaustive] enum Syscall from `reverie-syscalls`, generated by the syscall_list! macro) rather than raw registers. Each variant is a typed struct (generated by typed_syscall!) implementing SyscallInfo (reverie-syscalls/src/syscalls/mod.rs: NAME, NUMBER: Sysno, into_parts() -> (Sysno, SyscallArgs)), with typed getters and with_* setters. Pointer arguments are guest addresses — dereference them through the guest's memory interface, never the host's:
guest.memory()(reverie/src/guest.rs:73) returns aMemoryAccess
(reverie-memory). Its two primitives are read_vectored/write_vectored; the provided helpers you'll actually call are read/write/read_exact/ write_exact/read_value/write_value/read_cstring/reader/writer (e.g. read a pathname a syscall points at, or write a virtualized struct back into a guest buffer after inject). Addressing types: Addr<T>, AddrMut<T>, AddrSlice, LocalMemory (the in-process impl DBT uses).
guest.regs()/guest.set_regs()(:82/:98) for raw register access when
you need it (e.g. rewriting a syscall number/args before injection).
- To edit a syscall's arguments, construct a modified typed syscall with a
with_* builder and inject that — e.g. chaos does Syscall::Read(read.with_len(1.min(read.len()))).
- To print a syscall, use
Displayable:syscall.display(&mem)or
syscall.display_with_outputs(&mem) (what strace/chrome_trace use). Ordering trap: for execve/execveat, format before injecting — a successful exec wipes the old image and its argument memory.
4. Other trapped events
Same handle_* family on Tool (reverie/src/tool.rs): handle_cpuid_event (:250) and handle_rdtsc_event (:267) virtualize CPU identity/timestamps; handle_signal_event (:280) sees signal delivery; handle_timer_event (:289) fires from guest.set_timer[_precise] (reverie/src/guest.rs:215), driven by the RCB logical clock (read_clock, :228). Subscribe to each in subscriptions or the backend won't trap it.
5. Per-backend trap mechanism
The handler code is backend-agnostic, but how the syscall is trapped differs (see the benchmark memory for the cost model):
| Backend | Trap mechanism | Cost profile | |
|---|---|---|---|
ptrace (reverie-ptrace) | seccomp-BPF filter raises PTRACE_EVENT_SECCOMP only for subscribed syscalls; supervisor handles it in a ptrace stop | ~0 for unsubscribed; ~26–40 µs per observed syscall | |
DBT (reverie-dbt) | DynamoRIO rewrites the guest's code stream; a clean-call thunk lands in the tool .so on every syscall | flat ~2 µs every syscall (no free fast path) | |
KVM (reverie-kvm) | guest runs in a VM; syscalls surface as VM exits / hypercalls routed to the tool | VM-exit bounded | |
e9patch / liteinst (reverie-preload) | in-process instruction rewriting + an LD_PRELOAD + seccomp/SIGSYS runtime that redirects syscalls in-process | in-process, no supervisor round-trip |
Practical consequences you will hit:
- The KVM/DBT executor must enumerate the syscalls it services; an
un-enumerated syscall falls through to a default ENOSYS arm. Adding support means adding both the classification and the executor arm (this is the recurring "KVM ratchet" and "determinize family" work in the memory index).
- Out-of-process backends run
GlobalStatein a separate coordinator over
reverie-rpc-transport; send_rpc from a handler crosses a UDS, so keep RPC payloads bincode-serializable and coarse.
6. Reference tools to copy from
In reverie-examples (build/run instructions in the testing-tools skill):
- `strace` / `strace_minimal` — subscribe-all + decode + print; the canonical
"observe every syscall" tool.
- `counter1` / `counter2` — subscribe to a syscall, count it, aggregate into
GlobalState (in-process vs. UDS coordinator).
- `noop` — the minimal
Toolskeleton; start here for a new tool. - `chaos` — injects scheduling perturbation; shows signal/timer handling.
Post-facto human-review criteria
Apply post-facto-human-review exactly when a PR contains at least one of these four triggers:
- new syscall support, after verifying
AUTONOMOUS-BOT-IMPLEMENTEDat the
new dispatch/classification entry and TODO-HUMAN-REVIEW(PR-id) at the implementation or determinization block;
- a Reverie API/core-abstraction change to the
Tool,Guest,Backend,
or syscall-interception model;
- a new determinization strategy; or
- a core DetCore scheduling change affecting how programs are scheduled,
especially race search. Trigger 4 is always labeled.
Routine backend parity toward the golden ptrace reference implementation is not a trigger merely because it changes a non-ptrace backend. It is labeled only if it also meets one of the four triggers.
Every PR description starts with Plain Language Summary and Project Impact, stating the substantive outcome and its connection to the product vision or owner request. It also requires mandatory Determinism (why the change is deterministic plus its logic or informal proof), and Validation. KVM PRs also require Relationship to gVisor. A labeled PR additionally requires Human Review Required, naming the specific numbered trigger rather than vague prose such as "backend change". The syscall tags above verify trigger 1; they are not blanket backend-change markers. Hermit PR #1151, which moved slowdown into virtual-time/epoch scheduling, is the canonical good example for trigger 4.
Related skills
reverie-architecture— the Tool/Guest/Backend contracts these hooks live on.adding-a-backend— implementing the trap mechanism for a new backend.testing-tools— how to build and run the example tools above.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryChecking.skill_reset_20260816/skills/syscall-interception/SKILL.md
Popularity
- 7-day trend score
- 5
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/facebookexperimental/reverie/syscall-interception)