diff --git a/bpf/aya-bpf-macros/src/lib.rs b/bpf/aya-bpf-macros/src/lib.rs index 61d49bae..96b0267e 100644 --- a/bpf/aya-bpf-macros/src/lib.rs +++ b/bpf/aya-bpf-macros/src/lib.rs @@ -168,7 +168,7 @@ pub fn raw_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream { /// Marks a function as an LSM program that can be attached to Linux LSM hooks. /// Used to implement security policy and audit logging. /// -/// LSM probes can be attached to the kernel's [security hooks][1] to implement mandatory +/// LSM probes can be attached to the kernel's security hooks to implement mandatory /// access control policy and security auditing. /// /// LSM probes require a kernel compiled with `CONFIG_BPF_LSM=y` and `CONFIG_DEBUG_INFO_BTF=y`. diff --git a/bpf/aya-bpf/src/args.rs b/bpf/aya-bpf/src/args.rs index 310a9611..42bfad9f 100644 --- a/bpf/aya-bpf/src/args.rs +++ b/bpf/aya-bpf/src/args.rs @@ -120,6 +120,55 @@ impl FromPtRegs for *const T { } } +#[cfg(bpf_target_arch = "x86_64")] +impl FromPtRegs for *mut T { + fn from_argument(ctx: &pt_regs, n: usize) -> Option { + match n { + 0 => ctx.rdi().map(|v| v as _), + 1 => ctx.rsi().map(|v| v as _), + 2 => ctx.rdx().map(|v| v as _), + 3 => ctx.rcx().map(|v| v as _), + 4 => ctx.r8().map(|v| v as _), + 5 => ctx.r9().map(|v| v as _), + _ => None, + } + } + + fn from_retval(ctx: &pt_regs) -> Option { + ctx.rax().map(|v| v as _) + } +} + +#[cfg(bpf_target_arch = "armv7")] +impl FromPtRegs for *mut T { + fn from_argument(ctx: &pt_regs, n: usize) -> Option { + if n <= 6 { + ctx.uregs().map(|regs| regs[n] as _) + } else { + None + } + } + + fn from_retval(ctx: &pt_regs) -> Option { + ctx.uregs().map(|regs| regs[0] as _) + } +} + +#[cfg(bpf_target_arch = "aarch64")] +impl FromPtRegs for *mut T { + fn from_argument(ctx: &pt_regs, n: usize) -> Option { + if n <= 7 { + ctx.regs().map(|regs| regs[n] as _) + } else { + None + } + } + + fn from_retval(ctx: &pt_regs) -> Option { + ctx.regs().map(|regs| regs[0] as _) + } +} + /// Helper macro to implement [`FromPtRegs`] for a primitive type. macro_rules! impl_from_pt_regs { ($type:ident) => { diff --git a/bpf/aya-bpf/src/helpers.rs b/bpf/aya-bpf/src/helpers.rs index 1b7ea5b4..868c5c2d 100644 --- a/bpf/aya-bpf/src/helpers.rs +++ b/bpf/aya-bpf/src/helpers.rs @@ -364,6 +364,45 @@ pub unsafe fn bpf_probe_read_kernel_str(src: *const u8, dest: &mut [u8]) -> Resu Ok(len as usize) } +/// Write bytes to the _user space_ pointer `src` and store them as a `T`. +/// +/// # Examples +/// +/// ```no_run +/// # #![allow(dead_code)] +/// # use aya_bpf::{ +/// # cty::{c_int, c_long}, +/// # helpers::bpf_probe_write_user, +/// # programs::ProbeContext, +/// # }; +/// fn try_test(ctx: ProbeContext) -> Result<(), c_long> { +/// let retp: *mut c_int = ctx.arg(0).ok_or(1)?; +/// let val: i32 = 1; +/// // Write the value to the userspace pointer. +/// unsafe { bpf_probe_write_user(retp, &val as *const i32)? }; +/// +/// Ok::<(), c_long>(()) +/// } +/// ``` +/// +/// # Errors +/// +/// On failure, this function returns a negative value wrapped in an `Err`. +#[allow(clippy::fn_to_numeric_cast_with_truncation)] +#[inline] +pub unsafe fn bpf_probe_write_user(dst: *mut T, src: *const T) -> Result<(), c_long> { + let ret = gen::bpf_probe_write_user( + dst as *mut c_void, + src as *const c_void, + mem::size_of::() as u32, + ); + if ret < 0 { + return Err(ret); + } + + Ok(()) +} + /// Read the `comm` field associated with the current task struct /// as a `[c_char; 16]`. ///