mirror of https://github.com/aya-rs/aya
Add support for raw tracepoint and LSM programs
This change adds support for the following program types: * raw tracepoint * LSM Supporting LSM programs involved a necessity of supporting more load_attrs for the BPF_PROG_LOAD operation, concretely: * expected_attach_type - for LSM programs, it has always to be set to BPF_LSM_MAC * attach_btf_obj_fd - it's often used to reference the file descriptor of program's BTF info, altough in case of LSM programs, it only has to contain the value 0, which means the vmlinux object file (usually /sys/kernel/btf/vmlinux) * attach_btf_id - ID of the BTF object, which in case of LSM programs is the ID of the function (the LSM hook) The example of LSM program using that functionality can be found here: https://github.com/vadorovsky/aya-example-lsm Fixes: #9 Signed-off-by: William Findlay <william@williamfindlay.com> Signed-off-by: Michal Rostecki <mrostecki@opensuse.org>pull/68/head
parent
a94774755f
commit
169478c863
@ -0,0 +1,109 @@
|
|||||||
|
//! LSM probes.
|
||||||
|
use std::os::unix::io::RawFd;
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
generated::{bpf_attach_type::BPF_LSM_MAC, bpf_prog_type::BPF_PROG_TYPE_LSM},
|
||||||
|
obj::btf::{Btf, BtfError, BtfKind},
|
||||||
|
programs::{load_program, FdLink, LinkRef, ProgramData, ProgramError},
|
||||||
|
sys::bpf_raw_tracepoint_open,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A program that attaches 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
|
||||||
|
/// access control policy and security auditing.
|
||||||
|
///
|
||||||
|
/// LSM probes require a kernel compiled with `CONFIG_BPF_LSM=y` and `CONFIG_DEBUG_INFO_BTF=y`.
|
||||||
|
/// In order for the probes to fire, you also need the BPF LSM to be enabled through your
|
||||||
|
/// kernel's boot paramters (like `lsm=lockdown,yama,bpf`).
|
||||||
|
///
|
||||||
|
/// # Minimum kernel version
|
||||||
|
///
|
||||||
|
/// The minimum kernel version required to use this feature is 5.7.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # #[derive(thiserror::Error, Debug)]
|
||||||
|
/// # enum LsmError {
|
||||||
|
/// # #[error(transparent)]
|
||||||
|
/// # LsmLoad(#[from] aya::programs::LsmLoadError),
|
||||||
|
/// # #[error(transparent)]
|
||||||
|
/// # Program(#[from] aya::programs::ProgramError),
|
||||||
|
/// # #[error(transparent)]
|
||||||
|
/// # Bpf(#[from] aya::BpfError),
|
||||||
|
/// # }
|
||||||
|
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
|
||||||
|
/// use aya::{Bpf, programs::Lsm};
|
||||||
|
/// use std::convert::TryInto;
|
||||||
|
///
|
||||||
|
/// let program: &mut Lsm = bpf.program_mut("lsm_prog")?.try_into()?;
|
||||||
|
/// program.load("security_bprm_exec")?;
|
||||||
|
/// program.attach()?;
|
||||||
|
/// # Ok::<(), LsmError>(())
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [1]: https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hook_defs.h
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_LSM")]
|
||||||
|
pub struct Lsm {
|
||||||
|
pub(crate) data: ProgramData,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error type returned when loading LSM programs.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LsmLoadError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Btf(#[from] BtfError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
Program(#[from] ProgramError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lsm {
|
||||||
|
/// Loads the program inside the kernel.
|
||||||
|
///
|
||||||
|
/// See also [`Program::load`](crate::programs::Program::load).
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `lsm_hook_name` - full name of the LSM hook that the program should
|
||||||
|
/// be attached to
|
||||||
|
pub fn load(&mut self, lsm_hook_name: &str) -> Result<(), LsmLoadError> {
|
||||||
|
let btf = &Btf::from_sys_fs()?;
|
||||||
|
self.data.expected_attach_type = Some(BPF_LSM_MAC);
|
||||||
|
let type_name = format!("bpf_lsm_{}", lsm_hook_name);
|
||||||
|
self.data.attach_btf_id =
|
||||||
|
Some(btf.id_by_type_name_kind(type_name.as_str(), BtfKind::Func)?);
|
||||||
|
load_program(BPF_PROG_TYPE_LSM, &mut self.data).map_err(LsmLoadError::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the program.
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.data.name.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attaches the program.
|
||||||
|
pub fn attach(&mut self) -> Result<LinkRef, ProgramError> {
|
||||||
|
attach_btf_id(&mut self.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Common logic for all BPF program types that attach to a BTF id.
|
||||||
|
pub(crate) fn attach_btf_id(program_data: &mut ProgramData) -> Result<LinkRef, ProgramError> {
|
||||||
|
let prog_fd = program_data.fd_or_err()?;
|
||||||
|
|
||||||
|
// Attaching LSM programs doesn't require providing attach name. LSM
|
||||||
|
// programs are attached to LSM hook which is specified in the program.
|
||||||
|
let pfd = bpf_raw_tracepoint_open(None, prog_fd).map_err(|(_code, io_error)| {
|
||||||
|
ProgramError::SyscallError {
|
||||||
|
call: "bpf_raw_tracepoint_open".to_owned(),
|
||||||
|
io_error,
|
||||||
|
}
|
||||||
|
})? as RawFd;
|
||||||
|
|
||||||
|
Ok(program_data.link(FdLink { fd: Some(pfd) }))
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
//! Raw tracepoints.
|
||||||
|
use std::{ffi::CString, os::unix::io::RawFd};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
generated::bpf_prog_type::BPF_PROG_TYPE_RAW_TRACEPOINT,
|
||||||
|
programs::{load_program, FdLink, LinkRef, ProgramData, ProgramError},
|
||||||
|
sys::bpf_raw_tracepoint_open,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A program that can be attached at a pre-defined kernel trace point, but also
|
||||||
|
/// has an access to kernel internal arguments of trace points, which
|
||||||
|
/// differentiates them from traditional tracepoint eBPF programs.
|
||||||
|
///
|
||||||
|
/// The kernel provides a set of pre-defined trace points that eBPF programs can
|
||||||
|
/// be attached to. See`/sys/kernel/debug/tracing/events` for a list of which
|
||||||
|
/// events can be traced.
|
||||||
|
///
|
||||||
|
/// # Minimum kernel version
|
||||||
|
///
|
||||||
|
/// The minimum kernel version required to use this feature is 4.17.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
|
||||||
|
/// use aya::{Bpf, programs::RawTracePoint};
|
||||||
|
/// use std::convert::TryInto;
|
||||||
|
///
|
||||||
|
/// let program: &mut RawTracePoint = bpf.program_mut("sys_enter")?.try_into()?;
|
||||||
|
/// program.load()?;
|
||||||
|
/// program.attach("sys_enter")?;
|
||||||
|
/// # Ok::<(), aya::BpfError>(())
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_RAW_TRACEPOINT")]
|
||||||
|
pub struct RawTracePoint {
|
||||||
|
pub(crate) data: ProgramData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawTracePoint {
|
||||||
|
/// Loads the program inside the kernel.
|
||||||
|
///
|
||||||
|
/// See also [`Program::load`](crate::programs::Program::load).
|
||||||
|
pub fn load(&mut self) -> Result<(), ProgramError> {
|
||||||
|
load_program(BPF_PROG_TYPE_RAW_TRACEPOINT, &mut self.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the program.
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.data.name.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attaches the program to the given tracepoint.
|
||||||
|
pub fn attach(&mut self, tp_name: &str) -> Result<LinkRef, ProgramError> {
|
||||||
|
let prog_fd = self.data.fd_or_err()?;
|
||||||
|
let name = CString::new(tp_name).unwrap();
|
||||||
|
|
||||||
|
let pfd = bpf_raw_tracepoint_open(Some(&name), prog_fd).map_err(|(_code, io_error)| {
|
||||||
|
ProgramError::SyscallError {
|
||||||
|
call: "bpf_raw_tracepoint_open".to_owned(),
|
||||||
|
io_error,
|
||||||
|
}
|
||||||
|
})? as RawFd;
|
||||||
|
|
||||||
|
Ok(self.data.link(FdLink { fd: Some(pfd) }))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
use core::ffi::c_void;
|
||||||
|
|
||||||
|
use crate::BpfContext;
|
||||||
|
|
||||||
|
pub struct LsmContext {
|
||||||
|
ctx: *mut c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LsmContext {
|
||||||
|
pub fn new(ctx: *mut c_void) -> LsmContext {
|
||||||
|
LsmContext { ctx }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BpfContext for LsmContext {
|
||||||
|
fn as_ptr(&self) -> *mut c_void {
|
||||||
|
self.ctx
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
use core::ffi::c_void;
|
||||||
|
|
||||||
|
use crate::BpfContext;
|
||||||
|
|
||||||
|
pub struct RawTracePointContext {
|
||||||
|
ctx: *mut c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawTracePointContext {
|
||||||
|
pub fn new(ctx: *mut c_void) -> RawTracePointContext {
|
||||||
|
RawTracePointContext { ctx }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BpfContext for RawTracePointContext {
|
||||||
|
fn as_ptr(&self) -> *mut c_void {
|
||||||
|
self.ctx
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue