diff --git a/bpf/aya-bpf/src/helpers.rs b/bpf/aya-bpf/src/helpers.rs index 5387c2d4..23a1a962 100644 --- a/bpf/aya-bpf/src/helpers.rs +++ b/bpf/aya-bpf/src/helpers.rs @@ -9,6 +9,7 @@ use core::mem::{self, MaybeUninit}; +use aya_bpf_bindings::bindings::path; pub use aya_bpf_bindings::helpers as gen; #[doc(hidden)] pub use gen::*; @@ -837,3 +838,100 @@ pub unsafe fn bpf_printk_impl<const FMT_LEN: usize, const NUM_ARGS: usize>( _ => gen::bpf_trace_vprintk(fmt_ptr, fmt_size, args.as_ptr() as _, (NUM_ARGS * 8) as _), } } + +/// Returns a byte slice with a path read from the given `path` kernel object. +/// +/// Reads at most `dest.len()` bytes, truncating if the length of the path is +/// larger than `dest`. On success, the destination buffer is always null +/// terminated, and the returned slice includes the bytes up to and not including +/// NULL. +/// +/// # Safety +/// +/// This function is inherently unsafe, since it operates on mutable raw +/// pointers. +/// +/// # Examples +/// +/// With an array allocated on the stack (not recommended for bigger paths, +/// eBPF stack limit is 512 bytes). +/// +/// ```no_run +/// # use aya_bpf::{cty::c_long, helpers::bpf_d_path, programs::LsmContext}; +/// pub const PATH_LEN: usize = 32; +/// +/// #[derive(Copy, Clone)] +/// #[repr(C)] +/// pub struct Path { +/// pub path: [u8; PATH_LEN], +/// } +/// +/// # fn try_lsm(ctx: LsmContext) -> Result<i32, i32> { +/// let path: *mut path = unsafe { ctx.arg(0) }; +/// let mut buf = [0u8; PATH_LEN]; +/// let path = unsafe { bpf_d_path(path, buf.as_mut_ptr())? }; +/// +/// // Do something with path +/// # Ok(0) +/// # } +/// ``` +/// +/// With a `PerCpuArray`: +/// +/// ```no_run +/// use aya_bpf::{bindings::path, macros::map, maps::PerCpuArray}; +/// # use aya_bpf::{helpers::bpf_d_path, programs::LsmContext}; +/// +/// pub const PATH_LEN: usize = 512; +/// +/// #[repr(C)] +/// pub struct Path { +/// pub path: [u8; PATH_LEN], +/// } +/// +/// #[map] +/// pub static PATH_BUF: PerCpuArray<Path> = PerCpuArray::with_max_entries(1, 0); +/// +/// # fn try_lsm(ctx: LsmContext) -> Result<i32, i32> { +/// let path: *mut path = unsafe { ctx.arg(0) }; +/// let buf = unsafe { +/// let ptr = PATH_BUF.get_mut(0).ok_or(0)? +/// &mut *ptr +/// }; +/// let path = unsafe { bpf_d_path(path, &mut buf.path)? }; +/// # Ok(0) +/// # } +/// ``` +/// +/// You can also convert the resulted bytes slice into `&str` using +/// [core::str::from_utf8_unchecked]: +/// +/// ```no_run +/// # use aya_bpf::{cty::c_long, helpers::bpf_d_path, programs::LsmContext}; +/// # use core::str::from_utf8_unchecked; +/// # pub const PATH_LEN: usize = 512; +/// # #[repr(C)] +/// # pub struct Path { +/// # pub path: [u8; PATH_LEN], +/// # } +/// # #[map] +/// # pub static PATH_BUF: PerCpuArray<Path> = PerCpuArray::with_max_entries(1, 0); +/// # fn try_lsm(ctx: LsmContext) -> Result<i32, i32> { +/// # let path: *mut path = unsafe { ctx.arg(0) }; +/// # let mut buf = [0u8; PATH_LEN]; +/// let path_str = unsafe { core::str::from_utf8_unchecked(bpf_d_path(path, &mut buf)?) }; +/// +/// // Do something with path_str +/// # Ok(0) +/// # } +/// ``` +/// +/// # Errors +/// +/// On failure, this function returns Err(-1). +#[inline(always)] +pub unsafe fn bpf_d_path(path: *mut path, dest: &mut [u8]) -> Result<&[u8], c_long> { + let len = gen::bpf_d_path(path, dest.as_mut_ptr() as *mut c_char, dest.len() as u32); + + read_str_bytes(len, dest) +}