mirror of https://github.com/aya-rs/aya
aya-bpf: implement argument coercion for pt_regs and BTF programs
Implements argument and return value coercion helpers for: - LSM programs - BTF tracepoints - [ku]{ret}probes Signed-off-by: William Findlay <william@williamfindlay.com>pull/83/head
parent
972e5e636a
commit
89dee1a114
@ -0,0 +1,9 @@
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
if env::var("CARGO_CFG_BPF_TARGET_ARCH").is_err() {
|
||||
let arch = env::var("HOST").unwrap();
|
||||
let arch = arch.split_once('-').map_or(&*arch, |x| x.0);
|
||||
println!("cargo:rustc-cfg=bpf_target_arch=\"{}\"", arch);
|
||||
}
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
use crate::cty::c_void;
|
||||
|
||||
// aarch64 uses user_pt_regs instead of pt_regs
|
||||
#[cfg(not(bpf_target_arch = "aarch64"))]
|
||||
use crate::bindings::pt_regs;
|
||||
#[cfg(bpf_target_arch = "aarch64")]
|
||||
use crate::bindings::user_pt_regs as pt_regs;
|
||||
|
||||
/// A trait that indicates a valid type for an argument which can be coerced from a BTF
|
||||
/// context.
|
||||
///
|
||||
/// Users should not implement this trait.
|
||||
///
|
||||
/// SAFETY: This trait is _only_ safe to implement on primitive types that can fit into
|
||||
/// a `u64`. For example, integers and raw pointers may be coerced from a BTF context.
|
||||
pub unsafe trait FromBtfArgument: Sized {
|
||||
/// Coerces a `T` from the `n`th argument from a BTF context where `n` starts
|
||||
/// at 0 and increases by 1 for each successive argument.
|
||||
///
|
||||
/// SAFETY: This function is deeply unsafe, as we are reading raw pointers into kernel
|
||||
/// memory. In particular, the value of `n` must not exceed the number of function
|
||||
/// arguments. Moreover, `ctx` must be a valid pointer to a BTF context, and `T` must
|
||||
/// be the right type for the given argument.
|
||||
unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self;
|
||||
}
|
||||
|
||||
unsafe impl<T> FromBtfArgument for *const T {
|
||||
unsafe fn from_argument(ctx: *const c_void, n: usize) -> *const T {
|
||||
// BTF arguments are exposed as an array of `usize` where `usize` can
|
||||
// either be treated as a pointer or a primitive type
|
||||
*(ctx as *const usize).add(n) as _
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper macro to implement [`FromBtfArgument`] for a primitive type.
|
||||
macro_rules! unsafe_impl_from_btf_argument {
|
||||
($type:ident) => {
|
||||
unsafe impl FromBtfArgument for $type {
|
||||
unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self {
|
||||
// BTF arguments are exposed as an array of `usize` where `usize` can
|
||||
// either be treated as a pointer or a primitive type
|
||||
*(ctx as *const usize).add(n) as _
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe_impl_from_btf_argument!(u8);
|
||||
unsafe_impl_from_btf_argument!(u16);
|
||||
unsafe_impl_from_btf_argument!(u32);
|
||||
unsafe_impl_from_btf_argument!(u64);
|
||||
unsafe_impl_from_btf_argument!(i8);
|
||||
unsafe_impl_from_btf_argument!(i16);
|
||||
unsafe_impl_from_btf_argument!(i32);
|
||||
unsafe_impl_from_btf_argument!(i64);
|
||||
unsafe_impl_from_btf_argument!(usize);
|
||||
unsafe_impl_from_btf_argument!(isize);
|
||||
|
||||
/// A trait that indicates a valid type for an argument which can be coerced from
|
||||
/// a pt_regs context.
|
||||
///
|
||||
/// Any implementation of this trait is strictly architecture-specific and depends on the
|
||||
/// layout of the underlying pt_regs struct and the target processor's calling
|
||||
/// conventions. Users should not implement this trait.
|
||||
pub trait FromPtRegs: Sized {
|
||||
/// Coerces a `T` from the `n`th argument of a pt_regs context where `n` starts
|
||||
/// at 0 and increases by 1 for each successive argument.
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self>;
|
||||
|
||||
/// Coerces a `T` from the return value of a pt_regs context.
|
||||
fn from_retval(ctx: &pt_regs) -> Option<Self>;
|
||||
}
|
||||
|
||||
#[cfg(bpf_target_arch = "x86_64")]
|
||||
impl<T> FromPtRegs for *const T {
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
||||
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<Self> {
|
||||
ctx.rax().map(|v| v as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(bpf_target_arch = "armv7")]
|
||||
impl<T> FromPtRegs for *const T {
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
||||
if n <= 6 {
|
||||
ctx.uregs().map(|regs| regs[n] as _)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
||||
ctx.uregs().map(|regs| regs[0] as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(bpf_target_arch = "aarch64")]
|
||||
impl<T> FromPtRegs for *const T {
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
||||
if n <= 7 {
|
||||
ctx.regs().map(|regs| regs[n] as _)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
||||
ctx.regs().map(|regs| regs[0] as _)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper macro to implement [`FromPtRegs`] for a primitive type.
|
||||
macro_rules! impl_from_pt_regs {
|
||||
($type:ident) => {
|
||||
#[cfg(bpf_target_arch = "x86_64")]
|
||||
impl FromPtRegs for $type {
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
||||
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<Self> {
|
||||
ctx.rax().map(|v| v as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(bpf_target_arch = "armv7")]
|
||||
impl FromPtRegs for $type {
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
||||
if n <= 6 {
|
||||
ctx.uregs().map(|regs| regs[n] as _)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
||||
ctx.uregs().map(|regs| regs[0] as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(bpf_target_arch = "aarch64")]
|
||||
impl FromPtRegs for $type {
|
||||
fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
|
||||
if n <= 7 {
|
||||
ctx.regs().map(|regs| regs[n] as _)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn from_retval(ctx: &pt_regs) -> Option<Self> {
|
||||
ctx.regs().map(|regs| regs[0] as _)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_pt_regs!(u8);
|
||||
impl_from_pt_regs!(u16);
|
||||
impl_from_pt_regs!(u32);
|
||||
impl_from_pt_regs!(u64);
|
||||
impl_from_pt_regs!(i8);
|
||||
impl_from_pt_regs!(i16);
|
||||
impl_from_pt_regs!(i32);
|
||||
impl_from_pt_regs!(i64);
|
||||
impl_from_pt_regs!(usize);
|
||||
impl_from_pt_regs!(isize);
|
Loading…
Reference in New Issue