This issue ships the first executable agent: a Linux binary that observes process launches with eBPF and emits OCSF-shaped
process_activityJSON. Fixture replay covers CI and non-Linux hosts. Live kernel attach belongs on a Linux Reader VM.
eBPF programs run in the kernel under a verifier. They attach to hooks and move small records to userspace through maps. For process creation telemetry, two attachment styles appear in tutorials:
HookStabilityWhat you getsched_process_exec (tracepoint)Stable ABI across kernels that expose the eventFired after a successful exec; filename and task identity are available without reconstructing execve argv from user pagesexecve / execveat (kprobe)Fragile across kernel buildsEarly argv access at the cost of page-fault handling and symbol churn
This course prefers sched_process_exec for production-shaped exec telemetry. Use an execve kprobe only as a teaching contrast: argv capture looks attractive until page faults and symbol drift show up in the field.
Ring buffers (
BPF_MAP_TYPE_RINGBUF) replace older perf-event arrays for high-frequency events: one shared queue, reserve/submit in the program, poll in userspace. Aya (Rust) loads the bytecode, attaches the tracepoint, and reads the map. Check current Aya crate versions on crates.io at build time; this issue was verified against aya 0.14.x / aya-ebpf 0.2.x (July 2026).
Operating systems reuse PIDs. Lineage keyed only on pid collapses under wraparound and long-lived hosts. Issue 01 reserved process.uid; this agent populates it as {boot_id}:{pid}:{start_time_ns} (string). Parent events carry parent_process.uid with the same scheme. Tree reconstruction in userspace indexes by process.uid, not pid alone.
Classification fields stay top-level on each event:
class_uid1007,activity_id1 (Launch),type_uid100701,severity_id1.actor.processis the launching parent. Emptyprocess.uidwhile claiming OCSF alignment breaks Module 7 fixtures and Module 9 joins later.
An unfiltered exec stream includes the agent binary, shells spawning helpers, and package managers. Lab 3 adds a denylist of basenames and self-pid suppression. This is the first contact with alert fatigue: volume without selection is not detection.
Prevention products that deny exec use eBPF LSM hooks (
bpf_lsm), not observation-only tracepoints. This issue wires a log-only LSM stub behind a compile-time feature. Enforce mode needsCONFIG_BPF_LSMandbpfon the active LSM list (often a GRUB change and reboot on Ubuntu). Do not treat “flip a toggle” as a one-liner; Module 10 depth labs revisit enforce.
The Linux agent is layer 1 of the data plane. Events leave as JSON lines shaped for later protobuf/gRPC ingest. Ingestion, storage, and detection are still stubs.
linux-agentstreams OCSF-shaped process-creation events (stdout JSON). Completion criteria:
cargo test -p linux-agentpasses on any host (fixture-replay path).On a Linux Reader VM with privileges,
--mode liveattaches tosched_process_execand prints Launch events with non-emptyprocess.uidandtype_uid100701.You can explain why the agent uses
sched_process_execinstead of anexecvekprobe for the default path.
Workspace layout under
agent-linux/:
linux-agent-common— sharedExecEventwire struct (#[repr(C)]) for eBPF and userspacelinux-agent-ebpf— tracepoint program + optional LSM stub (Linux bpf target)linux-agent— loader, OCSF encoder, filter, tree,--mode replay|live
Replay mode reads
fixtures/exec-events.jsonland runs the same encoder/filter/tree path as live mode. Sandbox and macOS hosts use replay; live attach is the Reader VM column.Encoder helpers (verbatim from
agent-linux/linux-agent/src/ocsf.rs):
Full files and build commands:
docs/implementation-guides/02-linux-agent-ebpf.md.Limitation:
sched_process_execdoes not deliver a complete argv vector the way a carefully writtenexecvekprobe might. Command lines in this issue come from/proc/<pid>/cmdlinein userspace when the process still exists, with a short race window for short-lived binaries. Module 6 revisits richer capture if needed.
Run
linux-agent --mode replayand confirm stdout JSON includestype_uid100701 and non-emptyprocess.uid.Use
--print-treeon the fixture stream and verify parent–child edges key onprocess.uid.Add a basename to the noise denylist; confirm matching fixture lines are dropped while others remain.
On a Linux VM, build with
--features lsm-stub, confirm the stub loads (or fails with a clear LSM-list message), and leave enforce off.
Issue 03 builds the Windows peer with ETW. Command lines do not come from
Microsoft-Windows-Kernel-Processalone — plan for the NT Kernel Logger / system logger path before mirroring this OCSF shape on Windows.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.