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