mirror of https://github.com/aya-rs/aya
Merge pull request #68 from vadorovsky/lsm
Add support for raw tracepoint and LSM programspull/85/head
commit
140005d9e3
@ -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