1use crate::maps::{Map, MapKey, MapValueRef, RingBuffer, RingBufferWakeupPolicy};
6use ebpf::{BpfValue, EbpfHelperImpl, EbpfProgramContext, FromBpfValue, HelperSet};
7use inspect_stubs::track_stub;
8use linux_uapi::{
9 bpf_func_id_BPF_FUNC_get_current_pid_tgid, bpf_func_id_BPF_FUNC_get_current_uid_gid,
10 bpf_func_id_BPF_FUNC_get_smp_processor_id, bpf_func_id_BPF_FUNC_get_socket_cookie,
11 bpf_func_id_BPF_FUNC_get_socket_uid, bpf_func_id_BPF_FUNC_ktime_get_boot_ns,
12 bpf_func_id_BPF_FUNC_ktime_get_coarse_ns, bpf_func_id_BPF_FUNC_ktime_get_ns,
13 bpf_func_id_BPF_FUNC_map_delete_elem, bpf_func_id_BPF_FUNC_map_lookup_elem,
14 bpf_func_id_BPF_FUNC_map_update_elem, bpf_func_id_BPF_FUNC_probe_read_str,
15 bpf_func_id_BPF_FUNC_probe_read_user, bpf_func_id_BPF_FUNC_probe_read_user_str,
16 bpf_func_id_BPF_FUNC_ringbuf_discard, bpf_func_id_BPF_FUNC_ringbuf_reserve,
17 bpf_func_id_BPF_FUNC_ringbuf_submit, bpf_func_id_BPF_FUNC_sk_fullsock,
18 bpf_func_id_BPF_FUNC_sk_storage_get, bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
19 bpf_func_id_BPF_FUNC_trace_printk, gid_t, pid_t, uid_t,
20};
21use std::slice;
22
23pub trait MapsContext<'a> {
24 fn on_map_access(&mut self, map: &Map);
25 fn add_value_ref(&mut self, map_ref: MapValueRef<'a>);
26}
27
28pub trait MapsProgramContext: EbpfProgramContext {
29 fn on_map_access(context: &mut Self::RunContext<'_>, map: &Map);
30 fn add_value_ref<'a>(context: &mut Self::RunContext<'a>, map_ref: MapValueRef<'a>);
31}
32
33impl<C: EbpfProgramContext> MapsProgramContext for C
34where
35 for<'a> C::RunContext<'a>: MapsContext<'a>,
36{
37 fn on_map_access(context: &mut Self::RunContext<'_>, map: &Map) {
38 context.on_map_access(map);
39 }
40
41 fn add_value_ref<'a>(context: &mut Self::RunContext<'a>, map_ref: MapValueRef<'a>) {
42 context.add_value_ref(map_ref);
43 }
44}
45
46fn bpf_map_lookup_elem<'a, C: MapsProgramContext>(
47 context: &mut C::RunContext<'a>,
48 map: BpfValue,
49 key: BpfValue,
50 _: BpfValue,
51 _: BpfValue,
52 _: BpfValue,
53) -> BpfValue {
54 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
56 let key =
58 unsafe { std::slice::from_raw_parts(key.as_ptr::<u8>(), map.schema.key_size as usize) };
59
60 C::on_map_access(context, map);
61
62 let Some(value_ref) = map.lookup(key) else {
63 return BpfValue::default();
64 };
65
66 let result: BpfValue = value_ref.ptr().raw_ptr().into();
67
68 if value_ref.is_ref_counted() {
71 C::add_value_ref(context, value_ref);
72 }
73
74 result
75}
76
77fn bpf_map_update_elem<C: MapsProgramContext>(
78 context: &mut C::RunContext<'_>,
79 map: BpfValue,
80 key: BpfValue,
81 value: BpfValue,
82 flags: BpfValue,
83 _: BpfValue,
84) -> BpfValue {
85 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
87 let key =
89 unsafe { std::slice::from_raw_parts(key.as_ptr::<u8>(), map.schema.key_size as usize) };
90 let value =
92 unsafe { std::slice::from_raw_parts(value.as_ptr::<u8>(), map.schema.value_size as usize) };
93 let flags = flags.as_u64();
94
95 let key = MapKey::from_slice(key);
96
97 C::on_map_access(context, map);
98
99 map.update(key, value, flags).map(|_| 0).unwrap_or(u64::MAX).into()
100}
101
102fn bpf_map_delete_elem<C: MapsProgramContext>(
103 context: &mut C::RunContext<'_>,
104 map: BpfValue,
105 key: BpfValue,
106 _: BpfValue,
107 _: BpfValue,
108 _: BpfValue,
109) -> BpfValue {
110 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
112 let key =
114 unsafe { std::slice::from_raw_parts(key.as_ptr::<u8>(), map.schema.key_size as usize) };
115
116 C::on_map_access(context, map);
117
118 map.delete(key).map(|_| 0).unwrap_or(u64::MAX).into()
119}
120
121fn bpf_trace_printk<C: EbpfProgramContext>(
122 _context: &mut C::RunContext<'_>,
123 _fmt: BpfValue,
124 _fmt_size: BpfValue,
125 _: BpfValue,
126 _: BpfValue,
127 _: BpfValue,
128) -> BpfValue {
129 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_trace_printk");
130 0.into()
131}
132
133fn bpf_ktime_get_ns<C: EbpfProgramContext>(
134 _context: &mut C::RunContext<'_>,
135 _: BpfValue,
136 _: BpfValue,
137 _: BpfValue,
138 _: BpfValue,
139 _: BpfValue,
140) -> BpfValue {
141 zx::MonotonicInstant::get().into_nanos().into()
142}
143
144fn bpf_ringbuf_reserve<C: EbpfProgramContext>(
145 _context: &mut C::RunContext<'_>,
146 map: BpfValue,
147 size: BpfValue,
148 flags: BpfValue,
149 _: BpfValue,
150 _: BpfValue,
151) -> BpfValue {
152 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
155 let size = u32::from(size);
156 let flags = u64::from(flags);
157 map.ringbuf_reserve(size, flags).map(BpfValue::from).unwrap_or_else(|_| BpfValue::default())
158}
159
160fn bpf_ringbuf_submit<C: EbpfProgramContext>(
161 _context: &mut C::RunContext<'_>,
162 data: BpfValue,
163 flags: BpfValue,
164 _: BpfValue,
165 _: BpfValue,
166 _: BpfValue,
167) -> BpfValue {
168 let flags = RingBufferWakeupPolicy::from(u32::from(flags));
169
170 unsafe {
173 RingBuffer::submit(u64::from(data), flags);
174 }
175 0.into()
176}
177
178fn bpf_ringbuf_discard<C: EbpfProgramContext>(
179 _context: &mut C::RunContext<'_>,
180 data: BpfValue,
181 flags: BpfValue,
182 _: BpfValue,
183 _: BpfValue,
184 _: BpfValue,
185) -> BpfValue {
186 let flags = RingBufferWakeupPolicy::from(u32::from(flags));
187
188 unsafe {
191 RingBuffer::discard(u64::from(data), flags);
192 }
193 0.into()
194}
195
196fn bpf_ktime_get_boot_ns<C: EbpfProgramContext>(
197 _context: &mut C::RunContext<'_>,
198 _: BpfValue,
199 _: BpfValue,
200 _: BpfValue,
201 _: BpfValue,
202 _: BpfValue,
203) -> BpfValue {
204 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_ktime_get_boot_ns");
205 0.into()
206}
207
208fn bpf_probe_read_user<C: EbpfProgramContext>(
209 _context: &mut C::RunContext<'_>,
210 _: BpfValue,
211 _: BpfValue,
212 _: BpfValue,
213 _: BpfValue,
214 _: BpfValue,
215) -> BpfValue {
216 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_probe_read_user");
217 0.into()
218}
219
220fn bpf_probe_read_user_str<C: EbpfProgramContext>(
221 _context: &mut C::RunContext<'_>,
222 _: BpfValue,
223 _: BpfValue,
224 _: BpfValue,
225 _: BpfValue,
226 _: BpfValue,
227) -> BpfValue {
228 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_probe_read_user_str");
229 0.into()
230}
231
232fn bpf_ktime_get_coarse_ns<C: EbpfProgramContext>(
233 _context: &mut C::RunContext<'_>,
234 _: BpfValue,
235 _: BpfValue,
236 _: BpfValue,
237 _: BpfValue,
238 _: BpfValue,
239) -> BpfValue {
240 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_ktime_get_coarse_ns");
241 0.into()
242}
243
244fn bpf_probe_read_str<C: EbpfProgramContext>(
245 _context: &mut C::RunContext<'_>,
246 _: BpfValue,
247 _: BpfValue,
248 _: BpfValue,
249 _: BpfValue,
250 _: BpfValue,
251) -> BpfValue {
252 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_probe_read_str");
253 0.into()
254}
255
256fn bpf_get_smp_processor_id<C: EbpfProgramContext>(
257 _context: &mut C::RunContext<'_>,
258 _: BpfValue,
259 _: BpfValue,
260 _: BpfValue,
261 _: BpfValue,
262 _: BpfValue,
263) -> BpfValue {
264 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_get_smp_processor_id");
265 0.into()
266}
267
268pub trait CurrentTaskContext {
269 fn get_uid_gid(&self) -> (uid_t, gid_t);
270 fn get_tid_tgid(&self) -> (pid_t, pid_t);
271}
272
273pub trait CurrentTaskProgramContext: EbpfProgramContext {
274 fn get_uid_gid<'a>(context: &mut Self::RunContext<'a>) -> (uid_t, gid_t);
275 fn get_tid_tgid<'a>(context: &mut Self::RunContext<'a>) -> (pid_t, pid_t);
276}
277
278impl<C: EbpfProgramContext> CurrentTaskProgramContext for C
279where
280 for<'a> C::RunContext<'a>: CurrentTaskContext,
281{
282 fn get_uid_gid<'a>(context: &mut Self::RunContext<'a>) -> (uid_t, gid_t) {
283 context.get_uid_gid()
284 }
285 fn get_tid_tgid<'a>(context: &mut Self::RunContext<'a>) -> (pid_t, pid_t) {
286 context.get_tid_tgid()
287 }
288}
289
290fn bpf_get_current_uid_gid<C: CurrentTaskProgramContext>(
291 context: &mut C::RunContext<'_>,
292 _: BpfValue,
293 _: BpfValue,
294 _: BpfValue,
295 _: BpfValue,
296 _: BpfValue,
297) -> BpfValue {
298 let (uid, gid) = C::get_uid_gid(context);
299 (uid as u64 + (gid as u64) << 32).into()
300}
301
302fn bpf_get_current_pid_tgid<C: CurrentTaskProgramContext>(
303 context: &mut C::RunContext<'_>,
304 _: BpfValue,
305 _: BpfValue,
306 _: BpfValue,
307 _: BpfValue,
308 _: BpfValue,
309) -> BpfValue {
310 let (pid, tgid) = C::get_tid_tgid(context);
311 (pid as u64 + (tgid as u64) << 32).into()
312}
313
314pub trait SocketCookieContext<A> {
315 fn get_socket_cookie(&self, arg: A) -> u64;
316}
317
318pub trait SocketCookieProgramContext: EbpfProgramContext {
319 fn get_socket_cookie<'a>(context: &mut Self::RunContext<'a>, arg: BpfValue) -> u64;
320}
321
322impl<C: EbpfProgramContext> SocketCookieProgramContext for C
323where
324 for<'b, 'c> C::RunContext<'b>: SocketCookieContext<C::Arg1<'c>>,
325 for<'b> C::Arg1<'b>: FromBpfValue<C::RunContext<'b>>,
326{
327 fn get_socket_cookie<'a>(context: &mut Self::RunContext<'a>, arg: BpfValue) -> u64 {
328 let arg = unsafe { C::Arg1::from_bpf_value(context, arg) };
331 context.get_socket_cookie(arg)
332 }
333}
334
335fn bpf_get_socket_cookie<'a, C: SocketCookieProgramContext>(
336 context: &mut C::RunContext<'a>,
337 arg: BpfValue,
338 _: BpfValue,
339 _: BpfValue,
340 _: BpfValue,
341 _: BpfValue,
342) -> BpfValue {
343 C::get_socket_cookie(context, arg).into()
344}
345
346#[derive(Copy, Clone, Debug, PartialEq, Eq)]
347pub enum LoadBytesBase {
348 MacHeader,
349 NetworkHeader,
350}
351
352pub trait SocketUidContext<B> {
354 fn get_socket_uid(&self, sk_buf: B) -> Option<uid_t>;
355}
356
357pub trait SocketUidProgramContext: EbpfProgramContext {
359 fn get_socket_uid<'a>(context: &mut Self::RunContext<'a>, sk_buf: BpfValue) -> Option<uid_t>;
360}
361
362impl<C: EbpfProgramContext> SocketUidProgramContext for C
363where
364 for<'b, 'c> C::RunContext<'b>: SocketUidContext<C::Arg1<'c>>,
365 for<'b> C::Arg1<'b>: FromBpfValue<C::RunContext<'b>>,
366{
367 fn get_socket_uid<'a>(context: &mut Self::RunContext<'a>, sk_buf: BpfValue) -> Option<uid_t> {
368 let sk_buf = unsafe { C::Arg1::from_bpf_value(context, sk_buf) };
371 context.get_socket_uid(sk_buf)
372 }
373}
374
375fn bpf_get_socket_uid<'a, C: SocketUidProgramContext>(
376 context: &mut C::RunContext<'a>,
377 sk_buf: BpfValue,
378 _: BpfValue,
379 _: BpfValue,
380 _: BpfValue,
381 _: BpfValue,
382) -> BpfValue {
383 const OVERFLOW_UID: uid_t = 65534;
384 C::get_socket_uid(context, sk_buf).unwrap_or(OVERFLOW_UID).into()
385}
386
387pub trait PacketWithLoadBytes {
389 fn load_bytes_relative(&self, base: LoadBytesBase, offset: usize, buf: &mut [u8]) -> i64;
390}
391
392pub trait SkbLoadBytesProgramContext: EbpfProgramContext {
394 fn skb_load_bytes_relative<'a>(
395 context: &mut Self::RunContext<'a>,
396 sk_buf: BpfValue,
397 base: LoadBytesBase,
398 offset: usize,
399 buf: &mut [u8],
400 ) -> i64;
401}
402
403impl<C: EbpfProgramContext> SkbLoadBytesProgramContext for C
404where
405 for<'b> C::Arg1<'b>: FromBpfValue<C::RunContext<'b>>,
406 for<'b> C::Arg1<'b>: PacketWithLoadBytes,
407{
408 fn skb_load_bytes_relative<'a>(
409 context: &mut Self::RunContext<'a>,
410 sk_buf: BpfValue,
411 base: LoadBytesBase,
412 offset: usize,
413 buf: &mut [u8],
414 ) -> i64 {
415 let sk_buf = unsafe { C::Arg1::from_bpf_value(context, sk_buf) };
418 sk_buf.load_bytes_relative(base, offset, buf)
419 }
420}
421
422fn bpf_skb_load_bytes_relative<'a, C: SkbLoadBytesProgramContext>(
423 context: &mut C::RunContext<'a>,
424 sk_buf: BpfValue,
425 offset: BpfValue,
426 to: BpfValue,
427 len: BpfValue,
428 start_header: BpfValue,
429) -> BpfValue {
430 let base = match start_header.as_u32() {
431 0 => LoadBytesBase::MacHeader,
432 1 => LoadBytesBase::NetworkHeader,
433 _ => return u64::MAX.into(),
434 };
435
436 let Ok(offset) = offset.as_u64().try_into() else {
437 return u64::MAX.into();
438 };
439
440 let buf = unsafe { slice::from_raw_parts_mut(to.as_ptr::<u8>(), len.as_u64() as usize) };
443
444 C::skb_load_bytes_relative(context, sk_buf, base, offset, buf).into()
445}
446
447fn bpf_sk_storage_get<C: EbpfProgramContext>(
448 _context: &mut C::RunContext<'_>,
449 _: BpfValue,
450 _: BpfValue,
451 _: BpfValue,
452 _: BpfValue,
453 _: BpfValue,
454) -> BpfValue {
455 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_sk_storage_get");
456 0.into()
457}
458
459fn bpf_sk_fullsock<C: EbpfProgramContext>(
460 _context: &mut C::RunContext<'_>,
461 _: BpfValue,
462 _: BpfValue,
463 _: BpfValue,
464 _: BpfValue,
465 _: BpfValue,
466) -> BpfValue {
467 track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_sk_fullsock");
468 0.into()
469}
470
471fn get_common_helpers<C: MapsProgramContext>() -> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
472 [
473 (bpf_func_id_BPF_FUNC_ktime_get_boot_ns, EbpfHelperImpl(bpf_ktime_get_boot_ns)),
474 (bpf_func_id_BPF_FUNC_ktime_get_coarse_ns, EbpfHelperImpl(bpf_ktime_get_coarse_ns)),
475 (bpf_func_id_BPF_FUNC_ktime_get_ns, EbpfHelperImpl(bpf_ktime_get_ns)),
476 (bpf_func_id_BPF_FUNC_map_delete_elem, EbpfHelperImpl(bpf_map_delete_elem)),
477 (bpf_func_id_BPF_FUNC_map_lookup_elem, EbpfHelperImpl(bpf_map_lookup_elem)),
478 (bpf_func_id_BPF_FUNC_map_update_elem, EbpfHelperImpl(bpf_map_update_elem)),
479 (bpf_func_id_BPF_FUNC_probe_read_str, EbpfHelperImpl(bpf_probe_read_str)),
480 (bpf_func_id_BPF_FUNC_probe_read_user, EbpfHelperImpl(bpf_probe_read_user)),
481 (bpf_func_id_BPF_FUNC_probe_read_user_str, EbpfHelperImpl(bpf_probe_read_user_str)),
482 (bpf_func_id_BPF_FUNC_ringbuf_discard, EbpfHelperImpl(bpf_ringbuf_discard)),
483 (bpf_func_id_BPF_FUNC_ringbuf_reserve, EbpfHelperImpl(bpf_ringbuf_reserve)),
484 (bpf_func_id_BPF_FUNC_ringbuf_submit, EbpfHelperImpl(bpf_ringbuf_submit)),
485 (bpf_func_id_BPF_FUNC_trace_printk, EbpfHelperImpl(bpf_trace_printk)),
486 (bpf_func_id_BPF_FUNC_get_smp_processor_id, EbpfHelperImpl(bpf_get_smp_processor_id)),
487 ]
488 .into_iter()
489}
490
491fn get_current_task_helpers<C: CurrentTaskProgramContext>()
493-> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
494 [
495 (bpf_func_id_BPF_FUNC_get_current_uid_gid, EbpfHelperImpl(bpf_get_current_uid_gid)),
496 (bpf_func_id_BPF_FUNC_get_current_pid_tgid, EbpfHelperImpl(bpf_get_current_pid_tgid)),
497 ]
498 .into_iter()
499}
500
501pub trait CgroupSockProgramContext:
504 MapsProgramContext + SocketCookieProgramContext + CurrentTaskProgramContext
505{
506 fn get_helpers() -> HelperSet<Self> {
507 [
508 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
509 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
510 ]
511 .into_iter()
512 .chain(get_common_helpers())
513 .chain(get_current_task_helpers())
514 .collect()
515 }
516}
517
518pub trait CgroupSockAddrProgramContext:
521 MapsProgramContext + SocketCookieProgramContext + CurrentTaskProgramContext
522{
523 fn get_helpers() -> HelperSet<Self> {
524 [
525 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
526 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
527 ]
528 .into_iter()
529 .chain(get_common_helpers())
530 .chain(get_current_task_helpers())
531 .collect()
532 }
533}
534
535pub trait CgroupSockOptProgramContext:
538 MapsProgramContext + CurrentTaskProgramContext
539{
540 fn get_helpers() -> HelperSet<Self> {
541 get_common_helpers().chain(get_current_task_helpers()).collect()
542 }
543}
544
545pub trait SocketFilterProgramContext:
548 MapsProgramContext
549 + SocketUidProgramContext
550 + SocketCookieProgramContext
551 + SkbLoadBytesProgramContext
552{
553 fn get_helpers() -> HelperSet<Self> {
554 vec![
555 (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid)),
556 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
557 (
558 bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
559 EbpfHelperImpl(bpf_skb_load_bytes_relative),
560 ),
561 ]
562 .into_iter()
563 .chain(get_common_helpers())
564 .collect()
565 }
566}
567
568pub trait CgroupSkbProgramContext:
571 MapsProgramContext
572 + SocketUidProgramContext
573 + SocketCookieProgramContext
574 + SkbLoadBytesProgramContext
575{
576 fn get_helpers() -> HelperSet<Self> {
577 vec![
578 (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid)),
579 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
580 (
581 bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
582 EbpfHelperImpl(bpf_skb_load_bytes_relative),
583 ),
584 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
585 (bpf_func_id_BPF_FUNC_sk_fullsock, EbpfHelperImpl(bpf_sk_fullsock)),
586 ]
587 .into_iter()
588 .chain(get_common_helpers())
589 .collect()
590 }
591}
592
593#[macro_export]
605macro_rules! ebpf_program_context_type {
606 ($context:ty, $subtrait:ty) => {
607 impl $subtrait for $context {}
608 ebpf::static_helper_set!($context, <$context as $subtrait>::get_helpers());
609 };
610}