1use crate::MapKey;
6use crate::maps::{Map, MapValueRef, RingBuffer, RingBufferWakeupPolicy};
7use ebpf::{
8 BpfValue, EbpfBufferPtr, EbpfHelperImpl, EbpfProgramContext, FromBpfValue, HelperSet, MapFlags,
9};
10use inspect_stubs::track_stub;
11use linux_uapi::{
12 BPF_SK_STORAGE_GET_F_CREATE, bpf_func_id_BPF_FUNC_get_current_pid_tgid,
13 bpf_func_id_BPF_FUNC_get_current_uid_gid, bpf_func_id_BPF_FUNC_get_netns_cookie,
14 bpf_func_id_BPF_FUNC_get_retval, bpf_func_id_BPF_FUNC_get_smp_processor_id,
15 bpf_func_id_BPF_FUNC_get_socket_cookie, bpf_func_id_BPF_FUNC_get_socket_uid,
16 bpf_func_id_BPF_FUNC_ktime_get_boot_ns, bpf_func_id_BPF_FUNC_ktime_get_coarse_ns,
17 bpf_func_id_BPF_FUNC_ktime_get_ns, bpf_func_id_BPF_FUNC_map_delete_elem,
18 bpf_func_id_BPF_FUNC_map_lookup_elem, bpf_func_id_BPF_FUNC_map_update_elem,
19 bpf_func_id_BPF_FUNC_probe_read_str, bpf_func_id_BPF_FUNC_probe_read_user,
20 bpf_func_id_BPF_FUNC_probe_read_user_str, bpf_func_id_BPF_FUNC_ringbuf_discard,
21 bpf_func_id_BPF_FUNC_ringbuf_reserve, bpf_func_id_BPF_FUNC_ringbuf_submit,
22 bpf_func_id_BPF_FUNC_set_retval, bpf_func_id_BPF_FUNC_sk_fullsock,
23 bpf_func_id_BPF_FUNC_sk_lookup_tcp, bpf_func_id_BPF_FUNC_sk_lookup_udp,
24 bpf_func_id_BPF_FUNC_sk_release, bpf_func_id_BPF_FUNC_sk_storage_get,
25 bpf_func_id_BPF_FUNC_skb_load_bytes, bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
26 bpf_func_id_BPF_FUNC_trace_printk, bpf_map_type_BPF_MAP_TYPE_RINGBUF,
27 bpf_map_type_BPF_MAP_TYPE_SK_STORAGE, gid_t, pid_t, uid_t,
28};
29use smallvec::SmallVec;
30use zerocopy::IntoBytes as _;
31
32pub trait MapsContext<'a> {
33 fn on_map_access(&mut self, map: &Map);
34 fn add_value_ref(&mut self, map_ref: MapValueRef<'a>);
35}
36
37pub trait MapsProgramContext: EbpfProgramContext {
38 fn on_map_access(context: &mut Self::RunContext<'_>, map: &Map);
39 fn add_value_ref<'a>(context: &mut Self::RunContext<'a>, map_ref: MapValueRef<'a>);
40}
41
42impl<C: EbpfProgramContext> MapsProgramContext for C
43where
44 for<'a> C::RunContext<'a>: MapsContext<'a>,
45{
46 fn on_map_access(context: &mut Self::RunContext<'_>, map: &Map) {
47 context.on_map_access(map);
48 }
49
50 fn add_value_ref<'a>(context: &mut Self::RunContext<'a>, map_ref: MapValueRef<'a>) {
51 context.add_value_ref(map_ref);
52 }
53}
54
55fn bpf_map_lookup_elem<'a, C: MapsProgramContext>(
56 context: &mut C::RunContext<'a>,
57 map: BpfValue,
58 key: BpfValue,
59 _: BpfValue,
60 _: BpfValue,
61 _: BpfValue,
62) -> BpfValue {
63 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
65
66 let key = unsafe { EbpfBufferPtr::new(key.as_ptr::<u8>(), map.schema.key_size as usize) };
68 let key: MapKey = key.load();
69
70 C::on_map_access(context, map);
71
72 let Some(value_ref) = map.lookup(&key) else {
73 return BpfValue::default();
74 };
75
76 let result: BpfValue = value_ref.ptr().raw_ptr().into();
77
78 if value_ref.is_ref_counted() {
81 C::add_value_ref(context, value_ref);
82 }
83
84 result
85}
86
87fn bpf_map_update_elem<C: MapsProgramContext>(
88 context: &mut C::RunContext<'_>,
89 map: BpfValue,
90 key: BpfValue,
91 value: BpfValue,
92 flags: BpfValue,
93 _: BpfValue,
94) -> BpfValue {
95 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
97
98 assert!(!map.schema.flags.contains(MapFlags::ProgReadOnly));
99
100 if map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE {
102 return BpfValue::default();
103 }
104
105 let key = unsafe { EbpfBufferPtr::new(key.as_ptr::<u8>(), map.schema.key_size as usize) };
107 let key: MapKey = key.load();
108
109 let value = unsafe { EbpfBufferPtr::new(value.as_ptr::<u8>(), map.schema.value_size as usize) };
111 let flags = flags.as_u64();
112
113 C::on_map_access(context, map);
114
115 map.update(&key, value, flags).map(|_| 0).unwrap_or(u64::MAX).into()
116}
117
118fn bpf_map_delete_elem<C: MapsProgramContext>(
119 context: &mut C::RunContext<'_>,
120 map: BpfValue,
121 key: BpfValue,
122 _: BpfValue,
123 _: BpfValue,
124 _: BpfValue,
125) -> BpfValue {
126 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
128
129 assert!(!map.schema.flags.contains(MapFlags::ProgReadOnly));
130
131 if map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE {
133 return BpfValue::default();
134 }
135
136 let key = unsafe { EbpfBufferPtr::new(key.as_ptr::<u8>(), map.schema.key_size as usize) };
138 let key: MapKey = key.load();
139
140 C::on_map_access(context, map);
141
142 map.delete(&key).map(|_| 0).unwrap_or(u64::MAX).into()
143}
144
145fn bpf_trace_printk<C: EbpfProgramContext>(
146 _context: &mut C::RunContext<'_>,
147 _fmt: BpfValue,
148 _fmt_size: BpfValue,
149 _: BpfValue,
150 _: BpfValue,
151 _: BpfValue,
152) -> BpfValue {
153 track_stub!(TODO("https://fxbug.dev/534355500"), "bpf_trace_printk");
154 0.into()
155}
156
157fn bpf_ktime_get_ns<C: EbpfProgramContext>(
158 _context: &mut C::RunContext<'_>,
159 _: BpfValue,
160 _: BpfValue,
161 _: BpfValue,
162 _: BpfValue,
163 _: BpfValue,
164) -> BpfValue {
165 zx::MonotonicInstant::get().into_nanos().into()
166}
167
168fn bpf_ringbuf_reserve<C: EbpfProgramContext>(
169 _context: &mut C::RunContext<'_>,
170 map: BpfValue,
171 size: BpfValue,
172 flags: BpfValue,
173 _: BpfValue,
174 _: BpfValue,
175) -> BpfValue {
176 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
179
180 assert!(map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_RINGBUF);
182
183 let Ok(size) = u32::try_from(size) else {
184 return BpfValue::default();
185 };
186 let flags = u64::from(flags);
187 map.ringbuf_reserve(size, flags).map(BpfValue::from).unwrap_or_else(|_| BpfValue::default())
188}
189
190fn bpf_ringbuf_submit<C: EbpfProgramContext>(
191 _context: &mut C::RunContext<'_>,
192 data: BpfValue,
193 flags: BpfValue,
194 _: BpfValue,
195 _: BpfValue,
196 _: BpfValue,
197) -> BpfValue {
198 let flags = RingBufferWakeupPolicy::from(flags);
199
200 unsafe {
203 RingBuffer::submit(u64::from(data), flags);
204 }
205 0.into()
206}
207
208fn bpf_ringbuf_discard<C: EbpfProgramContext>(
209 _context: &mut C::RunContext<'_>,
210 data: BpfValue,
211 flags: BpfValue,
212 _: BpfValue,
213 _: BpfValue,
214 _: BpfValue,
215) -> BpfValue {
216 let flags = RingBufferWakeupPolicy::from(flags);
217
218 unsafe {
221 RingBuffer::discard(u64::from(data), flags);
222 }
223 0.into()
224}
225
226fn bpf_ktime_get_boot_ns<C: EbpfProgramContext>(
227 _context: &mut C::RunContext<'_>,
228 _: BpfValue,
229 _: BpfValue,
230 _: BpfValue,
231 _: BpfValue,
232 _: BpfValue,
233) -> BpfValue {
234 track_stub!(TODO("https://fxbug.dev/534355721"), "bpf_ktime_get_boot_ns");
235 0.into()
236}
237
238fn bpf_probe_read_user<C: EbpfProgramContext>(
239 _context: &mut C::RunContext<'_>,
240 dst: BpfValue,
241 size: BpfValue,
242 _src: BpfValue,
243 _: BpfValue,
244 _: BpfValue,
245) -> BpfValue {
246 track_stub!(TODO("https://fxbug.dev/534354547"), "bpf_probe_read_user");
247 let size = size.as_usize();
252 if size > 0 {
253 unsafe { std::ptr::write_bytes(dst.as_ptr::<u8>(), 0, size) };
256 }
257 0.into()
258}
259
260fn bpf_probe_read_user_str<C: EbpfProgramContext>(
261 _context: &mut C::RunContext<'_>,
262 dst: BpfValue,
263 size: BpfValue,
264 _src: BpfValue,
265 _: BpfValue,
266 _: BpfValue,
267) -> BpfValue {
268 track_stub!(TODO("https://fxbug.dev/534355539"), "bpf_probe_read_user_str");
269 let size = size.as_usize();
274 if size > 0 {
275 unsafe { std::ptr::write_bytes(dst.as_ptr::<u8>(), 0, size) };
278 }
279 0.into()
280}
281
282fn bpf_ktime_get_coarse_ns<C: EbpfProgramContext>(
283 _context: &mut C::RunContext<'_>,
284 _: BpfValue,
285 _: BpfValue,
286 _: BpfValue,
287 _: BpfValue,
288 _: BpfValue,
289) -> BpfValue {
290 track_stub!(TODO("https://fxbug.dev/534355976"), "bpf_ktime_get_coarse_ns");
291 0.into()
292}
293
294fn bpf_probe_read_str<C: EbpfProgramContext>(
295 _context: &mut C::RunContext<'_>,
296 _: BpfValue,
297 _: BpfValue,
298 _: BpfValue,
299 _: BpfValue,
300 _: BpfValue,
301) -> BpfValue {
302 track_stub!(TODO("https://fxbug.dev/534355560"), "bpf_probe_read_str");
303 0.into()
304}
305
306fn bpf_get_smp_processor_id<C: EbpfProgramContext>(
307 _context: &mut C::RunContext<'_>,
308 _: BpfValue,
309 _: BpfValue,
310 _: BpfValue,
311 _: BpfValue,
312 _: BpfValue,
313) -> BpfValue {
314 track_stub!(TODO("https://fxbug.dev/534354909"), "bpf_get_smp_processor_id");
315 0.into()
316}
317
318pub trait CurrentTaskContext {
319 fn get_uid_gid(&self) -> (uid_t, gid_t);
320 fn get_tid_tgid(&self) -> (pid_t, pid_t);
321}
322
323pub trait CurrentTaskProgramContext: EbpfProgramContext {
324 fn get_uid_gid<'a>(context: &mut Self::RunContext<'a>) -> (uid_t, gid_t);
325 fn get_tid_tgid<'a>(context: &mut Self::RunContext<'a>) -> (pid_t, pid_t);
326}
327
328impl<C: EbpfProgramContext> CurrentTaskProgramContext for C
329where
330 for<'a> C::RunContext<'a>: CurrentTaskContext,
331{
332 fn get_uid_gid<'a>(context: &mut Self::RunContext<'a>) -> (uid_t, gid_t) {
333 context.get_uid_gid()
334 }
335 fn get_tid_tgid<'a>(context: &mut Self::RunContext<'a>) -> (pid_t, pid_t) {
336 context.get_tid_tgid()
337 }
338}
339
340fn bpf_get_current_uid_gid<C: CurrentTaskProgramContext>(
341 context: &mut C::RunContext<'_>,
342 _: BpfValue,
343 _: BpfValue,
344 _: BpfValue,
345 _: BpfValue,
346 _: BpfValue,
347) -> BpfValue {
348 let (uid, gid) = C::get_uid_gid(context);
349 (uid as u64 | (gid as u64) << 32).into()
350}
351
352fn bpf_get_current_pid_tgid<C: CurrentTaskProgramContext>(
353 context: &mut C::RunContext<'_>,
354 _: BpfValue,
355 _: BpfValue,
356 _: BpfValue,
357 _: BpfValue,
358 _: BpfValue,
359) -> BpfValue {
360 let (pid, tgid) = C::get_tid_tgid(context);
361 (pid as u64 | (tgid as u64) << 32).into()
362}
363
364pub trait Arg1IsSocketProgramContext: EbpfProgramContext {
367 type Arg1AsSocket<'a>: FromBpfValue<Self::RunContext<'a>> + SocketRef;
368}
369
370impl<C> Arg1IsSocketProgramContext for C
371where
372 C: EbpfProgramContext,
373 for<'a> Self::Arg1<'a>: FromBpfValue<Self::RunContext<'a>> + SocketRef,
374{
375 type Arg1AsSocket<'a> = Self::Arg1<'a>;
376}
377
378pub trait SocketCookieProgramContext: Arg1IsSocketProgramContext {}
380impl<C> SocketCookieProgramContext for C where C: Arg1IsSocketProgramContext {}
381
382fn bpf_get_socket_cookie<'a, C: SocketCookieProgramContext>(
383 context: &mut C::RunContext<'a>,
384 arg1: BpfValue,
385 _: BpfValue,
386 _: BpfValue,
387 _: BpfValue,
388 _: BpfValue,
389) -> BpfValue {
390 let arg1_as_socket = unsafe { C::Arg1AsSocket::from_bpf_value(context, arg1) };
393 arg1_as_socket.get_socket_cookie().unwrap_or(0).into()
394}
395
396pub trait SocketRef {
397 fn get_socket_cookie(&self) -> Option<u64>;
398 fn get_socket_uid(&self) -> Option<uid_t>;
399}
400
401pub trait BpfSockContext: Sized {
403 type BpfSockRef: SocketRef + FromBpfValue<Self>;
404}
405
406pub trait SkStorageProgramContext: EbpfProgramContext {
407 type BpfSockRef<'a>: SocketRef + FromBpfValue<Self::RunContext<'a>>;
408}
409
410impl<C> SkStorageProgramContext for C
411where
412 C: EbpfProgramContext,
413 for<'a> C::RunContext<'a>: BpfSockContext,
414{
415 type BpfSockRef<'a> = <C::RunContext<'a> as BpfSockContext>::BpfSockRef;
416}
417
418#[derive(Copy, Clone, Debug, PartialEq, Eq)]
419pub enum LoadBytesBase {
420 MacHeader,
421 NetworkHeader,
422}
423
424pub trait SocketUidProgramContext: Arg1IsSocketProgramContext {}
426impl<C> SocketUidProgramContext for C where C: Arg1IsSocketProgramContext {}
427
428fn bpf_get_socket_uid<'a, C: SocketUidProgramContext>(
429 context: &mut C::RunContext<'a>,
430 sk_buf: BpfValue,
431 _: BpfValue,
432 _: BpfValue,
433 _: BpfValue,
434 _: BpfValue,
435) -> BpfValue {
436 const OVERFLOW_UID: uid_t = 65534;
437 let sk_buf = unsafe { C::Arg1AsSocket::from_bpf_value(context, sk_buf) };
439 sk_buf.get_socket_uid().unwrap_or(OVERFLOW_UID).into()
440}
441
442pub trait PacketWithLoadBytes {
444 fn load_bytes_relative(
445 &self,
446 base: LoadBytesBase,
447 offset: usize,
448 buf: EbpfBufferPtr<'_>,
449 ) -> i64;
450}
451
452pub trait SkbLoadBytesProgramContext: EbpfProgramContext {
454 fn skb_load_bytes_relative<'a>(
455 context: &mut Self::RunContext<'a>,
456 sk_buf: BpfValue,
457 base: LoadBytesBase,
458 offset: usize,
459 buf: EbpfBufferPtr<'_>,
460 ) -> i64;
461}
462
463impl<C: EbpfProgramContext> SkbLoadBytesProgramContext for C
464where
465 for<'b> C::Arg1<'b>: FromBpfValue<C::RunContext<'b>>,
466 for<'b> C::Arg1<'b>: PacketWithLoadBytes,
467{
468 fn skb_load_bytes_relative<'a>(
469 context: &mut Self::RunContext<'a>,
470 sk_buf: BpfValue,
471 base: LoadBytesBase,
472 offset: usize,
473 buf: EbpfBufferPtr<'_>,
474 ) -> i64 {
475 let sk_buf = unsafe { C::Arg1::from_bpf_value(context, sk_buf) };
478 sk_buf.load_bytes_relative(base, offset, buf)
479 }
480}
481
482fn bpf_skb_load_bytes<'a, C: SkbLoadBytesProgramContext>(
483 context: &mut C::RunContext<'a>,
484 sk_buf: BpfValue,
485 offset: BpfValue,
486 to: BpfValue,
487 len: BpfValue,
488 _: BpfValue,
489) -> BpfValue {
490 let base = LoadBytesBase::NetworkHeader;
491
492 let Ok(offset) = offset.as_u64().try_into() else {
493 return u64::MAX.into();
494 };
495
496 let buf = unsafe { EbpfBufferPtr::new(to.as_ptr::<u8>(), len.as_u64() as usize) };
499
500 C::skb_load_bytes_relative(context, sk_buf, base, offset, buf).into()
501}
502
503fn bpf_skb_load_bytes_relative<'a, C: SkbLoadBytesProgramContext>(
504 context: &mut C::RunContext<'a>,
505 sk_buf: BpfValue,
506 offset: BpfValue,
507 to: BpfValue,
508 len: BpfValue,
509 start_header: BpfValue,
510) -> BpfValue {
511 let base = match start_header.as_u64() {
512 0 => LoadBytesBase::MacHeader,
513 1 => LoadBytesBase::NetworkHeader,
514 _ => return u64::MAX.into(),
515 };
516
517 let Ok(offset) = offset.as_u64().try_into() else {
518 return u64::MAX.into();
519 };
520
521 let buf = unsafe { EbpfBufferPtr::new(to.as_ptr::<u8>(), len.as_u64() as usize) };
524
525 C::skb_load_bytes_relative(context, sk_buf, base, offset, buf).into()
526}
527
528fn bpf_sk_storage_get<'a, C: SkStorageProgramContext + MapsProgramContext>(
529 context: &mut C::RunContext<'a>,
530 map: BpfValue,
531 sk: BpfValue,
532 value: BpfValue,
533 flags: BpfValue,
534 _: BpfValue,
535) -> BpfValue {
536 if sk.is_zero() {
537 return BpfValue::default();
538 }
539
540 let bpf_sock = unsafe { C::BpfSockRef::from_bpf_value(context, sk) };
543
544 let Some(socket_id) = bpf_sock.get_socket_cookie() else {
546 return BpfValue::default();
547 };
548
549 let key = socket_id.as_bytes();
550
551 let map: &Map = unsafe { &*map.as_ptr::<Map>() };
553
554 assert!(map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE);
556
557 C::on_map_access(context, map);
558
559 if let Some(value_ref) = map.lookup(key) {
560 let result: BpfValue = value_ref.ptr().raw_ptr().into();
561 C::add_value_ref(context, value_ref);
562 return result;
563 }
564
565 if flags.as_u32() & BPF_SK_STORAGE_GET_F_CREATE != 0 {
566 let mut vec;
567 let init_val = if value.as_u64() == 0 {
568 vec = SmallVec::<[u8; 128]>::new();
569 vec.resize(map.schema.value_size as usize, 0);
570 (&mut vec[..]).into()
571 } else {
572 unsafe { EbpfBufferPtr::new(value.as_ptr::<u8>(), map.schema.value_size as usize) }
574 };
575
576 let r = map.update(key, init_val, 0);
577 if r.is_ok() {
578 if let Some(value_ref) = map.lookup(key) {
579 let result: BpfValue = value_ref.ptr().raw_ptr().into();
580 C::add_value_ref(context, value_ref);
581 return result;
582 }
583 }
584 }
585
586 BpfValue::default()
587}
588
589fn bpf_sk_fullsock<C: EbpfProgramContext>(
590 _context: &mut C::RunContext<'_>,
591 sk: BpfValue,
592 _: BpfValue,
593 _: BpfValue,
594 _: BpfValue,
595 _: BpfValue,
596) -> BpfValue {
597 sk
598}
599
600pub trait ReturnValueContext {
601 fn set_retval(&mut self, value: i32) -> i32;
602 fn get_retval(&self) -> i32;
603}
604
605pub trait ReturnValueProgramContext: EbpfProgramContext {
606 fn set_retval<'a>(context: &mut Self::RunContext<'a>, value: i32) -> i32;
607 fn get_retval<'a>(context: &mut Self::RunContext<'a>) -> i32;
608}
609
610impl<C: EbpfProgramContext> ReturnValueProgramContext for C
611where
612 for<'a> C::RunContext<'a>: ReturnValueContext,
613{
614 fn set_retval<'a>(context: &mut Self::RunContext<'a>, value: i32) -> i32 {
615 context.set_retval(value)
616 }
617 fn get_retval<'a>(context: &mut Self::RunContext<'a>) -> i32 {
618 context.get_retval()
619 }
620}
621
622fn bpf_set_retval<C: ReturnValueProgramContext>(
623 context: &mut C::RunContext<'_>,
624 value: BpfValue,
625 _: BpfValue,
626 _: BpfValue,
627 _: BpfValue,
628 _: BpfValue,
629) -> BpfValue {
630 C::set_retval(context, value.as_i32()).into()
631}
632
633fn bpf_get_retval<C: ReturnValueProgramContext>(
634 context: &mut C::RunContext<'_>,
635 _: BpfValue,
636 _: BpfValue,
637 _: BpfValue,
638 _: BpfValue,
639 _: BpfValue,
640) -> BpfValue {
641 C::get_retval(context).into()
642}
643
644fn bpf_sk_lookup_tcp<C: EbpfProgramContext>(
645 _context: &mut C::RunContext<'_>,
646 _: BpfValue,
647 _: BpfValue,
648 _: BpfValue,
649 _: BpfValue,
650 _: BpfValue,
651) -> BpfValue {
652 track_stub!(TODO("https://fxbug.dev/534355706"), "bpf_sk_lookup_tcp");
653 0.into()
654}
655
656fn bpf_sk_lookup_udp<C: EbpfProgramContext>(
657 _context: &mut C::RunContext<'_>,
658 _: BpfValue,
659 _: BpfValue,
660 _: BpfValue,
661 _: BpfValue,
662 _: BpfValue,
663) -> BpfValue {
664 track_stub!(TODO("https://fxbug.dev/534355185"), "bpf_sk_lookup_udp");
665 0.into()
666}
667
668fn bpf_sk_release<C: EbpfProgramContext>(
669 _context: &mut C::RunContext<'_>,
670 _: BpfValue,
671 _: BpfValue,
672 _: BpfValue,
673 _: BpfValue,
674 _: BpfValue,
675) -> BpfValue {
676 track_stub!(TODO("https://fxbug.dev/534355132"), "bpf_sk_release");
677 0.into()
678}
679
680fn bpf_get_netns_cookie<C: EbpfProgramContext>(
681 _context: &mut C::RunContext<'_>,
682 _: BpfValue,
683 _: BpfValue,
684 _: BpfValue,
685 _: BpfValue,
686 _: BpfValue,
687) -> BpfValue {
688 track_stub!(TODO("https://fxbug.dev/534354509"), "bpf_get_netns_cookie");
689 const DEFAULT_NETWORK_NAMESPACE_COOKIE: u64 = 1;
690 DEFAULT_NETWORK_NAMESPACE_COOKIE.into()
691}
692
693fn get_common_helpers<C: MapsProgramContext>() -> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
694 [
695 (bpf_func_id_BPF_FUNC_ktime_get_boot_ns, EbpfHelperImpl(bpf_ktime_get_boot_ns::<C>)),
696 (bpf_func_id_BPF_FUNC_ktime_get_coarse_ns, EbpfHelperImpl(bpf_ktime_get_coarse_ns::<C>)),
697 (bpf_func_id_BPF_FUNC_ktime_get_ns, EbpfHelperImpl(bpf_ktime_get_ns::<C>)),
698 (bpf_func_id_BPF_FUNC_map_delete_elem, EbpfHelperImpl(bpf_map_delete_elem::<C>)),
699 (bpf_func_id_BPF_FUNC_map_lookup_elem, EbpfHelperImpl(bpf_map_lookup_elem::<C>)),
700 (bpf_func_id_BPF_FUNC_map_update_elem, EbpfHelperImpl(bpf_map_update_elem::<C>)),
701 (bpf_func_id_BPF_FUNC_probe_read_str, EbpfHelperImpl(bpf_probe_read_str::<C>)),
702 (bpf_func_id_BPF_FUNC_probe_read_user, EbpfHelperImpl(bpf_probe_read_user::<C>)),
703 (bpf_func_id_BPF_FUNC_probe_read_user_str, EbpfHelperImpl(bpf_probe_read_user_str::<C>)),
704 (bpf_func_id_BPF_FUNC_ringbuf_discard, EbpfHelperImpl(bpf_ringbuf_discard::<C>)),
705 (bpf_func_id_BPF_FUNC_ringbuf_reserve, EbpfHelperImpl(bpf_ringbuf_reserve::<C>)),
706 (bpf_func_id_BPF_FUNC_ringbuf_submit, EbpfHelperImpl(bpf_ringbuf_submit::<C>)),
707 (bpf_func_id_BPF_FUNC_trace_printk, EbpfHelperImpl(bpf_trace_printk::<C>)),
708 (bpf_func_id_BPF_FUNC_get_smp_processor_id, EbpfHelperImpl(bpf_get_smp_processor_id::<C>)),
709 ]
710 .into_iter()
711}
712
713fn get_current_task_helpers<C: CurrentTaskProgramContext>()
715-> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
716 [
717 (bpf_func_id_BPF_FUNC_get_current_uid_gid, EbpfHelperImpl(bpf_get_current_uid_gid::<C>)),
718 (bpf_func_id_BPF_FUNC_get_current_pid_tgid, EbpfHelperImpl(bpf_get_current_pid_tgid::<C>)),
719 ]
720 .into_iter()
721}
722
723pub trait CgroupSockProgramContext:
726 MapsProgramContext
727 + SocketCookieProgramContext
728 + CurrentTaskProgramContext
729 + SkStorageProgramContext
730{
731 fn get_helpers() -> HelperSet<Self> {
732 [
733 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie::<Self>)),
734 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie::<Self>)),
735 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get::<Self>)),
736 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp::<Self>)),
737 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp::<Self>)),
738 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release::<Self>)),
739 ]
740 .into_iter()
741 .chain(get_common_helpers())
742 .chain(get_current_task_helpers())
743 .collect()
744 }
745}
746
747pub trait CgroupSockAddrProgramContext:
750 MapsProgramContext
751 + SocketCookieProgramContext
752 + CurrentTaskProgramContext
753 + SkStorageProgramContext
754{
755 fn get_helpers() -> HelperSet<Self> {
756 [
757 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie::<Self>)),
758 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie::<Self>)),
759 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get::<Self>)),
760 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp::<Self>)),
761 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp::<Self>)),
762 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release::<Self>)),
763 ]
764 .into_iter()
765 .chain(get_common_helpers())
766 .chain(get_current_task_helpers())
767 .collect()
768 }
769}
770
771pub trait CgroupSockOptProgramContext:
774 MapsProgramContext + CurrentTaskProgramContext + ReturnValueProgramContext + SkStorageProgramContext
775{
776 fn get_helpers() -> HelperSet<Self> {
777 [
778 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie::<Self>)),
779 (bpf_func_id_BPF_FUNC_set_retval, EbpfHelperImpl(bpf_set_retval::<Self>)),
780 (bpf_func_id_BPF_FUNC_get_retval, EbpfHelperImpl(bpf_get_retval::<Self>)),
781 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get::<Self>)),
782 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp::<Self>)),
783 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp::<Self>)),
784 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release::<Self>)),
785 ]
786 .into_iter()
787 .chain(get_common_helpers())
788 .chain(get_current_task_helpers())
789 .collect()
790 }
791}
792
793pub trait SocketFilterProgramContext:
796 MapsProgramContext
797 + SocketUidProgramContext
798 + SocketCookieProgramContext
799 + SkbLoadBytesProgramContext
800{
801 fn get_helpers() -> HelperSet<Self> {
802 vec![
803 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie::<Self>)),
804 (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid::<Self>)),
805 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie::<Self>)),
806 (bpf_func_id_BPF_FUNC_skb_load_bytes, EbpfHelperImpl(bpf_skb_load_bytes::<Self>)),
807 (
808 bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
809 EbpfHelperImpl(bpf_skb_load_bytes_relative::<Self>),
810 ),
811 ]
812 .into_iter()
813 .chain(get_common_helpers())
814 .collect()
815 }
816}
817
818pub trait CgroupSkbProgramContext:
821 MapsProgramContext
822 + SocketUidProgramContext
823 + SocketCookieProgramContext
824 + SkbLoadBytesProgramContext
825 + SkStorageProgramContext
826{
827 fn get_helpers() -> HelperSet<Self> {
828 vec![
829 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie::<Self>)),
830 (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid::<Self>)),
831 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie::<Self>)),
832 (bpf_func_id_BPF_FUNC_skb_load_bytes, EbpfHelperImpl(bpf_skb_load_bytes::<Self>)),
833 (
834 bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
835 EbpfHelperImpl(bpf_skb_load_bytes_relative::<Self>),
836 ),
837 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get::<Self>)),
838 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp::<Self>)),
839 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp::<Self>)),
840 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release::<Self>)),
841 (bpf_func_id_BPF_FUNC_sk_fullsock, EbpfHelperImpl(bpf_sk_fullsock::<Self>)),
842 ]
843 .into_iter()
844 .chain(get_common_helpers())
845 .collect()
846 }
847}
848
849#[macro_export]
861macro_rules! ebpf_program_context_type {
862 ($context:ty, $subtrait:ty) => {
863 impl $subtrait for $context {}
864 ebpf::static_helper_set!($context, <$context as $subtrait>::get_helpers());
865 };
866}
867
868#[cfg(test)]
869mod tests {
870 use super::*;
871 use crate::maps::{Map, PinnedMap};
872 use ebpf::{BpfValue, EbpfProgramContext, FromBpfValue, MapFlags, MapSchema};
873 use linux_uapi::{BPF_SK_STORAGE_GET_F_CREATE, bpf_map_type_BPF_MAP_TYPE_SK_STORAGE};
874
875 struct MockSocket {
876 cookie: u64,
877 }
878 impl SocketRef for MockSocket {
879 fn get_socket_cookie(&self) -> Option<u64> {
880 Some(self.cookie)
881 }
882 fn get_socket_uid(&self) -> Option<uid_t> {
883 Some(0)
884 }
885 }
886 impl<'a> FromBpfValue<TestRunContext<'a>> for MockSocket {
887 unsafe fn from_bpf_value(_context: &mut TestRunContext<'a>, value: BpfValue) -> Self {
888 Self { cookie: value.as_u64() }
889 }
890 }
891
892 struct TestRunContext<'a> {
893 map_refs: Vec<MapValueRef<'a>>,
894 }
895 impl<'a> BpfSockContext for TestRunContext<'a> {
896 type BpfSockRef = MockSocket;
897 }
898 impl<'a> MapsContext<'a> for TestRunContext<'a> {
899 fn on_map_access(&mut self, _map: &Map) {}
900 fn add_value_ref(&mut self, map_ref: MapValueRef<'a>) {
901 self.map_refs.push(map_ref);
902 }
903 }
904
905 struct TestContext;
906 impl EbpfProgramContext for TestContext {
907 type RunContext<'a> = TestRunContext<'a>;
908 type Packet<'a> = ();
909 type Arg1<'a> = ();
910 type Arg2<'a> = ();
911 type Arg3<'a> = ();
912 type Arg4<'a> = ();
913 type Arg5<'a> = ();
914 type Map = PinnedMap;
915 }
916
917 #[fuchsia::test]
918 fn test_sk_storage_get_uaf() {
919 let schema = MapSchema {
920 map_type: bpf_map_type_BPF_MAP_TYPE_SK_STORAGE,
921 key_size: 4,
922 value_size: 8,
923 max_entries: 0,
924 flags: MapFlags::NoPrealloc,
925 };
926 let map = Map::new(schema, "test").unwrap();
927 let map_value = BpfValue::from(&*map as *const Map);
928
929 let mut context = TestRunContext { map_refs: vec![] };
930
931 let sk_value1 = BpfValue::from(42u64);
933 let init_value1 = [0x11u8; 8];
934 let init_value_ptr1 = BpfValue::from(init_value1.as_ptr());
935 let flags = BpfValue::from(BPF_SK_STORAGE_GET_F_CREATE as u64);
936
937 let ptr1 = bpf_sk_storage_get::<TestContext>(
938 &mut context,
939 map_value,
940 sk_value1,
941 init_value_ptr1,
942 flags,
943 BpfValue::default(),
944 );
945 assert!(!ptr1.is_zero());
946
947 unsafe {
950 assert_eq!(*(ptr1.as_ptr::<u64>()), 0x1111111111111111);
951 }
952
953 let key_bytes = 42u64.to_ne_bytes();
955 map.delete(&key_bytes).unwrap();
956
957 let sk_value2 = BpfValue::from(43u64);
960 let init_value2 = [0x22u8; 8];
961 let init_value_ptr2 = BpfValue::from(init_value2.as_ptr());
962
963 let ptr2 = bpf_sk_storage_get::<TestContext>(
964 &mut context,
965 map_value,
966 sk_value2,
967 init_value_ptr2,
968 flags,
969 BpfValue::default(),
970 );
971 assert!(!ptr2.is_zero());
972
973 unsafe {
979 assert_eq!(*(ptr1.as_ptr::<u64>()), 0x1111111111111111);
980 }
981 }
982
983 #[fuchsia::test]
984 fn test_sk_storage_get_uaf_query() {
985 let schema = MapSchema {
986 map_type: bpf_map_type_BPF_MAP_TYPE_SK_STORAGE,
987 key_size: 4,
988 value_size: 8,
989 max_entries: 0,
990 flags: MapFlags::NoPrealloc,
991 };
992 let map = Map::new(schema, "test").unwrap();
993 let map_value = BpfValue::from(&*map as *const Map);
994
995 let mut context = TestRunContext { map_refs: vec![] };
996
997 let sk_value1 = BpfValue::from(42u64);
999 let init_value1 = [0x11u8; 8];
1000 let init_value_ptr1 = BpfValue::from(init_value1.as_ptr());
1001 let flags = BpfValue::from(BPF_SK_STORAGE_GET_F_CREATE as u64);
1002
1003 let ptr1 = bpf_sk_storage_get::<TestContext>(
1004 &mut context,
1005 map_value,
1006 sk_value1,
1007 init_value_ptr1,
1008 flags,
1009 BpfValue::default(),
1010 );
1011 assert!(!ptr1.is_zero());
1012
1013 context.map_refs.clear();
1016
1017 let ptr1_query = bpf_sk_storage_get::<TestContext>(
1019 &mut context,
1020 map_value,
1021 sk_value1,
1022 BpfValue::default(),
1023 BpfValue::default(),
1024 BpfValue::default(),
1025 );
1026 assert_eq!(ptr1.as_u64(), ptr1_query.as_u64());
1027
1028 let key_bytes = 42u64.to_ne_bytes();
1030 map.delete(&key_bytes).unwrap();
1031
1032 let sk_value2 = BpfValue::from(43u64);
1036 let init_value2 = [0x22u8; 8];
1037 let init_value_ptr2 = BpfValue::from(init_value2.as_ptr());
1038
1039 let ptr2 = bpf_sk_storage_get::<TestContext>(
1040 &mut context,
1041 map_value,
1042 sk_value2,
1043 init_value_ptr2,
1044 flags,
1045 BpfValue::default(),
1046 );
1047 assert!(!ptr2.is_zero());
1048
1049 unsafe {
1054 assert_eq!(*(ptr1_query.as_ptr::<u64>()), 0x1111111111111111);
1055 }
1056 }
1057
1058 #[fuchsia::test]
1067 fn test_probe_read_user_zeroes_destination() {
1068 let mut context = TestRunContext { map_refs: vec![] };
1069
1070 let mut dst = [0xAAu8; 8];
1072 let ret = bpf_probe_read_user::<TestContext>(
1073 &mut context,
1074 BpfValue::from(dst.as_mut_ptr()),
1075 BpfValue::from(dst.len() as u64),
1076 BpfValue::default(),
1077 BpfValue::default(),
1078 BpfValue::default(),
1079 );
1080 assert_eq!(ret.as_u64(), 0);
1081 assert_eq!(dst, [0u8; 8], "probe_read_user left the destination uninitialized");
1082
1083 let mut dst_str = [0xBBu8; 8];
1084 let _ = bpf_probe_read_user_str::<TestContext>(
1085 &mut context,
1086 BpfValue::from(dst_str.as_mut_ptr()),
1087 BpfValue::from(dst_str.len() as u64),
1088 BpfValue::default(),
1089 BpfValue::default(),
1090 BpfValue::default(),
1091 );
1092 assert_eq!(dst_str, [0u8; 8], "probe_read_user_str left the destination uninitialized");
1093 }
1094}