|
|
|
@ -69,7 +69,7 @@ use std::{
|
|
|
|
|
ffi::CString,
|
|
|
|
|
io,
|
|
|
|
|
os::unix::io::{AsRawFd, RawFd},
|
|
|
|
|
path::Path,
|
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
|
};
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
@ -108,8 +108,9 @@ use crate::{
|
|
|
|
|
obj::{self, btf::BtfError, Function, KernelVersion},
|
|
|
|
|
pin::PinError,
|
|
|
|
|
sys::{
|
|
|
|
|
bpf_get_object, bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id,
|
|
|
|
|
bpf_prog_get_info_by_fd, bpf_prog_query, retry_with_verifier_logs, BpfLoadProgramAttrs,
|
|
|
|
|
bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object,
|
|
|
|
|
bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_query, retry_with_verifier_logs,
|
|
|
|
|
BpfLoadProgramAttrs,
|
|
|
|
|
},
|
|
|
|
|
util::VerifierLog,
|
|
|
|
|
};
|
|
|
|
@ -337,33 +338,33 @@ impl Program {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Unload the program
|
|
|
|
|
fn unload(&mut self) -> Result<(), ProgramError> {
|
|
|
|
|
/// Unloads the program from the kernel.
|
|
|
|
|
pub fn unload(self) -> Result<(), ProgramError> {
|
|
|
|
|
match self {
|
|
|
|
|
Program::KProbe(p) => p.unload(),
|
|
|
|
|
Program::UProbe(p) => p.unload(),
|
|
|
|
|
Program::TracePoint(p) => p.unload(),
|
|
|
|
|
Program::SocketFilter(p) => p.unload(),
|
|
|
|
|
Program::Xdp(p) => p.unload(),
|
|
|
|
|
Program::SkMsg(p) => p.unload(),
|
|
|
|
|
Program::SkSkb(p) => p.unload(),
|
|
|
|
|
Program::SockOps(p) => p.unload(),
|
|
|
|
|
Program::SchedClassifier(p) => p.unload(),
|
|
|
|
|
Program::CgroupSkb(p) => p.unload(),
|
|
|
|
|
Program::CgroupSysctl(p) => p.unload(),
|
|
|
|
|
Program::CgroupSockopt(p) => p.unload(),
|
|
|
|
|
Program::LircMode2(p) => p.unload(),
|
|
|
|
|
Program::PerfEvent(p) => p.unload(),
|
|
|
|
|
Program::RawTracePoint(p) => p.unload(),
|
|
|
|
|
Program::Lsm(p) => p.unload(),
|
|
|
|
|
Program::BtfTracePoint(p) => p.unload(),
|
|
|
|
|
Program::FEntry(p) => p.unload(),
|
|
|
|
|
Program::FExit(p) => p.unload(),
|
|
|
|
|
Program::Extension(p) => p.unload(),
|
|
|
|
|
Program::CgroupSockAddr(p) => p.unload(),
|
|
|
|
|
Program::SkLookup(p) => p.unload(),
|
|
|
|
|
Program::CgroupSock(p) => p.unload(),
|
|
|
|
|
Program::CgroupDevice(p) => p.unload(),
|
|
|
|
|
Program::KProbe(mut p) => p.unload(),
|
|
|
|
|
Program::UProbe(mut p) => p.unload(),
|
|
|
|
|
Program::TracePoint(mut p) => p.unload(),
|
|
|
|
|
Program::SocketFilter(mut p) => p.unload(),
|
|
|
|
|
Program::Xdp(mut p) => p.unload(),
|
|
|
|
|
Program::SkMsg(mut p) => p.unload(),
|
|
|
|
|
Program::SkSkb(mut p) => p.unload(),
|
|
|
|
|
Program::SockOps(mut p) => p.unload(),
|
|
|
|
|
Program::SchedClassifier(mut p) => p.unload(),
|
|
|
|
|
Program::CgroupSkb(mut p) => p.unload(),
|
|
|
|
|
Program::CgroupSysctl(mut p) => p.unload(),
|
|
|
|
|
Program::CgroupSockopt(mut p) => p.unload(),
|
|
|
|
|
Program::LircMode2(mut p) => p.unload(),
|
|
|
|
|
Program::PerfEvent(mut p) => p.unload(),
|
|
|
|
|
Program::RawTracePoint(mut p) => p.unload(),
|
|
|
|
|
Program::Lsm(mut p) => p.unload(),
|
|
|
|
|
Program::BtfTracePoint(mut p) => p.unload(),
|
|
|
|
|
Program::FEntry(mut p) => p.unload(),
|
|
|
|
|
Program::FExit(mut p) => p.unload(),
|
|
|
|
|
Program::Extension(mut p) => p.unload(),
|
|
|
|
|
Program::CgroupSockAddr(mut p) => p.unload(),
|
|
|
|
|
Program::SkLookup(mut p) => p.unload(),
|
|
|
|
|
Program::CgroupSock(mut p) => p.unload(),
|
|
|
|
|
Program::CgroupDevice(mut p) => p.unload(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -401,16 +402,10 @@ impl Program {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for Program {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
let _ = self.unload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub(crate) struct ProgramData<T: Link> {
|
|
|
|
|
pub(crate) name: Option<String>,
|
|
|
|
|
pub(crate) obj: obj::Program,
|
|
|
|
|
pub(crate) obj: Option<obj::Program>,
|
|
|
|
|
pub(crate) fd: Option<RawFd>,
|
|
|
|
|
pub(crate) links: LinkMap<T>,
|
|
|
|
|
pub(crate) expected_attach_type: Option<bpf_attach_type>,
|
|
|
|
@ -419,6 +414,7 @@ pub(crate) struct ProgramData<T: Link> {
|
|
|
|
|
pub(crate) attach_prog_fd: Option<RawFd>,
|
|
|
|
|
pub(crate) btf_fd: Option<RawFd>,
|
|
|
|
|
pub(crate) verifier_log_level: u32,
|
|
|
|
|
pub(crate) path: Option<PathBuf>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Link> ProgramData<T> {
|
|
|
|
@ -430,7 +426,7 @@ impl<T: Link> ProgramData<T> {
|
|
|
|
|
) -> ProgramData<T> {
|
|
|
|
|
ProgramData {
|
|
|
|
|
name,
|
|
|
|
|
obj,
|
|
|
|
|
obj: Some(obj),
|
|
|
|
|
fd: None,
|
|
|
|
|
links: LinkMap::new(),
|
|
|
|
|
expected_attach_type: None,
|
|
|
|
@ -439,8 +435,68 @@ impl<T: Link> ProgramData<T> {
|
|
|
|
|
attach_prog_fd: None,
|
|
|
|
|
btf_fd,
|
|
|
|
|
verifier_log_level,
|
|
|
|
|
path: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn from_bpf_prog_info(
|
|
|
|
|
name: Option<String>,
|
|
|
|
|
fd: RawFd,
|
|
|
|
|
path: &Path,
|
|
|
|
|
info: bpf_prog_info,
|
|
|
|
|
) -> Result<ProgramData<T>, ProgramError> {
|
|
|
|
|
let attach_btf_id = if info.attach_btf_id > 0 {
|
|
|
|
|
Some(info.attach_btf_id)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
let attach_btf_obj_fd = if info.attach_btf_obj_id > 0 {
|
|
|
|
|
let fd = bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| {
|
|
|
|
|
ProgramError::SyscallError {
|
|
|
|
|
call: "bpf_btf_get_fd_by_id".to_string(),
|
|
|
|
|
io_error,
|
|
|
|
|
}
|
|
|
|
|
})?;
|
|
|
|
|
Some(fd as u32)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(ProgramData {
|
|
|
|
|
name,
|
|
|
|
|
obj: None,
|
|
|
|
|
fd: Some(fd),
|
|
|
|
|
links: LinkMap::new(),
|
|
|
|
|
expected_attach_type: None,
|
|
|
|
|
attach_btf_obj_fd,
|
|
|
|
|
attach_btf_id,
|
|
|
|
|
attach_prog_fd: None,
|
|
|
|
|
btf_fd: None,
|
|
|
|
|
verifier_log_level: 0,
|
|
|
|
|
path: Some(path.to_path_buf()),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn from_pinned_path<P: AsRef<Path>>(
|
|
|
|
|
path: P,
|
|
|
|
|
) -> Result<ProgramData<T>, ProgramError> {
|
|
|
|
|
let path_string =
|
|
|
|
|
CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap();
|
|
|
|
|
let fd =
|
|
|
|
|
bpf_get_object(&path_string).map_err(|(_, io_error)| ProgramError::SyscallError {
|
|
|
|
|
call: "bpf_obj_get".to_owned(),
|
|
|
|
|
io_error,
|
|
|
|
|
})? as RawFd;
|
|
|
|
|
|
|
|
|
|
let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| ProgramError::SyscallError {
|
|
|
|
|
call: "bpf_prog_get_info_by_fd".to_owned(),
|
|
|
|
|
io_error,
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
let info = ProgramInfo(info);
|
|
|
|
|
let name = info.name_as_str().map(|s| s.to_string());
|
|
|
|
|
ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info.0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Link> ProgramData<T> {
|
|
|
|
@ -493,6 +549,11 @@ fn load_program<T: Link>(
|
|
|
|
|
if fd.is_some() {
|
|
|
|
|
return Err(ProgramError::AlreadyLoaded);
|
|
|
|
|
}
|
|
|
|
|
if obj.is_none() {
|
|
|
|
|
// This program was loaded from a pin in bpffs
|
|
|
|
|
return Err(ProgramError::AlreadyLoaded);
|
|
|
|
|
}
|
|
|
|
|
let obj = obj.as_ref().unwrap();
|
|
|
|
|
let crate::obj::Program {
|
|
|
|
|
function:
|
|
|
|
|
Function {
|
|
|
|
@ -621,6 +682,12 @@ macro_rules! impl_program_unload {
|
|
|
|
|
unload_program(&mut self.data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for $struct_name {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
let _ = self.unload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)+
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -703,8 +770,17 @@ macro_rules! impl_program_pin{
|
|
|
|
|
/// To remove the program, the file on the BPF filesystem must be removed.
|
|
|
|
|
/// Any directories in the the path provided should have been created by the caller.
|
|
|
|
|
pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
|
|
|
|
|
self.data.path = Some(path.as_ref().to_path_buf());
|
|
|
|
|
pin_program(&mut self.data, path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Removes the pinned link from the filesystem.
|
|
|
|
|
pub fn unpin(mut self) -> Result<(), io::Error> {
|
|
|
|
|
if let Some(path) = self.data.path.take() {
|
|
|
|
|
std::fs::remove_file(path)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)+
|
|
|
|
|
}
|
|
|
|
@ -737,6 +813,45 @@ impl_program_pin!(
|
|
|
|
|
CgroupDevice,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_from_pin {
|
|
|
|
|
($($struct_name:ident),+ $(,)?) => {
|
|
|
|
|
$(
|
|
|
|
|
impl $struct_name {
|
|
|
|
|
/// Creates a program from a pinned entry on a bpffs.
|
|
|
|
|
///
|
|
|
|
|
/// Existing links will not be populated. To work with existing links you should use [`crate::programs::links::PinnedLink`].
|
|
|
|
|
///
|
|
|
|
|
/// On drop, any managed links are detached and the program is unloaded. This will not result in
|
|
|
|
|
/// the program being unloaded from the kernel if it is still pinned.
|
|
|
|
|
pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, ProgramError> {
|
|
|
|
|
let data = ProgramData::from_pinned_path(path)?;
|
|
|
|
|
Ok(Self { data })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)+
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use impl_from_pin if the program doesn't require additional data
|
|
|
|
|
impl_from_pin!(
|
|
|
|
|
TracePoint,
|
|
|
|
|
SocketFilter,
|
|
|
|
|
Xdp,
|
|
|
|
|
SkMsg,
|
|
|
|
|
CgroupSysctl,
|
|
|
|
|
LircMode2,
|
|
|
|
|
PerfEvent,
|
|
|
|
|
Lsm,
|
|
|
|
|
RawTracePoint,
|
|
|
|
|
BtfTracePoint,
|
|
|
|
|
FEntry,
|
|
|
|
|
FExit,
|
|
|
|
|
Extension,
|
|
|
|
|
SkLookup,
|
|
|
|
|
SockOps,
|
|
|
|
|
CgroupDevice,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_try_from_program {
|
|
|
|
|
($($ty:ident),+ $(,)?) => {
|
|
|
|
|
$(
|
|
|
|
@ -849,7 +964,6 @@ impl ProgramInfo {
|
|
|
|
|
unsafe {
|
|
|
|
|
libc::close(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(ProgramInfo(info))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|