1 // `rustdoc` is buggy, claiming that we have some links to private items
2 // when they are actually public.
3 #![allow(rustdoc::private_intra_doc_links)]
4 
5 use std::ffi::c_void;
6 use std::ffi::CStr;
7 use std::ffi::OsStr;
8 use std::marker::PhantomData;
9 use std::mem;
10 use std::mem::size_of;
11 use std::mem::size_of_val;
12 use std::mem::transmute;
13 use std::ops::Deref;
14 use std::os::unix::ffi::OsStrExt as _;
15 use std::os::unix::io::AsFd;
16 use std::os::unix::io::AsRawFd;
17 use std::os::unix::io::BorrowedFd;
18 use std::os::unix::io::FromRawFd;
19 use std::os::unix::io::OwnedFd;
20 use std::path::Path;
21 use std::ptr;
22 use std::ptr::NonNull;
23 use std::slice;
24 
25 use libbpf_sys::bpf_func_id;
26 
27 use crate::util;
28 use crate::util::validate_bpf_ret;
29 use crate::AsRawLibbpf;
30 use crate::Error;
31 use crate::ErrorExt as _;
32 use crate::Link;
33 use crate::Mut;
34 use crate::Result;
35 
36 /// Options to optionally be provided when attaching to a uprobe.
37 #[derive(Clone, Debug, Default)]
38 pub struct UprobeOpts {
39     /// Offset of kernel reference counted USDT semaphore.
40     pub ref_ctr_offset: usize,
41     /// Custom user-provided value accessible through `bpf_get_attach_cookie`.
42     pub cookie: u64,
43     /// uprobe is return probe, invoked at function return time.
44     pub retprobe: bool,
45     /// Function name to attach to.
46     ///
47     /// Could be an unqualified ("abc") or library-qualified "abc@LIBXYZ" name.
48     /// To specify function entry, `func_name` should be set while `func_offset`
49     /// argument to should be 0. To trace an offset within a function, specify
50     /// `func_name` and use `func_offset` argument to specify offset within the
51     /// function. Shared library functions must specify the shared library
52     /// binary_path.
53     pub func_name: String,
54     #[doc(hidden)]
55     pub _non_exhaustive: (),
56 }
57 
58 /// Options to optionally be provided when attaching to a USDT.
59 #[derive(Clone, Debug, Default)]
60 pub struct UsdtOpts {
61     /// Custom user-provided value accessible through `bpf_usdt_cookie`.
62     pub cookie: u64,
63     #[doc(hidden)]
64     pub _non_exhaustive: (),
65 }
66 
67 impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts {
from(opts: UsdtOpts) -> Self68     fn from(opts: UsdtOpts) -> Self {
69         let UsdtOpts {
70             cookie,
71             _non_exhaustive,
72         } = opts;
73         #[allow(clippy::needless_update)]
74         libbpf_sys::bpf_usdt_opts {
75             sz: size_of::<Self>() as _,
76             usdt_cookie: cookie,
77             // bpf_usdt_opts might have padding fields on some platform
78             ..Default::default()
79         }
80     }
81 }
82 
83 /// Options to optionally be provided when attaching to a tracepoint.
84 #[derive(Clone, Debug, Default)]
85 pub struct TracepointOpts {
86     /// Custom user-provided value accessible through `bpf_get_attach_cookie`.
87     pub cookie: u64,
88     #[doc(hidden)]
89     pub _non_exhaustive: (),
90 }
91 
92 impl From<TracepointOpts> for libbpf_sys::bpf_tracepoint_opts {
from(opts: TracepointOpts) -> Self93     fn from(opts: TracepointOpts) -> Self {
94         let TracepointOpts {
95             cookie,
96             _non_exhaustive,
97         } = opts;
98 
99         #[allow(clippy::needless_update)]
100         libbpf_sys::bpf_tracepoint_opts {
101             sz: size_of::<Self>() as _,
102             bpf_cookie: cookie,
103             // bpf_tracepoint_opts might have padding fields on some platform
104             ..Default::default()
105         }
106     }
107 }
108 
109 
110 /// An immutable parsed but not yet loaded BPF program.
111 pub type OpenProgram<'obj> = OpenProgramImpl<'obj>;
112 /// A mutable parsed but not yet loaded BPF program.
113 pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>;
114 
115 /// Represents a parsed but not yet loaded BPF program.
116 ///
117 /// This object exposes operations that need to happen before the program is loaded.
118 #[derive(Debug)]
119 #[repr(transparent)]
120 pub struct OpenProgramImpl<'obj, T = ()> {
121     ptr: NonNull<libbpf_sys::bpf_program>,
122     _phantom: PhantomData<&'obj T>,
123 }
124 
125 // TODO: Document variants.
126 #[allow(missing_docs)]
127 impl<'obj> OpenProgram<'obj> {
128     /// Create a new [`OpenProgram`] from a ptr to a `libbpf_sys::bpf_program`.
new(prog: &'obj libbpf_sys::bpf_program) -> Self129     pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
130         // SAFETY: We inferred the address from a reference, which is always
131         //         valid.
132         Self {
133             ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
134             _phantom: PhantomData,
135         }
136     }
137 
138     // The `ProgramType` of this `OpenProgram`.
prog_type(&self) -> ProgramType139     pub fn prog_type(&self) -> ProgramType {
140         ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
141     }
142 
143     /// Retrieve the name of this `OpenProgram`.
name(&self) -> &OsStr144     pub fn name(&self) -> &OsStr {
145         let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
146         let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
147         // SAFETY: `bpf_program__name` always returns a non-NULL pointer.
148         OsStr::from_bytes(name_c_str.to_bytes())
149     }
150 
151     /// Retrieve the name of the section this `OpenProgram` belongs to.
section(&self) -> &OsStr152     pub fn section(&self) -> &OsStr {
153         // SAFETY: The program is always valid.
154         let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
155         // SAFETY: `bpf_program__section_name` will always return a non-NULL
156         //         pointer.
157         let section_c_str = unsafe { CStr::from_ptr(p) };
158         let section = OsStr::from_bytes(section_c_str.to_bytes());
159         section
160     }
161 
162     /// Returns the number of instructions that form the program.
163     ///
164     /// Note: Keep in mind, libbpf can modify the program's instructions
165     /// and consequently its instruction count, as it processes the BPF object file.
166     /// So [`OpenProgram::insn_cnt`] and [`Program::insn_cnt`] may return different values.
insn_cnt(&self) -> usize167     pub fn insn_cnt(&self) -> usize {
168         unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
169     }
170 
171     /// Gives read-only access to BPF program's underlying BPF instructions.
172     ///
173     /// Keep in mind, libbpf can modify and append/delete BPF program's
174     /// instructions as it processes BPF object file and prepares everything for
175     /// uploading into the kernel. So [`OpenProgram::insns`] and [`Program::insns`] may return
176     /// different sets of instructions. As an example, during BPF object load phase BPF program
177     /// instructions will be CO-RE-relocated, BPF subprograms instructions will be appended, ldimm64
178     /// instructions will have FDs embedded, etc. So instructions returned before load and after it
179     /// might be quite different.
insns(&self) -> &[libbpf_sys::bpf_insn]180     pub fn insns(&self) -> &[libbpf_sys::bpf_insn] {
181         let count = self.insn_cnt();
182         let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
183         unsafe { slice::from_raw_parts(ptr, count) }
184     }
185 }
186 
187 impl<'obj> OpenProgramMut<'obj> {
188     /// Create a new [`OpenProgram`] from a ptr to a `libbpf_sys::bpf_program`.
new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self189     pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
190         Self {
191             ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
192             _phantom: PhantomData,
193         }
194     }
195 
set_prog_type(&mut self, prog_type: ProgramType)196     pub fn set_prog_type(&mut self, prog_type: ProgramType) {
197         let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) };
198         debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
199     }
200 
set_attach_type(&mut self, attach_type: ProgramAttachType)201     pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) {
202         let rc = unsafe {
203             libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32)
204         };
205         debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
206     }
207 
set_ifindex(&mut self, idx: u32)208     pub fn set_ifindex(&mut self, idx: u32) {
209         unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) }
210     }
211 
212     /// Set the log level for the bpf program.
213     ///
214     /// The log level is interpreted by bpf kernel code and interpretation may
215     /// change with newer kernel versions. Refer to the kernel source code for
216     /// details.
217     ///
218     /// In general, a value of `0` disables logging while values `> 0` enables
219     /// it.
set_log_level(&mut self, log_level: u32)220     pub fn set_log_level(&mut self, log_level: u32) {
221         let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) };
222         debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
223     }
224 
225     /// Set whether a bpf program should be automatically loaded by default
226     /// when the bpf object is loaded.
set_autoload(&mut self, autoload: bool)227     pub fn set_autoload(&mut self, autoload: bool) {
228         let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) };
229         debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
230     }
231 
set_attach_target( &mut self, attach_prog_fd: i32, attach_func_name: Option<String>, ) -> Result<()>232     pub fn set_attach_target(
233         &mut self,
234         attach_prog_fd: i32,
235         attach_func_name: Option<String>,
236     ) -> Result<()> {
237         let ret = if let Some(name) = attach_func_name {
238             // NB: we must hold onto a CString otherwise our pointer dangles
239             let name_c = util::str_to_cstring(&name)?;
240             unsafe {
241                 libbpf_sys::bpf_program__set_attach_target(
242                     self.ptr.as_ptr(),
243                     attach_prog_fd,
244                     name_c.as_ptr(),
245                 )
246             }
247         } else {
248             unsafe {
249                 libbpf_sys::bpf_program__set_attach_target(
250                     self.ptr.as_ptr(),
251                     attach_prog_fd,
252                     ptr::null(),
253                 )
254             }
255         };
256         util::parse_ret(ret)
257     }
258 
set_flags(&mut self, flags: u32)259     pub fn set_flags(&mut self, flags: u32) {
260         let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) };
261         debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
262     }
263 }
264 
265 impl<'obj> Deref for OpenProgramMut<'obj> {
266     type Target = OpenProgram<'obj>;
267 
deref(&self) -> &Self::Target268     fn deref(&self) -> &Self::Target {
269         // SAFETY: `OpenProgramImpl` is `repr(transparent)` and so
270         //         in-memory representation of both types is the same.
271         unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) }
272     }
273 }
274 
275 impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> {
276     type LibbpfType = libbpf_sys::bpf_program;
277 
278     /// Retrieve the underlying [`libbpf_sys::bpf_program`].
as_libbpf_object(&self) -> NonNull<Self::LibbpfType>279     fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
280         self.ptr
281     }
282 }
283 
284 /// Type of a [`Program`]. Maps to `enum bpf_prog_type` in kernel uapi.
285 #[non_exhaustive]
286 #[repr(u32)]
287 #[derive(Copy, Clone, Debug)]
288 // TODO: Document variants.
289 #[allow(missing_docs)]
290 pub enum ProgramType {
291     Unspec = 0,
292     SocketFilter,
293     Kprobe,
294     SchedCls,
295     SchedAct,
296     Tracepoint,
297     Xdp,
298     PerfEvent,
299     CgroupSkb,
300     CgroupSock,
301     LwtIn,
302     LwtOut,
303     LwtXmit,
304     SockOps,
305     SkSkb,
306     CgroupDevice,
307     SkMsg,
308     RawTracepoint,
309     CgroupSockAddr,
310     LwtSeg6local,
311     LircMode2,
312     SkReuseport,
313     FlowDissector,
314     CgroupSysctl,
315     RawTracepointWritable,
316     CgroupSockopt,
317     Tracing,
318     StructOps,
319     Ext,
320     Lsm,
321     SkLookup,
322     Syscall,
323     /// See [`MapType::Unknown`][crate::MapType::Unknown]
324     Unknown = u32::MAX,
325 }
326 
327 impl ProgramType {
328     /// Detects if host kernel supports this BPF program type
329     ///
330     /// Make sure the process has required set of CAP_* permissions (or runs as
331     /// root) when performing feature checking.
is_supported(&self) -> Result<bool>332     pub fn is_supported(&self) -> Result<bool> {
333         let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) };
334         match ret {
335             0 => Ok(false),
336             1 => Ok(true),
337             _ => Err(Error::from_raw_os_error(-ret)),
338         }
339     }
340 
341     /// Detects if host kernel supports the use of a given BPF helper from this BPF program type.
342     /// * `helper_id` - BPF helper ID (enum bpf_func_id) to check support for
343     ///
344     /// Make sure the process has required set of CAP_* permissions (or runs as
345     /// root) when performing feature checking.
is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool>346     pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> {
347         let ret =
348             unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) };
349         match ret {
350             0 => Ok(false),
351             1 => Ok(true),
352             _ => Err(Error::from_raw_os_error(-ret)),
353         }
354     }
355 }
356 
357 impl From<u32> for ProgramType {
from(value: u32) -> Self358     fn from(value: u32) -> Self {
359         use ProgramType::*;
360 
361         match value {
362             x if x == Unspec as u32 => Unspec,
363             x if x == SocketFilter as u32 => SocketFilter,
364             x if x == Kprobe as u32 => Kprobe,
365             x if x == SchedCls as u32 => SchedCls,
366             x if x == SchedAct as u32 => SchedAct,
367             x if x == Tracepoint as u32 => Tracepoint,
368             x if x == Xdp as u32 => Xdp,
369             x if x == PerfEvent as u32 => PerfEvent,
370             x if x == CgroupSkb as u32 => CgroupSkb,
371             x if x == CgroupSock as u32 => CgroupSock,
372             x if x == LwtIn as u32 => LwtIn,
373             x if x == LwtOut as u32 => LwtOut,
374             x if x == LwtXmit as u32 => LwtXmit,
375             x if x == SockOps as u32 => SockOps,
376             x if x == SkSkb as u32 => SkSkb,
377             x if x == CgroupDevice as u32 => CgroupDevice,
378             x if x == SkMsg as u32 => SkMsg,
379             x if x == RawTracepoint as u32 => RawTracepoint,
380             x if x == CgroupSockAddr as u32 => CgroupSockAddr,
381             x if x == LwtSeg6local as u32 => LwtSeg6local,
382             x if x == LircMode2 as u32 => LircMode2,
383             x if x == SkReuseport as u32 => SkReuseport,
384             x if x == FlowDissector as u32 => FlowDissector,
385             x if x == CgroupSysctl as u32 => CgroupSysctl,
386             x if x == RawTracepointWritable as u32 => RawTracepointWritable,
387             x if x == CgroupSockopt as u32 => CgroupSockopt,
388             x if x == Tracing as u32 => Tracing,
389             x if x == StructOps as u32 => StructOps,
390             x if x == Ext as u32 => Ext,
391             x if x == Lsm as u32 => Lsm,
392             x if x == SkLookup as u32 => SkLookup,
393             x if x == Syscall as u32 => Syscall,
394             _ => Unknown,
395         }
396     }
397 }
398 
399 /// Attach type of a [`Program`]. Maps to `enum bpf_attach_type` in kernel uapi.
400 #[non_exhaustive]
401 #[repr(u32)]
402 #[derive(Clone, Debug)]
403 // TODO: Document variants.
404 #[allow(missing_docs)]
405 pub enum ProgramAttachType {
406     CgroupInetIngress,
407     CgroupInetEgress,
408     CgroupInetSockCreate,
409     CgroupSockOps,
410     SkSkbStreamParser,
411     SkSkbStreamVerdict,
412     CgroupDevice,
413     SkMsgVerdict,
414     CgroupInet4Bind,
415     CgroupInet6Bind,
416     CgroupInet4Connect,
417     CgroupInet6Connect,
418     CgroupInet4PostBind,
419     CgroupInet6PostBind,
420     CgroupUdp4Sendmsg,
421     CgroupUdp6Sendmsg,
422     LircMode2,
423     FlowDissector,
424     CgroupSysctl,
425     CgroupUdp4Recvmsg,
426     CgroupUdp6Recvmsg,
427     CgroupGetsockopt,
428     CgroupSetsockopt,
429     TraceRawTp,
430     TraceFentry,
431     TraceFexit,
432     ModifyReturn,
433     LsmMac,
434     TraceIter,
435     CgroupInet4Getpeername,
436     CgroupInet6Getpeername,
437     CgroupInet4Getsockname,
438     CgroupInet6Getsockname,
439     XdpDevmap,
440     CgroupInetSockRelease,
441     XdpCpumap,
442     SkLookup,
443     Xdp,
444     SkSkbVerdict,
445     SkReuseportSelect,
446     SkReuseportSelectOrMigrate,
447     PerfEvent,
448     /// See [`MapType::Unknown`][crate::MapType::Unknown]
449     Unknown = u32::MAX,
450 }
451 
452 impl From<u32> for ProgramAttachType {
from(value: u32) -> Self453     fn from(value: u32) -> Self {
454         use ProgramAttachType::*;
455 
456         match value {
457             x if x == CgroupInetIngress as u32 => CgroupInetIngress,
458             x if x == CgroupInetEgress as u32 => CgroupInetEgress,
459             x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate,
460             x if x == CgroupSockOps as u32 => CgroupSockOps,
461             x if x == SkSkbStreamParser as u32 => SkSkbStreamParser,
462             x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict,
463             x if x == CgroupDevice as u32 => CgroupDevice,
464             x if x == SkMsgVerdict as u32 => SkMsgVerdict,
465             x if x == CgroupInet4Bind as u32 => CgroupInet4Bind,
466             x if x == CgroupInet6Bind as u32 => CgroupInet6Bind,
467             x if x == CgroupInet4Connect as u32 => CgroupInet4Connect,
468             x if x == CgroupInet6Connect as u32 => CgroupInet6Connect,
469             x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind,
470             x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind,
471             x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg,
472             x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg,
473             x if x == LircMode2 as u32 => LircMode2,
474             x if x == FlowDissector as u32 => FlowDissector,
475             x if x == CgroupSysctl as u32 => CgroupSysctl,
476             x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg,
477             x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg,
478             x if x == CgroupGetsockopt as u32 => CgroupGetsockopt,
479             x if x == CgroupSetsockopt as u32 => CgroupSetsockopt,
480             x if x == TraceRawTp as u32 => TraceRawTp,
481             x if x == TraceFentry as u32 => TraceFentry,
482             x if x == TraceFexit as u32 => TraceFexit,
483             x if x == ModifyReturn as u32 => ModifyReturn,
484             x if x == LsmMac as u32 => LsmMac,
485             x if x == TraceIter as u32 => TraceIter,
486             x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername,
487             x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername,
488             x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname,
489             x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname,
490             x if x == XdpDevmap as u32 => XdpDevmap,
491             x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease,
492             x if x == XdpCpumap as u32 => XdpCpumap,
493             x if x == SkLookup as u32 => SkLookup,
494             x if x == Xdp as u32 => Xdp,
495             x if x == SkSkbVerdict as u32 => SkSkbVerdict,
496             x if x == SkReuseportSelect as u32 => SkReuseportSelect,
497             x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate,
498             x if x == PerfEvent as u32 => PerfEvent,
499             _ => Unknown,
500         }
501     }
502 }
503 
504 /// The input a program accepts.
505 ///
506 /// This type is mostly used in conjunction with the [`Program::test_run`]
507 /// facility.
508 #[derive(Debug, Default)]
509 pub struct Input<'dat> {
510     /// The input context to provide.
511     ///
512     /// The input is mutable because the kernel may modify it.
513     pub context_in: Option<&'dat mut [u8]>,
514     /// The output context buffer provided to the program.
515     pub context_out: Option<&'dat mut [u8]>,
516     /// Additional data to provide to the program.
517     pub data_in: Option<&'dat [u8]>,
518     /// The output data buffer provided to the program.
519     pub data_out: Option<&'dat mut [u8]>,
520     /// The 'cpu' value passed to the kernel.
521     pub cpu: u32,
522     /// The 'flags' value passed to the kernel.
523     pub flags: u32,
524     /// The struct is non-exhaustive and open to extension.
525     #[doc(hidden)]
526     pub _non_exhaustive: (),
527 }
528 
529 /// The output a program produces.
530 ///
531 /// This type is mostly used in conjunction with the [`Program::test_run`]
532 /// facility.
533 #[derive(Debug)]
534 pub struct Output<'dat> {
535     /// The value returned by the program.
536     pub return_value: u32,
537     /// The output context filled by the program/kernel.
538     pub context: Option<&'dat mut [u8]>,
539     /// Output data filled by the program.
540     pub data: Option<&'dat mut [u8]>,
541     /// The struct is non-exhaustive and open to extension.
542     #[doc(hidden)]
543     pub _non_exhaustive: (),
544 }
545 
546 /// An immutable loaded BPF program.
547 pub type Program<'obj> = ProgramImpl<'obj>;
548 /// A mutable loaded BPF program.
549 pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>;
550 
551 
552 /// Represents a loaded [`Program`].
553 ///
554 /// This struct is not safe to clone because the underlying libbpf resource cannot currently
555 /// be protected from data races.
556 ///
557 /// If you attempt to attach a `Program` with the wrong attach method, the `attach_*`
558 /// method will fail with the appropriate error.
559 #[derive(Debug)]
560 #[repr(transparent)]
561 pub struct ProgramImpl<'obj, T = ()> {
562     pub(crate) ptr: NonNull<libbpf_sys::bpf_program>,
563     _phantom: PhantomData<&'obj T>,
564 }
565 
566 impl<'obj> Program<'obj> {
567     /// Create a [`Program`] from a [`libbpf_sys::bpf_program`]
new(prog: &'obj libbpf_sys::bpf_program) -> Self568     pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
569         // SAFETY: We inferred the address from a reference, which is always
570         //         valid.
571         Self {
572             ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
573             _phantom: PhantomData,
574         }
575     }
576 
577     /// Retrieve the name of this `Program`.
name(&self) -> &OsStr578     pub fn name(&self) -> &OsStr {
579         let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
580         let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
581         // SAFETY: `bpf_program__name` always returns a non-NULL pointer.
582         OsStr::from_bytes(name_c_str.to_bytes())
583     }
584 
585     /// Retrieve the name of the section this `Program` belongs to.
section(&self) -> &OsStr586     pub fn section(&self) -> &OsStr {
587         // SAFETY: The program is always valid.
588         let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
589         // SAFETY: `bpf_program__section_name` will always return a non-NULL
590         //         pointer.
591         let section_c_str = unsafe { CStr::from_ptr(p) };
592         let section = OsStr::from_bytes(section_c_str.to_bytes());
593         section
594     }
595 
596     /// Retrieve the type of the program.
prog_type(&self) -> ProgramType597     pub fn prog_type(&self) -> ProgramType {
598         ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
599     }
600 
601     /// Returns program fd by id
get_fd_by_id(id: u32) -> Result<OwnedFd>602     pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> {
603         let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) };
604         let fd = util::parse_ret_i32(ret)?;
605         // SAFETY
606         // A file descriptor coming from the bpf_prog_get_fd_by_id function is always suitable for
607         // ownership and can be cleaned up with close.
608         Ok(unsafe { OwnedFd::from_raw_fd(fd) })
609     }
610 
611     /// Returns program id by fd
get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32>612     pub fn get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32> {
613         let mut prog_info = libbpf_sys::bpf_prog_info::default();
614         let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info;
615         let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32;
616         let ret = unsafe {
617             libbpf_sys::bpf_obj_get_info_by_fd(
618                 fd.as_raw_fd(),
619                 prog_info_ptr as *mut c_void,
620                 &mut len,
621             )
622         };
623         util::parse_ret(ret)?;
624         Ok(prog_info.id)
625     }
626 
627     /// Returns flags that have been set for the program.
flags(&self) -> u32628     pub fn flags(&self) -> u32 {
629         unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) }
630     }
631 
632     /// Retrieve the attach type of the program.
attach_type(&self) -> ProgramAttachType633     pub fn attach_type(&self) -> ProgramAttachType {
634         ProgramAttachType::from(unsafe {
635             libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr())
636         })
637     }
638 
639     /// Return `true` if the bpf program is set to autoload, `false` otherwise.
autoload(&self) -> bool640     pub fn autoload(&self) -> bool {
641         unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
642     }
643 
644     /// Return the bpf program's log level.
log_level(&self) -> u32645     pub fn log_level(&self) -> u32 {
646         unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) }
647     }
648 
649     /// Returns the number of instructions that form the program.
650     ///
651     /// Please see note in [`OpenProgram::insn_cnt`].
insn_cnt(&self) -> usize652     pub fn insn_cnt(&self) -> usize {
653         unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
654     }
655 
656     /// Gives read-only access to BPF program's underlying BPF instructions.
657     ///
658     /// Please see note in [`OpenProgram::insns`].
insns(&self) -> &[libbpf_sys::bpf_insn]659     pub fn insns(&self) -> &[libbpf_sys::bpf_insn] {
660         let count = self.insn_cnt();
661         let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
662         unsafe { slice::from_raw_parts(ptr, count) }
663     }
664 }
665 
666 impl<'obj> ProgramMut<'obj> {
667     /// Create a [`Program`] from a [`libbpf_sys::bpf_program`]
new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self668     pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
669         Self {
670             ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
671             _phantom: PhantomData,
672         }
673     }
674 
675     /// [Pin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs)
676     /// this program to bpffs.
pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>677     pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
678         let path_c = util::path_to_cstring(path)?;
679         let path_ptr = path_c.as_ptr();
680 
681         let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) };
682         util::parse_ret(ret)
683     }
684 
685     /// [Unpin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs)
686     /// this program from bpffs
unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>687     pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
688         let path_c = util::path_to_cstring(path)?;
689         let path_ptr = path_c.as_ptr();
690 
691         let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) };
692         util::parse_ret(ret)
693     }
694 
695     /// Auto-attach based on prog section
attach(&mut self) -> Result<Link>696     pub fn attach(&mut self) -> Result<Link> {
697         let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) };
698         let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?;
699         // SAFETY: the pointer came from libbpf and has been checked for errors.
700         let link = unsafe { Link::new(ptr) };
701         Ok(link)
702     }
703 
704     /// Attach this program to a
705     /// [cgroup](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html).
attach_cgroup(&mut self, cgroup_fd: i32) -> Result<Link>706     pub fn attach_cgroup(&mut self, cgroup_fd: i32) -> Result<Link> {
707         let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) };
708         let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?;
709         // SAFETY: the pointer came from libbpf and has been checked for errors.
710         let link = unsafe { Link::new(ptr) };
711         Ok(link)
712     }
713 
714     /// Attach this program to a [perf event](https://linux.die.net/man/2/perf_event_open).
attach_perf_event(&mut self, pfd: i32) -> Result<Link>715     pub fn attach_perf_event(&mut self, pfd: i32) -> Result<Link> {
716         let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) };
717         let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
718         // SAFETY: the pointer came from libbpf and has been checked for errors.
719         let link = unsafe { Link::new(ptr) };
720         Ok(link)
721     }
722 
723     /// Attach this program to a [userspace
724     /// probe](https://www.kernel.org/doc/html/latest/trace/uprobetracer.html).
attach_uprobe<T: AsRef<Path>>( &mut self, retprobe: bool, pid: i32, binary_path: T, func_offset: usize, ) -> Result<Link>725     pub fn attach_uprobe<T: AsRef<Path>>(
726         &mut self,
727         retprobe: bool,
728         pid: i32,
729         binary_path: T,
730         func_offset: usize,
731     ) -> Result<Link> {
732         let path = util::path_to_cstring(binary_path)?;
733         let path_ptr = path.as_ptr();
734         let ptr = unsafe {
735             libbpf_sys::bpf_program__attach_uprobe(
736                 self.ptr.as_ptr(),
737                 retprobe,
738                 pid,
739                 path_ptr,
740                 func_offset as libbpf_sys::size_t,
741             )
742         };
743         let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
744         // SAFETY: the pointer came from libbpf and has been checked for errors.
745         let link = unsafe { Link::new(ptr) };
746         Ok(link)
747     }
748 
749     /// Attach this program to a [userspace
750     /// probe](https://www.kernel.org/doc/html/latest/trace/uprobetracer.html),
751     /// providing additional options.
attach_uprobe_with_opts( &mut self, pid: i32, binary_path: impl AsRef<Path>, func_offset: usize, opts: UprobeOpts, ) -> Result<Link>752     pub fn attach_uprobe_with_opts(
753         &mut self,
754         pid: i32,
755         binary_path: impl AsRef<Path>,
756         func_offset: usize,
757         opts: UprobeOpts,
758     ) -> Result<Link> {
759         let path = util::path_to_cstring(binary_path)?;
760         let path_ptr = path.as_ptr();
761         let UprobeOpts {
762             ref_ctr_offset,
763             cookie,
764             retprobe,
765             func_name,
766             _non_exhaustive,
767         } = opts;
768 
769         let func_name = util::str_to_cstring(&func_name)?;
770         let opts = libbpf_sys::bpf_uprobe_opts {
771             sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _,
772             ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t,
773             bpf_cookie: cookie,
774             retprobe,
775             func_name: func_name.as_ptr(),
776             ..Default::default()
777         };
778 
779         let ptr = unsafe {
780             libbpf_sys::bpf_program__attach_uprobe_opts(
781                 self.ptr.as_ptr(),
782                 pid,
783                 path_ptr,
784                 func_offset as libbpf_sys::size_t,
785                 &opts as *const _,
786             )
787         };
788         let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
789         // SAFETY: the pointer came from libbpf and has been checked for errors.
790         let link = unsafe { Link::new(ptr) };
791         Ok(link)
792     }
793 
794     /// Attach this program to a [kernel
795     /// probe](https://www.kernel.org/doc/html/latest/trace/kprobetrace.html).
attach_kprobe<T: AsRef<str>>(&mut self, retprobe: bool, func_name: T) -> Result<Link>796     pub fn attach_kprobe<T: AsRef<str>>(&mut self, retprobe: bool, func_name: T) -> Result<Link> {
797         let func_name = util::str_to_cstring(func_name.as_ref())?;
798         let func_name_ptr = func_name.as_ptr();
799         let ptr = unsafe {
800             libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr)
801         };
802         let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
803         // SAFETY: the pointer came from libbpf and has been checked for errors.
804         let link = unsafe { Link::new(ptr) };
805         Ok(link)
806     }
807 
808     /// Attach this program to the specified syscall
attach_ksyscall<T: AsRef<str>>( &mut self, retprobe: bool, syscall_name: T, ) -> Result<Link>809     pub fn attach_ksyscall<T: AsRef<str>>(
810         &mut self,
811         retprobe: bool,
812         syscall_name: T,
813     ) -> Result<Link> {
814         let opts = libbpf_sys::bpf_ksyscall_opts {
815             sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _,
816             retprobe,
817             ..Default::default()
818         };
819 
820         let syscall_name = util::str_to_cstring(syscall_name.as_ref())?;
821         let syscall_name_ptr = syscall_name.as_ptr();
822         let ptr = unsafe {
823             libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts)
824         };
825         let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?;
826         // SAFETY: the pointer came from libbpf and has been checked for errors.
827         let link = unsafe { Link::new(ptr) };
828         Ok(link)
829     }
830 
attach_tracepoint_impl( &mut self, tp_category: &str, tp_name: &str, tp_opts: Option<TracepointOpts>, ) -> Result<Link>831     fn attach_tracepoint_impl(
832         &mut self,
833         tp_category: &str,
834         tp_name: &str,
835         tp_opts: Option<TracepointOpts>,
836     ) -> Result<Link> {
837         let tp_category = util::str_to_cstring(tp_category)?;
838         let tp_category_ptr = tp_category.as_ptr();
839         let tp_name = util::str_to_cstring(tp_name)?;
840         let tp_name_ptr = tp_name.as_ptr();
841 
842         let ptr = if let Some(tp_opts) = tp_opts {
843             let tp_opts = libbpf_sys::bpf_tracepoint_opts::from(tp_opts);
844             unsafe {
845                 libbpf_sys::bpf_program__attach_tracepoint_opts(
846                     self.ptr.as_ptr(),
847                     tp_category_ptr,
848                     tp_name_ptr,
849                     &tp_opts as *const _,
850                 )
851             }
852         } else {
853             unsafe {
854                 libbpf_sys::bpf_program__attach_tracepoint(
855                     self.ptr.as_ptr(),
856                     tp_category_ptr,
857                     tp_name_ptr,
858                 )
859             }
860         };
861 
862         let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?;
863         // SAFETY: the pointer came from libbpf and has been checked for errors.
864         let link = unsafe { Link::new(ptr) };
865         Ok(link)
866     }
867 
868     /// Attach this program to a [kernel
869     /// tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html).
attach_tracepoint( &mut self, tp_category: impl AsRef<str>, tp_name: impl AsRef<str>, ) -> Result<Link>870     pub fn attach_tracepoint(
871         &mut self,
872         tp_category: impl AsRef<str>,
873         tp_name: impl AsRef<str>,
874     ) -> Result<Link> {
875         self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None)
876     }
877 
878     /// Attach this program to a [kernel
879     /// tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html),
880     /// providing additional options.
attach_tracepoint_with_opts( &mut self, tp_category: impl AsRef<str>, tp_name: impl AsRef<str>, tp_opts: TracepointOpts, ) -> Result<Link>881     pub fn attach_tracepoint_with_opts(
882         &mut self,
883         tp_category: impl AsRef<str>,
884         tp_name: impl AsRef<str>,
885         tp_opts: TracepointOpts,
886     ) -> Result<Link> {
887         self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts))
888     }
889 
890     /// Attach this program to a [raw kernel
891     /// tracepoint](https://lwn.net/Articles/748352/).
attach_raw_tracepoint<T: AsRef<str>>(&mut self, tp_name: T) -> Result<Link>892     pub fn attach_raw_tracepoint<T: AsRef<str>>(&mut self, tp_name: T) -> Result<Link> {
893         let tp_name = util::str_to_cstring(tp_name.as_ref())?;
894         let tp_name_ptr = tp_name.as_ptr();
895         let ptr = unsafe {
896             libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr)
897         };
898         let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
899         // SAFETY: the pointer came from libbpf and has been checked for errors.
900         let link = unsafe { Link::new(ptr) };
901         Ok(link)
902     }
903 
904     /// Attach to an [LSM](https://en.wikipedia.org/wiki/Linux_Security_Modules) hook
attach_lsm(&mut self) -> Result<Link>905     pub fn attach_lsm(&mut self) -> Result<Link> {
906         let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) };
907         let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?;
908         // SAFETY: the pointer came from libbpf and has been checked for errors.
909         let link = unsafe { Link::new(ptr) };
910         Ok(link)
911     }
912 
913     /// Attach to a [fentry/fexit kernel probe](https://lwn.net/Articles/801479/)
attach_trace(&mut self) -> Result<Link>914     pub fn attach_trace(&mut self) -> Result<Link> {
915         let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) };
916         let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?;
917         // SAFETY: the pointer came from libbpf and has been checked for errors.
918         let link = unsafe { Link::new(ptr) };
919         Ok(link)
920     }
921 
922     /// Attach a verdict/parser to a [sockmap/sockhash](https://lwn.net/Articles/731133/)
attach_sockmap(&self, map_fd: i32) -> Result<()>923     pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> {
924         let err = unsafe {
925             libbpf_sys::bpf_prog_attach(
926                 self.as_fd().as_raw_fd(),
927                 map_fd,
928                 self.attach_type() as u32,
929                 0,
930             )
931         };
932         util::parse_ret(err)
933     }
934 
935     /// Attach this program to [XDP](https://lwn.net/Articles/825998/)
attach_xdp(&mut self, ifindex: i32) -> Result<Link>936     pub fn attach_xdp(&mut self, ifindex: i32) -> Result<Link> {
937         let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) };
938         let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?;
939         // SAFETY: the pointer came from libbpf and has been checked for errors.
940         let link = unsafe { Link::new(ptr) };
941         Ok(link)
942     }
943 
944     /// Attach this program to [netns-based programs](https://lwn.net/Articles/819618/)
attach_netns(&mut self, netns_fd: i32) -> Result<Link>945     pub fn attach_netns(&mut self, netns_fd: i32) -> Result<Link> {
946         let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) };
947         let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?;
948         // SAFETY: the pointer came from libbpf and has been checked for errors.
949         let link = unsafe { Link::new(ptr) };
950         Ok(link)
951     }
952 
attach_usdt_impl( &mut self, pid: i32, binary_path: &Path, usdt_provider: &str, usdt_name: &str, usdt_opts: Option<UsdtOpts>, ) -> Result<Link>953     fn attach_usdt_impl(
954         &mut self,
955         pid: i32,
956         binary_path: &Path,
957         usdt_provider: &str,
958         usdt_name: &str,
959         usdt_opts: Option<UsdtOpts>,
960     ) -> Result<Link> {
961         let path = util::path_to_cstring(binary_path)?;
962         let path_ptr = path.as_ptr();
963         let usdt_provider = util::str_to_cstring(usdt_provider)?;
964         let usdt_provider_ptr = usdt_provider.as_ptr();
965         let usdt_name = util::str_to_cstring(usdt_name)?;
966         let usdt_name_ptr = usdt_name.as_ptr();
967         let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from);
968         let usdt_opts_ptr = usdt_opts
969             .as_ref()
970             .map(|opts| opts as *const _)
971             .unwrap_or_else(ptr::null);
972 
973         let ptr = unsafe {
974             libbpf_sys::bpf_program__attach_usdt(
975                 self.ptr.as_ptr(),
976                 pid,
977                 path_ptr,
978                 usdt_provider_ptr,
979                 usdt_name_ptr,
980                 usdt_opts_ptr,
981             )
982         };
983         let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?;
984         // SAFETY: the pointer came from libbpf and has been checked for errors.
985         let link = unsafe { Link::new(ptr) };
986         Ok(link)
987     }
988 
989     /// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe
990     /// point. The entry point of the program must be defined with
991     /// `SEC("usdt")`.
attach_usdt( &mut self, pid: i32, binary_path: impl AsRef<Path>, usdt_provider: impl AsRef<str>, usdt_name: impl AsRef<str>, ) -> Result<Link>992     pub fn attach_usdt(
993         &mut self,
994         pid: i32,
995         binary_path: impl AsRef<Path>,
996         usdt_provider: impl AsRef<str>,
997         usdt_name: impl AsRef<str>,
998     ) -> Result<Link> {
999         self.attach_usdt_impl(
1000             pid,
1001             binary_path.as_ref(),
1002             usdt_provider.as_ref(),
1003             usdt_name.as_ref(),
1004             None,
1005         )
1006     }
1007 
1008     /// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe
1009     /// point, providing additional options. The entry point of the program must
1010     /// be defined with `SEC("usdt")`.
attach_usdt_with_opts( &mut self, pid: i32, binary_path: impl AsRef<Path>, usdt_provider: impl AsRef<str>, usdt_name: impl AsRef<str>, usdt_opts: UsdtOpts, ) -> Result<Link>1011     pub fn attach_usdt_with_opts(
1012         &mut self,
1013         pid: i32,
1014         binary_path: impl AsRef<Path>,
1015         usdt_provider: impl AsRef<str>,
1016         usdt_name: impl AsRef<str>,
1017         usdt_opts: UsdtOpts,
1018     ) -> Result<Link> {
1019         self.attach_usdt_impl(
1020             pid,
1021             binary_path.as_ref(),
1022             usdt_provider.as_ref(),
1023             usdt_name.as_ref(),
1024             Some(usdt_opts),
1025         )
1026     }
1027 
1028     /// Attach this program to a
1029     /// [BPF Iterator](https://www.kernel.org/doc/html/latest/bpf/bpf_iterators.html).
1030     /// The entry point of the program must be defined with `SEC("iter")` or `SEC("iter.s")`.
attach_iter(&mut self, map_fd: BorrowedFd<'_>) -> Result<Link>1031     pub fn attach_iter(&mut self, map_fd: BorrowedFd<'_>) -> Result<Link> {
1032         let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1033         linkinfo.map.map_fd = map_fd.as_raw_fd() as _;
1034         let attach_opt = libbpf_sys::bpf_iter_attach_opts {
1035             link_info: &mut linkinfo as *mut libbpf_sys::bpf_iter_link_info,
1036             link_info_len: size_of::<libbpf_sys::bpf_iter_link_info>() as _,
1037             sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _,
1038             ..Default::default()
1039         };
1040         let ptr = unsafe {
1041             libbpf_sys::bpf_program__attach_iter(
1042                 self.ptr.as_ptr(),
1043                 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts,
1044             )
1045         };
1046 
1047         let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
1048         // SAFETY: the pointer came from libbpf and has been checked for errors.
1049         let link = unsafe { Link::new(ptr) };
1050         Ok(link)
1051     }
1052 
1053     /// Test run the program with the given input data.
1054     ///
1055     /// This function uses the
1056     /// [BPF_PROG_RUN](https://www.kernel.org/doc/html/latest/bpf/bpf_prog_run.html)
1057     /// facility.
test_run<'dat>(&mut self, input: Input<'dat>) -> Result<Output<'dat>>1058     pub fn test_run<'dat>(&mut self, input: Input<'dat>) -> Result<Output<'dat>> {
1059         unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> {
1060             if items.is_null() {
1061                 None
1062             } else {
1063                 Some(unsafe { slice::from_raw_parts_mut(items, num_items) })
1064             }
1065         }
1066 
1067         let Input {
1068             context_in,
1069             mut context_out,
1070             data_in,
1071             mut data_out,
1072             cpu,
1073             flags,
1074             _non_exhaustive: (),
1075         } = input;
1076 
1077         let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() };
1078         opts.sz = size_of_val(&opts) as _;
1079         opts.ctx_in = context_in
1080             .as_ref()
1081             .map(|data| data.as_ptr().cast())
1082             .unwrap_or_else(ptr::null);
1083         opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0);
1084         opts.ctx_out = context_out
1085             .as_mut()
1086             .map(|data| data.as_mut_ptr().cast())
1087             .unwrap_or_else(ptr::null_mut);
1088         opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0);
1089         opts.data_in = data_in
1090             .map(|data| data.as_ptr().cast())
1091             .unwrap_or_else(ptr::null);
1092         opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0);
1093         opts.data_out = data_out
1094             .as_mut()
1095             .map(|data| data.as_mut_ptr().cast())
1096             .unwrap_or_else(ptr::null_mut);
1097         opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0);
1098         opts.cpu = cpu;
1099         opts.flags = flags;
1100 
1101         let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) };
1102         let () = util::parse_ret(rc)?;
1103         let output = Output {
1104             return_value: opts.retval,
1105             context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) },
1106             data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) },
1107             _non_exhaustive: (),
1108         };
1109         Ok(output)
1110     }
1111 }
1112 
1113 impl<'obj> Deref for ProgramMut<'obj> {
1114     type Target = Program<'obj>;
1115 
deref(&self) -> &Self::Target1116     fn deref(&self) -> &Self::Target {
1117         // SAFETY: `ProgramImpl` is `repr(transparent)` and so in-memory
1118         //         representation of both types is the same.
1119         unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) }
1120     }
1121 }
1122 
1123 impl<T> AsFd for ProgramImpl<'_, T> {
as_fd(&self) -> BorrowedFd<'_>1124     fn as_fd(&self) -> BorrowedFd<'_> {
1125         let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) };
1126         unsafe { BorrowedFd::borrow_raw(fd) }
1127     }
1128 }
1129 
1130 impl<T> AsRawLibbpf for ProgramImpl<'_, T> {
1131     type LibbpfType = libbpf_sys::bpf_program;
1132 
1133     /// Retrieve the underlying [`libbpf_sys::bpf_program`].
as_libbpf_object(&self) -> NonNull<Self::LibbpfType>1134     fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
1135         self.ptr
1136     }
1137 }
1138 
1139 #[cfg(test)]
1140 mod tests {
1141     use super::*;
1142 
1143     use std::mem::discriminant;
1144 
1145     #[test]
program_type()1146     fn program_type() {
1147         use ProgramType::*;
1148 
1149         for t in [
1150             Unspec,
1151             SocketFilter,
1152             Kprobe,
1153             SchedCls,
1154             SchedAct,
1155             Tracepoint,
1156             Xdp,
1157             PerfEvent,
1158             CgroupSkb,
1159             CgroupSock,
1160             LwtIn,
1161             LwtOut,
1162             LwtXmit,
1163             SockOps,
1164             SkSkb,
1165             CgroupDevice,
1166             SkMsg,
1167             RawTracepoint,
1168             CgroupSockAddr,
1169             LwtSeg6local,
1170             LircMode2,
1171             SkReuseport,
1172             FlowDissector,
1173             CgroupSysctl,
1174             RawTracepointWritable,
1175             CgroupSockopt,
1176             Tracing,
1177             StructOps,
1178             Ext,
1179             Lsm,
1180             SkLookup,
1181             Syscall,
1182             Unknown,
1183         ] {
1184             // check if discriminants match after a roundtrip conversion
1185             assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32)));
1186         }
1187     }
1188 
1189     #[test]
program_attach_type()1190     fn program_attach_type() {
1191         use ProgramAttachType::*;
1192 
1193         for t in [
1194             CgroupInetIngress,
1195             CgroupInetEgress,
1196             CgroupInetSockCreate,
1197             CgroupSockOps,
1198             SkSkbStreamParser,
1199             SkSkbStreamVerdict,
1200             CgroupDevice,
1201             SkMsgVerdict,
1202             CgroupInet4Bind,
1203             CgroupInet6Bind,
1204             CgroupInet4Connect,
1205             CgroupInet6Connect,
1206             CgroupInet4PostBind,
1207             CgroupInet6PostBind,
1208             CgroupUdp4Sendmsg,
1209             CgroupUdp6Sendmsg,
1210             LircMode2,
1211             FlowDissector,
1212             CgroupSysctl,
1213             CgroupUdp4Recvmsg,
1214             CgroupUdp6Recvmsg,
1215             CgroupGetsockopt,
1216             CgroupSetsockopt,
1217             TraceRawTp,
1218             TraceFentry,
1219             TraceFexit,
1220             ModifyReturn,
1221             LsmMac,
1222             TraceIter,
1223             CgroupInet4Getpeername,
1224             CgroupInet6Getpeername,
1225             CgroupInet4Getsockname,
1226             CgroupInet6Getsockname,
1227             XdpDevmap,
1228             CgroupInetSockRelease,
1229             XdpCpumap,
1230             SkLookup,
1231             Xdp,
1232             SkSkbVerdict,
1233             SkReuseportSelect,
1234             SkReuseportSelectOrMigrate,
1235             PerfEvent,
1236             Unknown,
1237         ] {
1238             // check if discriminants match after a roundtrip conversion
1239             assert_eq!(
1240                 discriminant(&t),
1241                 discriminant(&ProgramAttachType::from(t as u32))
1242             );
1243         }
1244     }
1245 }
1246