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