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