Skip to main content

ebpf_api/
helpers.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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 std::slice;
29use zerocopy::IntoBytes as _;
30
31pub trait MapsContext<'a> {
32    fn on_map_access(&mut self, map: &Map);
33    fn add_value_ref(&mut self, map_ref: MapValueRef<'a>);
34}
35
36pub trait MapsProgramContext: EbpfProgramContext {
37    fn on_map_access(context: &mut Self::RunContext<'_>, map: &Map);
38    fn add_value_ref<'a>(context: &mut Self::RunContext<'a>, map_ref: MapValueRef<'a>);
39}
40
41impl<C: EbpfProgramContext> MapsProgramContext for C
42where
43    for<'a> C::RunContext<'a>: MapsContext<'a>,
44{
45    fn on_map_access(context: &mut Self::RunContext<'_>, map: &Map) {
46        context.on_map_access(map);
47    }
48
49    fn add_value_ref<'a>(context: &mut Self::RunContext<'a>, map_ref: MapValueRef<'a>) {
50        context.add_value_ref(map_ref);
51    }
52}
53
54fn bpf_map_lookup_elem<'a, C: MapsProgramContext>(
55    context: &mut C::RunContext<'a>,
56    map: BpfValue,
57    key: BpfValue,
58    _: BpfValue,
59    _: BpfValue,
60    _: BpfValue,
61) -> BpfValue {
62    // SAFETY: The `map` must be a reference to a `Map` object kept alive by the program itself.
63    let map: &Map = unsafe { &*map.as_ptr::<Map>() };
64
65    // SAFETY: safety is ensured by the verifier.
66    let key = unsafe { EbpfBufferPtr::new(key.as_ptr::<u8>(), map.schema.key_size as usize) };
67    let key: MapKey = key.load();
68
69    C::on_map_access(context, map);
70
71    let Some(value_ref) = map.lookup(&key) else {
72        return BpfValue::default();
73    };
74
75    let result: BpfValue = value_ref.ptr().raw_ptr().into();
76
77    // If this is a map with ref-counted elements then save the reference for
78    // the lifetime of the program.
79    if value_ref.is_ref_counted() {
80        C::add_value_ref(context, value_ref);
81    }
82
83    result
84}
85
86fn bpf_map_update_elem<C: MapsProgramContext>(
87    context: &mut C::RunContext<'_>,
88    map: BpfValue,
89    key: BpfValue,
90    value: BpfValue,
91    flags: BpfValue,
92    _: BpfValue,
93) -> BpfValue {
94    // SAFETY: The `map` must be a reference to a `Map` object kept alive by the program itself.
95    let map: &Map = unsafe { &*map.as_ptr::<Map>() };
96
97    // TODO(https://fxbug.dev/496639039): This should be checked by the verifier.
98    if map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE {
99        return BpfValue::default();
100    }
101
102    // SAFETY: safety is ensured by the verifier.
103    let key = unsafe { EbpfBufferPtr::new(key.as_ptr::<u8>(), map.schema.key_size as usize) };
104    let key: MapKey = key.load();
105
106    // SAFETY: safety is ensured by the verifier.
107    let value = unsafe { EbpfBufferPtr::new(value.as_ptr::<u8>(), map.schema.value_size as usize) };
108    let flags = flags.as_u64();
109
110    C::on_map_access(context, map);
111
112    map.update(&key, value, flags).map(|_| 0).unwrap_or(u64::MAX).into()
113}
114
115fn bpf_map_delete_elem<C: MapsProgramContext>(
116    context: &mut C::RunContext<'_>,
117    map: BpfValue,
118    key: BpfValue,
119    _: BpfValue,
120    _: BpfValue,
121    _: BpfValue,
122) -> BpfValue {
123    // SAFETY: The `map` must be a reference to a `Map` object kept alive by the program itself.
124    let map: &Map = unsafe { &*map.as_ptr::<Map>() };
125
126    // TODO(https://fxbug.dev/496639039): This should be checked by the verifier.
127    if map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE {
128        return BpfValue::default();
129    }
130
131    // SAFETY: safety is ensured by the verifier.
132    let key = unsafe { EbpfBufferPtr::new(key.as_ptr::<u8>(), map.schema.key_size as usize) };
133    let key: MapKey = key.load();
134
135    C::on_map_access(context, map);
136
137    map.delete(&key).map(|_| 0).unwrap_or(u64::MAX).into()
138}
139
140fn bpf_trace_printk<C: EbpfProgramContext>(
141    _context: &mut C::RunContext<'_>,
142    _fmt: BpfValue,
143    _fmt_size: BpfValue,
144    _: BpfValue,
145    _: BpfValue,
146    _: BpfValue,
147) -> BpfValue {
148    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_trace_printk");
149    0.into()
150}
151
152fn bpf_ktime_get_ns<C: EbpfProgramContext>(
153    _context: &mut C::RunContext<'_>,
154    _: BpfValue,
155    _: BpfValue,
156    _: BpfValue,
157    _: BpfValue,
158    _: BpfValue,
159) -> BpfValue {
160    zx::MonotonicInstant::get().into_nanos().into()
161}
162
163fn bpf_ringbuf_reserve<C: EbpfProgramContext>(
164    _context: &mut C::RunContext<'_>,
165    map: BpfValue,
166    size: BpfValue,
167    flags: BpfValue,
168    _: BpfValue,
169    _: BpfValue,
170) -> BpfValue {
171    // SAFETY: The safety of the operation is ensured by the bpf verifier. The `map` must be a
172    // reference to a `Map` object kept alive by the program itself.
173    let map: &Map = unsafe { &*map.as_ptr::<Map>() };
174
175    // Map type is checked by the verifier.
176    assert!(map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_RINGBUF);
177
178    let size = u32::from(size);
179    let flags = u64::from(flags);
180    map.ringbuf_reserve(size, flags).map(BpfValue::from).unwrap_or_else(|_| BpfValue::default())
181}
182
183fn bpf_ringbuf_submit<C: EbpfProgramContext>(
184    _context: &mut C::RunContext<'_>,
185    data: BpfValue,
186    flags: BpfValue,
187    _: BpfValue,
188    _: BpfValue,
189    _: BpfValue,
190) -> BpfValue {
191    let flags = RingBufferWakeupPolicy::from(u32::from(flags));
192
193    // SAFETY: The safety of the operation is ensured by the bpf verifier. The data has to come from
194    // the result of a reserve call.
195    unsafe {
196        RingBuffer::submit(u64::from(data), flags);
197    }
198    0.into()
199}
200
201fn bpf_ringbuf_discard<C: EbpfProgramContext>(
202    _context: &mut C::RunContext<'_>,
203    data: BpfValue,
204    flags: BpfValue,
205    _: BpfValue,
206    _: BpfValue,
207    _: BpfValue,
208) -> BpfValue {
209    let flags = RingBufferWakeupPolicy::from(u32::from(flags));
210
211    // SAFETY: The safety of the operation is ensured by the bpf verifier. The data has to come from
212    // the result of a reserve call.
213    unsafe {
214        RingBuffer::discard(u64::from(data), flags);
215    }
216    0.into()
217}
218
219fn bpf_ktime_get_boot_ns<C: EbpfProgramContext>(
220    _context: &mut C::RunContext<'_>,
221    _: BpfValue,
222    _: BpfValue,
223    _: BpfValue,
224    _: BpfValue,
225    _: BpfValue,
226) -> BpfValue {
227    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_ktime_get_boot_ns");
228    0.into()
229}
230
231fn bpf_probe_read_user<C: EbpfProgramContext>(
232    _context: &mut C::RunContext<'_>,
233    _: BpfValue,
234    _: BpfValue,
235    _: BpfValue,
236    _: BpfValue,
237    _: BpfValue,
238) -> BpfValue {
239    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_probe_read_user");
240    0.into()
241}
242
243fn bpf_probe_read_user_str<C: EbpfProgramContext>(
244    _context: &mut C::RunContext<'_>,
245    _: BpfValue,
246    _: BpfValue,
247    _: BpfValue,
248    _: BpfValue,
249    _: BpfValue,
250) -> BpfValue {
251    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_probe_read_user_str");
252    0.into()
253}
254
255fn bpf_ktime_get_coarse_ns<C: EbpfProgramContext>(
256    _context: &mut C::RunContext<'_>,
257    _: BpfValue,
258    _: BpfValue,
259    _: BpfValue,
260    _: BpfValue,
261    _: BpfValue,
262) -> BpfValue {
263    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_ktime_get_coarse_ns");
264    0.into()
265}
266
267fn bpf_probe_read_str<C: EbpfProgramContext>(
268    _context: &mut C::RunContext<'_>,
269    _: BpfValue,
270    _: BpfValue,
271    _: BpfValue,
272    _: BpfValue,
273    _: BpfValue,
274) -> BpfValue {
275    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_probe_read_str");
276    0.into()
277}
278
279fn bpf_get_smp_processor_id<C: EbpfProgramContext>(
280    _context: &mut C::RunContext<'_>,
281    _: BpfValue,
282    _: BpfValue,
283    _: BpfValue,
284    _: BpfValue,
285    _: BpfValue,
286) -> BpfValue {
287    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_get_smp_processor_id");
288    0.into()
289}
290
291pub trait CurrentTaskContext {
292    fn get_uid_gid(&self) -> (uid_t, gid_t);
293    fn get_tid_tgid(&self) -> (pid_t, pid_t);
294}
295
296pub trait CurrentTaskProgramContext: EbpfProgramContext {
297    fn get_uid_gid<'a>(context: &mut Self::RunContext<'a>) -> (uid_t, gid_t);
298    fn get_tid_tgid<'a>(context: &mut Self::RunContext<'a>) -> (pid_t, pid_t);
299}
300
301impl<C: EbpfProgramContext> CurrentTaskProgramContext for C
302where
303    for<'a> C::RunContext<'a>: CurrentTaskContext,
304{
305    fn get_uid_gid<'a>(context: &mut Self::RunContext<'a>) -> (uid_t, gid_t) {
306        context.get_uid_gid()
307    }
308    fn get_tid_tgid<'a>(context: &mut Self::RunContext<'a>) -> (pid_t, pid_t) {
309        context.get_tid_tgid()
310    }
311}
312
313fn bpf_get_current_uid_gid<C: CurrentTaskProgramContext>(
314    context: &mut C::RunContext<'_>,
315    _: BpfValue,
316    _: BpfValue,
317    _: BpfValue,
318    _: BpfValue,
319    _: BpfValue,
320) -> BpfValue {
321    let (uid, gid) = C::get_uid_gid(context);
322    (uid as u64 | (gid as u64) << 32).into()
323}
324
325fn bpf_get_current_pid_tgid<C: CurrentTaskProgramContext>(
326    context: &mut C::RunContext<'_>,
327    _: BpfValue,
328    _: BpfValue,
329    _: BpfValue,
330    _: BpfValue,
331    _: BpfValue,
332) -> BpfValue {
333    let (pid, tgid) = C::get_tid_tgid(context);
334    (pid as u64 | (tgid as u64) << 32).into()
335}
336
337// Trait for `EbpfProgramContext` where the first argument is a `SocketRef`,
338// i.e. it references a socket.
339pub trait Arg1IsSocketProgramContext: EbpfProgramContext {
340    type Arg1AsSocket<'a>: FromBpfValue<Self::RunContext<'a>> + SocketRef;
341}
342
343impl<C> Arg1IsSocketProgramContext for C
344where
345    C: EbpfProgramContext,
346    for<'a> Self::Arg1<'a>: FromBpfValue<Self::RunContext<'a>> + SocketRef,
347{
348    type Arg1AsSocket<'a> = Self::Arg1<'a>;
349}
350
351// Marker trait for `EbpfProgramContext` that supports `bpf_get_socket_uid`.
352pub trait SocketCookieProgramContext: Arg1IsSocketProgramContext {}
353impl<C> SocketCookieProgramContext for C where C: Arg1IsSocketProgramContext {}
354
355fn bpf_get_socket_cookie<'a, C: SocketCookieProgramContext>(
356    context: &mut C::RunContext<'a>,
357    arg1: BpfValue,
358    _: BpfValue,
359    _: BpfValue,
360    _: BpfValue,
361    _: BpfValue,
362) -> BpfValue {
363    // SAFETY: Verifier checks that the argument points at the value that
364    // that's passed as the first argument.
365    let arg1_as_socket = unsafe { C::Arg1AsSocket::from_bpf_value(context, arg1) };
366    arg1_as_socket.get_socket_cookie().unwrap_or(0).into()
367}
368
369pub trait SocketRef {
370    fn get_socket_cookie(&self) -> Option<u64>;
371    fn get_socket_uid(&self) -> Option<uid_t>;
372}
373
374// A trait for eBPF run context with `bpf_sock` pointers.
375pub trait BpfSockContext: Sized {
376    type BpfSockRef: SocketRef + FromBpfValue<Self>;
377}
378
379pub trait SkStorageProgramContext: EbpfProgramContext {
380    type BpfSockRef<'a>: SocketRef + FromBpfValue<Self::RunContext<'a>>;
381}
382
383impl<C> SkStorageProgramContext for C
384where
385    C: EbpfProgramContext,
386    for<'a> C::RunContext<'a>: BpfSockContext,
387{
388    type BpfSockRef<'a> = <C::RunContext<'a> as BpfSockContext>::BpfSockRef;
389}
390
391#[derive(Copy, Clone, Debug, PartialEq, Eq)]
392pub enum LoadBytesBase {
393    MacHeader,
394    NetworkHeader,
395}
396
397// Marker trait for `EbpfProgramContext` that supports `bpf_get_socket_uid`.
398pub trait SocketUidProgramContext: Arg1IsSocketProgramContext {}
399impl<C> SocketUidProgramContext for C where C: Arg1IsSocketProgramContext {}
400
401fn bpf_get_socket_uid<'a, C: SocketUidProgramContext>(
402    context: &mut C::RunContext<'a>,
403    sk_buf: BpfValue,
404    _: BpfValue,
405    _: BpfValue,
406    _: BpfValue,
407    _: BpfValue,
408) -> BpfValue {
409    const OVERFLOW_UID: uid_t = 65534;
410    // SAFETY: Verifier checks that the first argument points at a `__sk_buff`.
411    let sk_buf = unsafe { C::Arg1AsSocket::from_bpf_value(context, sk_buf) };
412    sk_buf.get_socket_uid().unwrap_or(OVERFLOW_UID).into()
413}
414
415// Trait for packets that support `bpf_load_bytes_relative`.
416pub trait PacketWithLoadBytes {
417    fn load_bytes_relative(&self, base: LoadBytesBase, offset: usize, buf: &mut [u8]) -> i64;
418}
419
420// Trait for `EbpfProgramContext` that supports `bpf_load_bytes_relative`.
421pub trait SkbLoadBytesProgramContext: EbpfProgramContext {
422    fn skb_load_bytes_relative<'a>(
423        context: &mut Self::RunContext<'a>,
424        sk_buf: BpfValue,
425        base: LoadBytesBase,
426        offset: usize,
427        buf: &mut [u8],
428    ) -> i64;
429}
430
431impl<C: EbpfProgramContext> SkbLoadBytesProgramContext for C
432where
433    for<'b> C::Arg1<'b>: FromBpfValue<C::RunContext<'b>>,
434    for<'b> C::Arg1<'b>: PacketWithLoadBytes,
435{
436    fn skb_load_bytes_relative<'a>(
437        context: &mut Self::RunContext<'a>,
438        sk_buf: BpfValue,
439        base: LoadBytesBase,
440        offset: usize,
441        buf: &mut [u8],
442    ) -> i64 {
443        // SAFETY: Verifier checks that the argument points at the same value
444        // that was passed to the program as the first argument.
445        let sk_buf = unsafe { C::Arg1::from_bpf_value(context, sk_buf) };
446        sk_buf.load_bytes_relative(base, offset, buf)
447    }
448}
449
450fn bpf_skb_load_bytes<'a, C: SkbLoadBytesProgramContext>(
451    context: &mut C::RunContext<'a>,
452    sk_buf: BpfValue,
453    offset: BpfValue,
454    to: BpfValue,
455    len: BpfValue,
456    _: BpfValue,
457) -> BpfValue {
458    let base = LoadBytesBase::NetworkHeader;
459
460    let Ok(offset) = offset.as_u64().try_into() else {
461        return u64::MAX.into();
462    };
463
464    // SAFETY: The verifier ensures that `to` points to a valid buffer of at
465    // least `len` bytes that the eBPF program has permission to access.
466    let buf = unsafe { slice::from_raw_parts_mut(to.as_ptr::<u8>(), len.as_u64() as usize) };
467
468    C::skb_load_bytes_relative(context, sk_buf, base, offset, buf).into()
469}
470
471fn bpf_skb_load_bytes_relative<'a, C: SkbLoadBytesProgramContext>(
472    context: &mut C::RunContext<'a>,
473    sk_buf: BpfValue,
474    offset: BpfValue,
475    to: BpfValue,
476    len: BpfValue,
477    start_header: BpfValue,
478) -> BpfValue {
479    let base = match start_header.as_u32() {
480        0 => LoadBytesBase::MacHeader,
481        1 => LoadBytesBase::NetworkHeader,
482        _ => return u64::MAX.into(),
483    };
484
485    let Ok(offset) = offset.as_u64().try_into() else {
486        return u64::MAX.into();
487    };
488
489    // SAFETY: The verifier ensures that `to` points to a valid buffer of at
490    // least `len` bytes that the eBPF program has permission to access.
491    let buf = unsafe { slice::from_raw_parts_mut(to.as_ptr::<u8>(), len.as_u64() as usize) };
492
493    C::skb_load_bytes_relative(context, sk_buf, base, offset, buf).into()
494}
495
496fn bpf_sk_storage_get<'a, C: SkStorageProgramContext + MapsProgramContext>(
497    context: &mut C::RunContext<'a>,
498    map: BpfValue,
499    sk: BpfValue,
500    value: BpfValue,
501    flags: BpfValue,
502    _: BpfValue,
503) -> BpfValue {
504    if sk.is_zero() {
505        return BpfValue::default();
506    }
507
508    // SAFETY: Verifier ensures that `sk` is either null or a pointer to
509    // `bpf_sock`. The null case is checked above.
510    let bpf_sock = unsafe { C::BpfSockRef::from_bpf_value(context, sk) };
511
512    // Use socket cookie to identify the socket in the map.
513    let Some(socket_id) = bpf_sock.get_socket_cookie() else {
514        return BpfValue::default();
515    };
516
517    let key = socket_id.as_bytes();
518
519    // SAFETY: The `map` must be a reference to a `Map` object kept alive by the program itself.
520    let map: &Map = unsafe { &*map.as_ptr::<Map>() };
521
522    // Checked by the verifier.
523    assert!(map.schema.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE);
524
525    C::on_map_access(context, map);
526
527    if let Some(value_ref) = map.lookup(key) {
528        let result: BpfValue = value_ref.ptr().raw_ptr().into();
529        return result;
530    }
531
532    if flags.as_u32() & BPF_SK_STORAGE_GET_F_CREATE != 0 {
533        let mut vec;
534        let init_val = if value.as_u64() == 0 {
535            vec = SmallVec::<[u8; 128]>::new();
536            vec.resize(map.schema.value_size as usize, 0);
537            (&mut vec[..]).into()
538        } else {
539            // SAFETY: The verifier ensures that `value` points to a valid buffer.
540            unsafe { EbpfBufferPtr::new(value.as_ptr::<u8>(), map.schema.value_size as usize) }
541        };
542
543        let r = map.update(key, init_val, 0);
544        if r.is_ok() {
545            if let Some(value_ref) = map.lookup(key) {
546                let result: BpfValue = value_ref.ptr().raw_ptr().into();
547                return result;
548            }
549        }
550    }
551
552    BpfValue::default()
553}
554
555fn bpf_sk_fullsock<C: EbpfProgramContext>(
556    _context: &mut C::RunContext<'_>,
557    _: BpfValue,
558    _: BpfValue,
559    _: BpfValue,
560    _: BpfValue,
561    _: BpfValue,
562) -> BpfValue {
563    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_sk_fullsock");
564    0.into()
565}
566
567pub trait ReturnValueContext {
568    fn set_retval(&mut self, value: i32) -> i32;
569    fn get_retval(&self) -> i32;
570}
571
572pub trait ReturnValueProgramContext: EbpfProgramContext {
573    fn set_retval<'a>(context: &mut Self::RunContext<'a>, value: i32) -> i32;
574    fn get_retval<'a>(context: &mut Self::RunContext<'a>) -> i32;
575}
576
577impl<C: EbpfProgramContext> ReturnValueProgramContext for C
578where
579    for<'a> C::RunContext<'a>: ReturnValueContext,
580{
581    fn set_retval<'a>(context: &mut Self::RunContext<'a>, value: i32) -> i32 {
582        context.set_retval(value)
583    }
584    fn get_retval<'a>(context: &mut Self::RunContext<'a>) -> i32 {
585        context.get_retval()
586    }
587}
588
589fn bpf_set_retval<C: ReturnValueProgramContext>(
590    context: &mut C::RunContext<'_>,
591    value: BpfValue,
592    _: BpfValue,
593    _: BpfValue,
594    _: BpfValue,
595    _: BpfValue,
596) -> BpfValue {
597    C::set_retval(context, value.as_i32()).into()
598}
599
600fn bpf_get_retval<C: ReturnValueProgramContext>(
601    context: &mut C::RunContext<'_>,
602    _: BpfValue,
603    _: BpfValue,
604    _: BpfValue,
605    _: BpfValue,
606    _: BpfValue,
607) -> BpfValue {
608    C::get_retval(context).into()
609}
610
611fn bpf_sk_lookup_tcp<C: EbpfProgramContext>(
612    _context: &mut C::RunContext<'_>,
613    _: BpfValue,
614    _: BpfValue,
615    _: BpfValue,
616    _: BpfValue,
617    _: BpfValue,
618) -> BpfValue {
619    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_sk_lookup_tcp");
620    0.into()
621}
622
623fn bpf_sk_lookup_udp<C: EbpfProgramContext>(
624    _context: &mut C::RunContext<'_>,
625    _: BpfValue,
626    _: BpfValue,
627    _: BpfValue,
628    _: BpfValue,
629    _: BpfValue,
630) -> BpfValue {
631    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_sk_lookup_udp");
632    0.into()
633}
634
635fn bpf_sk_release<C: EbpfProgramContext>(
636    _context: &mut C::RunContext<'_>,
637    _: BpfValue,
638    _: BpfValue,
639    _: BpfValue,
640    _: BpfValue,
641    _: BpfValue,
642) -> BpfValue {
643    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_sk_release");
644    0.into()
645}
646
647fn bpf_get_netns_cookie<C: EbpfProgramContext>(
648    _context: &mut C::RunContext<'_>,
649    _: BpfValue,
650    _: BpfValue,
651    _: BpfValue,
652    _: BpfValue,
653    _: BpfValue,
654) -> BpfValue {
655    track_stub!(TODO("https://fxbug.dev/287120494"), "bpf_get_netns_cookie");
656    const DEFAULT_NETWORK_NAMESPACE_COOKIE: u64 = 1;
657    DEFAULT_NETWORK_NAMESPACE_COOKIE.into()
658}
659
660fn get_common_helpers<C: MapsProgramContext>() -> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
661    [
662        (bpf_func_id_BPF_FUNC_ktime_get_boot_ns, EbpfHelperImpl(bpf_ktime_get_boot_ns)),
663        (bpf_func_id_BPF_FUNC_ktime_get_coarse_ns, EbpfHelperImpl(bpf_ktime_get_coarse_ns)),
664        (bpf_func_id_BPF_FUNC_ktime_get_ns, EbpfHelperImpl(bpf_ktime_get_ns)),
665        (bpf_func_id_BPF_FUNC_map_delete_elem, EbpfHelperImpl(bpf_map_delete_elem)),
666        (bpf_func_id_BPF_FUNC_map_lookup_elem, EbpfHelperImpl(bpf_map_lookup_elem)),
667        (bpf_func_id_BPF_FUNC_map_update_elem, EbpfHelperImpl(bpf_map_update_elem)),
668        (bpf_func_id_BPF_FUNC_probe_read_str, EbpfHelperImpl(bpf_probe_read_str)),
669        (bpf_func_id_BPF_FUNC_probe_read_user, EbpfHelperImpl(bpf_probe_read_user)),
670        (bpf_func_id_BPF_FUNC_probe_read_user_str, EbpfHelperImpl(bpf_probe_read_user_str)),
671        (bpf_func_id_BPF_FUNC_ringbuf_discard, EbpfHelperImpl(bpf_ringbuf_discard)),
672        (bpf_func_id_BPF_FUNC_ringbuf_reserve, EbpfHelperImpl(bpf_ringbuf_reserve)),
673        (bpf_func_id_BPF_FUNC_ringbuf_submit, EbpfHelperImpl(bpf_ringbuf_submit)),
674        (bpf_func_id_BPF_FUNC_trace_printk, EbpfHelperImpl(bpf_trace_printk)),
675        (bpf_func_id_BPF_FUNC_get_smp_processor_id, EbpfHelperImpl(bpf_get_smp_processor_id)),
676    ]
677    .into_iter()
678}
679
680/// Returns helper implementations that depend on `CurrentTask`.
681fn get_current_task_helpers<C: CurrentTaskProgramContext>()
682-> impl Iterator<Item = (u32, EbpfHelperImpl<C>)> {
683    [
684        (bpf_func_id_BPF_FUNC_get_current_uid_gid, EbpfHelperImpl(bpf_get_current_uid_gid)),
685        (bpf_func_id_BPF_FUNC_get_current_pid_tgid, EbpfHelperImpl(bpf_get_current_pid_tgid)),
686    ]
687    .into_iter()
688}
689
690// Trait for `EbpfProgramContext` implementations that are used for
691// `BPF_PROG_TYPE_CGROUP_SOCK` programs.
692pub trait CgroupSockProgramContext:
693    MapsProgramContext
694    + SocketCookieProgramContext
695    + CurrentTaskProgramContext
696    + SkStorageProgramContext
697{
698    fn get_helpers() -> HelperSet<Self> {
699        [
700            (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
701            (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
702            (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
703            (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
704            (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
705            (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
706        ]
707        .into_iter()
708        .chain(get_common_helpers())
709        .chain(get_current_task_helpers())
710        .collect()
711    }
712}
713
714// Trait for `EbpfProgramContext` implementations that are used for
715// `BPF_PROG_TYPE_CGROUP_SOCKADDR` programs.
716pub trait CgroupSockAddrProgramContext:
717    MapsProgramContext
718    + SocketCookieProgramContext
719    + CurrentTaskProgramContext
720    + SkStorageProgramContext
721{
722    fn get_helpers() -> HelperSet<Self> {
723        [
724            (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
725            (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
726            (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
727            (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
728            (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
729            (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
730        ]
731        .into_iter()
732        .chain(get_common_helpers())
733        .chain(get_current_task_helpers())
734        .collect()
735    }
736}
737
738// Trait for `EbpfProgramContext` implementations that are used for
739// `BPF_PROG_TYPE_CGROUP_SOCKOPT` programs.
740pub trait CgroupSockOptProgramContext:
741    MapsProgramContext + CurrentTaskProgramContext + ReturnValueProgramContext + SkStorageProgramContext
742{
743    fn get_helpers() -> HelperSet<Self> {
744        [
745            (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
746            (bpf_func_id_BPF_FUNC_set_retval, EbpfHelperImpl(bpf_set_retval)),
747            (bpf_func_id_BPF_FUNC_get_retval, EbpfHelperImpl(bpf_get_retval)),
748            (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
749            (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
750            (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
751            (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
752        ]
753        .into_iter()
754        .chain(get_common_helpers())
755        .chain(get_current_task_helpers())
756        .collect()
757    }
758}
759
760// Trait for `EbpfProgramContext` implementations that are used for
761// `BPF_PROG_TYPE_SOCKET_FILTER` programs.
762pub trait SocketFilterProgramContext:
763    MapsProgramContext
764    + SocketUidProgramContext
765    + SocketCookieProgramContext
766    + SkbLoadBytesProgramContext
767{
768    fn get_helpers() -> HelperSet<Self> {
769        vec![
770            (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
771            (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid)),
772            (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
773            (bpf_func_id_BPF_FUNC_skb_load_bytes, EbpfHelperImpl(bpf_skb_load_bytes)),
774            (
775                bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
776                EbpfHelperImpl(bpf_skb_load_bytes_relative),
777            ),
778        ]
779        .into_iter()
780        .chain(get_common_helpers())
781        .collect()
782    }
783}
784
785// Trait for `EbpfProgramContext` implementations that are used for
786// `BPF_PROG_TYPE_CGROUP_SKB` programs.
787pub trait CgroupSkbProgramContext:
788    MapsProgramContext
789    + SocketUidProgramContext
790    + SocketCookieProgramContext
791    + SkbLoadBytesProgramContext
792    + SkStorageProgramContext
793{
794    fn get_helpers() -> HelperSet<Self> {
795        vec![
796            (bpf_func_id_BPF_FUNC_get_netns_cookie, EbpfHelperImpl(bpf_get_netns_cookie)),
797            (bpf_func_id_BPF_FUNC_get_socket_uid, EbpfHelperImpl(bpf_get_socket_uid)),
798            (bpf_func_id_BPF_FUNC_get_socket_cookie, EbpfHelperImpl(bpf_get_socket_cookie)),
799            (bpf_func_id_BPF_FUNC_skb_load_bytes, EbpfHelperImpl(bpf_skb_load_bytes)),
800            (
801                bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
802                EbpfHelperImpl(bpf_skb_load_bytes_relative),
803            ),
804            (bpf_func_id_BPF_FUNC_sk_storage_get, EbpfHelperImpl(bpf_sk_storage_get)),
805            (bpf_func_id_BPF_FUNC_sk_lookup_tcp, EbpfHelperImpl(bpf_sk_lookup_tcp)),
806            (bpf_func_id_BPF_FUNC_sk_lookup_udp, EbpfHelperImpl(bpf_sk_lookup_udp)),
807            (bpf_func_id_BPF_FUNC_sk_release, EbpfHelperImpl(bpf_sk_release)),
808            (bpf_func_id_BPF_FUNC_sk_fullsock, EbpfHelperImpl(bpf_sk_fullsock)),
809        ]
810        .into_iter()
811        .chain(get_common_helpers())
812        .collect()
813    }
814}
815
816/// Macro used to declare program type for a `EbpfProgramContext` implementation.
817/// Implements `StaticHelperSet` trait for the context type.
818///
819/// # Example
820///
821/// The following example declares that `MyEbpfProgramContext` is used to run
822/// socket filter programs:
823///
824/// ```
825/// ebpf_program_context_type!(MyEbpfProgramContext, SocketFilterProgramContext);
826/// ```
827#[macro_export]
828macro_rules! ebpf_program_context_type {
829    ($context:ty, $subtrait:ty) => {
830        impl $subtrait for $context {}
831        ebpf::static_helper_set!($context, <$context as $subtrait>::get_helpers());
832    };
833}