1 use core::ffi::c_void;
2 use std::ffi::CStr;
3 use std::ffi::CString;
4 use std::ffi::OsStr;
5 use std::mem;
6 use std::os::unix::ffi::OsStrExt as _;
7 use std::path::Path;
8 use std::ptr;
9 use std::ptr::addr_of;
10 use std::ptr::NonNull;
11 
12 use crate::map::map_fd;
13 use crate::set_print;
14 use crate::util;
15 use crate::util::validate_bpf_ret;
16 use crate::Btf;
17 use crate::ErrorExt as _;
18 use crate::Map;
19 use crate::MapMut;
20 use crate::OpenMap;
21 use crate::OpenMapMut;
22 use crate::OpenProgram;
23 use crate::OpenProgramMut;
24 use crate::PrintLevel;
25 use crate::Program;
26 use crate::ProgramMut;
27 use crate::Result;
28 
29 
30 /// An iterator over the maps in a BPF object.
31 #[derive(Debug)]
32 pub struct MapIter<'obj> {
33     obj: &'obj libbpf_sys::bpf_object,
34     last: *mut libbpf_sys::bpf_map,
35 }
36 
37 impl<'obj> MapIter<'obj> {
38     /// Create a new iterator over the maps of the given BPF object.
new(obj: &'obj libbpf_sys::bpf_object) -> Self39     pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
40         Self {
41             obj,
42             last: ptr::null_mut(),
43         }
44     }
45 }
46 
47 impl Iterator for MapIter<'_> {
48     type Item = NonNull<libbpf_sys::bpf_map>;
49 
next(&mut self) -> Option<Self::Item>50     fn next(&mut self) -> Option<Self::Item> {
51         self.last = unsafe { libbpf_sys::bpf_object__next_map(self.obj, self.last) };
52         NonNull::new(self.last)
53     }
54 }
55 
56 
57 /// An iterator over the programs in a BPF object.
58 #[derive(Debug)]
59 pub struct ProgIter<'obj> {
60     obj: &'obj libbpf_sys::bpf_object,
61     last: *mut libbpf_sys::bpf_program,
62 }
63 
64 impl<'obj> ProgIter<'obj> {
65     /// Create a new iterator over the programs of the given BPF object.
new(obj: &'obj libbpf_sys::bpf_object) -> Self66     pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
67         Self {
68             obj,
69             last: ptr::null_mut(),
70         }
71     }
72 }
73 
74 impl Iterator for ProgIter<'_> {
75     type Item = NonNull<libbpf_sys::bpf_program>;
76 
next(&mut self) -> Option<Self::Item>77     fn next(&mut self) -> Option<Self::Item> {
78         self.last = unsafe { libbpf_sys::bpf_object__next_program(self.obj, self.last) };
79         NonNull::new(self.last)
80     }
81 }
82 
83 
84 /// A trait implemented for types that are thin wrappers around `libbpf` types.
85 ///
86 /// The trait provides access to the underlying `libbpf` (or `libbpf-sys`)
87 /// object. In many cases, this enables direct usage of `libbpf-sys`
88 /// functionality when higher-level bindings are not yet provided by this crate.
89 pub trait AsRawLibbpf {
90     /// The underlying `libbpf` type.
91     type LibbpfType;
92 
93     /// Retrieve the underlying `libbpf` object.
94     ///
95     /// # Warning
96     /// By virtue of working with a mutable raw pointer this method effectively
97     /// circumvents mutability and liveness checks. While by-design, usage is
98     /// meant as an escape-hatch more than anything else. If you find yourself
99     /// making use of it, please consider discussing your workflow with crate
100     /// maintainers to see if it would make sense to provide safer wrappers.
as_libbpf_object(&self) -> NonNull<Self::LibbpfType>101     fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType>;
102 }
103 
104 /// Builder for creating an [`OpenObject`]. Typically the entry point into libbpf-rs.
105 #[derive(Debug)]
106 pub struct ObjectBuilder {
107     name: Option<CString>,
108     pin_root_path: Option<CString>,
109 
110     opts: libbpf_sys::bpf_object_open_opts,
111 }
112 
113 impl Default for ObjectBuilder {
default() -> Self114     fn default() -> Self {
115         let opts = libbpf_sys::bpf_object_open_opts {
116             sz: mem::size_of::<libbpf_sys::bpf_object_open_opts>() as libbpf_sys::size_t,
117             object_name: ptr::null(),
118             relaxed_maps: false,
119             pin_root_path: ptr::null(),
120             kconfig: ptr::null(),
121             btf_custom_path: ptr::null(),
122             kernel_log_buf: ptr::null_mut(),
123             kernel_log_size: 0,
124             kernel_log_level: 0,
125             ..Default::default()
126         };
127         Self {
128             name: None,
129             pin_root_path: None,
130             opts,
131         }
132     }
133 }
134 
135 impl ObjectBuilder {
136     /// Override the generated name that would have been inferred from the constructor.
name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self>137     pub fn name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self> {
138         self.name = Some(util::str_to_cstring(name.as_ref())?);
139         self.opts.object_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr());
140         Ok(self)
141     }
142 
143     /// Set the pin_root_path for maps that are pinned by name.
144     ///
145     /// By default, this is NULL which bpf translates to /sys/fs/bpf
pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self>146     pub fn pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
147         self.pin_root_path = Some(util::path_to_cstring(path)?);
148         self.opts.pin_root_path = self
149             .pin_root_path
150             .as_ref()
151             .map_or(ptr::null(), |p| p.as_ptr());
152         Ok(self)
153     }
154 
155     /// Option to parse map definitions non-strictly, allowing extra attributes/data
relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self156     pub fn relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self {
157         self.opts.relaxed_maps = relaxed_maps;
158         self
159     }
160 
161     /// Option to print debug output to stderr.
162     ///
163     /// Note: This function uses [`set_print`] internally and will overwrite any callbacks
164     /// currently in use.
debug(&mut self, dbg: bool) -> &mut Self165     pub fn debug(&mut self, dbg: bool) -> &mut Self {
166         if dbg {
167             set_print(Some((PrintLevel::Debug, |_, s| print!("{s}"))));
168         } else {
169             set_print(None);
170         }
171         self
172     }
173 
174     /// Open an object using the provided path on the file system.
open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject>175     pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject> {
176         let path = path.as_ref();
177         let path_c = util::path_to_cstring(path)?;
178         let path_ptr = path_c.as_ptr();
179         let opts_ptr = self.as_libbpf_object().as_ptr();
180 
181         let ptr = unsafe { libbpf_sys::bpf_object__open_file(path_ptr, opts_ptr) };
182         let ptr = validate_bpf_ret(ptr)
183             .with_context(|| format!("failed to open object from `{}`", path.display()))?;
184 
185         let obj = unsafe { OpenObject::from_ptr(ptr) };
186         Ok(obj)
187     }
188 
189     /// Open an object from memory.
open_memory(&mut self, mem: &[u8]) -> Result<OpenObject>190     pub fn open_memory(&mut self, mem: &[u8]) -> Result<OpenObject> {
191         let opts_ptr = self.as_libbpf_object().as_ptr();
192         let ptr = unsafe {
193             libbpf_sys::bpf_object__open_mem(
194                 mem.as_ptr() as *const c_void,
195                 mem.len() as libbpf_sys::size_t,
196                 opts_ptr,
197             )
198         };
199         let ptr = validate_bpf_ret(ptr).context("failed to open object from memory")?;
200         let obj = unsafe { OpenObject::from_ptr(ptr) };
201         Ok(obj)
202     }
203 }
204 
205 impl AsRawLibbpf for ObjectBuilder {
206     type LibbpfType = libbpf_sys::bpf_object_open_opts;
207 
208     /// Retrieve the underlying [`libbpf_sys::bpf_object_open_opts`].
as_libbpf_object(&self) -> NonNull<Self::LibbpfType>209     fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
210         // SAFETY: A reference is always a valid pointer.
211         unsafe { NonNull::new_unchecked(addr_of!(self.opts).cast_mut()) }
212     }
213 }
214 
215 
216 /// Represents an opened (but not yet loaded) BPF object file.
217 ///
218 /// Use this object to access [`OpenMap`]s and [`OpenProgram`]s.
219 #[derive(Debug)]
220 #[repr(transparent)]
221 pub struct OpenObject {
222     ptr: NonNull<libbpf_sys::bpf_object>,
223 }
224 
225 impl OpenObject {
226     /// Takes ownership from pointer.
227     ///
228     /// # Safety
229     ///
230     /// Operations on the returned object are undefined if `ptr` is any one of:
231     ///     - null
232     ///     - points to an unopened `bpf_object`
233     ///     - points to a loaded `bpf_object`
234     ///
235     /// It is not safe to manipulate `ptr` after this operation.
from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self236     pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
237         Self { ptr }
238     }
239 
240     /// Takes underlying `libbpf_sys::bpf_object` pointer.
take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object>241     pub fn take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object> {
242         let ptr = {
243             let Self { ptr } = &mut self;
244             *ptr
245         };
246         // avoid double free of self.ptr
247         mem::forget(self);
248         ptr
249     }
250 
251     /// Retrieve the object's name.
name(&self) -> Option<&OsStr>252     pub fn name(&self) -> Option<&OsStr> {
253         // SAFETY: We ensured `ptr` is valid during construction.
254         let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
255         // SAFETY: `libbpf_get_error` is always safe to call.
256         let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
257         if err != 0 {
258             return None
259         }
260         let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
261         let str = OsStr::from_bytes(name_c_str.to_bytes());
262         Some(str)
263     }
264 
265     /// Retrieve an iterator over all BPF maps in the object.
maps(&self) -> impl Iterator<Item = OpenMap<'_>>266     pub fn maps(&self) -> impl Iterator<Item = OpenMap<'_>> {
267         MapIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { OpenMap::new(ptr.as_ref()) })
268     }
269 
270     /// Retrieve an iterator over all BPF maps in the object.
maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>>271     pub fn maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>> {
272         MapIter::new(unsafe { self.ptr.as_ref() })
273             .map(|mut ptr| unsafe { OpenMapMut::new_mut(ptr.as_mut()) })
274     }
275 
276     /// Retrieve an iterator over all BPF programs in the object.
progs(&self) -> impl Iterator<Item = OpenProgram<'_>>277     pub fn progs(&self) -> impl Iterator<Item = OpenProgram<'_>> {
278         ProgIter::new(unsafe { self.ptr.as_ref() })
279             .map(|ptr| unsafe { OpenProgram::new(ptr.as_ref()) })
280     }
281 
282     /// Retrieve an iterator over all BPF programs in the object.
progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>>283     pub fn progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>> {
284         ProgIter::new(unsafe { self.ptr.as_ref() })
285             .map(|mut ptr| unsafe { OpenProgramMut::new_mut(ptr.as_mut()) })
286     }
287 
288     /// Load the maps and programs contained in this BPF object into the system.
load(self) -> Result<Object>289     pub fn load(self) -> Result<Object> {
290         let ret = unsafe { libbpf_sys::bpf_object__load(self.ptr.as_ptr()) };
291         let () = util::parse_ret(ret)?;
292 
293         let obj = unsafe { Object::from_ptr(self.take_ptr()) };
294 
295         Ok(obj)
296     }
297 }
298 
299 impl AsRawLibbpf for OpenObject {
300     type LibbpfType = libbpf_sys::bpf_object;
301 
302     /// Retrieve the underlying [`libbpf_sys::bpf_object`].
as_libbpf_object(&self) -> NonNull<Self::LibbpfType>303     fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
304         self.ptr
305     }
306 }
307 
308 impl Drop for OpenObject {
drop(&mut self)309     fn drop(&mut self) {
310         // `self.ptr` may be null if `load()` was called. This is ok: libbpf noops
311         unsafe {
312             libbpf_sys::bpf_object__close(self.ptr.as_ptr());
313         }
314     }
315 }
316 
317 /// Represents a loaded BPF object file.
318 ///
319 /// An `Object` is logically in charge of all the contained [`Program`]s and [`Map`]s as well as
320 /// the associated metadata and runtime state that underpins the userspace portions of BPF program
321 /// execution. As a libbpf-rs user, you must keep the `Object` alive during the entire lifetime
322 /// of your interaction with anything inside the `Object`.
323 ///
324 /// Note that this is an explanation of the motivation -- Rust's lifetime system should already be
325 /// enforcing this invariant.
326 #[derive(Debug)]
327 #[repr(transparent)]
328 pub struct Object {
329     ptr: NonNull<libbpf_sys::bpf_object>,
330 }
331 
332 impl Object {
333     /// Takes ownership from pointer.
334     ///
335     /// # Safety
336     ///
337     /// If `ptr` is not already loaded then further operations on the returned object are
338     /// undefined.
339     ///
340     /// It is not safe to manipulate `ptr` after this operation.
from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self341     pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
342         Self { ptr }
343     }
344 
345     /// Retrieve the object's name.
name(&self) -> Option<&OsStr>346     pub fn name(&self) -> Option<&OsStr> {
347         // SAFETY: We ensured `ptr` is valid during construction.
348         let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
349         // SAFETY: `libbpf_get_error` is always safe to call.
350         let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
351         if err != 0 {
352             return None
353         }
354         let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
355         let str = OsStr::from_bytes(name_c_str.to_bytes());
356         Some(str)
357     }
358 
359     /// Parse the btf information associated with this bpf object.
btf(&self) -> Result<Option<Btf<'_>>>360     pub fn btf(&self) -> Result<Option<Btf<'_>>> {
361         Btf::from_bpf_object(unsafe { &*self.ptr.as_ptr() })
362     }
363 
364     /// Retrieve an iterator over all BPF maps in the object.
maps(&self) -> impl Iterator<Item = Map<'_>>365     pub fn maps(&self) -> impl Iterator<Item = Map<'_>> {
366         MapIter::new(unsafe { self.ptr.as_ref() })
367             .filter(|ptr| map_fd(*ptr).is_some())
368             .map(|ptr| unsafe { Map::new(ptr.as_ref()) })
369     }
370 
371     /// Retrieve an iterator over all BPF maps in the object.
maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>>372     pub fn maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>> {
373         MapIter::new(unsafe { self.ptr.as_ref() })
374             .filter(|ptr| map_fd(*ptr).is_some())
375             .map(|mut ptr| unsafe { MapMut::new_mut(ptr.as_mut()) })
376     }
377 
378     /// Retrieve an iterator over all BPF programs in the object.
progs(&self) -> impl Iterator<Item = Program<'_>>379     pub fn progs(&self) -> impl Iterator<Item = Program<'_>> {
380         ProgIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { Program::new(ptr.as_ref()) })
381     }
382 
383     /// Retrieve an iterator over all BPF programs in the object.
progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>>384     pub fn progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>> {
385         ProgIter::new(unsafe { self.ptr.as_ref() })
386             .map(|mut ptr| unsafe { ProgramMut::new_mut(ptr.as_mut()) })
387     }
388 }
389 
390 impl AsRawLibbpf for Object {
391     type LibbpfType = libbpf_sys::bpf_object;
392 
393     /// Retrieve the underlying [`libbpf_sys::bpf_object`].
as_libbpf_object(&self) -> NonNull<Self::LibbpfType>394     fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
395         self.ptr
396     }
397 }
398 
399 impl Drop for Object {
drop(&mut self)400     fn drop(&mut self) {
401         unsafe {
402             libbpf_sys::bpf_object__close(self.ptr.as_ptr());
403         }
404     }
405 }
406