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