From c63d9904f7e64349bd23c029a3bf31aaf1d97291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Medina?= Date: Sun, 16 Jul 2023 12:02:57 -0700 Subject: [PATCH 1/3] Replace std::os::unix::io for std::os::fd This is just taking https://github.com/aya-rs/aya/pull/633 to its logical conclusion. Because `std::os::fd` was only introduced as a module in Rust v1.66.0 I have also updated the `Cargo.toml` of the `aya` package to reflect the true MSRV. Note that this commit is *not* the cause for this MSRV bump, that was done by a previous commit, this commit is just making it explicit in the `Cargo.toml` --- aya/Cargo.toml | 1 + aya/src/bpf.rs | 2 +- aya/src/maps/perf/perf_buffer.rs | 2 +- aya/src/maps/perf/perf_event_array.rs | 6 +++--- aya/src/maps/sock/mod.rs | 2 +- aya/src/maps/sock/sock_hash.rs | 4 ++-- aya/src/programs/links.rs | 2 +- aya/src/programs/perf_attach.rs | 2 +- aya/src/programs/sk_msg.rs | 4 ++-- aya/src/programs/sk_skb.rs | 2 +- aya/src/programs/sock_ops.rs | 2 +- aya/src/programs/socket_filter.rs | 2 +- aya/src/programs/utils.rs | 2 +- aya/src/programs/xdp.rs | 2 +- aya/src/sys/netlink.rs | 2 +- 15 files changed, 19 insertions(+), 18 deletions(-) diff --git a/aya/Cargo.toml b/aya/Cargo.toml index 9adf07c0..4e5eec16 100644 --- a/aya/Cargo.toml +++ b/aya/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/aya-rs/aya" readme = "README.md" documentation = "https://docs.rs/aya" edition = "2021" +rust-version = "1.66" [dependencies] async-io = { workspace = true, optional = true } diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 90e33488..818a063b 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -3,7 +3,7 @@ use std::{ collections::{HashMap, HashSet}, ffi::CString, fs, io, - os::{raw::c_int, unix::io::RawFd}, + os::{fd::RawFd, raw::c_int}, path::{Path, PathBuf}, }; diff --git a/aya/src/maps/perf/perf_buffer.rs b/aya/src/maps/perf/perf_buffer.rs index e3e99e3e..19813557 100644 --- a/aya/src/maps/perf/perf_buffer.rs +++ b/aya/src/maps/perf/perf_buffer.rs @@ -1,7 +1,7 @@ use std::{ ffi::c_void, io, mem, - os::unix::io::{AsRawFd, RawFd}, + os::fd::{AsRawFd, RawFd}, ptr, slice, sync::atomic::{self, AtomicPtr, Ordering}, }; diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index c241a37b..3d6a8103 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -4,7 +4,7 @@ use std::{ borrow::{Borrow, BorrowMut}, ops::Deref, - os::unix::io::{AsRawFd, RawFd}, + os::fd::{AsRawFd, RawFd}, sync::Arc, }; @@ -64,7 +64,7 @@ impl + Borrow> AsRawFd for PerfEventArrayBuffer + Borrow> AsRawFd for PerfEventArrayBuffer Date: Thu, 20 Jul 2023 00:25:54 -0700 Subject: [PATCH 2/3] aya: Make SysResult generic on Ok variant --- aya/src/maps/bloom_filter.rs | 4 +-- aya/src/maps/hash_map/hash_map.rs | 8 +++--- aya/src/maps/lpm_trie.rs | 4 +-- aya/src/sys/bpf.rs | 42 +++++++++++++++---------------- aya/src/sys/fake.rs | 8 +++--- aya/src/sys/mod.rs | 4 +-- aya/src/sys/perf_event.rs | 15 ++++++----- 7 files changed, 44 insertions(+), 41 deletions(-) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index 6135da5b..f646c2bb 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -90,7 +90,7 @@ mod tests { }; use assert_matches::assert_matches; use libc::{EFAULT, ENOENT}; - use std::io; + use std::{ffi::c_long, io}; fn new_obj_map() -> obj::Map { obj::Map::Legacy(LegacyMap { @@ -108,7 +108,7 @@ mod tests { }) } - fn sys_error(value: i32) -> SysResult { + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 34f0b851..2fcb1334 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -105,7 +105,7 @@ impl, K: Pod, V: Pod> IterableMap for HashMap #[cfg(test)] mod tests { - use std::io; + use std::{ffi::c_long, io}; use assert_matches::assert_matches; use libc::{EFAULT, ENOENT}; @@ -139,7 +139,7 @@ mod tests { }) } - fn sys_error(value: i32) -> SysResult { + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } @@ -451,7 +451,7 @@ mod tests { assert_matches!(keys, Ok(ks) if ks.is_empty()) } - fn get_next_key(attr: &bpf_attr) -> SysResult { + fn get_next_key(attr: &bpf_attr) -> SysResult { match bpf_key(attr) { None => set_next_key(attr, 10), Some(10) => set_next_key(attr, 20), @@ -463,7 +463,7 @@ mod tests { Ok(1) } - fn lookup_elem(attr: &bpf_attr) -> SysResult { + fn lookup_elem(attr: &bpf_attr) -> SysResult { match bpf_key(attr) { Some(10) => set_ret(attr, 100), Some(20) => set_ret(attr, 200), diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index b2e21e88..4adb3f47 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -209,7 +209,7 @@ mod tests { }; use assert_matches::assert_matches; use libc::{EFAULT, ENOENT}; - use std::{io, mem, net::Ipv4Addr}; + use std::{ffi::c_long, io, mem, net::Ipv4Addr}; fn new_obj_map() -> obj::Map { obj::Map::Legacy(LegacyMap { @@ -227,7 +227,7 @@ mod tests { }) } - fn sys_error(value: i32) -> SysResult { + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index e9f2eba8..5a26c57f 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -37,7 +37,7 @@ pub(crate) fn bpf_create_map( def: &obj::Map, btf_fd: Option, kernel_version: KernelVersion, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_1 }; @@ -93,7 +93,7 @@ pub(crate) fn bpf_create_map( sys_bpf(bpf_cmd::BPF_MAP_CREATE, &attr) } -pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult { +pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_4 }; u.bpf_fd = fd as u32; @@ -101,7 +101,7 @@ pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult { sys_bpf(bpf_cmd::BPF_OBJ_PIN, &attr) } -pub(crate) fn bpf_get_object(path: &CStr) -> SysResult { +pub(crate) fn bpf_get_object(path: &CStr) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_4 }; u.pathname = path.as_ptr() as u64; @@ -130,7 +130,7 @@ pub(crate) fn bpf_load_program( aya_attr: &BpfLoadProgramAttrs, log_buf: &mut [u8], verifier_log_level: VerifierLogLevel, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; @@ -272,7 +272,7 @@ pub(crate) fn bpf_map_update_elem( key: Option<&K>, value: &V, flags: u64, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; @@ -286,7 +286,7 @@ pub(crate) fn bpf_map_update_elem( sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) } -pub(crate) fn bpf_map_push_elem(fd: RawFd, value: &V, flags: u64) -> SysResult { +pub(crate) fn bpf_map_push_elem(fd: RawFd, value: &V, flags: u64) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; @@ -302,7 +302,7 @@ pub(crate) fn bpf_map_update_elem_ptr( key: *const K, value: *mut V, flags: u64, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; @@ -319,12 +319,12 @@ pub(crate) fn bpf_map_update_elem_per_cpu( key: &K, values: &PerCpuValues, flags: u64, -) -> SysResult { +) -> SysResult { let mut mem = values.build_kernel_mem().map_err(|e| (-1, e))?; bpf_map_update_elem_ptr(fd, key, mem.as_mut_ptr(), flags) } -pub(crate) fn bpf_map_delete_elem(fd: RawFd, key: &K) -> SysResult { +pub(crate) fn bpf_map_delete_elem(fd: RawFd, key: &K) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; @@ -356,7 +356,7 @@ pub(crate) fn bpf_map_get_next_key( } // since kernel 5.2 -pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult { +pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd as u32; @@ -370,7 +370,7 @@ pub(crate) fn bpf_link_create( attach_type: bpf_attach_type, btf_id: Option, flags: u32, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.link_create.__bindgen_anon_1.prog_fd = prog_fd as u32; @@ -390,7 +390,7 @@ pub(crate) fn bpf_link_update( new_prog_fd: RawFd, old_prog_fd: Option, flags: u32, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.link_update.link_fd = link_fd as u32; @@ -409,7 +409,7 @@ pub(crate) fn bpf_prog_attach( prog_fd: RawFd, target_fd: RawFd, attach_type: bpf_attach_type, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32; @@ -423,7 +423,7 @@ pub(crate) fn bpf_prog_detach( prog_fd: RawFd, map_fd: RawFd, attach_type: bpf_attach_type, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32; @@ -440,7 +440,7 @@ pub(crate) fn bpf_prog_query( attach_flags: Option<&mut u32>, prog_ids: &mut [u32], prog_cnt: &mut u32, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.query.target_fd = target_fd as u32; @@ -545,7 +545,7 @@ pub(crate) fn btf_obj_get_info_by_fd( } } -pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult { +pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.raw_tracepoint.name = match name { @@ -561,7 +561,7 @@ pub(crate) fn bpf_load_btf( raw_btf: &[u8], log_buf: &mut [u8], verifier_log_level: VerifierLogLevel, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_7 }; u.btf = raw_btf.as_ptr() as *const _ as u64; @@ -987,7 +987,7 @@ pub(crate) fn is_btf_type_tag_supported() -> bool { } } -pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult { +pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } @@ -1002,10 +1002,10 @@ pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result, (c_long, io:: } } -pub(crate) fn retry_with_verifier_logs( +pub(crate) fn retry_with_verifier_logs( max_retries: usize, - f: impl Fn(&mut [u8]) -> SysResult, -) -> (SysResult, String) { + f: impl Fn(&mut [u8]) -> SysResult, +) -> (SysResult, String) { const MIN_LOG_BUF_SIZE: usize = 1024 * 10; const MAX_LOG_BUF_SIZE: usize = (std::u32::MAX >> 8) as usize; diff --git a/aya/src/sys/fake.rs b/aya/src/sys/fake.rs index 2c2c337c..6cac51b6 100644 --- a/aya/src/sys/fake.rs +++ b/aya/src/sys/fake.rs @@ -1,10 +1,10 @@ -use std::{cell::RefCell, io, ptr}; +use std::{cell::RefCell, ffi::c_long, io, ptr}; use libc::c_void; use super::{SysResult, Syscall}; -type SyscallFn = unsafe fn(Syscall) -> SysResult; +type SyscallFn = unsafe fn(Syscall) -> SysResult; #[cfg(test)] thread_local! { @@ -13,11 +13,11 @@ thread_local! { } #[cfg(test)] -unsafe fn test_syscall(_call: Syscall) -> SysResult { +unsafe fn test_syscall(_call: Syscall) -> SysResult { Err((-1, io::Error::from_raw_os_error(libc::EINVAL))) } #[cfg(test)] -pub(crate) fn override_syscall(call: unsafe fn(Syscall) -> SysResult) { +pub(crate) fn override_syscall(call: unsafe fn(Syscall) -> SysResult) { TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call); } diff --git a/aya/src/sys/mod.rs b/aya/src/sys/mod.rs index 646d6cfe..448e7fee 100644 --- a/aya/src/sys/mod.rs +++ b/aya/src/sys/mod.rs @@ -17,7 +17,7 @@ pub(crate) use perf_event::*; use crate::generated::{bpf_attr, bpf_cmd, perf_event_attr}; -pub(crate) type SysResult = Result; +pub(crate) type SysResult = Result; pub(crate) enum Syscall<'a> { Bpf { @@ -38,7 +38,7 @@ pub(crate) enum Syscall<'a> { }, } -fn syscall(call: Syscall) -> SysResult { +fn syscall(call: Syscall) -> SysResult { #[cfg(test)] return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) }); diff --git a/aya/src/sys/perf_event.rs b/aya/src/sys/perf_event.rs index 68eddd35..586bd50a 100644 --- a/aya/src/sys/perf_event.rs +++ b/aya/src/sys/perf_event.rs @@ -1,4 +1,7 @@ -use std::{ffi::CString, mem}; +use std::{ + ffi::{c_long, CString}, + mem, +}; use libc::{c_int, pid_t}; @@ -22,7 +25,7 @@ pub(crate) fn perf_event_open( sample_frequency: Option, wakeup: bool, flags: u32, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.config = config; @@ -48,7 +51,7 @@ pub(crate) fn perf_event_open( }) } -pub(crate) fn perf_event_open_bpf(cpu: c_int) -> SysResult { +pub(crate) fn perf_event_open_bpf(cpu: c_int) -> SysResult { perf_event_open( PERF_TYPE_SOFTWARE as u32, PERF_COUNT_SW_BPF_OUTPUT as u64, @@ -67,7 +70,7 @@ pub(crate) fn perf_event_open_probe( name: &str, offset: u64, pid: Option, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; if let Some(ret_bit) = ret_bit { @@ -93,7 +96,7 @@ pub(crate) fn perf_event_open_probe( }) } -pub(crate) fn perf_event_open_trace_point(id: u32, pid: Option) -> SysResult { +pub(crate) fn perf_event_open_trace_point(id: u32, pid: Option) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.size = mem::size_of::() as u32; @@ -112,7 +115,7 @@ pub(crate) fn perf_event_open_trace_point(id: u32, pid: Option) -> SysRes }) } -pub(crate) fn perf_event_ioctl(fd: c_int, request: c_int, arg: c_int) -> SysResult { +pub(crate) fn perf_event_ioctl(fd: c_int, request: c_int, arg: c_int) -> SysResult { let call = Syscall::PerfEventIoctl { fd, request, arg }; #[cfg(not(test))] return syscall(call); From ea96c29ccbae6c59a6a5bfc90f402ad307e22665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Medina?= Date: Thu, 27 Jul 2023 22:01:55 -0700 Subject: [PATCH 3/3] aya: Use Arc when loading BTF fd This fixes an existing file descriptor leak when there is BTF data in the loaded object. To avoid lifetime issues while having minimal impact to UX the `OwnedFd` returned from the BPF_BTF_LOAD syscall will be wrapped in an `Arc` and shared accross the programs and maps of the loaded BPF file. --- aya/src/bpf.rs | 24 +++++++++++---------- aya/src/maps/mod.rs | 35 +++++++++++++++++------------- aya/src/programs/mod.rs | 9 ++++---- aya/src/sys/bpf.rs | 47 ++++++++++++++++++++++------------------- 4 files changed, 63 insertions(+), 52 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 818a063b..eed006d4 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -3,8 +3,12 @@ use std::{ collections::{HashMap, HashSet}, ffi::CString, fs, io, - os::{fd::RawFd, raw::c_int}, + os::{ + fd::{OwnedFd, RawFd}, + raw::c_int, + }, path::{Path, PathBuf}, + sync::Arc, }; use aya_obj::{ @@ -390,7 +394,7 @@ impl<'a> BpfLoader<'a> { let btf_fd = if let Some(features) = &FEATURES.btf() { if let Some(btf) = obj.fixup_and_sanitize_btf(features)? { match load_btf(btf.to_bytes(), *verifier_log_level) { - Ok(btf_fd) => Some(btf_fd), + Ok(btf_fd) => Some(Arc::new(btf_fd)), // Only report an error here if the BTF is truely needed, otherwise proceed without. Err(err) => { for program in obj.programs.values() { @@ -473,7 +477,7 @@ impl<'a> BpfLoader<'a> { obj, fd: None, pinned: false, - btf_fd, + btf_fd: btf_fd.as_ref().map(Arc::clone), }; let fd = match map.obj.pinning() { PinningType::ByName => { @@ -543,6 +547,7 @@ impl<'a> BpfLoader<'a> { let section = prog_obj.section.clone(); let obj = (prog_obj, function_obj); + let btf_fd = btf_fd.as_ref().map(Arc::clone); let program = if extensions.contains(name.as_str()) { Program::Extension(Extension { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), @@ -993,17 +998,14 @@ pub enum BpfError { ProgramError(#[from] ProgramError), } -fn load_btf(raw_btf: Vec, verifier_log_level: VerifierLogLevel) -> Result { +fn load_btf(raw_btf: Vec, verifier_log_level: VerifierLogLevel) -> Result { 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), - Err((_, io_error)) => Err(BtfError::LoadError { - io_error, - verifier_log, - }), - } + ret.map_err(|(_, io_error)| BtfError::LoadError { + io_error, + verifier_log, + }) } /// Global data that can be exported to eBPF programs before they are loaded. diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index fca42110..5dce668e 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -42,9 +42,10 @@ use std::{ marker::PhantomData, mem, ops::Deref, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd, AsRawFd, OwnedFd, RawFd}, path::Path, ptr, + sync::Arc, }; use crate::util::KernelVersion; @@ -486,7 +487,7 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { pub struct MapData { pub(crate) obj: obj::Map, pub(crate) fd: Option, - pub(crate) btf_fd: Option, + pub(crate) btf_fd: Option>, /// Indicates if this map has been pinned to bpffs pub pinned: bool, } @@ -504,19 +505,23 @@ 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( - |(code, io_error)| { - if kernel_version < KernelVersion::new(5, 11, 0) { - maybe_warn_rlimit(); - } + let fd = bpf_create_map( + &c_name, + &self.obj, + self.btf_fd.as_ref().map(|f| f.as_fd()), + kernel_version, + ) + .map_err(|(code, io_error)| { + if kernel_version < KernelVersion::new(5, 11, 0) { + maybe_warn_rlimit(); + } - MapError::CreateError { - name: name.into(), - code, - io_error, - } - }, - )? as RawFd; + MapError::CreateError { + name: name.into(), + code, + io_error, + } + })? as RawFd; self.fd = Some(fd); @@ -639,7 +644,7 @@ impl Clone for MapData { MapData { obj: self.obj.clone(), fd: self.fd.map(|fd| unsafe { libc::dup(fd) }), - btf_fd: self.btf_fd, + btf_fd: self.btf_fd.as_ref().map(Arc::clone), pinned: self.pinned, } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index f868dfc8..5d25b8cb 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -69,8 +69,9 @@ use libc::ENOSPC; use std::{ ffi::CString, io, - os::fd::{AsRawFd, IntoRawFd as _, RawFd}, + os::fd::{AsFd, AsRawFd, IntoRawFd as _, OwnedFd, RawFd}, path::{Path, PathBuf}, + sync::Arc, }; use thiserror::Error; @@ -413,7 +414,7 @@ pub(crate) struct ProgramData { pub(crate) attach_btf_obj_fd: Option, pub(crate) attach_btf_id: Option, pub(crate) attach_prog_fd: Option, - pub(crate) btf_fd: Option, + pub(crate) btf_fd: Option>, pub(crate) verifier_log_level: VerifierLogLevel, pub(crate) path: Option, pub(crate) flags: u32, @@ -423,7 +424,7 @@ impl ProgramData { pub(crate) fn new( name: Option, obj: (obj::Program, obj::Function), - btf_fd: Option, + btf_fd: Option>, verifier_log_level: VerifierLogLevel, ) -> ProgramData { ProgramData { @@ -613,7 +614,7 @@ fn load_program( 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, diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 5a26c57f..858ccc55 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -3,7 +3,7 @@ use std::{ ffi::{CStr, CString}, io, mem::{self, MaybeUninit}, - os::fd::{FromRawFd as _, OwnedFd, RawFd}, + os::fd::{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, + btf_fd: Option>, kernel_version: KernelVersion, ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; @@ -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_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, - pub(crate) prog_btf_fd: Option, + pub(crate) prog_btf_fd: Option>, pub(crate) attach_btf_obj_fd: Option, pub(crate) attach_btf_id: Option, pub(crate) attach_prog_fd: Option, @@ -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; @@ -464,21 +464,8 @@ pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id; - - match sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr) { - Ok(v) => { - let v = v.try_into().map_err(|_err| { - // _err is std::num::TryFromIntError or std::convert::Infallible depending on - // target, so we can't ascribe. - io::Error::new( - io::ErrorKind::InvalidData, - format!("bpf_prog_get_fd_by_id: invalid fd returned: {}", v), - ) - })?; - Ok(unsafe { OwnedFd::from_raw_fd(v) }) - } - Err((_, err)) => Err(err), - } + // SAFETY: BPF_PROG_GET_FD_BY_ID returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr).map_err(|(_, e)| e) } } pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result { @@ -561,7 +548,7 @@ pub(crate) fn bpf_load_btf( raw_btf: &[u8], log_buf: &mut [u8], verifier_log_level: VerifierLogLevel, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_7 }; u.btf = raw_btf.as_ptr() as *const _ as u64; @@ -571,7 +558,23 @@ 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) + // SAFETY: `BPF_BTF_LOAD` returns a newly created fd. + unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) } +} + +// SAFETY: only use for bpf_cmd that return a new file descriptor on success. +unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult { + let fd = sys_bpf(cmd, attr)?; + let fd = fd.try_into().map_err(|_| { + ( + fd, + io::Error::new( + io::ErrorKind::InvalidData, + format!("{cmd:?}: invalid fd returned: {fd}"), + ), + ) + })?; + Ok(OwnedFd::from_raw_fd(fd)) } pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result {