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 _: BpfValue,
586 _: BpfValue,
587 _: BpfValue,
588 _: BpfValue,
589 _: BpfValue,
590) -> BpfValue {
591 track_stub!(TODO("https://fxbug.dev/534355421"), "bpf_sk_fullsock");
592 0.into()
593}
594
595pub trait ReturnValueContext {
596 fn set_retval(&mut self, value: i32) -> i32;
597 fn get_retval(&self) -> i32;
598}
599
600pub trait ReturnValueProgramContext: EbpfProgramContext {
601 fn set_retval<'a>(context: &mut Self::RunContext<'a>, value: i32) -> i32;
602 fn get_retval<'a>(context: &mut Self::RunContext<'a>) -> i32;
603}
604
605impl<C: EbpfProgramContext> ReturnValueProgramContext for C
606where
607 for<'a> C::RunContext<'a>: ReturnValueContext,
608{
609 fn set_retval<'a>(context: &mut Self::RunContext<'a>, value: i32) -> i32 {
610 context.set_retval(value)
611 }
612 fn get_retval<'a>(context: &mut Self::RunContext<'a>) -> i32 {
613 context.get_retval()
614 }
615}
616
617fn bpf_set_retval<C: ReturnValueProgramContext>(
618 context: &mut C::RunContext<'_>,
619 value: BpfValue,
620 _: BpfValue,
621 _: BpfValue,
622 _: BpfValue,
623 _: BpfValue,
624) -> BpfValue {
625 C::set_retval(context, value.as_i32()).into()
626}
627
628fn bpf_get_retval<C: ReturnValueProgramContext>(
629 context: &mut C::RunContext<'_>,
630 _: BpfValue,
631 _: BpfValue,
632 _: BpfValue,
633 _: BpfValue,
634 _: BpfValue,
635) -> BpfValue {
636 C::get_retval(context).into()
637}
638
639fn bpf_sk_lookup_tcp<C: EbpfProgramContext>(
640 _context: &mut C::RunContext<'_>,
641 _: BpfValue,
642 _: BpfValue,
643 _: BpfValue,
644 _: BpfValue,
645 _: BpfValue,
646) -> BpfValue {
647 track_stub!(TODO("https://fxbug.dev/534355706"), "bpf_sk_lookup_tcp");
648 0.into()
649}
650
651fn bpf_sk_lookup_udp<C: EbpfProgramContext>(
652 _context: &mut C::RunContext<'_>,
653 _: BpfValue,
654 _: BpfValue,
655 _: BpfValue,
656 _: BpfValue,
657 _: BpfValue,
658) -> BpfValue {
659 track_stub!(TODO("https://fxbug.dev/534355185"), "bpf_sk_lookup_udp");
660 0.into()
661}
662
663fn bpf_sk_release<C: EbpfProgramContext>(
664 _context: &mut C::RunContext<'_>,
665 _: BpfValue,
666 _: BpfValue,
667 _: BpfValue,
668 _: BpfValue,
669 _: BpfValue,
670) -> BpfValue {
671 track_stub!(TODO("https://fxbug.dev/534355132"), "bpf_sk_release");
672 0.into()
673}
674
675fn bpf_get_netns_cookie<C: EbpfProgramContext>(
676 _context: &mut C::RunContext<'_>,
677 _: BpfValue,
678 _: BpfValue,
679 _: BpfValue,
680 _: BpfValue,
681 _: BpfValue,
682) -> BpfValue {
683 track_stub!(TODO("https://fxbug.dev/534354509"), "bpf_get_netns_cookie");
684 const DEFAULT_NETWORK_NAMESPACE_COOKIE: u64 = 1;
685 DEFAULT_NETWORK_NAMESPACE_COOKIE.into()
686}
687
688fn get_common_helpers<C: MapsProgramContext>() -> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
689 [
690 (bpf_func_id_BPF_FUNC_ktime_get_boot_ns, EbpfHelperImpl(bpf_ktime_get_boot_ns)),
691 (bpf_func_id_BPF_FUNC_ktime_get_coarse_ns, EbpfHelperImpl(bpf_ktime_get_coarse_ns)),
692 (bpf_func_id_BPF_FUNC_ktime_get_ns, EbpfHelperImpl(bpf_ktime_get_ns)),
693 (bpf_func_id_BPF_FUNC_map_delete_elem, EbpfHelperImpl(bpf_map_delete_elem)),
694 (bpf_func_id_BPF_FUNC_map_lookup_elem, EbpfHelperImpl(bpf_map_lookup_elem)),
695 (bpf_func_id_BPF_FUNC_map_update_elem, EbpfHelperImpl(bpf_map_update_elem)),
696 (bpf_func_id_BPF_FUNC_probe_read_str, EbpfHelperImpl(bpf_probe_read_str)),
697 (bpf_func_id_BPF_FUNC_probe_read_user, EbpfHelperImpl(bpf_probe_read_user)),
698 (bpf_func_id_BPF_FUNC_probe_read_user_str, EbpfHelperImpl(bpf_probe_read_user_str)),
699 (bpf_func_id_BPF_FUNC_ringbuf_discard, EbpfHelperImpl(bpf_ringbuf_discard)),
700 (bpf_func_id_BPF_FUNC_ringbuf_reserve, EbpfHelperImpl(bpf_ringbuf_reserve)),
701 (bpf_func_id_BPF_FUNC_ringbuf_submit, EbpfHelperImpl(bpf_ringbuf_submit)),
702 (bpf_func_id_BPF_FUNC_trace_printk, EbpfHelperImpl(bpf_trace_printk)),
703 (bpf_func_id_BPF_FUNC_get_smp_processor_id, EbpfHelperImpl(bpf_get_smp_processor_id)),
704 ]
705 .into_iter()
706}
707
708fn get_current_task_helpers<C: CurrentTaskProgramContext>()
710-> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
711 [
712 (bpf_func_id_BPF_FUNC_get_current_uid_gid, EbpfHelperImpl(bpf_get_current_uid_gid)),
713 (bpf_func_id_BPF_FUNC_get_current_pid_tgid, EbpfHelperImpl(bpf_get_current_pid_tgid)),
714 ]
715 .into_iter()
716}
717
718pub trait CgroupSockProgramContext:
721 MapsProgramContext
722 + SocketCookieProgramContext
723 + CurrentTaskProgramContext
724 + SkStorageProgramContext
725{
726 fn get_helpers() -> HelperSet<Self> {
727 [
728 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
729 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
730 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
731 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
732 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
733 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
734 ]
735 .into_iter()
736 .chain(get_common_helpers())
737 .chain(get_current_task_helpers())
738 .collect()
739 }
740}
741
742pub trait CgroupSockAddrProgramContext:
745 MapsProgramContext
746 + SocketCookieProgramContext
747 + CurrentTaskProgramContext
748 + SkStorageProgramContext
749{
750 fn get_helpers() -> HelperSet<Self> {
751 [
752 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
753 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
754 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
755 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
756 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
757 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
758 ]
759 .into_iter()
760 .chain(get_common_helpers())
761 .chain(get_current_task_helpers())
762 .collect()
763 }
764}
765
766pub trait CgroupSockOptProgramContext:
769 MapsProgramContext + CurrentTaskProgramContext + ReturnValueProgramContext + SkStorageProgramContext
770{
771 fn get_helpers() -> HelperSet<Self> {
772 [
773 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
774 (bpf_func_id_BPF_FUNC_set_retval, EbpfHelperImpl(bpf_set_retval)),
775 (bpf_func_id_BPF_FUNC_get_retval, EbpfHelperImpl(bpf_get_retval)),
776 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
777 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
778 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
779 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
780 ]
781 .into_iter()
782 .chain(get_common_helpers())
783 .chain(get_current_task_helpers())
784 .collect()
785 }
786}
787
788pub trait SocketFilterProgramContext:
791 MapsProgramContext
792 + SocketUidProgramContext
793 + SocketCookieProgramContext
794 + SkbLoadBytesProgramContext
795{
796 fn get_helpers() -> HelperSet<Self> {
797 vec![
798 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
799 (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid)),
800 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
801 (bpf_func_id_BPF_FUNC_skb_load_bytes, EbpfHelperImpl(bpf_skb_load_bytes)),
802 (
803 bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
804 EbpfHelperImpl(bpf_skb_load_bytes_relative),
805 ),
806 ]
807 .into_iter()
808 .chain(get_common_helpers())
809 .collect()
810 }
811}
812
813pub trait CgroupSkbProgramContext:
816 MapsProgramContext
817 + SocketUidProgramContext
818 + SocketCookieProgramContext
819 + SkbLoadBytesProgramContext
820 + SkStorageProgramContext
821{
822 fn get_helpers() -> HelperSet<Self> {
823 vec![
824 (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
825 (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid)),
826 (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
827 (bpf_func_id_BPF_FUNC_skb_load_bytes, EbpfHelperImpl(bpf_skb_load_bytes)),
828 (
829 bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
830 EbpfHelperImpl(bpf_skb_load_bytes_relative),
831 ),
832 (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
833 (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
834 (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
835 (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
836 (bpf_func_id_BPF_FUNC_sk_fullsock, EbpfHelperImpl(bpf_sk_fullsock)),
837 ]
838 .into_iter()
839 .chain(get_common_helpers())
840 .collect()
841 }
842}
843
844#[macro_export]
856macro_rules! ebpf_program_context_type {
857 ($context:ty, $subtrait:ty) => {
858 impl $subtrait for $context {}
859 ebpf::static_helper_set!($context, <$context as $subtrait>::get_helpers());
860 };
861}
862
863#[cfg(test)]
864mod tests {
865 use super::*;
866 use crate::maps::{Map, PinnedMap};
867 use ebpf::{BpfValue, EbpfProgramContext, FromBpfValue, MapFlags, MapSchema};
868 use linux_uapi::{BPF_SK_STORAGE_GET_F_CREATE, bpf_map_type_BPF_MAP_TYPE_SK_STORAGE};
869
870 struct MockSocket {
871 cookie: u64,
872 }
873 impl SocketRef for MockSocket {
874 fn get_socket_cookie(&self) -> Option<u64> {
875 Some(self.cookie)
876 }
877 fn get_socket_uid(&self) -> Option<uid_t> {
878 Some(0)
879 }
880 }
881 impl<'a> FromBpfValue<TestRunContext<'a>> for MockSocket {
882 unsafe fn from_bpf_value(_context: &mut TestRunContext<'a>, value: BpfValue) -> Self {
883 Self { cookie: value.as_u64() }
884 }
885 }
886
887 struct TestRunContext<'a> {
888 map_refs: Vec<MapValueRef<'a>>,
889 }
890 impl<'a> BpfSockContext for TestRunContext<'a> {
891 type BpfSockRef = MockSocket;
892 }
893 impl<'a> MapsContext<'a> for TestRunContext<'a> {
894 fn on_map_access(&mut self, _map: &Map) {}
895 fn add_value_ref(&mut self, map_ref: MapValueRef<'a>) {
896 self.map_refs.push(map_ref);
897 }
898 }
899
900 struct TestContext;
901 impl EbpfProgramContext for TestContext {
902 type RunContext<'a> = TestRunContext<'a>;
903 type Packet<'a> = ();
904 type Arg1<'a> = ();
905 type Arg2<'a> = ();
906 type Arg3<'a> = ();
907 type Arg4<'a> = ();
908 type Arg5<'a> = ();
909 type Map = PinnedMap;
910 }
911
912 #[fuchsia::test]
913 fn test_sk_storage_get_uaf() {
914 let schema = MapSchema {
915 map_type: bpf_map_type_BPF_MAP_TYPE_SK_STORAGE,
916 key_size: 4,
917 value_size: 8,
918 max_entries: 0,
919 flags: MapFlags::NoPrealloc,
920 };
921 let map = Map::new(schema, "test").unwrap();
922 let map_value = BpfValue::from(&*map as *const Map);
923
924 let mut context = TestRunContext { map_refs: vec![] };
925
926 let sk_value1 = BpfValue::from(42u64);
928 let init_value1 = [0x11u8; 8];
929 let init_value_ptr1 = BpfValue::from(init_value1.as_ptr());
930 let flags = BpfValue::from(BPF_SK_STORAGE_GET_F_CREATE as u64);
931
932 let ptr1 = bpf_sk_storage_get::<TestContext>(
933 &mut context,
934 map_value,
935 sk_value1,
936 init_value_ptr1,
937 flags,
938 BpfValue::default(),
939 );
940 assert!(!ptr1.is_zero());
941
942 unsafe {
945 assert_eq!(*(ptr1.as_ptr::<u64>()), 0x1111111111111111);
946 }
947
948 let key_bytes = 42u64.to_ne_bytes();
950 map.delete(&key_bytes).unwrap();
951
952 let sk_value2 = BpfValue::from(43u64);
955 let init_value2 = [0x22u8; 8];
956 let init_value_ptr2 = BpfValue::from(init_value2.as_ptr());
957
958 let ptr2 = bpf_sk_storage_get::<TestContext>(
959 &mut context,
960 map_value,
961 sk_value2,
962 init_value_ptr2,
963 flags,
964 BpfValue::default(),
965 );
966 assert!(!ptr2.is_zero());
967
968 unsafe {
974 assert_eq!(*(ptr1.as_ptr::<u64>()), 0x1111111111111111);
975 }
976 }
977
978 #[fuchsia::test]
979 fn test_sk_storage_get_uaf_query() {
980 let schema = MapSchema {
981 map_type: bpf_map_type_BPF_MAP_TYPE_SK_STORAGE,
982 key_size: 4,
983 value_size: 8,
984 max_entries: 0,
985 flags: MapFlags::NoPrealloc,
986 };
987 let map = Map::new(schema, "test").unwrap();
988 let map_value = BpfValue::from(&*map as *const Map);
989
990 let mut context = TestRunContext { map_refs: vec![] };
991
992 let sk_value1 = BpfValue::from(42u64);
994 let init_value1 = [0x11u8; 8];
995 let init_value_ptr1 = BpfValue::from(init_value1.as_ptr());
996 let flags = BpfValue::from(BPF_SK_STORAGE_GET_F_CREATE as u64);
997
998 let ptr1 = bpf_sk_storage_get::<TestContext>(
999 &mut context,
1000 map_value,
1001 sk_value1,
1002 init_value_ptr1,
1003 flags,
1004 BpfValue::default(),
1005 );
1006 assert!(!ptr1.is_zero());
1007
1008 context.map_refs.clear();
1011
1012 let ptr1_query = bpf_sk_storage_get::<TestContext>(
1014 &mut context,
1015 map_value,
1016 sk_value1,
1017 BpfValue::default(),
1018 BpfValue::default(),
1019 BpfValue::default(),
1020 );
1021 assert_eq!(ptr1.as_u64(), ptr1_query.as_u64());
1022
1023 let key_bytes = 42u64.to_ne_bytes();
1025 map.delete(&key_bytes).unwrap();
1026
1027 let sk_value2 = BpfValue::from(43u64);
1031 let init_value2 = [0x22u8; 8];
1032 let init_value_ptr2 = BpfValue::from(init_value2.as_ptr());
1033
1034 let ptr2 = bpf_sk_storage_get::<TestContext>(
1035 &mut context,
1036 map_value,
1037 sk_value2,
1038 init_value_ptr2,
1039 flags,
1040 BpfValue::default(),
1041 );
1042 assert!(!ptr2.is_zero());
1043
1044 unsafe {
1049 assert_eq!(*(ptr1_query.as_ptr::<u64>()), 0x1111111111111111);
1050 }
1051 }
1052
1053 #[fuchsia::test]
1062 fn test_probe_read_user_zeroes_destination() {
1063 let mut context = TestRunContext { map_refs: vec![] };
1064
1065 let mut dst = [0xAAu8; 8];
1067 let ret = bpf_probe_read_user::<TestContext>(
1068 &mut context,
1069 BpfValue::from(dst.as_mut_ptr()),
1070 BpfValue::from(dst.len() as u64),
1071 BpfValue::default(),
1072 BpfValue::default(),
1073 BpfValue::default(),
1074 );
1075 assert_eq!(ret.as_u64(), 0);
1076 assert_eq!(dst, [0u8; 8], "probe_read_user left the destination uninitialized");
1077
1078 let mut dst_str = [0xBBu8; 8];
1079 let _ = bpf_probe_read_user_str::<TestContext>(
1080 &mut context,
1081 BpfValue::from(dst_str.as_mut_ptr()),
1082 BpfValue::from(dst_str.len() as u64),
1083 BpfValue::default(),
1084 BpfValue::default(),
1085 BpfValue::default(),
1086 );
1087 assert_eq!(dst_str, [0u8; 8], "probe_read_user_str left the destination uninitialized");
1088 }
1089}