|
|
|
@ -259,6 +259,9 @@ pub unsafe fn bpf_probe_read_kernel_buf(src: *const u8, dst: &mut [u8]) -> Resul
|
|
|
|
|
/// # Errors
|
|
|
|
|
///
|
|
|
|
|
/// On failure, this function returns Err(-1).
|
|
|
|
|
#[deprecated(
|
|
|
|
|
note = "Use `bpf_probe_read_user_str_bytes` or `bpf_probe_read_kernel_str_bytes` instead"
|
|
|
|
|
)]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn bpf_probe_read_str(src: *const u8, dest: &mut [u8]) -> Result<usize, c_long> {
|
|
|
|
|
let len = gen::bpf_probe_read_str(
|
|
|
|
@ -302,6 +305,7 @@ pub unsafe fn bpf_probe_read_str(src: *const u8, dest: &mut [u8]) -> Result<usiz
|
|
|
|
|
/// # Errors
|
|
|
|
|
///
|
|
|
|
|
/// On failure, this function returns Err(-1).
|
|
|
|
|
#[deprecated(note = "Use `bpf_probe_read_user_str_bytes` instead")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn bpf_probe_read_user_str(src: *const u8, dest: &mut [u8]) -> Result<usize, c_long> {
|
|
|
|
|
let len = gen::bpf_probe_read_user_str(
|
|
|
|
@ -322,6 +326,113 @@ pub unsafe fn bpf_probe_read_user_str(src: *const u8, dest: &mut [u8]) -> Result
|
|
|
|
|
Ok(len as usize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a byte slice read from _user space_ address `src`.
|
|
|
|
|
///
|
|
|
|
|
/// Reads at most `dest.len()` bytes from the `src` address, truncating if the
|
|
|
|
|
/// length of the source string 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.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// With an array allocated on the stack (not recommended for bigger strings,
|
|
|
|
|
/// eBPF stack limit is 512 bytes):
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// # #![allow(dead_code)]
|
|
|
|
|
/// # use aya_bpf::{cty::c_long, helpers::bpf_probe_read_user_str_bytes};
|
|
|
|
|
/// # fn try_test() -> Result<(), c_long> {
|
|
|
|
|
/// # let user_ptr: *const u8 = 0 as _;
|
|
|
|
|
/// let mut buf = [0u8; 16];
|
|
|
|
|
/// let my_str_bytes = unsafe { bpf_probe_read_user_str_bytes(user_ptr, &mut buf)? };
|
|
|
|
|
///
|
|
|
|
|
/// // Do something with my_str_bytes
|
|
|
|
|
/// # Ok::<(), c_long>(())
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// With a `PerCpuArray` (with size defined by us):
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// # use aya_bpf::{cty::c_long, helpers::bpf_probe_read_user_str_bytes};
|
|
|
|
|
/// use aya_bpf::{macros::map, maps::PerCpuArray};
|
|
|
|
|
///
|
|
|
|
|
/// #[repr(C)]
|
|
|
|
|
/// pub struct Buf {
|
|
|
|
|
/// pub buf: [u8; 4096],
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// #[map]
|
|
|
|
|
/// pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0);
|
|
|
|
|
///
|
|
|
|
|
/// # fn try_test() -> Result<(), c_long> {
|
|
|
|
|
/// # let user_ptr: *const u8 = 0 as _;
|
|
|
|
|
/// let buf = unsafe {
|
|
|
|
|
/// let ptr = BUF.get_ptr_mut(0).ok_or(0)?;
|
|
|
|
|
/// &mut *ptr
|
|
|
|
|
/// };
|
|
|
|
|
/// let my_str_bytes = unsafe { bpf_probe_read_user_str_bytes(user_ptr, &mut buf.buf)? };
|
|
|
|
|
///
|
|
|
|
|
/// // Do something with my_str_bytes
|
|
|
|
|
/// # Ok::<(), c_long>(())
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// You can also convert the resulted bytes slice into `&str` using
|
|
|
|
|
/// [core::str::from_utf8_unchecked]:
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// # #![allow(dead_code)]
|
|
|
|
|
/// # use aya_bpf::{cty::c_long, helpers::bpf_probe_read_user_str_bytes};
|
|
|
|
|
/// # use aya_bpf::{macros::map, maps::PerCpuArray};
|
|
|
|
|
/// # #[repr(C)]
|
|
|
|
|
/// # pub struct Buf {
|
|
|
|
|
/// # pub buf: [u8; 4096],
|
|
|
|
|
/// # }
|
|
|
|
|
/// # #[map]
|
|
|
|
|
/// # pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0);
|
|
|
|
|
/// # fn try_test() -> Result<(), c_long> {
|
|
|
|
|
/// # let user_ptr: *const u8 = 0 as _;
|
|
|
|
|
/// # let buf = unsafe {
|
|
|
|
|
/// # let ptr = BUF.get_ptr_mut(0).ok_or(0)?;
|
|
|
|
|
/// # &mut *ptr
|
|
|
|
|
/// # };
|
|
|
|
|
/// let my_str = unsafe {
|
|
|
|
|
/// core::str::from_utf8_unchecked(bpf_probe_read_user_str_bytes(user_ptr, &mut buf.buf)?)
|
|
|
|
|
/// };
|
|
|
|
|
///
|
|
|
|
|
/// // Do something with my_str
|
|
|
|
|
/// # Ok::<(), c_long>(())
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
|
|
|
|
///
|
|
|
|
|
/// On failure, this function returns Err(-1).
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn bpf_probe_read_user_str_bytes(
|
|
|
|
|
src: *const u8,
|
|
|
|
|
dest: &mut [u8],
|
|
|
|
|
) -> Result<&[u8], c_long> {
|
|
|
|
|
let len = gen::bpf_probe_read_user_str(
|
|
|
|
|
dest.as_mut_ptr() as *mut c_void,
|
|
|
|
|
dest.len() as u32,
|
|
|
|
|
src as *const c_void,
|
|
|
|
|
);
|
|
|
|
|
if len < 0 {
|
|
|
|
|
return Err(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let len = len as usize;
|
|
|
|
|
if len >= dest.len() {
|
|
|
|
|
// this can never happen, it's needed to tell the verifier that len is
|
|
|
|
|
// bounded
|
|
|
|
|
return Err(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(&dest[..len])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Read a null-terminated string from _kernel space_ stored at `src` into `dest`.
|
|
|
|
|
///
|
|
|
|
|
/// In case the length of `dest` is smaller then the length of `src`, the read bytes will
|
|
|
|
@ -345,6 +456,7 @@ pub unsafe fn bpf_probe_read_user_str(src: *const u8, dest: &mut [u8]) -> Result
|
|
|
|
|
/// # Errors
|
|
|
|
|
///
|
|
|
|
|
/// On failure, this function returns Err(-1).
|
|
|
|
|
#[deprecated(note = "Use bpf_probe_read_kernel_str_bytes instead")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn bpf_probe_read_kernel_str(src: *const u8, dest: &mut [u8]) -> Result<usize, c_long> {
|
|
|
|
|
let len = gen::bpf_probe_read_kernel_str(
|
|
|
|
@ -365,6 +477,114 @@ pub unsafe fn bpf_probe_read_kernel_str(src: *const u8, dest: &mut [u8]) -> Resu
|
|
|
|
|
Ok(len as usize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a byte slice read from _kernel space_ address `src`.
|
|
|
|
|
///
|
|
|
|
|
/// Reads at most `dest.len()` bytes from the `src` address, truncating if the
|
|
|
|
|
/// length of the source string 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.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// With an array allocated on the stack (not recommended for bigger strings,
|
|
|
|
|
/// eBPF stack limit is 512 bytes):
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// # #![allow(dead_code)]
|
|
|
|
|
/// # use aya_bpf::{cty::c_long, helpers::bpf_probe_read_kernel_str_bytes};
|
|
|
|
|
/// # fn try_test() -> Result<(), c_long> {
|
|
|
|
|
/// # let kernel_ptr: *const u8 = 0 as _;
|
|
|
|
|
/// let mut buf = [0u8; 16];
|
|
|
|
|
/// let my_str_bytes = unsafe { bpf_probe_read_kernel_str_bytes(kernel_ptr, &mut buf)? };
|
|
|
|
|
///
|
|
|
|
|
/// // Do something with my_str_bytes
|
|
|
|
|
/// # Ok::<(), c_long>(())
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// With a `PerCpuArray` (with size defined by us):
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// # #![allow(dead_code)]
|
|
|
|
|
/// # use aya_bpf::{cty::c_long, helpers::bpf_probe_read_kernel_str_bytes};
|
|
|
|
|
/// use aya_bpf::{macros::map, maps::PerCpuArray};
|
|
|
|
|
///
|
|
|
|
|
/// #[repr(C)]
|
|
|
|
|
/// pub struct Buf {
|
|
|
|
|
/// pub buf: [u8; 4096],
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// #[map]
|
|
|
|
|
/// pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0);
|
|
|
|
|
///
|
|
|
|
|
/// # fn try_test() -> Result<(), c_long> {
|
|
|
|
|
/// # let kernel_ptr: *const u8 = 0 as _;
|
|
|
|
|
/// let buf = unsafe {
|
|
|
|
|
/// let ptr = BUF.get_ptr_mut(0).ok_or(0)?;
|
|
|
|
|
/// &mut *ptr
|
|
|
|
|
/// };
|
|
|
|
|
/// let my_str_bytes = unsafe { bpf_probe_read_kernel_str_bytes(kernel_ptr, &mut buf.buf)? };
|
|
|
|
|
///
|
|
|
|
|
/// // Do something with my_str_bytes
|
|
|
|
|
/// # Ok::<(), c_long>(())
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// You can also convert the resulted bytes slice into `&str` using
|
|
|
|
|
/// [core::str::from_utf8_unchecked]:
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// # #![allow(dead_code)]
|
|
|
|
|
/// # use aya_bpf::{cty::c_long, helpers::bpf_probe_read_kernel_str_bytes};
|
|
|
|
|
/// # use aya_bpf::{macros::map, maps::PerCpuArray};
|
|
|
|
|
/// # #[repr(C)]
|
|
|
|
|
/// # pub struct Buf {
|
|
|
|
|
/// # pub buf: [u8; 4096],
|
|
|
|
|
/// # }
|
|
|
|
|
/// # #[map]
|
|
|
|
|
/// # pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0);
|
|
|
|
|
/// # fn try_test() -> Result<(), c_long> {
|
|
|
|
|
/// # let kernel_ptr: *const u8 = 0 as _;
|
|
|
|
|
/// # let buf = unsafe {
|
|
|
|
|
/// # let ptr = BUF.get_ptr_mut(0).ok_or(0)?;
|
|
|
|
|
/// # &mut *ptr
|
|
|
|
|
/// # };
|
|
|
|
|
/// let my_str = unsafe {
|
|
|
|
|
/// core::str::from_utf8_unchecked(bpf_probe_read_kernel_str_bytes(kernel_ptr, &mut buf.buf)?)
|
|
|
|
|
/// };
|
|
|
|
|
///
|
|
|
|
|
/// // Do something with my_str
|
|
|
|
|
/// # Ok::<(), c_long>(())
|
|
|
|
|
/// # }
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
|
|
|
|
///
|
|
|
|
|
/// On failure, this function returns Err(-1).
|
|
|
|
|
#[inline]
|
|
|
|
|
pub unsafe fn bpf_probe_read_kernel_str_bytes(
|
|
|
|
|
src: *const u8,
|
|
|
|
|
dest: &mut [u8],
|
|
|
|
|
) -> Result<&[u8], c_long> {
|
|
|
|
|
let len = gen::bpf_probe_read_kernel_str(
|
|
|
|
|
dest.as_mut_ptr() as *mut c_void,
|
|
|
|
|
dest.len() as u32,
|
|
|
|
|
src as *const c_void,
|
|
|
|
|
);
|
|
|
|
|
if len < 0 {
|
|
|
|
|
return Err(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let len = len as usize;
|
|
|
|
|
if len >= dest.len() {
|
|
|
|
|
// this can never happen, it's needed to tell the verifier that len is
|
|
|
|
|
// bounded
|
|
|
|
|
return Err(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(&dest[..len])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Write bytes to the _user space_ pointer `src` and store them as a `T`.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|