// ============================================================================ // WARLOCK'S STAVE: Linux eBPF Kernel Tracing Engine // ============================================================================ // // Provides kernel-level event tracing via eBPF kprobe programs. // Requires: aya 0.11.0, clang for eBPF bytecode compilation, // and elevated permissions (CAP_BPF or root). #[cfg(target_os = "linux")] use aya::{Bpf, programs::KProbe, maps::perf::AsyncPerfEventArray}; #[cfg(target_os = "linux")] use bytes::BytesMut; /// Kernel-level event structure populated by eBPF probe programs. #[repr(C)] #[derive(Clone, Copy, Debug)] pub struct KernelTraceEvent { pub pid: u32, pub vlan_id: u16, pub network_namespace: u32, } pub struct LinuxEbpfEngine; impl LinuxEbpfEngine { /// Spawns eBPF kprobe on sys_enter_connect to intercept outbound /// network connections. Requires a pre-compiled eBPF object at /// `ebpf_bin/stave_probe.o` (built by `build.sh`). #[cfg(target_os = "linux")] pub fn spawn_kernel_hooks() -> Result<(), Box> { let mut bpf = Bpf::load(include_bytes!("../../ebpf_bin/stave_probe.o"))?; let program: &mut KProbe = bpf.program_mut("sys_enter_connect").unwrap().try_into()?; program.load()?; program.attach("sys_connect", 0)?; let mut perf_array = AsyncPerfEventArray::try_from(bpf.map_mut("STAVE_EVENTS").unwrap())?; std::thread::spawn(move || { let runtime = tokio::runtime::Runtime::new().unwrap(); runtime.block_on(async { let mut buffers = vec![BytesMut::with_capacity(1024); 4]; loop { if let Ok(events) = perf_array.read_events(&mut buffers).await { for i in 0..events.read { let event = unsafe { *(buffers[i].as_ptr() as *const KernelTraceEvent) }; println!( "[KERNEL ALERT] Intercepted Outbound Connect! \ PID: {} | NS: {}", event.pid, event.network_namespace ); } } } }); }); Ok(()) } /// No-op on non-Linux platforms. #[cfg(not(target_os = "linux"))] pub fn spawn_kernel_hooks() -> Result<(), Box> { Ok(()) } }