aya: Use `OwnedFd` when loading BTF fd

This fixes an existing file descriptor leak when there is BTF data in
the loaded object.

There is a required breaking change in that now the btf fd will be
passed in the programs and maps when loading them instead of them
storing a raw fd to them as to avoid the maps/programs needing to be
tied by lifetime to the btf fd (since they aren't needed at load
time).

To avoid lifetime issues caused by the bpf object owning both the btf
fd and the map of programs/maps but needing to reference the fd while
mutating the programs these fields are now made public. As far as I
can tell there are no safety issues with making these fields public,
the only issue would be tying that struct's public API more. I did
make the structure non exhaustive so that adding fields wouldn't
become a breaking change.
reviewable/pr662/r11
Andrés Medina 2 years ago
parent ab1ca8fb60
commit b2b52aac9e

@ -82,7 +82,7 @@ use aya::programs::{CgroupSkb, CgroupSkbAttachType};
let mut bpf = Bpf::load_file("bpf.o")?;
// get the `ingress_filter` program compiled into `bpf.o`.
let ingress: &mut CgroupSkb = bpf.program_mut("ingress_filter")?.try_into()?;
let mut ingress: aya::WithBtfFd<CgroupSkb> = bpf.program_mut("ingress_filter")?.try_into()?;
// load the program into the kernel
ingress.load()?;

@ -82,7 +82,7 @@ use aya::programs::{CgroupSkb, CgroupSkbAttachType};
let mut bpf = Bpf::load_file("bpf.o")?;
// get the `ingress_filter` program compiled into `bpf.o`.
let ingress: &mut CgroupSkb = bpf.program_mut("ingress_filter")?.try_into()?;
let mut ingress: aya::WithBtfFd<CgroupSkb> = bpf.program_mut("ingress_filter")?.try_into()?;
// load the program into the kernel
ingress.load()?;

