Skip to content

Commit 7a1c685

Browse files
authored
Drop syscall enter event parsing (#55)
* turn this one down too * ensure we propagate tid * Fix parsers to only handle exit events * Remove threadstate bits we no longer need * fmt * cleanup
1 parent 7683dfa commit 7a1c685

4 files changed

Lines changed: 138 additions & 526 deletions

File tree

src/base_plugin/mod.rs

Lines changed: 37 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -156,85 +156,32 @@ impl EderaPlugin {
156156
self.with_zone_syscall_evt_ctx(&mut req, |zone_evt| Ok(zone_evt.cpuid as u64))
157157
}
158158

159-
pub fn extract_latency(&mut self, mut req: ExtractRequest<Self>) -> Result<u64> {
160-
let ctx = self.get_or_cache_evt_ctx(&mut req);
161-
162-
let enter_ts = self
163-
.threadstate
164-
.with_zoneinfo(&ctx.decoded_evt.zone_id, |zinfo| {
165-
zinfo
166-
.get_enter_event(&ctx.decoded_evt)
167-
.map(|enter_evt| enter_evt.timestamp)
168-
});
169-
let Some(enter_t) = enter_ts else {
170-
return Ok(0);
171-
};
172-
173-
Ok(ctx.decoded_evt.timestamp - enter_t)
159+
// Latency fields are deprecated in Falco 0.43+ because modern_bpf only captures
160+
// exit events. Like libsinsp, we hardcode to 0 to avoid breaking changes.
161+
// See: libs/userspace/libsinsp/sinsp_filtercheck_event.cpp lines 859-867
162+
pub fn extract_latency(&mut self, _req: ExtractRequest<Self>) -> Result<u64> {
163+
Ok(0)
174164
}
175165

176-
pub fn extract_latency_s(&mut self, mut req: ExtractRequest<Self>) -> Result<u64> {
177-
let ctx = self.get_or_cache_evt_ctx(&mut req);
178-
179-
let enter_ts = self
180-
.threadstate
181-
.with_zoneinfo(&ctx.decoded_evt.zone_id, |zinfo| {
182-
zinfo
183-
.get_enter_event(&ctx.decoded_evt)
184-
.map(|enter_evt| enter_evt.timestamp)
185-
});
186-
let Some(enter_t) = enter_ts else {
187-
return Ok(0);
188-
};
189-
190-
Ok(ctx.decoded_evt.timestamp - enter_t / 1_000_000_000)
166+
// Latency fields are deprecated in Falco 0.43+ because modern_bpf only captures
167+
// exit events. Like libsinsp, we hardcode to 0 to avoid breaking changes.
168+
// See: libs/userspace/libsinsp/sinsp_filtercheck_event.cpp lines 859-867
169+
pub fn extract_latency_s(&mut self, _req: ExtractRequest<Self>) -> Result<u64> {
170+
Ok(0)
191171
}
192172

193-
pub fn extract_latency_ns(&mut self, mut req: ExtractRequest<Self>) -> Result<u64> {
194-
let ctx = self.get_or_cache_evt_ctx(&mut req);
195-
196-
let enter_ts = self
197-
.threadstate
198-
.with_zoneinfo(&ctx.decoded_evt.zone_id, |zinfo| {
199-
zinfo
200-
.get_enter_event(&ctx.decoded_evt)
201-
.map(|enter_evt| enter_evt.timestamp)
202-
});
203-
let Some(enter_t) = enter_ts else {
204-
return Ok(0);
205-
};
206-
207-
Ok(ctx.decoded_evt.timestamp - enter_t % 1_000_000_000)
173+
// Latency fields are deprecated in Falco 0.43+ because modern_bpf only captures
174+
// exit events. Like libsinsp, we hardcode to 0 to avoid breaking changes.
175+
// See: libs/userspace/libsinsp/sinsp_filtercheck_event.cpp lines 859-867
176+
pub fn extract_latency_ns(&mut self, _req: ExtractRequest<Self>) -> Result<u64> {
177+
Ok(0)
208178
}
209179

210-
pub fn extract_latency_human(&mut self, mut req: ExtractRequest<Self>) -> Result<CString> {
211-
let ctx = self.get_or_cache_evt_ctx(&mut req);
212-
213-
let enter_ts = self
214-
.threadstate
215-
.with_zoneinfo(&ctx.decoded_evt.zone_id, |zinfo| {
216-
zinfo
217-
.get_enter_event(&ctx.decoded_evt)
218-
.map(|enter_evt| enter_evt.timestamp)
219-
});
220-
221-
let Some(enter_t) = enter_ts else {
222-
return Ok(CString::new("0s")?);
223-
};
224-
225-
let latency_ns = ctx.decoded_evt.timestamp - enter_t;
226-
227-
let formatted = if latency_ns < 1_000 {
228-
format!("{}ns", latency_ns)
229-
} else if latency_ns < 1_000_000 {
230-
format!("{:.1}us", latency_ns as f64 / 1_000.0)
231-
} else if latency_ns < 1_000_000_000 {
232-
format!("{:.1}ms", latency_ns as f64 / 1_000_000.0)
233-
} else {
234-
format!("{:.1}s", latency_ns as f64 / 1_000_000_000.0)
235-
};
236-
237-
Ok(CString::new(formatted)?)
180+
// Latency fields are deprecated in Falco 0.43+ because modern_bpf only captures
181+
// exit events. Like libsinsp, we hardcode to "0ns" to avoid breaking changes.
182+
// See: libs/userspace/libsinsp/sinsp_filtercheck_event.cpp lines 869-874
183+
pub fn extract_latency_human(&mut self, _req: ExtractRequest<Self>) -> Result<CString> {
184+
Ok(CString::new("0ns")?)
238185
}
239186

240187
pub fn extract_args(&mut self, mut req: ExtractRequest<Self>) -> Result<CString> {
@@ -598,9 +545,10 @@ impl EderaPlugin {
598545

599546
let zid = &context.decoded_evt.zone_id;
600547
if matches!(context.fdinfo, Cached::NotFetched) {
601-
context.fdinfo = match self.threadstate.with_zoneinfo(zid, |zinfo| {
602-
zinfo.get_enterexit_event_fdinfo(&context.decoded_evt)
603-
}) {
548+
context.fdinfo = match self
549+
.threadstate
550+
.with_zoneinfo(zid, |zinfo| zinfo.get_event_fdinfo(&context.decoded_evt))
551+
{
604552
Some(t) => Cached::Found(t),
605553
None => Cached::NotFound,
606554
};
@@ -2836,33 +2784,19 @@ impl EderaPlugin {
28362784
}
28372785

28382786
fn get_fs_path_nameraw(&mut self, event: &ZoneKernelSyscallEvent) -> Result<CString> {
2839-
// OPENAT_X is specialcased to get the path from the ENTER event in libsinsp.
2840-
// For all others, it's pulled from the exit event.
2841-
if event.event_type == event_codes::PPME_SYSCALL_OPENAT_X as u32 {
2842-
Ok(self
2843-
.threadstate
2844-
.with_zoneinfo(&event.zone_id, |zinfo| {
2845-
zinfo.get_enter_event(event).and_then(|enter_evt| {
2846-
enter_evt
2847-
.event_params
2848-
.iter()
2849-
.find(|param| param.name == "name")
2850-
.and_then(|param| CString::new(param.param_pretty.clone()).ok())
2851-
})
2852-
})
2853-
.unwrap_or(CString::new("NA").expect("default value must parse")))
2854-
} else {
2855-
Ok(Self::get_paths_from_evt_params(event)
2856-
.into_iter()
2857-
.find_map(|path_type| {
2858-
if let EventPathType::Singular(path) = path_type {
2859-
CString::new(path).ok()
2860-
} else {
2861-
None
2862-
}
2863-
})
2864-
.unwrap_or(CString::new("NA").expect("default value must parse")))
2865-
}
2787+
// With modern_bpf (exit-only events), all paths are in the exit event params.
2788+
// The old libsinsp code that retrieved openat paths from enter events is obsolete.
2789+
// See: libs/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat.bpf.c
2790+
Ok(Self::get_paths_from_evt_params(event)
2791+
.into_iter()
2792+
.find_map(|path_type| {
2793+
if let EventPathType::Singular(path) = path_type {
2794+
CString::new(path).ok()
2795+
} else {
2796+
None
2797+
}
2798+
})
2799+
.unwrap_or(CString::new("NA").expect("default value must parse")))
28662800
}
28672801

28682802
fn get_fs_path_sourceraw(&mut self, event: &ZoneKernelSyscallEvent) -> Result<CString> {

src/parsers.rs

Lines changed: 37 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use crate::proto::generated::protect::control::v1::{
55
use anyhow::{Result, anyhow};
66
use libscap_bindings::consts as ppm_consts;
77
use libscap_bindings::types::{
8-
ppm_event_code as event_codes, ppm_event_flags as event_flags, scap_l4_proto as l4_types,
8+
ppm_event_code as event_codes, ppm_event_flags as event_flags, ppm_param_type as param_type,
9+
scap_l4_proto as l4_types,
910
};
10-
use log::debug;
1111
use std::ffi::CStr;
1212
use std::fs::File;
1313
use std::io::{BufRead, BufReader};
@@ -92,7 +92,16 @@ pub fn is_wait(evt: &ZoneKernelSyscallEvent) -> bool {
9292
}
9393

9494
pub fn has_fd(evt: &ZoneKernelSyscallEvent) -> bool {
95-
(evt.event_flags & (event_flags::EF_USES_FD as u32)) != 0
95+
// Check event_flags first
96+
if (evt.event_flags & (event_flags::EF_USES_FD as u32)) != 0 {
97+
return true;
98+
}
99+
100+
// Fallback: check if any parameter is of type PT_FD
101+
// This handles edge cases where event_flags might still not be populated
102+
evt.event_params
103+
.iter()
104+
.any(|param| param.param_type == param_type::PT_FD as u32)
96105
}
97106

98107
pub fn reads_fd(evt: &ZoneKernelSyscallEvent) -> bool {
@@ -145,12 +154,14 @@ pub fn has_retval(evt: &ZoneKernelSyscallEvent) -> bool {
145154
return false;
146155
}
147156
// The event has a return value if:
148-
// * it is a syscall event.
157+
// * it is a syscall event (or a syscall-like metaevent).
149158
// * it is an exit event.
150159
// * it has at least one parameter. Some exit events are not instrumented, see
151160
// `PPME_SOCKET_GETSOCKNAME_X`
152-
153-
if evt.event_category.contains("SYSCALL") && !is_enter(evt) && !evt.event_params.is_empty() {
161+
if (evt.event_category.contains("SYSCALL") || evt.event_category.contains("EC_METAEVENT"))
162+
&& !is_enter(evt)
163+
&& !evt.event_params.is_empty()
164+
{
154165
return true;
155166
}
156167

@@ -167,38 +178,33 @@ pub fn get_retval(evt: &ZoneKernelSyscallEvent) -> Option<i64> {
167178
}
168179
}
169180

170-
/// If this event is the kind of syscall event (enter types, some others) that encodes an FD,
171-
/// return the FD number (for table lookup, etc).
172-
/// Note that unlike libsinsp's equivalents, this can be passed an enter or exit event,
173-
/// and will suck out the FDI (if present) in either case.
181+
/// Extract FD number from an event.
182+
///
183+
/// Modern BPF driver only captures exit events, so this extracts FD from exit event parameters.
184+
/// It searches for a parameter with type PT_FD and returns its value.
174185
pub fn get_fdi(event: &ZoneKernelSyscallEvent) -> Option<u64> {
175186
use event_codes::*;
187+
188+
if !has_fd(event) {
189+
return None;
190+
}
191+
176192
let etype = event_codes::from_repr(event.event_type)
177193
.ok_or(anyhow!("could not parse event type"))
178194
.expect("should parse");
179195

180-
// most FDs come in the enter event
181-
let maybe_fd_loc: Option<usize> = if is_enter(event) {
182-
if has_fd(event) {
183-
match etype {
184-
PPME_SYSCALL_MMAP_E | PPME_SYSCALL_MMAP2_E => Some(4),
185-
186-
PPME_SYSCALL_SPLICE_E => Some(1),
187-
_ => {
188-
Some(0) // *most* of the time, the 0th param is the fd
189-
}
190-
}
196+
// For exit events (modern_bpf only captures these), search for the FD parameter
197+
// Special case: sendmmsg and recvmmsg have FD at position 1
198+
let maybe_fd_loc: Option<usize> =
199+
if etype == PPME_SOCKET_SENDMMSG_X || etype == PPME_SOCKET_RECVMMSG_X {
200+
Some(1)
191201
} else {
192-
None
193-
}
194-
// sendmmsg and recvmmsg send all data in the EXIT event, fd included.
195-
} else if (etype == PPME_SOCKET_SENDMMSG_X || etype == PPME_SOCKET_RECVMMSG_X)
196-
&& !event.event_params.is_empty()
197-
{
198-
Some(1)
199-
} else {
200-
None
201-
};
202+
// For other exit events, search for the PT_FD parameter
203+
event
204+
.event_params
205+
.iter()
206+
.position(|param| param.param_type == param_type::PT_FD as u32)
207+
};
202208

203209
if let Some(loc) = maybe_fd_loc {
204210
let res = i64::from_ne_bytes(
@@ -247,23 +253,6 @@ pub fn hex_char_to_nibble(c: u8) -> Option<u8> {
247253
}
248254
}
249255

250-
pub fn get_enter_event_fd_loc(event: &ZoneKernelSyscallEvent, etype: event_codes) -> Option<u64> {
251-
use event_codes::*;
252-
if !is_enter(event) || !has_fd(event) {
253-
debug!("not an enter event or has no FD {:?}", event);
254-
return None;
255-
}
256-
257-
match etype {
258-
PPME_SYSCALL_MMAP_E | PPME_SYSCALL_MMAP2_E => Some(4),
259-
PPME_SYSCALL_SPLICE_E => Some(1),
260-
_ => {
261-
// For almost all parameters the default position is `0`
262-
Some(0)
263-
}
264-
}
265-
}
266-
267256
// libscap stores the "list of caps" as a bitmask in the driver,
268257
// and libsinsp munges the bitmask on syscall events.
269258
// This naturally requires that the discriminants/ordering of Linux caps are identical

src/source_plugin/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ impl EderaSourcePluginInstance {
7272
// pull out the timestamp and use it as the scap event's timestamp.
7373
let encoded = evt.encode_length_delimited_to_vec();
7474
let mut wrapped_evt = Self::plugin_event(encoded.as_slice());
75-
// set the wrapped evt TS to the original evt ts
75+
// set the wrapped evt TS and TID to the original evt values
7676
wrapped_evt.metadata.ts = evt.timestamp;
77+
wrapped_evt.metadata.tid = evt.thread_id as i64;
7778
batch.add(wrapped_evt).expect("event should add");
7879
drained_event_count += 1;
7980

0 commit comments

Comments
 (0)