|
@@ -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))
|
|
|
}
|
|
|
}
|