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