@ -3,7 +3,11 @@ use std::{
collections::{HashMap, HashSet},
ffi::CString,
fs, io,
os::{fd::RawFd, raw::c_int},
ops::{Deref, DerefMut},
os::{
fd::{AsFd, BorrowedFd, OwnedFd, RawFd},
raw::c_int,
},
path::{Path, PathBuf},
};
@ -473,7 +477,6 @@ impl<'a> BpfLoader<'a> {
obj,
fd: None,
pinned: false,
btf_fd,
};
let fd = match map.obj.pinning() {
PinningType::ByName => {
@ -488,7 +491,7 @@ impl<'a> BpfLoader<'a> {
fd as RawFd
}
Err(_) => {
let fd = map.create(&name)?;
let fd = map.create(&name, btf_fd.as_ref())?;
map.pin(&name, path).map_err(|error| MapError::PinError {
name: Some(name.to_string()),
error,
@ -497,7 +500,7 @@ impl<'a> BpfLoader<'a> {
}
}
}
PinningType::None => map.create(&name)?,
PinningType::None => map.create(&name, btf_fd.as_ref())?,
};
if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss {
bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0)
@ -545,70 +548,69 @@ impl<'a> BpfLoader<'a> {
let program = if extensions.contains(name.as_str()) {
Program::Extension(Extension {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
})
} else {
match &section {
ProgramSection::KProbe { .. } => Program::KProbe(KProbe {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
kind: ProbeKind::KProbe,
}),
ProgramSection::KRetProbe { .. } => Program::KProbe(KProbe {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
kind: ProbeKind::KRetProbe,
}),
ProgramSection::UProbe { .. } => Program::UProbe(UProbe {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
kind: ProbeKind::UProbe,
}),
ProgramSection::URetProbe { .. } => Program::UProbe(UProbe {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
kind: ProbeKind::URetProbe,
}),
ProgramSection::TracePoint { .. } => Program::TracePoint(TracePoint {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::SocketFilter { .. } => {
Program::SocketFilter(SocketFilter {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
})
}
ProgramSection::Xdp { frags, .. } => {
let mut data =
ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
let mut data = ProgramData::new(prog_name, obj, *verifier_log_level);
if *frags {
data.flags = BPF_F_XDP_HAS_FRAGS;
}
Program::Xdp(Xdp { data })
}
ProgramSection::SkMsg { .. } => Program::SkMsg(SkMsg {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::CgroupSysctl { .. } => {
Program::CgroupSysctl(CgroupSysctl {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
})
}
ProgramSection::CgroupSockopt { attach_type, .. } => {
Program::CgroupSockopt(CgroupSockopt {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
attach_type: *attach_type,
})
}
ProgramSection::SkSkbStreamParser { .. } => Program::SkSkb(SkSkb {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
kind: SkSkbKind::StreamParser,
}),
ProgramSection::SkSkbStreamVerdict { .. } => Program::SkSkb(SkSkb {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
kind: SkSkbKind::StreamVerdict,
}),
ProgramSection::SockOps { .. } => Program::SockOps(SockOps {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::SchedClassifier { .. } => {
Program::SchedClassifier(SchedClassifier {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
name: unsafe {
CString::from_vec_unchecked(Vec::from(name.clone()))
.into_boxed_c_str()
@ -616,37 +618,36 @@ impl<'a> BpfLoader<'a> {
})
}
ProgramSection::CgroupSkb { .. } => Program::CgroupSkb(CgroupSkb {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
expected_attach_type: None,
}),
ProgramSection::CgroupSkbIngress { .. } => Program::CgroupSkb(CgroupSkb {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
expected_attach_type: Some(CgroupSkbAttachType::Ingress),
}),
ProgramSection::CgroupSkbEgress { .. } => Program::CgroupSkb(CgroupSkb {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
expected_attach_type: Some(CgroupSkbAttachType::Egress),
}),
ProgramSection::CgroupSockAddr { attach_type, .. } => {
Program::CgroupSockAddr(CgroupSockAddr {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
attach_type: *attach_type,
})
}
ProgramSection::LircMode2 { .. } => Program::LircMode2(LircMode2 {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::PerfEvent { .. } => Program::PerfEvent(PerfEvent {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::RawTracePoint { .. } => {
Program::RawTracePoint(RawTracePoint {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
})
}
ProgramSection::Lsm { sleepable, .. } => {
let mut data =
ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
let mut data = ProgramData::new(prog_name, obj, *verifier_log_level);
if *sleepable {
data.flags = BPF_F_SLEEPABLE;
}
@ -654,30 +655,30 @@ impl<'a> BpfLoader<'a> {
}
ProgramSection::BtfTracePoint { .. } => {
Program::BtfTracePoint(BtfTracePoint {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
})
}
ProgramSection::FEntry { .. } => Program::FEntry(FEntry {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::FExit { .. } => Program::FExit(FExit {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::Extension { .. } => Program::Extension(Extension {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::SkLookup { .. } => Program::SkLookup(SkLookup {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
}),
ProgramSection::CgroupSock { attach_type, .. } => {
Program::CgroupSock(CgroupSock {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
attach_type: *attach_type,
})
}
ProgramSection::CgroupDevice { .. } => {
Program::CgroupDevice(CgroupDevice {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
data: ProgramData::new(prog_name, obj, *verifier_log_level),
})
}
}
@ -699,7 +700,11 @@ impl<'a> BpfLoader<'a> {
})?;
};
Ok(Bpf { maps, programs })
Ok(Bpf {
maps,
programs,
btf_fd,
})
}
}
@ -741,11 +746,53 @@ impl<'a> Default for BpfLoader<'a> {
}
}
/// A program with a BTF file descriptor
pub struct WithBtfFd<'p, P> {
/// The program underneath
pub program: &'p mut P,
pub(crate) btf_fd: Option<BorrowedFd<'p>>,
}
impl<'f, P> Deref for WithBtfFd<'f, P> {
type Target = P;
fn deref(&self) -> &Self::Target {
&*self.program
}
}
impl<'f, P> DerefMut for WithBtfFd<'f, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.program
}
}
impl<'p, P, T> AsRef<T> for WithBtfFd<'p, P>
where
T: ?Sized,
<WithBtfFd<'p, P> as Deref>::Target: AsRef<T>,
{
fn as_ref(&self) -> &T {
self.deref().as_ref()
}
}
impl<'p, P, T> AsMut<T> for WithBtfFd<'p, P>
where
<WithBtfFd<'p, P> as Deref>::Target: AsMut<T>,
{
fn as_mut(&mut self) -> &mut T {
self.deref_mut().as_mut()
}
}
/// The main entry point into the library, used to work with eBPF programs and maps.
#[derive(Debug)]
#[non_exhaustive]
pub struct Bpf {
maps: HashMap<String, Map>,
programs: HashMap<String, Program>,
btf_fd: Option<OwnedFd>,
}
impl Bpf {
@ -882,13 +929,16 @@ impl Bpf {
/// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::programs::UProbe;
///
/// let program: &mut UProbe = bpf.program_mut("SSL_read").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<UProbe> = bpf.program_mut("SSL_read").unwrap().try_into()?;
/// program.load()?;
/// program.attach(Some("SSL_read"), 0, "libssl", None)?;
/// # Ok::<(), aya::BpfError>(())
/// ```
pub fn program_mut(&mut self, name: &str) -> Option<&mut Program> {
self.programs.get_mut(name)
pub fn program_mut(&mut self, name: &str) -> Option<WithBtfFd<'_, Program>> {
self.programs.get_mut(name).map(|program| WithBtfFd {
program,
btf_fd: self.btf_fd.as_ref().map(|p| p.as_fd()),
})
}
/// An iterator over all the programs.
@ -993,12 +1043,12 @@ pub enum BpfError {
ProgramError(#[from] ProgramError),
}
fn load_btf(raw_btf: Vec<u8>, verifier_log_level: VerifierLogLevel) -> Result<RawFd, BtfError> {
fn load_btf(raw_btf: Vec<u8>, verifier_log_level: VerifierLogLevel) -> Result<OwnedFd, BtfError> {
let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
bpf_load_btf(raw_btf.as_slice(), logger, verifier_log_level)
});
match ret {
Ok(fd) => Ok(fd as RawFd),
Ok(fd) => Ok(fd),
Err((_, io_error)) => Err(BtfError::LoadError {
io_error,
verifier_log,

@ -118,7 +118,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
BloomFilter::<_, u16>::new(&map),
@ -147,7 +146,6 @@ mod tests {
}),
fd: None,
pinned: false,
btf_fd: None,
};
let map = Map::PerfEventArray(map_data);
@ -164,7 +162,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
@ -179,7 +176,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
assert!(BloomFilter::<_, u32>::new(&mut map).is_ok());
@ -191,7 +187,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let map = Map::BloomFilter(map_data);
@ -206,7 +201,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap();
@ -230,7 +224,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap();
@ -244,7 +237,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap();
@ -267,7 +259,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap();

@ -149,7 +149,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
HashMap::<_, u8, u32>::new(&map),
@ -166,7 +165,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
HashMap::<_, u32, u16>::new(&map),
@ -183,7 +181,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
let map = Map::Array(map_data);
@ -199,7 +196,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
let map = Map::HashMap(map_data);
@ -218,7 +214,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
@ -233,7 +228,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
assert!(HashMap::<_, u32, u32>::new(&mut map).is_ok());
@ -245,7 +239,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let map = Map::HashMap(map_data);
@ -270,7 +263,6 @@ mod tests {
}),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let map = Map::HashMap(map_data);
@ -286,7 +278,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap();
@ -310,7 +301,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap();
@ -331,7 +321,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap();
@ -346,7 +335,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap();
@ -370,7 +358,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap();
@ -384,7 +371,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
@ -407,7 +393,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
@ -444,7 +429,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
let keys = hm.keys().collect::<Result<Vec<_>, _>>();
@ -493,7 +477,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
@ -526,7 +509,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
@ -561,7 +543,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
let items = hm.iter().collect::<Result<Vec<_>, _>>().unwrap();
@ -599,7 +580,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
@ -638,7 +618,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();
@ -683,7 +662,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let hm = HashMap::<_, u32, u32>::new(&map).unwrap();

@ -237,7 +237,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
LpmTrie::<_, u16, u32>::new(&map),
@ -254,7 +253,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
LpmTrie::<_, u32, u16>::new(&map),
@ -282,7 +280,6 @@ mod tests {
data: Vec::new(),
}),
fd: None,
btf_fd: None,
pinned: false,
};
@ -300,7 +297,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
};
assert_matches!(
@ -315,7 +311,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
assert!(LpmTrie::<_, u32, u32>::new(&mut map).is_ok());
@ -327,7 +322,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let map = Map::LpmTrie(map_data);
@ -342,7 +336,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
@ -367,7 +360,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
@ -384,7 +376,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
@ -409,7 +400,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
@ -424,7 +414,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8);
@ -449,7 +438,6 @@ mod tests {
obj: new_obj_map(),
fd: Some(42),
pinned: false,
btf_fd: None,
};
let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap();
let ipaddr = Ipv4Addr::new(8, 8, 8, 8);

@ -24,7 +24,7 @@
//!
//! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?;
//! let map_fd = intercept_egress.fd()?;
//! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
//! let mut prog: aya::WithBtfFd<SkMsg> = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
//! prog.load()?;
//! prog.attach(map_fd)?;
//!
@ -42,7 +42,7 @@ use std::{
marker::PhantomData,
mem,
ops::Deref,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
path::Path,
ptr,
};
@ -486,14 +486,13 @@ pub(crate) fn check_v_size<V>(map: &MapData) -> Result<(), MapError> {
pub struct MapData {
pub(crate) obj: obj::Map,
pub(crate) fd: Option<RawFd>,
pub(crate) btf_fd: Option<RawFd>,
/// Indicates if this map has been pinned to bpffs
pub pinned: bool,
}
impl MapData {
/// Creates a new map with the provided `name`
pub fn create(&mut self, name: &str) -> Result<RawFd, MapError> {
pub fn create(&mut self, name: &str, btf_fd: Option<impl AsFd>) -> Result<RawFd, MapError> {
if self.fd.is_some() {
return Err(MapError::AlreadyCreated { name: name.into() });
}
@ -504,7 +503,7 @@ impl MapData {
let kernel_version = KernelVersion::current().unwrap();
#[cfg(test)]
let kernel_version = KernelVersion::new(0xff, 0xff, 0xff);
let fd = bpf_create_map(&c_name, &self.obj, self.btf_fd, kernel_version).map_err(
let fd = bpf_create_map(&c_name, &self.obj, btf_fd, kernel_version).map_err(
|(code, io_error)| {
if kernel_version < KernelVersion::new(5, 11, 0) {
maybe_warn_rlimit();
@ -568,7 +567,6 @@ impl MapData {
Ok(MapData {
obj: parse_map_info(info, PinningType::ByName),
fd: Some(fd),
btf_fd: None,
pinned: true,
})
}
@ -587,7 +585,6 @@ impl MapData {
Ok(MapData {
obj: parse_map_info(info, PinningType::None),
fd: Some(fd),
btf_fd: None,
pinned: false,
})
}
@ -639,7 +636,6 @@ impl Clone for MapData {
MapData {
obj: self.obj.clone(),
fd: self.fd.map(|fd| unsafe { libc::dup(fd) }),
btf_fd: self.btf_fd,
pinned: self.pinned,
}
}
@ -842,6 +838,8 @@ impl<T: Pod> Deref for PerCpuValues<T> {
#[cfg(test)]
mod tests {
use std::os::fd::BorrowedFd;
use assert_matches::assert_matches;
use libc::EFAULT;
@ -876,7 +874,6 @@ mod tests {
obj: new_obj_map(),
fd: None,
pinned: false,
btf_fd: None,
}
}
@ -891,9 +888,12 @@ mod tests {
});
let mut map = new_map();
assert_matches!(map.create("foo"), Ok(42));
assert_matches!(map.create("foo", Option::<BorrowedFd>::None), Ok(42));
assert_eq!(map.fd, Some(42));
assert_matches!(map.create("foo"), Err(MapError::AlreadyCreated { .. }));
assert_matches!(
map.create("foo", Option::<BorrowedFd>::None),
Err(MapError::AlreadyCreated { .. })
);
}
#[test]
@ -901,7 +901,7 @@ mod tests {
override_syscall(|_| Err((-42, io::Error::from_raw_os_error(EFAULT))));
let mut map = new_map();
let ret = map.create("foo");
let ret = map.create("foo", Option::<BorrowedFd>::None);
assert_matches!(ret, Err(MapError::CreateError { .. }));
if let Err(MapError::CreateError {
name,

@ -49,7 +49,7 @@ use crate::{
/// let mut intercept_egress = SockHash::<_, u32>::try_from(bpf.map("INTERCEPT_EGRESS").unwrap())?;
/// let map_fd = intercept_egress.fd()?;
///
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SkMsg> = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach(map_fd)?;
///

@ -17,7 +17,7 @@ use crate::{
/// sockets.
///
/// A `SockMap` can also be used to redirect packets to sockets contained by the
/// map using `bpf_redirect_map()`, `bpf_sk_redirect_map()` etc.
/// map using `bpf_redirect_map()`, `bpf_sk_redirect_map()` etc.
///
/// # Minimum kernel version
///
@ -33,7 +33,7 @@ use crate::{
/// let intercept_ingress = SockMap::try_from(bpf.map("INTERCEPT_INGRESS").unwrap())?;
/// let map_fd = intercept_ingress.fd()?;
///
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SkSkb> = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach(map_fd)?;
///

@ -1,7 +1,7 @@
//! Cgroup device programs.
use crate::util::KernelVersion;
use std::os::fd::{AsRawFd, RawFd};
use crate::{util::KernelVersion, WithBtfFd};
use std::os::fd::{AsFd, AsRawFd, RawFd};
use crate::{
generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE},
@ -40,7 +40,7 @@ use crate::{
/// use aya::programs::CgroupDevice;
///
/// let cgroup = std::fs::File::open("/sys/fs/cgroup/unified")?;
/// let program: &mut CgroupDevice = bpf.program_mut("cgroup_dev").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<CgroupDevice> = bpf.program_mut("cgroup_dev").unwrap().try_into()?;
/// program.load()?;
/// program.attach(cgroup)?;
/// # Ok::<(), Error>(())
@ -51,10 +51,17 @@ pub struct CgroupDevice {
pub(crate) data: ProgramData<CgroupDeviceLink>,
}
impl<'p> WithBtfFd<'p, CgroupDevice> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl CgroupDevice {
/// Loads the program inside the kernel
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_CGROUP_DEVICE, &mut self.data)
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_CGROUP_DEVICE, &mut self.data, btf_fd)
}
/// Attaches the program to the given cgroup.

@ -1,9 +1,9 @@
//! Cgroup skb programs.
use crate::util::KernelVersion;
use crate::{util::KernelVersion, WithBtfFd};
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
path::Path,
};
@ -50,7 +50,7 @@ use crate::{
/// use aya::programs::{CgroupSkb, CgroupSkbAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let egress: &mut CgroupSkb = bpf.program_mut("egress_filter").unwrap().try_into()?;
/// let mut egress: aya::WithBtfFd<CgroupSkb> = bpf.program_mut("egress_filter").unwrap().try_into()?;
/// egress.load()?;
/// egress.attach(file, CgroupSkbAttachType::Egress)?;
/// # Ok::<(), Error>(())
@ -62,16 +62,23 @@ pub struct CgroupSkb {
pub(crate) expected_attach_type: Option<CgroupSkbAttachType>,
}
impl CgroupSkb {
impl<'p> WithBtfFd<'p, CgroupSkb> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl CgroupSkb {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
self.data.expected_attach_type =
self.expected_attach_type
.map(|attach_type| match attach_type {
CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS,
CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
});
load_program(BPF_PROG_TYPE_CGROUP_SKB, &mut self.data)
load_program(BPF_PROG_TYPE_CGROUP_SKB, &mut self.data, btf_fd)
}
/// Returns the expected attach type of the program.

@ -2,10 +2,10 @@
pub use aya_obj::programs::CgroupSockAttachType;
use crate::util::KernelVersion;
use crate::{util::KernelVersion, WithBtfFd};
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
path::Path,
};
@ -48,7 +48,7 @@ use crate::{
/// use aya::programs::{CgroupSock, CgroupSockAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let bind: &mut CgroupSock = bpf.program_mut("bind").unwrap().try_into()?;
/// let mut bind: aya::WithBtfFd<CgroupSock> = bpf.program_mut("bind").unwrap().try_into()?;
/// bind.load()?;
/// bind.attach(file)?;
/// # Ok::<(), Error>(())
@ -60,11 +60,18 @@ pub struct CgroupSock {
pub(crate) attach_type: CgroupSockAttachType,
}
impl CgroupSock {
impl<'p> WithBtfFd<'p, CgroupSock> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl CgroupSock {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(self.attach_type.into());
load_program(BPF_PROG_TYPE_CGROUP_SOCK, &mut self.data)
load_program(BPF_PROG_TYPE_CGROUP_SOCK, &mut self.data, btf_fd)
}
/// Attaches the program to the given cgroup.

@ -2,10 +2,10 @@
pub use aya_obj::programs::CgroupSockAddrAttachType;
use crate::util::KernelVersion;
use crate::{util::KernelVersion, WithBtfFd};
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
path::Path,
};
@ -49,7 +49,7 @@ use crate::{
/// use aya::programs::{CgroupSockAddr, CgroupSockAddrAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let egress: &mut CgroupSockAddr = bpf.program_mut("connect4").unwrap().try_into()?;
/// let mut egress: aya::WithBtfFd<CgroupSockAddr> = bpf.program_mut("connect4").unwrap().try_into()?;
/// egress.load()?;
/// egress.attach(file)?;
/// # Ok::<(), Error>(())
@ -61,11 +61,18 @@ pub struct CgroupSockAddr {
pub(crate) attach_type: CgroupSockAddrAttachType,
}
impl CgroupSockAddr {
impl<'p> WithBtfFd<'p, CgroupSockAddr> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl CgroupSockAddr {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(self.attach_type.into());
load_program(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, &mut self.data)
load_program(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, &mut self.data, btf_fd)
}
/// Attaches the program to the given cgroup.

@ -2,10 +2,10 @@
pub use aya_obj::programs::CgroupSockoptAttachType;
use crate::util::KernelVersion;
use crate::{util::KernelVersion, WithBtfFd};
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
path::Path,
};
@ -46,7 +46,7 @@ use crate::{
/// use aya::programs::CgroupSockopt;
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let program: &mut CgroupSockopt = bpf.program_mut("cgroup_sockopt").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<CgroupSockopt> = bpf.program_mut("cgroup_sockopt").unwrap().try_into()?;
/// program.load()?;
/// program.attach(file)?;
/// # Ok::<(), Error>(())
@ -58,11 +58,18 @@ pub struct CgroupSockopt {
pub(crate) attach_type: CgroupSockoptAttachType,
}
impl CgroupSockopt {
impl<'p> WithBtfFd<'p, CgroupSockopt> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl CgroupSockopt {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(self.attach_type.into());
load_program(BPF_PROG_TYPE_CGROUP_SOCKOPT, &mut self.data)
load_program(BPF_PROG_TYPE_CGROUP_SOCKOPT, &mut self.data, btf_fd)
}
/// Attaches the program to the given cgroup.

@ -1,9 +1,9 @@
//! Cgroup sysctl programs.
use crate::util::KernelVersion;
use crate::{util::KernelVersion, WithBtfFd};
use std::{
hash::Hash,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
};
use crate::{
@ -42,7 +42,7 @@ use crate::{
/// use aya::programs::CgroupSysctl;
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let program: &mut CgroupSysctl = bpf.program_mut("cgroup_sysctl").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<CgroupSysctl> = bpf.program_mut("cgroup_sysctl").unwrap().try_into()?;
/// program.load()?;
/// program.attach(file)?;
/// # Ok::<(), Error>(())
@ -53,10 +53,17 @@ pub struct CgroupSysctl {
pub(crate) data: ProgramData<CgroupSysctlLink>,
}
impl CgroupSysctl {
impl<'p> WithBtfFd<'p, CgroupSysctl> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_CGROUP_SYSCTL, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl CgroupSysctl {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_CGROUP_SYSCTL, &mut self.data, btf_fd)
}
/// Attaches the program to the given cgroup.

@ -1,5 +1,5 @@
//! Extension programs.
use std::os::fd::{AsRawFd, RawFd};
use std::os::fd::{AsFd, AsRawFd, RawFd};
use thiserror::Error;
use object::Endianness;
@ -11,7 +11,7 @@ use crate::{
define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd,
},
sys::{self, bpf_link_create},
Btf,
Btf, WithBtfFd,
};
/// The type returned when loading or attaching an [`Extension`] fails.
@ -37,12 +37,12 @@ pub enum ExtensionError {
/// use aya::{BpfLoader, programs::{Xdp, XdpFlags, Extension}};
///
/// let mut bpf = BpfLoader::new().extension("extension").load_file("app.o")?;
/// let prog: &mut Xdp = bpf.program_mut("main").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<Xdp> = bpf.program_mut("main").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach("eth0", XdpFlags::default())?;
///
/// let prog_fd = prog.fd().unwrap();
/// let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?;
/// let mut ext: aya::WithBtfFd<Extension> = bpf.program_mut("extension").unwrap().try_into()?;
/// ext.load(prog_fd, "function_to_replace")?;
/// ext.attach()?;
/// Ok::<(), aya::BpfError>(())
@ -53,6 +53,13 @@ pub struct Extension {
pub(crate) data: ProgramData<ExtensionLink>,
}
impl<'p> WithBtfFd<'p, Extension> {
/// Loads the program inside the kernel.
pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> {
self.program.load(program, func_name, self.btf_fd)
}
}
impl Extension {
/// Loads the extension inside the kernel.
///
@ -68,14 +75,19 @@ impl Extension {
/// The extension code will be loaded but inactive until it's attached.
/// There are no restrictions on what functions may be replaced, so you could replace
/// the main entry point of your program with an extension.
pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> {
pub fn load(
&mut self,
program: ProgramFd,
func_name: &str,
btf_fd: Option<impl AsFd>,
) -> Result<(), ProgramError> {
let target_prog_fd = program.as_raw_fd();
let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?;
let (prog_btf_fd, prog_btf_id) = get_btf_info(target_prog_fd, func_name)?;
self.data.attach_btf_obj_fd = Some(btf_fd as u32);
self.data.attach_btf_obj_fd = Some(prog_btf_fd as u32);
self.data.attach_prog_fd = Some(target_prog_fd);
self.data.attach_btf_id = Some(btf_id);
load_program(BPF_PROG_TYPE_EXT, &mut self.data)
self.data.attach_btf_id = Some(prog_btf_id);
load_program(BPF_PROG_TYPE_EXT, &mut self.data, btf_fd)
}
/// Attaches the extension.

@ -1,5 +1,7 @@
//! Fentry programs.
use std::os::fd::AsFd;
use crate::{
generated::{bpf_attach_type::BPF_TRACE_FENTRY, bpf_prog_type::BPF_PROG_TYPE_TRACING},
obj::btf::{Btf, BtfKind},
@ -7,6 +9,7 @@ use crate::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
ProgramData, ProgramError,
},
WithBtfFd,
};
/// A program that can be attached to the entry point of (almost) any kernel
@ -37,7 +40,7 @@ use crate::{
/// use aya::{Bpf, programs::FEntry, BtfError, Btf};
///
/// let btf = Btf::from_sys_fs()?;
/// let program: &mut FEntry = bpf.program_mut("filename_lookup").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<FEntry> = bpf.program_mut("filename_lookup").unwrap().try_into()?;
/// program.load("filename_lookup", &btf)?;
/// program.attach()?;
/// # Ok::<(), Error>(())
@ -49,16 +52,28 @@ pub struct FEntry {
pub(crate) data: ProgramData<FEntryLink>,
}
impl<'p> WithBtfFd<'p, FEntry> {
/// Loads the program inside the kernel.
pub fn load(&mut self, fn_name: &str, btf: &Btf) -> Result<(), ProgramError> {
self.program.load(fn_name, btf, self.btf_fd)
}
}
impl FEntry {
/// Loads the program inside the kernel.
///
/// Loads the program so it's executed when the kernel function `fn_name`
/// is entered. The `btf` argument must contain the BTF info for the
/// running kernel.
pub fn load(&mut self, fn_name: &str, btf: &Btf) -> Result<(), ProgramError> {
pub fn load(
&mut self,
fn_name: &str,
btf: &Btf,
btf_fd: Option<impl AsFd>,
) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(BPF_TRACE_FENTRY);
self.data.attach_btf_id = Some(btf.id_by_type_name_kind(fn_name, BtfKind::Func)?);
load_program(BPF_PROG_TYPE_TRACING, &mut self.data)
load_program(BPF_PROG_TYPE_TRACING, &mut self.data, btf_fd)
}
/// Attaches the program.

@ -1,5 +1,7 @@
//! Fexit programs.
use std::os::fd::AsFd;
use crate::{
generated::{bpf_attach_type::BPF_TRACE_FEXIT, bpf_prog_type::BPF_PROG_TYPE_TRACING},
obj::btf::{Btf, BtfKind},
@ -7,6 +9,7 @@ use crate::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
ProgramData, ProgramError,
},
WithBtfFd,
};
/// A program that can be attached to the exit point of (almost) anny kernel
@ -37,7 +40,7 @@ use crate::{
/// use aya::{Bpf, programs::FExit, BtfError, Btf};
///
/// let btf = Btf::from_sys_fs()?;
/// let program: &mut FExit = bpf.program_mut("filename_lookup").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<FExit> = bpf.program_mut("filename_lookup").unwrap().try_into()?;
/// program.load("filename_lookup", &btf)?;
/// program.attach()?;
/// # Ok::<(), Error>(())
@ -49,16 +52,28 @@ pub struct FExit {
pub(crate) data: ProgramData<FExitLink>,
}
impl<'p> WithBtfFd<'p, FExit> {
/// Loads the program inside the kernel.
pub fn load(&mut self, fn_name: &str, btf: &Btf) -> Result<(), ProgramError> {
self.program.load(fn_name, btf, self.btf_fd)
}
}
impl FExit {
/// Loads the program inside the kernel.
///
/// Loads the program so it's executed when the kernel function `fn_name`
/// is exited. The `btf` argument must contain the BTF info for the running
/// kernel.
pub fn load(&mut self, fn_name: &str, btf: &Btf) -> Result<(), ProgramError> {
pub fn load(
&mut self,
fn_name: &str,
btf: &Btf,
btf_fd: Option<impl AsFd>,
) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(BPF_TRACE_FEXIT);
self.data.attach_btf_id = Some(btf.id_by_type_name_kind(fn_name, BtfKind::Func)?);
load_program(BPF_PROG_TYPE_TRACING, &mut self.data)
load_program(BPF_PROG_TYPE_TRACING, &mut self.data, btf_fd)
}
/// Attaches the program.

@ -1,5 +1,5 @@
//! Kernel space probes.
use std::{io, path::Path};
use std::{io, os::fd::AsFd, path::Path};
use thiserror::Error;
use crate::{
@ -11,7 +11,7 @@ use crate::{
FdLink, LinkError, ProgramData, ProgramError,
},
sys::bpf_link_get_info_by_fd,
VerifierLogLevel,
VerifierLogLevel, WithBtfFd,
};
/// A kernel probe.
@ -32,7 +32,7 @@ use crate::{
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::KProbe};
///
/// let program: &mut KProbe = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<KProbe> = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
/// program.load()?;
/// program.attach("try_to_wake_up", 0)?;
/// # Ok::<(), aya::BpfError>(())
@ -44,10 +44,17 @@ pub struct KProbe {
pub(crate) kind: ProbeKind,
}
impl KProbe {
impl<'p> WithBtfFd<'p, KProbe> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_KPROBE, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl KProbe {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_KPROBE, &mut self.data, btf_fd)
}
/// Returns `KProbe` if the program is a `kprobe`, or `KRetProbe` if the

@ -97,7 +97,7 @@ pub struct FdLinkId(pub(crate) RawFd);
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::{links::FdLink, KProbe}};
///
/// let program: &mut KProbe = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<KProbe> = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
/// program.load()?;
/// let link_id = program.attach("try_to_wake_up", 0)?;
/// let link = program.take_link(link_id).unwrap();
@ -138,7 +138,7 @@ impl FdLink {
/// # Program(#[from] aya::programs::ProgramError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[])?;
/// # let prog: &mut Extension = bpf.program_mut("example").unwrap().try_into()?;
/// # let mut prog: aya::WithBtfFd<Extension> = bpf.program_mut("example").unwrap().try_into()?;
/// let link_id = prog.attach()?;
/// let owned_link = prog.take_link(link_id)?;
/// let fd_link: FdLink = owned_link.into();

@ -1,10 +1,11 @@
//! Lirc programs.
use std::os::fd::{AsRawFd, IntoRawFd as _, RawFd};
use std::os::fd::{AsFd, AsRawFd, IntoRawFd as _, RawFd};
use crate::{
generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo},
sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd},
WithBtfFd,
};
use libc::{close, dup};
@ -40,7 +41,7 @@ use libc::{close, dup};
///
/// let file = File::open("/dev/lirc0")?;
/// let mut bpf = aya::Bpf::load_file("imon_rsc.o")?;
/// let decoder: &mut LircMode2 = bpf.program_mut("imon_rsc").unwrap().try_into().unwrap();
/// let mut decoder: aya::WithBtfFd<LircMode2> = bpf.program_mut("imon_rsc").unwrap().try_into().unwrap();
/// decoder.load()?;
/// decoder.attach(file)?;
/// # Ok::<(), Error>(())
@ -51,10 +52,17 @@ pub struct LircMode2 {
pub(crate) data: ProgramData<LircLink>,
}
impl LircMode2 {
impl<'p> WithBtfFd<'p, LircMode2> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_LIRC_MODE2, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl LircMode2 {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_LIRC_MODE2, &mut self.data, btf_fd)
}
/// Attaches the program to the given lirc device.

@ -1,5 +1,7 @@
//! LSM probes.
use std::os::fd::AsFd;
use crate::{
generated::{bpf_attach_type::BPF_LSM_MAC, bpf_prog_type::BPF_PROG_TYPE_LSM},
obj::btf::{Btf, BtfKind},
@ -7,6 +9,7 @@ use crate::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
ProgramData, ProgramError,
},
WithBtfFd,
};
/// A program that attaches to Linux LSM hooks. Used to implement security policy and
@ -39,7 +42,7 @@ use crate::{
/// use aya::{Bpf, programs::Lsm, BtfError, Btf};
///
/// let btf = Btf::from_sys_fs()?;
/// let program: &mut Lsm = bpf.program_mut("lsm_prog").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<Lsm> = bpf.program_mut("lsm_prog").unwrap().try_into()?;
/// program.load("security_bprm_exec", &btf)?;
/// program.attach()?;
/// # Ok::<(), LsmError>(())
@ -52,6 +55,13 @@ pub struct Lsm {
pub(crate) data: ProgramData<LsmLink>,
}
impl<'p> WithBtfFd<'p, Lsm> {
/// Loads the program inside the kernel.
pub fn load(&mut self, lsm_hook_name: &str, btf: &Btf) -> Result<(), ProgramError> {
self.program.load(lsm_hook_name, btf, self.btf_fd)
}
}
impl Lsm {
/// Loads the program inside the kernel.
///
@ -59,12 +69,17 @@ impl Lsm {
///
/// * `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, btf: &Btf) -> Result<(), ProgramError> {
pub fn load(
&mut self,
lsm_hook_name: &str,
btf: &Btf,
btf_fd: Option<impl AsFd>,
) -> Result<(), ProgramError> {
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)
load_program(BPF_PROG_TYPE_LSM, &mut self.data, btf_fd)
}
/// Attaches the program.

@ -18,7 +18,7 @@
//!
//! let mut bpf = Bpf::load_file("ebpf_programs.o")?;
//! // intercept_wakeups is the name of the program we want to load
//! let program: &mut KProbe = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
//! let mut program: aya::WithBtfFd<KProbe> = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
//! program.load()?;
//! // intercept_wakeups will be called every time try_to_wake_up() is called
//! // inside the kernel
@ -69,7 +69,7 @@ use libc::ENOSPC;
use std::{
ffi::CString,
io,
os::fd::{AsRawFd, IntoRawFd as _, RawFd},
os::fd::{AsFd, AsRawFd, IntoRawFd as _, RawFd},
path::{Path, PathBuf},
};
use thiserror::Error;
@ -413,7 +413,6 @@ pub(crate) struct ProgramData<T: Link> {
pub(crate) attach_btf_obj_fd: Option<u32>,
pub(crate) attach_btf_id: Option<u32>,
pub(crate) attach_prog_fd: Option<RawFd>,
pub(crate) btf_fd: Option<RawFd>,
pub(crate) verifier_log_level: VerifierLogLevel,
pub(crate) path: Option<PathBuf>,
pub(crate) flags: u32,
@ -423,7 +422,6 @@ impl<T: Link> ProgramData<T> {
pub(crate) fn new(
name: Option<String>,
obj: (obj::Program, obj::Function),
btf_fd: Option<RawFd>,
verifier_log_level: VerifierLogLevel,
) -> ProgramData<T> {
ProgramData {
@ -435,7 +433,6 @@ impl<T: Link> ProgramData<T> {
attach_btf_obj_fd: None,
attach_btf_id: None,
attach_prog_fd: None,
btf_fd,
verifier_log_level,
path: None,
flags: 0,
@ -475,7 +472,6 @@ impl<T: Link> ProgramData<T> {
attach_btf_obj_fd,
attach_btf_id,
attach_prog_fd: None,
btf_fd: None,
verifier_log_level,
path: Some(path.to_path_buf()),
flags: 0,
@ -546,6 +542,7 @@ fn pin_program<T: Link, P: AsRef<Path>>(data: &ProgramData<T>, path: P) -> Resul
fn load_program<T: Link>(
prog_type: bpf_prog_type,
data: &mut ProgramData<T>,
btf_fd: Option<impl AsFd>,
) -> Result<(), ProgramError> {
let ProgramData {
name,
@ -556,7 +553,6 @@ fn load_program<T: Link>(
attach_btf_obj_fd,
attach_btf_id,
attach_prog_fd,
btf_fd,
verifier_log_level,
path: _,
flags,
@ -613,7 +609,7 @@ fn load_program<T: Link>(
license,
kernel_version: target_kernel_version,
expected_attach_type: *expected_attach_type,
prog_btf_fd: *btf_fd,
prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()),
attach_btf_obj_fd: *attach_btf_obj_fd,
attach_btf_id: *attach_btf_id,
attach_prog_fd: *attach_prog_fd,
@ -885,6 +881,17 @@ macro_rules! impl_try_from_program {
}
}
}
impl<'a> TryFrom<$crate::WithBtfFd<'a, Program>> for $crate::bpf::WithBtfFd<'a, $ty> {
type Error = ProgramError;
fn try_from(program: $crate::WithBtfFd<'a, Program>) -> Result<$crate::WithBtfFd<'a, $ty>, ProgramError> {
Ok($crate::bpf::WithBtfFd {
program: program.program.try_into()?,
btf_fd: program.btf_fd
})
}
}
)+
}
}

@ -1,5 +1,7 @@
//! Perf event programs.
use std::os::fd::AsFd;
pub use crate::generated::{
perf_hw_cache_id, perf_hw_cache_op_id, perf_hw_cache_op_result_id, perf_hw_id, perf_sw_ids,
};
@ -20,6 +22,7 @@ use crate::{
FdLink, LinkError, ProgramData, ProgramError,
},
sys::{bpf_link_get_info_by_fd, perf_event_open},
WithBtfFd,
};
/// The type of perf event
@ -105,7 +108,7 @@ pub enum PerfEventScope {
/// perf_sw_ids::PERF_COUNT_SW_CPU_CLOCK, PerfEvent, PerfEventScope, PerfTypeId, SamplePolicy,
/// };
///
/// let prog: &mut PerfEvent = bpf.program_mut("observe_cpu_clock").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<PerfEvent> = bpf.program_mut("observe_cpu_clock").unwrap().try_into()?;
/// prog.load()?;
///
/// for cpu in online_cpus()? {
@ -124,10 +127,17 @@ pub struct PerfEvent {
pub(crate) data: ProgramData<PerfEventLink>,
}
impl PerfEvent {
impl<'p> WithBtfFd<'p, PerfEvent> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_PERF_EVENT, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl PerfEvent {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_PERF_EVENT, &mut self.data, btf_fd)
}
/// Attaches to the given perf event.

@ -1,5 +1,5 @@
//! Raw tracepoints.
use std::ffi::CString;
use std::{ffi::CString, os::fd::AsFd};
use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_RAW_TRACEPOINT,
@ -7,6 +7,7 @@ use crate::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
ProgramData, ProgramError,
},
WithBtfFd,
};
/// A program that can be attached at a pre-defined kernel trace point, but also
@ -27,7 +28,7 @@ use crate::{
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::RawTracePoint};
///
/// let program: &mut RawTracePoint = bpf.program_mut("sys_enter").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<RawTracePoint> = bpf.program_mut("sys_enter").unwrap().try_into()?;
/// program.load()?;
/// program.attach("sys_enter")?;
/// # Ok::<(), aya::BpfError>(())
@ -38,10 +39,17 @@ pub struct RawTracePoint {
pub(crate) data: ProgramData<RawTracePointLink>,
}
impl RawTracePoint {
impl<'p> WithBtfFd<'p, RawTracePoint> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_RAW_TRACEPOINT, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl RawTracePoint {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_RAW_TRACEPOINT, &mut self.data, btf_fd)
}
/// Attaches the program to the given tracepoint.

@ -1,9 +1,10 @@
use std::os::fd::{AsRawFd, RawFd};
use std::os::fd::{AsFd, AsRawFd, RawFd};
use crate::{
generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP},
programs::{define_link_wrapper, load_program, FdLinkId, ProgramData, ProgramError},
sys::bpf_link_create,
WithBtfFd,
};
use super::links::FdLink;
@ -39,7 +40,7 @@ use super::links::FdLink;
/// use aya::programs::SkLookup;
///
/// let file = File::open("/var/run/netns/test")?;
/// let program: &mut SkLookup = bpf.program_mut("sk_lookup").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<SkLookup> = bpf.program_mut("sk_lookup").unwrap().try_into()?;
/// program.load()?;
/// program.attach(file)?;
/// # Ok::<(), Error>(())
@ -50,11 +51,18 @@ pub struct SkLookup {
pub(crate) data: ProgramData<SkLookupLink>,
}
impl SkLookup {
impl<'p> WithBtfFd<'p, SkLookup> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl SkLookup {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(BPF_SK_LOOKUP);
load_program(BPF_PROG_TYPE_SK_LOOKUP, &mut self.data)
load_program(BPF_PROG_TYPE_SK_LOOKUP, &mut self.data, btf_fd)
}
/// Attaches the program to the given network namespace.

@ -1,6 +1,6 @@
//! Skmsg programs.
use std::os::fd::AsRawFd;
use std::os::fd::{AsFd, AsRawFd};
use crate::{
generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
@ -10,6 +10,7 @@ use crate::{
ProgramError,
},
sys::bpf_prog_attach,
WithBtfFd,
};
/// A program used to intercept messages sent with `sendmsg()`/`sendfile()`.
@ -46,7 +47,7 @@ use crate::{
/// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS").unwrap().try_into()?;
/// let map_fd = intercept_egress.fd()?;
///
/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SkMsg> = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach(map_fd)?;
///
@ -69,10 +70,17 @@ pub struct SkMsg {
pub(crate) data: ProgramData<SkMsgLink>,
}
impl SkMsg {
impl<'p> WithBtfFd<'p, SkMsg> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SK_MSG, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl SkMsg {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SK_MSG, &mut self.data, btf_fd)
}
/// Attaches the program to the given sockmap.

@ -1,6 +1,9 @@
//! Skskb programs.
use std::{os::fd::AsRawFd, path::Path};
use std::{
os::fd::{AsFd, AsRawFd},
path::Path,
};
use crate::{
generated::{
@ -13,7 +16,7 @@ use crate::{
ProgramError,
},
sys::bpf_prog_attach,
VerifierLogLevel,
VerifierLogLevel, WithBtfFd,
};
/// The kind of [`SkSkb`] program.
@ -45,7 +48,7 @@ pub enum SkSkbKind {
/// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS").unwrap().try_into()?;
/// let map_fd = intercept_ingress.fd()?;
///
/// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SkSkb> = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach(map_fd)?;
///
@ -62,10 +65,17 @@ pub struct SkSkb {
pub(crate) kind: SkSkbKind,
}
impl SkSkb {
impl<'p> WithBtfFd<'p, SkSkb> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SK_SKB, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl SkSkb {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SK_SKB, &mut self.data, btf_fd)
}
/// Attaches the program to the given socket map.

@ -1,5 +1,5 @@
//! Socket option programs.
use std::os::fd::AsRawFd;
use std::os::fd::{AsFd, AsRawFd};
use crate::{
generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS},
@ -8,6 +8,7 @@ use crate::{
ProgramError,
},
sys::bpf_prog_attach,
WithBtfFd,
};
/// A program used to work with sockets.
@ -39,7 +40,7 @@ use crate::{
/// use aya::programs::SockOps;
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let prog: &mut SockOps = bpf.program_mut("intercept_active_sockets").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SockOps> = bpf.program_mut("intercept_active_sockets").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach(file)?;
/// # Ok::<(), Error>(())
@ -49,10 +50,17 @@ pub struct SockOps {
pub(crate) data: ProgramData<SockOpsLink>,
}
impl SockOps {
impl<'p> WithBtfFd<'p, SockOps> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SOCK_OPS, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl SockOps {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SOCK_OPS, &mut self.data, btf_fd)
}
/// Attaches the program to the given cgroup.

@ -2,13 +2,14 @@
use libc::{setsockopt, SOL_SOCKET};
use std::{
io, mem,
os::fd::{AsRawFd, RawFd},
os::fd::{AsFd, AsRawFd, RawFd},
};
use thiserror::Error;
use crate::{
generated::{bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER, SO_ATTACH_BPF, SO_DETACH_BPF},
programs::{load_program, Link, ProgramData, ProgramError},
WithBtfFd,
};
/// The type returned when attaching a [`SocketFilter`] fails.
@ -52,7 +53,7 @@ pub enum SocketFilterError {
/// use aya::programs::SocketFilter;
///
/// let mut client = TcpStream::connect("127.0.0.1:1234")?;
/// let prog: &mut SocketFilter = bpf.program_mut("filter_packets").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SocketFilter> = bpf.program_mut("filter_packets").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach(client.as_raw_fd())?;
/// # Ok::<(), Error>(())
@ -63,10 +64,17 @@ pub struct SocketFilter {
pub(crate) data: ProgramData<SocketFilterLink>,
}
impl SocketFilter {
impl<'p> WithBtfFd<'p, SocketFilter> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SOCKET_FILTER, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl SocketFilter {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SOCKET_FILTER, &mut self.data, btf_fd)
}
/// Attaches the filter on the given socket.

@ -4,6 +4,7 @@ use thiserror::Error;
use std::{
ffi::{CStr, CString},
io,
os::fd::AsFd,
path::Path,
};
@ -17,7 +18,7 @@ use crate::{
netlink_qdisc_detach,
},
util::{ifindex_from_ifname, tc_handler_make},
VerifierLogLevel,
VerifierLogLevel, WithBtfFd,
};
/// Traffic control attach type.
@ -63,7 +64,7 @@ pub enum TcAttachType {
/// // attached
/// tc::qdisc_add_clsact("eth0")?;
///
/// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<SchedClassifier> = bpf.program_mut("redirect_ingress").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach("eth0", TcAttachType::Ingress)?;
///
@ -112,10 +113,17 @@ pub struct TcOptions {
pub handle: u32,
}
impl SchedClassifier {
impl<'p> WithBtfFd<'p, SchedClassifier> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl SchedClassifier {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data, btf_fd)
}
/// Attaches the program to the given `interface` using the default options.

@ -1,5 +1,7 @@
//! BTF-enabled raw tracepoints.
use std::os::fd::AsFd;
use crate::{
generated::{bpf_attach_type::BPF_TRACE_RAW_TP, bpf_prog_type::BPF_PROG_TYPE_TRACING},
obj::btf::{Btf, BtfKind},
@ -7,6 +9,7 @@ use crate::{
define_link_wrapper, load_program, utils::attach_raw_tracepoint, FdLink, FdLinkId,
ProgramData, ProgramError,
},
WithBtfFd,
};
/// Marks a function as a [BTF-enabled raw tracepoint][1] eBPF program that can be attached at
@ -36,7 +39,7 @@ use crate::{
/// use aya::{Bpf, programs::BtfTracePoint, BtfError, Btf};
///
/// let btf = Btf::from_sys_fs()?;
/// let program: &mut BtfTracePoint = bpf.program_mut("sched_process_fork").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<BtfTracePoint> = bpf.program_mut("sched_process_fork").unwrap().try_into()?;
/// program.load("sched_process_fork", &btf)?;
/// program.attach()?;
/// # Ok::<(), Error>(())
@ -50,6 +53,13 @@ pub struct BtfTracePoint {
pub(crate) data: ProgramData<BtfTracePointLink>,
}
impl<'p> WithBtfFd<'p, BtfTracePoint> {
/// Loads the program inside the kernel.
pub fn load(&mut self, tracepoint: &str, btf: &Btf) -> Result<(), ProgramError> {
self.program.load(tracepoint, btf, self.btf_fd)
}
}
impl BtfTracePoint {
/// Loads the program inside the kernel.
///
@ -57,12 +67,17 @@ impl BtfTracePoint {
///
/// * `tracepoint` - full name of the tracepoint that we should attach to
/// * `btf` - btf information for the target system
pub fn load(&mut self, tracepoint: &str, btf: &Btf) -> Result<(), ProgramError> {
pub fn load(
&mut self,
tracepoint: &str,
btf: &Btf,
btf_fd: Option<impl AsFd>,
) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(BPF_TRACE_RAW_TP);
let type_name = format!("btf_trace_{tracepoint}");
self.data.attach_btf_id =
Some(btf.id_by_type_name_kind(type_name.as_str(), BtfKind::Typedef)?);
load_program(BPF_PROG_TYPE_TRACING, &mut self.data)
load_program(BPF_PROG_TYPE_TRACING, &mut self.data, btf_fd)
}
/// Attaches the program.

@ -1,5 +1,5 @@
//! Tracepoint programs.
use std::{fs, io, path::Path};
use std::{fs, io, os::fd::AsFd, path::Path};
use thiserror::Error;
use crate::{
@ -11,6 +11,7 @@ use crate::{
FdLink, LinkError, ProgramData, ProgramError,
},
sys::{bpf_link_get_info_by_fd, perf_event_open_trace_point},
WithBtfFd,
};
/// The type returned when attaching a [`TracePoint`] fails.
@ -54,7 +55,7 @@ pub enum TracePointError {
/// # let mut bpf = aya::Bpf::load(&[])?;
/// use aya::programs::TracePoint;
///
/// let prog: &mut TracePoint = bpf.program_mut("trace_context_switch").unwrap().try_into()?;
/// let mut prog: aya::WithBtfFd<TracePoint> = bpf.program_mut("trace_context_switch").unwrap().try_into()?;
/// prog.load()?;
/// prog.attach("sched", "sched_switch")?;
/// # Ok::<(), Error>(())
@ -65,10 +66,17 @@ pub struct TracePoint {
pub(crate) data: ProgramData<TracePointLink>,
}
impl TracePoint {
impl<'p> WithBtfFd<'p, TracePoint> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_TRACEPOINT, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl TracePoint {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_TRACEPOINT, &mut self.data, btf_fd)
}
/// Attaches to a given trace point.

@ -7,7 +7,7 @@ use std::{
fs,
io::{self, BufRead, Cursor, Read},
mem,
os::raw::c_char,
os::{fd::AsFd, raw::c_char},
path::{Path, PathBuf},
sync::Arc,
};
@ -22,7 +22,7 @@ use crate::{
FdLink, LinkError, ProgramData, ProgramError,
},
sys::bpf_link_get_info_by_fd,
VerifierLogLevel,
VerifierLogLevel, WithBtfFd,
};
const LD_SO_CACHE_FILE: &str = "/etc/ld.so.cache";
@ -48,10 +48,17 @@ pub struct UProbe {
pub(crate) kind: ProbeKind,
}
impl UProbe {
impl<'p> WithBtfFd<'p, UProbe> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_KPROBE, &mut self.data)
self.program.load(self.btf_fd)
}
}
impl UProbe {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_KPROBE, &mut self.data, btf_fd)
}
/// Returns `UProbe` if the program is a `uprobe`, or `URetProbe` if the

@ -1,9 +1,15 @@
//! eXpress Data Path (XDP) programs.
use crate::util::KernelVersion;
use crate::{util::KernelVersion, WithBtfFd};
use bitflags;
use libc::if_nametoindex;
use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::fd::RawFd};
use std::{
convert::TryFrom,
ffi::CString,
hash::Hash,
io, mem,
os::fd::{AsFd, RawFd},
};
use thiserror::Error;
use crate::{
@ -66,7 +72,7 @@ bitflags! {
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::{Xdp, XdpFlags}};
///
/// let program: &mut Xdp = bpf.program_mut("intercept_packets").unwrap().try_into()?;
/// let mut program: aya::WithBtfFd<Xdp> = bpf.program_mut("intercept_packets").unwrap().try_into()?;
/// program.attach("eth0", XdpFlags::default())?;
/// # Ok::<(), aya::BpfError>(())
/// ```
@ -76,11 +82,18 @@ pub struct Xdp {
pub(crate) data: ProgramData<XdpLink>,
}
impl Xdp {
impl<'f> WithBtfFd<'f, Xdp> {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.program.load(self.btf_fd)
}
}
impl Xdp {
/// Loads the program inside the kernel.
pub fn load(&mut self, btf_fd: Option<impl AsFd>) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(bpf_attach_type::BPF_XDP);
load_program(BPF_PROG_TYPE_XDP, &mut self.data)
load_program(BPF_PROG_TYPE_XDP, &mut self.data, btf_fd)
}
/// Attaches the program to the given `interface`.

@ -3,7 +3,7 @@ use std::{
ffi::{CStr, CString},
io,
mem::{self, MaybeUninit},
os::fd::{FromRawFd as _, OwnedFd, RawFd},
os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd},
slice,
};
@ -35,7 +35,7 @@ use crate::{
pub(crate) fn bpf_create_map(
name: &CStr,
def: &obj::Map,
btf_fd: Option<RawFd>,
btf_fd: Option<impl AsFd>,
kernel_version: KernelVersion,
) -> SysResult<c_long> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
@ -75,7 +75,7 @@ pub(crate) fn bpf_create_map(
_ => {
u.btf_key_type_id = m.def.btf_key_type_id;
u.btf_value_type_id = m.def.btf_value_type_id;
u.btf_fd = btf_fd.unwrap_or_default() as u32;
u.btf_fd = btf_fd.map(|fd| fd.as_fd().as_raw_fd()).unwrap_or_default() as u32;
}
}
}
@ -115,7 +115,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> {
pub(crate) license: &'a CStr,
pub(crate) kernel_version: u32,
pub(crate) expected_attach_type: Option<bpf_attach_type>,
pub(crate) prog_btf_fd: Option<RawFd>,
pub(crate) prog_btf_fd: Option<BorrowedFd<'a>>,
pub(crate) attach_btf_obj_fd: Option<u32>,
pub(crate) attach_btf_id: Option<u32>,
pub(crate) attach_prog_fd: Option<RawFd>,
@ -161,7 +161,7 @@ pub(crate) fn bpf_load_program(
let func_info_buf = aya_attr.func_info.func_info_bytes();
if let Some(btf_fd) = aya_attr.prog_btf_fd {
u.prog_btf_fd = btf_fd as u32;
u.prog_btf_fd = btf_fd.as_raw_fd() as u32;
if aya_attr.line_info_rec_size > 0 {
u.line_info = line_info_buf.as_ptr() as *const _ as u64;
u.line_info_cnt = aya_attr.line_info.len() as u32;
@ -561,7 +561,7 @@ pub(crate) fn bpf_load_btf(
raw_btf: &[u8],
log_buf: &mut [u8],
verifier_log_level: VerifierLogLevel,
) -> SysResult<c_long> {
) -> SysResult<OwnedFd> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_7 };
u.btf = raw_btf.as_ptr() as *const _ as u64;
@ -571,7 +571,9 @@ pub(crate) fn bpf_load_btf(
u.btf_log_buf = log_buf.as_mut_ptr() as u64;
u.btf_log_size = log_buf.len() as u32;
}
sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr)
let raw_fd = sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr)? as RawFd;
// SAFETY: BPF_BTF_LOAD returns a newly created file descriptor
Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
}
pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result<RawFd, io::Error> {
@ -711,10 +713,9 @@ pub(crate) fn is_bpf_global_data_supported() -> bool {
}),
fd: None,
pinned: false,
btf_fd: None,
};
if let Ok(map_fd) = map_data.create("aya_global") {
if let Ok(map_fd) = map_data.create("aya_global", Option::<BorrowedFd>::None) {
insns[0].imm = map_fd;
let gpl = b"GPL\0";

@ -1,4 +1,4 @@
use aya::{maps::Array, programs::UProbe, Bpf};
use aya::{maps::Array, programs::UProbe, Bpf, WithBtfFd};
const RESULT_BUF_LEN: usize = 1024;
@ -104,8 +104,7 @@ fn result_bytes(bpf: &Bpf) -> Vec<u8> {
fn load_and_attach_uprobe(prog_name: &str, func_name: &str, bytes: &[u8]) -> Bpf {
let mut bpf = Bpf::load(bytes).unwrap();
let prog: &mut UProbe = bpf.program_mut(prog_name).unwrap().try_into().unwrap();
let mut prog: WithBtfFd<UProbe> = bpf.program_mut(prog_name).unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach(Some(func_name), 0, "/proc/self/exe", None)

@ -5,7 +5,9 @@ use std::{
time::Duration,
};
use aya::{maps::Array, programs::TracePoint, util::KernelVersion, BpfLoader, Btf, Endianness};
use aya::{
maps::Array, programs::TracePoint, util::KernelVersion, BpfLoader, Btf, Endianness, WithBtfFd,
};
// In the tests below we often use values like 0xAAAAAAAA or -0x7AAAAAAA. Those values have no
// special meaning, they just have "nice" bit patterns that can be helpful while debugging.
@ -384,7 +386,7 @@ impl RelocationTestRunner {
loader.btf(None);
}
let mut bpf = loader.load(&self.ebpf).context("Loading eBPF failed")?;
let program: &mut TracePoint = bpf
let mut program: WithBtfFd<TracePoint> = bpf
.program_mut("bpf_prog")
.context("bpf_prog not found")?
.try_into()

@ -7,7 +7,7 @@ use aya::{
loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags,
},
util::KernelVersion,
Bpf,
Bpf, WithBtfFd,
};
const MAX_RETRIES: u32 = 100;
@ -16,7 +16,7 @@ const RETRY_DURATION_MS: u64 = 10;
#[test]
fn long_name() {
let mut bpf = Bpf::load(crate::NAME_TEST).unwrap();
let name_prog: &mut Xdp = bpf
let mut name_prog: WithBtfFd<Xdp> = bpf
.program_mut("ihaveaverylongname")
.unwrap()
.try_into()
@ -36,7 +36,8 @@ fn multiple_btf_maps() {
let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap();
let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap();
let prog: &mut TracePoint = bpf.program_mut("tracepoint").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<TracePoint> =
bpf.program_mut("tracepoint").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach("sched", "sched_switch").unwrap();
@ -110,7 +111,7 @@ macro_rules! assert_loaded {
#[test]
fn unload_xdp() {
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut Xdp = bpf.program_mut("test_xdp").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<Xdp> = bpf.program_mut("test_xdp").unwrap().try_into().unwrap();
prog.load().unwrap();
assert_loaded!("test_xdp", true);
let link = prog.attach("lo", XdpFlags::default()).unwrap();
@ -135,7 +136,7 @@ fn unload_xdp() {
#[test]
fn unload_kprobe() {
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut KProbe = bpf.program_mut("test_kprobe").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<KProbe> = bpf.program_mut("test_kprobe").unwrap().try_into().unwrap();
prog.load().unwrap();
assert_loaded!("test_kprobe", true);
let link = prog.attach("try_to_wake_up", 0).unwrap();
@ -160,7 +161,7 @@ fn unload_kprobe() {
#[test]
fn basic_tracepoint() {
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut TracePoint = bpf
let mut prog: WithBtfFd<TracePoint> = bpf
.program_mut("test_tracepoint")
.unwrap()
.try_into()
@ -191,7 +192,7 @@ fn basic_tracepoint() {
#[test]
fn basic_uprobe() {
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut UProbe = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<UProbe> = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap();
prog.load().unwrap();
assert_loaded!("test_uprobe", true);
@ -224,7 +225,7 @@ fn pin_link() {
}
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut Xdp = bpf.program_mut("test_xdp").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<Xdp> = bpf.program_mut("test_xdp").unwrap().try_into().unwrap();
prog.load().unwrap();
let link_id = prog.attach("lo", XdpFlags::default()).unwrap();
let link = prog.take_link(link_id).unwrap();
@ -257,7 +258,7 @@ fn pin_lifecycle() {
// 1. Load Program and Pin
{
let mut bpf = Bpf::load(crate::PASS).unwrap();
let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<Xdp> = bpf.program_mut("pass").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.pin("/sys/fs/bpf/aya-xdp-test-prog").unwrap();
}
@ -291,7 +292,7 @@ fn pin_lifecycle() {
// 4. Load a new version of the program, unpin link, and atomically replace old program
{
let mut bpf = Bpf::load(crate::PASS).unwrap();
let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<Xdp> = bpf.program_mut("pass").unwrap().try_into().unwrap();
prog.load().unwrap();
let link = PinnedLink::from_pin("/sys/fs/bpf/aya-xdp-test-lo")
@ -311,7 +312,7 @@ fn pin_lifecycle_tracepoint() {
// 1. Load Program and Pin
{
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut TracePoint = bpf
let mut prog: WithBtfFd<TracePoint> = bpf
.program_mut("test_tracepoint")
.unwrap()
.try_into()
@ -365,7 +366,8 @@ fn pin_lifecycle_kprobe() {
// 1. Load Program and Pin
{
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut KProbe = bpf.program_mut("test_kprobe").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<KProbe> =
bpf.program_mut("test_kprobe").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.pin("/sys/fs/bpf/aya-kprobe-test-prog").unwrap();
}
@ -423,7 +425,8 @@ fn pin_lifecycle_uprobe() {
// 1. Load Program and Pin
{
let mut bpf = Bpf::load(crate::TEST).unwrap();
let prog: &mut UProbe = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<UProbe> =
bpf.program_mut("test_uprobe").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.pin("/sys/fs/bpf/aya-uprobe-test-prog").unwrap();
}

@ -3,7 +3,7 @@ use std::{
sync::{Arc, Mutex},
};
use aya::{programs::UProbe, Bpf};
use aya::{programs::UProbe, Bpf, WithBtfFd};
use aya_log::BpfLogger;
use log::{Level, Log, Record};
@ -60,7 +60,7 @@ async fn log() {
.unwrap();
}
let prog: &mut UProbe = bpf.program_mut("test_log").unwrap().try_into().unwrap();
let mut prog: WithBtfFd<UProbe> = bpf.program_mut("test_log").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach(Some("trigger_ebpf_program"), 0, "/proc/self/exe", None)
.unwrap();

@ -1,6 +1,6 @@
use std::time::Duration;
use aya::{programs::UProbe, Bpf};
use aya::{programs::UProbe, Bpf, WithBtfFd};
#[test]
fn relocations() {
@ -32,8 +32,7 @@ fn text_64_64_reloc() {
fn load_and_attach(name: &str, bytes: &[u8]) -> Bpf {
let mut bpf = Bpf::load(bytes).unwrap();
let prog: &mut UProbe = bpf.program_mut(name).unwrap().try_into().unwrap();
let mut prog: WithBtfFd<UProbe> = bpf.program_mut(name).unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach(

@ -1,7 +1,7 @@
use aya::{
programs::{Extension, Xdp, XdpFlags},
util::KernelVersion,
Bpf, BpfLoader,
Bpf, BpfLoader, WithBtfFd,
};
#[test]
@ -13,7 +13,7 @@ fn xdp() {
}
let mut bpf = Bpf::load(crate::PASS).unwrap();
let dispatcher: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
let mut dispatcher: WithBtfFd<Xdp> = bpf.program_mut("pass").unwrap().try_into().unwrap();
dispatcher.load().unwrap();
dispatcher.attach("lo", XdpFlags::default()).unwrap();
}
@ -26,11 +26,11 @@ fn extension() {
return;
}
let mut bpf = Bpf::load(crate::MAIN).unwrap();
let pass: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
let mut pass: WithBtfFd<Xdp> = bpf.program_mut("pass").unwrap().try_into().unwrap();
pass.load().unwrap();
pass.attach("lo", XdpFlags::default()).unwrap();
let mut bpf = BpfLoader::new().extension("drop").load(crate::EXT).unwrap();
let drop_: &mut Extension = bpf.program_mut("drop").unwrap().try_into().unwrap();
let mut drop_: WithBtfFd<Extension> = bpf.program_mut("drop").unwrap().try_into().unwrap();
drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap();
}

Loading…
Cancel
Save