From aeb2befc00eb36cd3e8ac7173e55580b32820e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Medina?= Date: Thu, 3 Aug 2023 21:19:13 -0700 Subject: [PATCH] aya: Use OwnedFd for Program related actions This commit reveals but does not address a file descriptor leak in LircLink2::query. This function returns a list of `LircLink`s where each of them have a program file descriptor that is not going to be closed. This commit does not add this leak; it merely makes it louder in the code. --- aya/src/programs/cgroup_device.rs | 1 - aya/src/programs/cgroup_skb.rs | 1 - aya/src/programs/cgroup_sock.rs | 1 - aya/src/programs/cgroup_sock_addr.rs | 1 - aya/src/programs/cgroup_sockopt.rs | 1 - aya/src/programs/cgroup_sysctl.rs | 1 - aya/src/programs/extension.rs | 2 - aya/src/programs/links.rs | 6 +- aya/src/programs/lirc_mode2.rs | 14 ++-- aya/src/programs/perf_attach.rs | 19 ++--- aya/src/programs/perf_event.rs | 3 +- aya/src/programs/probe.rs | 3 +- aya/src/programs/sk_lookup.rs | 1 - aya/src/programs/sk_msg.rs | 1 - aya/src/programs/sk_skb.rs | 1 - aya/src/programs/sock_ops.rs | 3 +- aya/src/programs/socket_filter.rs | 5 +- aya/src/programs/tc.rs | 3 +- aya/src/programs/trace_point.rs | 7 +- aya/src/programs/utils.rs | 1 - aya/src/programs/xdp.rs | 27 +++---- aya/src/sys/bpf.rs | 102 +++++++++++---------------- aya/src/sys/netlink.rs | 17 +++-- 23 files changed, 101 insertions(+), 120 deletions(-) diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index 1244d27c..eb2cc5ec 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -63,7 +63,6 @@ impl CgroupDevice { pub fn attach(&mut self, cgroup: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index 684fd18e..b5af4eae 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -94,7 +94,6 @@ impl CgroupSkb { ) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = match attach_type { diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index c906ee6c..7337f0ff 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -73,7 +73,6 @@ impl CgroupSock { pub fn attach(&mut self, cgroup: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 98d60eb1..58b20802 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -74,7 +74,6 @@ impl CgroupSockAddr { pub fn attach(&mut self, cgroup: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index c137d769..f989662e 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -71,7 +71,6 @@ impl CgroupSockopt { pub fn attach(&mut self, cgroup: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index d5325089..0b23a757 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -65,7 +65,6 @@ impl CgroupSysctl { pub fn attach(&mut self, cgroup: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index fd955ddc..b10cd935 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -89,7 +89,6 @@ impl Extension { pub fn attach(&mut self) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let target_fd = self.data.attach_prog_fd.ok_or(ProgramError::NotLoaded)?; let btf_id = self.data.attach_btf_id.ok_or(ProgramError::NotLoaded)?; // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS @@ -123,7 +122,6 @@ impl Extension { let (_, btf_id) = get_btf_info(target_fd, func_name)?; let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS let link_fd = bpf_link_create( prog_fd, diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index 52aa60de..17176ff4 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -6,7 +6,7 @@ use std::{ collections::{hash_map::Entry, HashMap}, ffi::CString, io, - os::fd::{AsRawFd as _, OwnedFd, RawFd}, + os::fd::{AsRawFd as _, BorrowedFd, OwnedFd, RawFd}, path::{Path, PathBuf}, }; @@ -237,12 +237,12 @@ pub struct ProgAttachLink { impl ProgAttachLink { pub(crate) fn new( - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, target_fd: RawFd, attach_type: bpf_attach_type, ) -> ProgAttachLink { ProgAttachLink { - prog_fd, + prog_fd: prog_fd.as_raw_fd(), target_fd: unsafe { dup(target_fd) }, attach_type, } diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index 906eec96..5b1aa06c 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -63,7 +63,6 @@ impl LircMode2 { pub fn attach(&mut self, lircdev: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let lircdev_fd = lircdev.as_raw_fd(); bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| { @@ -104,7 +103,14 @@ impl LircMode2 { Ok(prog_fds .into_iter() - .map(|prog_fd| LircLink::new(prog_fd.into_raw_fd(), target_fd.as_raw_fd())) + .map(|prog_fd| { + LircLink::new( + // SAFETY: The file descriptor will stay valid because we are leaking it + // TODO: Do not leak it? + unsafe { BorrowedFd::borrow_raw(prog_fd.into_raw_fd()) }, + target_fd.as_raw_fd(), + ) + }) .collect()) } } @@ -121,9 +127,9 @@ pub struct LircLink { } impl LircLink { - pub(crate) fn new(prog_fd: RawFd, target_fd: RawFd) -> LircLink { + pub(crate) fn new(prog_fd: BorrowedFd<'_>, target_fd: RawFd) -> LircLink { LircLink { - prog_fd, + prog_fd: prog_fd.as_raw_fd(), target_fd: unsafe { dup(target_fd) }, } } diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index e9be37d5..d6454793 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -1,5 +1,5 @@ //! Perf attach links. -use std::os::fd::{AsFd as _, AsRawFd as _, OwnedFd, RawFd}; +use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd, RawFd}; use crate::{ generated::bpf_attach_type::BPF_PERF_EVENT, @@ -70,7 +70,10 @@ impl Link for PerfLink { } } -pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result { +pub(crate) fn perf_attach( + prog_fd: std::os::fd::BorrowedFd<'_>, + fd: OwnedFd, +) -> Result { if FEATURES.bpf_perf_link() { let link_fd = bpf_link_create(prog_fd, fd.as_raw_fd(), BPF_PERF_EVENT, None, 0).map_err( |(_, io_error)| SyscallError { @@ -85,7 +88,7 @@ pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result, fd: OwnedFd, event: ProbeEvent, ) -> Result { @@ -93,16 +96,16 @@ pub(crate) fn perf_attach_debugfs( } fn perf_attach_either( - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, fd: OwnedFd, event: Option, ) -> Result { - perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd).map_err(|(_, io_error)| { - SyscallError { + perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd.as_raw_fd()).map_err( + |(_, io_error)| SyscallError { call: "PERF_EVENT_IOC_SET_BPF", io_error, - } - })?; + }, + )?; perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0).map_err(|(_, io_error)| { SyscallError { call: "PERF_EVENT_IOC_ENABLE", diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index bb60f082..dc4de264 100644 --- a/aya/src/programs/perf_event.rs +++ b/aya/src/programs/perf_event.rs @@ -1,6 +1,6 @@ //! Perf event programs. -use std::os::fd::{AsFd as _, AsRawFd as _}; +use std::os::fd::AsFd as _; 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, @@ -148,7 +148,6 @@ impl PerfEvent { ) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let (sample_period, sample_frequency) = match sample_policy { SamplePolicy::Period(period) => (period, None), SamplePolicy::Frequency(frequency) => (0, Some(frequency)), diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index 151c87ef..2a7946f1 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -3,7 +3,7 @@ use libc::pid_t; use std::{ fs::{self, OpenOptions}, io::{self, Write}, - os::fd::{AsFd as _, AsRawFd as _, OwnedFd}, + os::fd::{AsFd as _, OwnedFd}, path::Path, process, sync::atomic::{AtomicUsize, Ordering}, @@ -59,7 +59,6 @@ pub(crate) fn attach>( // Use debugfs to create probe let prog_fd = program_data.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let link = if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) { let (fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; perf_attach_debugfs(prog_fd, fd, ProbeEvent { kind, event_alias }) diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index bbcdc3a3..ab322daa 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -63,7 +63,6 @@ impl SkLookup { pub fn attach(&mut self, netns: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let netns_fd = netns.as_raw_fd(); let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err( diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 7a03b8e3..e7776d5d 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -81,7 +81,6 @@ impl SkMsg { pub fn attach(&mut self, map: SockMapFd) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let map_fd = map.as_raw_fd(); bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index a4c5de63..79ac0c23 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -77,7 +77,6 @@ impl SkSkb { pub fn attach(&mut self, map: SockMapFd) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let map_fd = map.as_raw_fd(); let attach_type = match self.kind { diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index 2a469048..d221e797 100644 --- a/aya/src/programs/sock_ops.rs +++ b/aya/src/programs/sock_ops.rs @@ -61,7 +61,6 @@ impl SockOps { pub fn attach(&mut self, cgroup: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS).map_err(|(_, io_error)| { @@ -71,7 +70,7 @@ impl SockOps { } })?; self.data.links.insert(SockOpsLink::new(ProgAttachLink::new( - prog_fd, + prog_fd.as_fd(), cgroup_fd, BPF_CGROUP_SOCK_OPS, ))) diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index e737d8ae..84825d6f 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -94,7 +94,10 @@ impl SocketFilter { .into()); } - self.data.links.insert(SocketFilterLink { socket, prog_fd }) + self.data.links.insert(SocketFilterLink { + socket, + prog_fd: prog_fd.as_raw_fd(), + }) } /// Detaches the program. diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index e289e7d0..89e33271 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -4,7 +4,7 @@ use thiserror::Error; use std::{ ffi::{CStr, CString}, io, - os::fd::{AsFd as _, AsRawFd as _}, + os::fd::AsFd as _, path::Path, }; @@ -155,7 +155,6 @@ impl SchedClassifier { ) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let if_index = ifindex_from_ifname(interface) .map_err(|io_error| TcError::NetlinkError { io_error })?; let (priority, handle) = unsafe { diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 4c5d38db..ae828449 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -1,9 +1,5 @@ //! Tracepoint programs. -use std::{ - fs, io, - os::fd::{AsFd as _, AsRawFd as _}, - path::Path, -}; +use std::{fs, io, os::fd::AsFd as _, path::Path}; use thiserror::Error; use crate::{ @@ -84,7 +80,6 @@ impl TracePoint { pub fn attach(&mut self, category: &str, name: &str) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let tracefs = find_tracefs_path()?; let id = read_sys_fs_trace_point_id(tracefs, category, name)?; let fd = diff --git a/aya/src/programs/utils.rs b/aya/src/programs/utils.rs index beb9b5f5..38b08286 100644 --- a/aya/src/programs/utils.rs +++ b/aya/src/programs/utils.rs @@ -20,7 +20,6 @@ pub(crate) fn attach_raw_tracepoint>( ) -> Result { let prog_fd = program_data.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let pfd = bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| SyscallError { call: "bpf_raw_tracepoint_open", diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 36eec7d6..e96c1922 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -130,7 +130,6 @@ impl Xdp { ) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); let if_index = if_index as RawFd; if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) { @@ -144,14 +143,14 @@ impl Xdp { .links .insert(XdpLink::new(XdpLinkInner::FdLink(FdLink::new(link_fd)))) } else { - unsafe { netlink_set_xdp_fd(if_index, prog_fd, None, flags.bits()) } + unsafe { netlink_set_xdp_fd(if_index, Some(prog_fd), None, flags.bits()) } .map_err(|io_error| XdpError::NetlinkError { io_error })?; self.data .links .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink { if_index, - prog_fd, + prog_fd: prog_fd.as_raw_fd(), flags, }))) } @@ -178,16 +177,15 @@ impl Xdp { pub fn attach_to_link(&mut self, link: XdpLink) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); - let prog_fd = prog_fd.as_raw_fd(); match link.into_inner() { XdpLinkInner::FdLink(fd_link) => { let link_fd = fd_link.fd; - bpf_link_update(link_fd.as_fd(), prog_fd, None, 0).map_err(|(_, io_error)| { - SyscallError { + bpf_link_update(link_fd.as_fd(), prog_fd.as_fd(), None, 0).map_err( + |(_, io_error)| SyscallError { call: "bpf_link_update", io_error, - } - })?; + }, + )?; self.data .links @@ -199,15 +197,20 @@ impl Xdp { let flags = nl_link.flags; let replace_flags = flags | XdpFlags::REPLACE; unsafe { - netlink_set_xdp_fd(if_index, prog_fd, Some(old_prog_fd), replace_flags.bits()) - .map_err(|io_error| XdpError::NetlinkError { io_error })?; + netlink_set_xdp_fd( + if_index, + Some(prog_fd.as_fd()), + Some(old_prog_fd), + replace_flags.bits(), + ) + .map_err(|io_error| XdpError::NetlinkError { io_error })?; } self.data .links .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink { if_index, - prog_fd, + prog_fd: prog_fd.as_raw_fd(), flags, }))) } @@ -235,7 +238,7 @@ impl Link for NlLink { } else { self.flags.bits() }; - let _ = unsafe { netlink_set_xdp_fd(self.if_index, -1, Some(self.prog_fd), flags) }; + let _ = unsafe { netlink_set_xdp_fd(self.if_index, None, Some(self.prog_fd), flags) }; Ok(()) } } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 9b9fab5b..c71ea237 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -3,12 +3,12 @@ use std::{ ffi::{CStr, CString}, io, iter, mem::{self, MaybeUninit}, - os::fd::{AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, }; use crate::util::KernelVersion; -use libc::{c_char, c_long, close, ENOENT, ENOSPC}; +use libc::{c_char, c_long, ENOENT, ENOSPC}; use obj::{ btf::{BtfEnum64, Enum64}, maps::{bpf_map_def, LegacyMap}, @@ -190,8 +190,8 @@ pub(crate) fn bpf_load_program( if let Some(v) = aya_attr.attach_btf_id { u.attach_btf_id = v; } - // SAFETY: BPF_PROG_LOAD returns a new file descriptor. - unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) } + + bpf_prog_load(&mut attr) } fn lookup( @@ -368,7 +368,7 @@ pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult { // since kernel 5.7 pub(crate) fn bpf_link_create( - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, target_fd: RawFd, attach_type: bpf_attach_type, btf_id: Option, @@ -376,7 +376,7 @@ pub(crate) fn bpf_link_create( ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; - attr.link_create.__bindgen_anon_1.prog_fd = prog_fd as u32; + attr.link_create.__bindgen_anon_1.prog_fd = prog_fd.as_raw_fd() as u32; attr.link_create.__bindgen_anon_2.target_fd = target_fd as u32; attr.link_create.attach_type = attach_type as u32; attr.link_create.flags = flags; @@ -391,14 +391,14 @@ pub(crate) fn bpf_link_create( // since kernel 5.7 pub(crate) fn bpf_link_update( link_fd: BorrowedFd<'_>, - new_prog_fd: RawFd, + new_prog_fd: BorrowedFd<'_>, old_prog_fd: Option, flags: u32, ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.link_update.link_fd = link_fd.as_raw_fd() as u32; - attr.link_update.__bindgen_anon_1.new_prog_fd = new_prog_fd as u32; + attr.link_update.__bindgen_anon_1.new_prog_fd = new_prog_fd.as_raw_fd() as u32; if let Some(fd) = old_prog_fd { attr.link_update.__bindgen_anon_2.old_prog_fd = fd as u32; attr.link_update.flags = flags | BPF_F_REPLACE; @@ -410,13 +410,13 @@ pub(crate) fn bpf_link_update( } pub(crate) fn bpf_prog_attach( - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, target_fd: RawFd, attach_type: bpf_attach_type, ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; - attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32; + attr.__bindgen_anon_5.attach_bpf_fd = prog_fd.as_raw_fd() as u32; attr.__bindgen_anon_5.target_fd = target_fd as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32; @@ -548,14 +548,17 @@ 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: BorrowedFd<'_>, +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.raw_tracepoint.name = match name { Some(n) => n.as_ptr() as u64, None => 0, }; - attr.raw_tracepoint.prog_fd = prog_fd as u32; + attr.raw_tracepoint.prog_fd = prog_fd.as_raw_fd() as u32; // SAFETY: BPF_RAW_TRACEPOINT_OPEN returns a new file descriptor. unsafe { fd_sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &mut attr) } @@ -633,14 +636,7 @@ pub(crate) fn is_prog_name_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_probe_read_kernel_supported() -> bool { @@ -664,14 +660,7 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_perf_link_supported() -> bool { @@ -691,17 +680,16 @@ pub(crate) fn is_perf_link_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - if let Err((_, e)) = - // Uses an invalid target FD so we get EBADF if supported. - bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) - { - // Returns EINVAL if unsupported. EBADF if supported. - let res = e.raw_os_error() == Some(libc::EBADF); - unsafe { libc::close(fd as i32) }; - return res; - } + let Ok(fd) = bpf_prog_load(&mut attr) else { return false }; + + if let Err((_, e)) = + // Uses an invalid target FD so we get EBADF if supported. + bpf_link_create(fd.as_fd(), -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) + { + // Returns EINVAL if unsupported. EBADF if supported. + return e.raw_os_error() == Some(libc::EBADF); } + false } @@ -737,25 +725,17 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { pinned: false, }; - if let Ok(map_fd) = map_data.create("aya_global", None) { - insns[0].imm = map_fd; - - let gpl = b"GPL\0"; - u.license = gpl.as_ptr() as u64; - u.insn_cnt = insns.len() as u32; - u.insns = insns.as_ptr() as u64; - u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; + let Ok(map_fd) = map_data.create("aya_global", None) else { return false }; - if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - let fd = v as RawFd; + insns[0].imm = map_fd; - unsafe { close(fd) }; - - return true; - } - } + let gpl = b"GPL\0"; + u.license = gpl.as_ptr() as u64; + u.insn_cnt = insns.len() as u32; + u.insns = insns.as_ptr() as u64; + u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - false + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_bpf_cookie_supported() -> bool { @@ -775,14 +755,7 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_btf_supported() -> bool { @@ -941,6 +914,11 @@ pub(crate) fn is_btf_type_tag_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } +fn bpf_prog_load(attr: &mut bpf_attr) -> SysResult { + // SAFETY: BPF_PROG_LOAD returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) } +} + fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } diff --git a/aya/src/sys/netlink.rs b/aya/src/sys/netlink.rs index 1dfae70d..9bc75609 100644 --- a/aya/src/sys/netlink.rs +++ b/aya/src/sys/netlink.rs @@ -1,4 +1,10 @@ -use std::{collections::HashMap, ffi::CStr, io, mem, os::fd::RawFd, ptr, slice}; +use std::{ + collections::HashMap, + ffi::CStr, + io, mem, + os::fd::{AsRawFd as _, BorrowedFd, RawFd}, + ptr, slice, +}; use thiserror::Error; use libc::{ @@ -25,7 +31,7 @@ const NLA_HDR_LEN: usize = align_to(mem::size_of::(), NLA_ALIGNTO as usi // netlink alignments pub(crate) unsafe fn netlink_set_xdp_fd( if_index: i32, - fd: RawFd, + fd: Option>, old_fd: Option, flags: u32, ) -> Result<(), io::Error> { @@ -48,7 +54,10 @@ pub(crate) unsafe fn netlink_set_xdp_fd( // write the attrs let attrs_buf = request_attributes(&mut req, nlmsg_len); let mut attrs = NestedAttrs::new(attrs_buf, IFLA_XDP); - attrs.write_attr(IFLA_XDP_FD as u16, fd)?; + attrs.write_attr( + IFLA_XDP_FD as u16, + fd.map(|fd| fd.as_raw_fd()).unwrap_or(-1), + )?; if flags > 0 { attrs.write_attr(IFLA_XDP_FLAGS as u16, flags)?; @@ -101,7 +110,7 @@ pub(crate) unsafe fn netlink_qdisc_add_clsact(if_index: i32) -> Result<(), io::E pub(crate) unsafe fn netlink_qdisc_attach( if_index: i32, attach_type: &TcAttachType, - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, prog_name: &CStr, priority: u16, handle: u32,