Browse Source

Merge pull request #744 from aya-rs/programfd-borrowed

programs: `ProgramFd` is owned
Tamir Duberstein 1 year ago
parent
commit
e813a054ad

+ 7 - 6
aya/src/maps/array/program_array.rs

@@ -2,7 +2,7 @@
 
 use std::{
     borrow::{Borrow, BorrowMut},
-    os::fd::{AsRawFd, RawFd},
+    os::fd::{AsFd as _, AsRawFd as _, RawFd},
 };
 
 use crate::{
@@ -37,13 +37,13 @@ use crate::{
 /// let flags = 0;
 ///
 /// // bpf_tail_call(ctx, JUMP_TABLE, 0) will jump to prog_0
-/// prog_array.set(0, prog_0_fd, flags);
+/// prog_array.set(0, &prog_0_fd, flags);
 ///
 /// // bpf_tail_call(ctx, JUMP_TABLE, 1) will jump to prog_1
-/// prog_array.set(1, prog_1_fd, flags);
+/// prog_array.set(1, &prog_1_fd, flags);
 ///
 /// // bpf_tail_call(ctx, JUMP_TABLE, 2) will jump to prog_2
-/// prog_array.set(2, prog_2_fd, flags);
+/// prog_array.set(2, &prog_2_fd, flags);
 /// # Ok::<(), aya::BpfError>(())
 /// ```
 #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")]
@@ -73,11 +73,12 @@ impl<T: BorrowMut<MapData>> ProgramArray<T> {
     ///
     /// When an eBPF program calls `bpf_tail_call(ctx, prog_array, index)`, control
     /// flow will jump to `program`.
-    pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> {
+    pub fn set(&mut self, index: u32, program: &ProgramFd, flags: u64) -> Result<(), MapError> {
         let data = self.inner.borrow_mut();
         check_bounds(data, index)?;
         let fd = data.fd_or_err()?;
-        let prog_fd = program.as_raw_fd();
+        let prog_fd = program.as_fd();
+        let prog_fd = prog_fd.as_raw_fd();
 
         bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| {
             SyscallError {

+ 1 - 1
aya/src/maps/perf/async_perf_event_array.rs

@@ -1,7 +1,7 @@
 use bytes::BytesMut;
 use std::{
     borrow::{Borrow, BorrowMut},
-    os::fd::{AsRawFd, RawFd},
+    os::fd::{AsRawFd as _, RawFd},
 };
 
 // See https://doc.rust-lang.org/cargo/reference/features.html#mutually-exclusive-features.

+ 4 - 2
aya/src/programs/cgroup_device.rs

@@ -1,7 +1,7 @@
 //! Cgroup device programs.
 
 use crate::util::KernelVersion;
-use std::os::fd::AsRawFd;
+use std::os::fd::{AsFd as _, AsRawFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE},
@@ -61,7 +61,9 @@ impl CgroupDevice {
     ///
     /// The returned value can be used to detach, see [CgroupDevice::detach]
     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupDeviceLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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) {

+ 8 - 2
aya/src/programs/cgroup_skb.rs

@@ -1,7 +1,11 @@
 //! Cgroup skb programs.
 
 use crate::util::KernelVersion;
-use std::{hash::Hash, os::fd::AsRawFd, path::Path};
+use std::{
+    hash::Hash,
+    os::fd::{AsFd as _, AsRawFd},
+    path::Path,
+};
 
 use crate::{
     generated::{
@@ -88,7 +92,9 @@ impl CgroupSkb {
         cgroup: T,
         attach_type: CgroupSkbAttachType,
     ) -> Result<CgroupSkbLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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 {

+ 8 - 2
aya/src/programs/cgroup_sock.rs

@@ -3,7 +3,11 @@
 pub use aya_obj::programs::CgroupSockAttachType;
 
 use crate::util::KernelVersion;
-use std::{hash::Hash, os::fd::AsRawFd, path::Path};
+use std::{
+    hash::Hash,
+    os::fd::{AsFd as _, AsRawFd},
+    path::Path,
+};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK,
@@ -67,7 +71,9 @@ impl CgroupSock {
     ///
     /// The returned value can be used to detach, see [CgroupSock::detach].
     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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) {

+ 8 - 2
aya/src/programs/cgroup_sock_addr.rs

@@ -3,7 +3,11 @@
 pub use aya_obj::programs::CgroupSockAddrAttachType;
 
 use crate::util::KernelVersion;
-use std::{hash::Hash, os::fd::AsRawFd, path::Path};
+use std::{
+    hash::Hash,
+    os::fd::{AsFd as _, AsRawFd},
+    path::Path,
+};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
@@ -68,7 +72,9 @@ impl CgroupSockAddr {
     ///
     /// The returned value can be used to detach, see [CgroupSockAddr::detach].
     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockAddrLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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) {

+ 8 - 2
aya/src/programs/cgroup_sockopt.rs

@@ -3,7 +3,11 @@
 pub use aya_obj::programs::CgroupSockoptAttachType;
 
 use crate::util::KernelVersion;
-use std::{hash::Hash, os::fd::AsRawFd, path::Path};
+use std::{
+    hash::Hash,
+    os::fd::{AsFd as _, AsRawFd},
+    path::Path,
+};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT,
@@ -65,7 +69,9 @@ impl CgroupSockopt {
     ///
     /// The returned value can be used to detach, see [CgroupSockopt::detach].
     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockoptLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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) {

+ 7 - 2
aya/src/programs/cgroup_sysctl.rs

@@ -1,7 +1,10 @@
 //! Cgroup sysctl programs.
 
 use crate::util::KernelVersion;
-use std::{hash::Hash, os::fd::AsRawFd};
+use std::{
+    hash::Hash,
+    os::fd::{AsFd as _, AsRawFd},
+};
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL},
@@ -60,7 +63,9 @@ impl CgroupSysctl {
     ///
     /// The returned value can be used to detach, see [CgroupSysctl::detach].
     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSysctlLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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) {

+ 26 - 15
aya/src/programs/extension.rs

@@ -1,5 +1,5 @@
 //! Extension programs.
-use std::os::fd::{AsFd as _, AsRawFd as _, OwnedFd};
+use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd};
 use thiserror::Error;
 
 use object::Endianness;
@@ -42,8 +42,9 @@ pub enum ExtensionError {
 /// prog.attach("eth0", XdpFlags::default())?;
 ///
 /// let prog_fd = prog.fd().unwrap();
+/// let prog_fd = prog_fd.try_clone().unwrap();
 /// let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?;
-/// ext.load(prog_fd, "function_to_replace")?;
+/// ext.load(&prog_fd, "function_to_replace")?;
 /// ext.attach()?;
 /// Ok::<(), aya::BpfError>(())
 /// ```
@@ -68,12 +69,12 @@ 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> {
-        let target_prog_fd = program.as_raw_fd();
+    pub fn load(&mut self, program: &ProgramFd, func_name: &str) -> Result<(), ProgramError> {
+        let target_prog_fd = program.as_fd();
         let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?;
 
         self.data.attach_btf_obj_fd = Some(btf_fd);
-        self.data.attach_prog_fd = Some(target_prog_fd);
+        self.data.attach_prog_fd = Some(target_prog_fd.as_raw_fd());
         self.data.attach_btf_id = Some(btf_id);
         load_program(BPF_PROG_TYPE_EXT, &mut self.data)
     }
@@ -86,7 +87,9 @@ impl Extension {
     /// The returned value can be used to detach the extension and restore the
     /// original function, see [Extension::detach].
     pub fn attach(&mut self) -> Result<ExtensionLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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
@@ -113,18 +116,26 @@ impl Extension {
     /// original function, see [Extension::detach].
     pub fn attach_to_program(
         &mut self,
-        program: ProgramFd,
+        program: &ProgramFd,
         func_name: &str,
     ) -> Result<ExtensionLinkId, ProgramError> {
-        let target_fd = program.as_raw_fd();
+        let target_fd = program.as_fd();
         let (_, btf_id) = get_btf_info(target_fd, func_name)?;
-        let prog_fd = self.data.fd_or_err()?;
+        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, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0)
-            .map_err(|(_, io_error)| SyscallError {
-                call: "bpf_link_create",
-                io_error,
-            })?;
+        let link_fd = bpf_link_create(
+            prog_fd,
+            target_fd.as_raw_fd(),
+            BPF_CGROUP_INET_INGRESS,
+            Some(btf_id),
+            0,
+        )
+        .map_err(|(_, io_error)| SyscallError {
+            call: "bpf_link_create",
+            io_error,
+        })?;
         self.data
             .links
             .insert(ExtensionLink::new(FdLink::new(link_fd)))
@@ -149,7 +160,7 @@ impl Extension {
 
 /// Retrieves the FD of the BTF object for the provided `prog_fd` and the BTF ID of the function
 /// with the name `func_name` within that BTF object.
-fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(OwnedFd, u32), ProgramError> {
+fn get_btf_info(prog_fd: BorrowedFd<'_>, func_name: &str) -> Result<(OwnedFd, u32), ProgramError> {
     // retrieve program information
     let info = sys::bpf_prog_get_info_by_fd(prog_fd, &mut [])?;
 

+ 7 - 3
aya/src/programs/lirc_mode2.rs

@@ -1,5 +1,5 @@
 //! Lirc programs.
-use std::os::fd::{AsRawFd, IntoRawFd as _, RawFd};
+use std::os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, RawFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
@@ -61,7 +61,9 @@ impl LircMode2 {
     ///
     /// The returned value can be used to detach, see [LircMode2::detach].
     pub fn attach<T: AsRawFd>(&mut self, lircdev: T) -> Result<LircLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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)| {
@@ -128,7 +130,9 @@ impl LircLink {
 
     /// Get ProgramInfo from this link
     pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
-        ProgramInfo::new_from_fd(self.prog_fd)
+        // SAFETY: TODO(https://github.com/aya-rs/aya/issues/612): make this safe by not holding `RawFd`s.
+        let prog_fd = unsafe { BorrowedFd::borrow_raw(self.prog_fd) };
+        ProgramInfo::new_from_fd(prog_fd)
     }
 }
 

+ 43 - 35
aya/src/programs/mod.rs

@@ -69,7 +69,7 @@ use std::{
     ffi::CString,
     io,
     num::NonZeroU32,
-    os::fd::{AsFd, AsRawFd, IntoRawFd as _, OwnedFd, RawFd},
+    os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd},
     path::{Path, PathBuf},
     sync::Arc,
     time::{Duration, SystemTime},
@@ -214,12 +214,23 @@ pub enum ProgramError {
 }
 
 /// A [`Program`] file descriptor.
-#[derive(Copy, Clone)]
-pub struct ProgramFd(RawFd);
+#[derive(Debug)]
+pub struct ProgramFd(OwnedFd);
+
+impl ProgramFd {
+    /// Creates a new `ProgramFd` instance that shares the same underlying file
+    /// description as the existing `ProgramFd` instance.
+    pub fn try_clone(&self) -> Result<Self, ProgramError> {
+        let Self(inner) = self;
+        let inner = inner.try_clone()?;
+        Ok(Self(inner))
+    }
+}
 
-impl AsRawFd for ProgramFd {
-    fn as_raw_fd(&self) -> RawFd {
-        self.0
+impl AsFd for ProgramFd {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        let Self(fd) = self;
+        fd.as_fd()
     }
 }
 
@@ -372,7 +383,7 @@ impl Program {
     ///
     /// Can be used to add a program to a [`crate::maps::ProgramArray`] or attach an [`Extension`] program.
     /// Can be converted to [`RawFd`] using [`AsRawFd`].
-    pub fn fd(&self) -> Option<ProgramFd> {
+    pub fn fd(&self) -> Result<&ProgramFd, ProgramError> {
         match self {
             Program::KProbe(p) => p.fd(),
             Program::UProbe(p) => p.fd(),
@@ -406,7 +417,7 @@ impl Program {
 pub(crate) struct ProgramData<T: Link> {
     pub(crate) name: Option<String>,
     pub(crate) obj: Option<(obj::Program, obj::Function)>,
-    pub(crate) fd: Option<RawFd>,
+    pub(crate) fd: Option<ProgramFd>,
     pub(crate) links: LinkMap<T>,
     pub(crate) expected_attach_type: Option<bpf_attach_type>,
     pub(crate) attach_btf_obj_fd: Option<OwnedFd>,
@@ -460,7 +471,7 @@ impl<T: Link> ProgramData<T> {
         Ok(ProgramData {
             name,
             obj: None,
-            fd: Some(fd.into_raw_fd()),
+            fd: Some(ProgramFd(fd)),
             links: LinkMap::new(),
             expected_attach_type: None,
             attach_btf_obj_fd,
@@ -485,15 +496,15 @@ impl<T: Link> ProgramData<T> {
             io_error,
         })?;
 
-        let info = ProgramInfo::new_from_fd(fd.as_raw_fd())?;
+        let info = ProgramInfo::new_from_fd(fd.as_fd())?;
         let name = info.name_as_str().map(|s| s.to_string());
         ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level)
     }
 }
 
 impl<T: Link> ProgramData<T> {
-    fn fd_or_err(&self) -> Result<RawFd, ProgramError> {
-        self.fd.ok_or(ProgramError::NotLoaded)
+    fn fd(&self) -> Result<&ProgramFd, ProgramError> {
+        self.fd.as_ref().ok_or(ProgramError::NotLoaded)
     }
 
     pub(crate) fn take_link(&mut self, link_id: T::Id) -> Result<T, ProgramError> {
@@ -503,15 +514,14 @@ impl<T: Link> ProgramData<T> {
 
 fn unload_program<T: Link>(data: &mut ProgramData<T>) -> Result<(), ProgramError> {
     data.links.remove_all()?;
-    let fd = data.fd.take().ok_or(ProgramError::NotLoaded)?;
-    unsafe {
-        libc::close(fd);
-    }
-    Ok(())
+    data.fd
+        .take()
+        .ok_or(ProgramError::NotLoaded)
+        .map(|ProgramFd { .. }| ())
 }
 
 fn pin_program<T: Link, P: AsRef<Path>>(data: &ProgramData<T>, path: P) -> Result<(), PinError> {
-    let fd = data.fd.ok_or(PinError::NoFd {
+    let fd = data.fd.as_ref().ok_or(PinError::NoFd {
         name: data
             .name
             .as_deref()
@@ -523,7 +533,7 @@ fn pin_program<T: Link, P: AsRef<Path>>(data: &ProgramData<T>, path: P) -> Resul
             error: e.to_string(),
         }
     })?;
-    bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError {
+    bpf_pin_object(fd.as_fd().as_raw_fd(), &path_string).map_err(|(_, io_error)| SyscallError {
         call: "BPF_OBJ_PIN",
         io_error,
     })?;
@@ -617,7 +627,7 @@ fn load_program<T: Link>(
 
     match ret {
         Ok(prog_fd) => {
-            *fd = Some(prog_fd as RawFd);
+            *fd = Some(ProgramFd(prog_fd));
             Ok(())
         }
         Err((_, io_error)) => Err(ProgramError::LoadError {
@@ -722,8 +732,8 @@ macro_rules! impl_fd {
         $(
             impl $struct_name {
                 /// Returns the file descriptor of this Program.
-                pub fn fd(&self) -> Option<ProgramFd> {
-                    self.data.fd.map(|fd| ProgramFd(fd))
+                pub fn fd(&self) -> Result<&ProgramFd, ProgramError> {
+                    self.data.fd()
                 }
             }
         )+
@@ -916,9 +926,9 @@ macro_rules! impl_program_info {
             impl $struct_name {
                 /// Returns the file descriptor of this Program.
                 pub fn program_info(&self) -> Result<ProgramInfo, ProgramError> {
-                    let fd = self.data.fd_or_err()?;
+                    let ProgramFd(fd) = self.fd()?;
 
-                    ProgramInfo::new_from_fd(fd.as_raw_fd())
+                    ProgramInfo::new_from_fd(fd.as_fd())
                 }
             }
         )+
@@ -957,11 +967,9 @@ impl_program_info!(
 pub struct ProgramInfo(bpf_prog_info);
 
 impl ProgramInfo {
-    fn new_from_fd(fd: RawFd) -> Result<Self, ProgramError> {
-        Ok(ProgramInfo(bpf_prog_get_info_by_fd(
-            fd.as_raw_fd(),
-            &mut [],
-        )?))
+    fn new_from_fd(fd: BorrowedFd<'_>) -> Result<Self, ProgramError> {
+        let info = bpf_prog_get_info_by_fd(fd, &mut [])?;
+        Ok(Self(info))
     }
 
     /// The name of the program as was provided when it was load. This is limited to 16 bytes
@@ -1011,10 +1019,10 @@ impl ProgramInfo {
 
     /// The ids of the maps used by the program.
     pub fn map_ids(&self) -> Result<Vec<u32>, ProgramError> {
-        let fd = self.fd()?;
+        let ProgramFd(fd) = self.fd()?;
         let mut map_ids = vec![0u32; self.0.nr_map_ids as usize];
 
-        bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut map_ids)?;
+        bpf_prog_get_info_by_fd(fd.as_fd(), &mut map_ids)?;
 
         Ok(map_ids)
     }
@@ -1058,10 +1066,10 @@ impl ProgramInfo {
     ///
     /// The returned file descriptor can be closed at any time and doing so does
     /// not influence the life cycle of the program.
-    pub fn fd(&self) -> Result<OwnedFd, ProgramError> {
+    pub fn fd(&self) -> Result<ProgramFd, ProgramError> {
         let Self(info) = self;
         let fd = bpf_prog_get_fd_by_id(info.id)?;
-        Ok(fd)
+        Ok(ProgramFd(fd))
     }
 
     /// Loads a program from a pinned path in bpffs.
@@ -1072,7 +1080,7 @@ impl ProgramInfo {
             io_error,
         })?;
 
-        let info = bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut [])?;
+        let info = bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])?;
         Ok(ProgramInfo(info))
     }
 }
@@ -1108,7 +1116,7 @@ pub fn loaded_programs() -> impl Iterator<Item = Result<ProgramInfo, ProgramErro
         })
         .map(|fd| {
             let fd = fd?;
-            bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut [])
+            bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])
         })
         .map(|result| result.map(ProgramInfo).map_err(Into::into))
 }

+ 5 - 2
aya/src/programs/perf_event.rs

@@ -1,6 +1,6 @@
 //! Perf event programs.
 
-use std::os::fd::AsFd as _;
+use std::os::fd::{AsFd as _, AsRawFd 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,
@@ -146,6 +146,9 @@ impl PerfEvent {
         scope: PerfEventScope,
         sample_policy: SamplePolicy,
     ) -> Result<PerfEventLinkId, ProgramError> {
+        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)),
@@ -172,7 +175,7 @@ impl PerfEvent {
             io_error,
         })?;
 
-        let link = perf_attach(self.data.fd_or_err()?, fd)?;
+        let link = perf_attach(prog_fd, fd)?;
         self.data.links.insert(PerfEventLink::new(link))
     }
 

+ 11 - 13
aya/src/programs/probe.rs

@@ -3,7 +3,7 @@ use libc::pid_t;
 use std::{
     fs::{self, OpenOptions},
     io::{self, Write},
-    os::fd::OwnedFd,
+    os::fd::{AsFd as _, AsRawFd as _, OwnedFd},
     path::Path,
     process,
     sync::atomic::{AtomicUsize, Ordering},
@@ -57,19 +57,17 @@ pub(crate) fn attach<T: Link + From<PerfLinkInner>>(
 ) -> Result<T::Id, ProgramError> {
     // https://github.com/torvalds/linux/commit/e12f03d7031a977356e3d7b75a68c2185ff8d155
     // Use debugfs to create probe
-    if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) {
+    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)?;
-        let link = T::from(perf_attach_debugfs(
-            program_data.fd_or_err()?,
-            fd,
-            ProbeEvent { kind, event_alias },
-        )?);
-        return program_data.links.insert(link);
-    };
-
-    let fd = create_as_probe(kind, fn_name, offset, pid)?;
-    let link = T::from(perf_attach(program_data.fd_or_err()?, fd)?);
-    program_data.links.insert(link)
+        perf_attach_debugfs(prog_fd, fd, ProbeEvent { kind, event_alias })
+    } else {
+        let fd = create_as_probe(kind, fn_name, offset, pid)?;
+        perf_attach(prog_fd, fd)
+    }?;
+    program_data.links.insert(T::from(link))
 }
 
 pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> {

+ 4 - 2
aya/src/programs/sk_lookup.rs

@@ -1,4 +1,4 @@
-use std::os::fd::AsRawFd;
+use std::os::fd::{AsFd as _, AsRawFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP},
@@ -61,7 +61,9 @@ impl SkLookup {
     ///
     /// The returned value can be used to detach, see [SkLookup::detach].
     pub fn attach<T: AsRawFd>(&mut self, netns: T) -> Result<SkLookupLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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(

+ 4 - 2
aya/src/programs/sk_msg.rs

@@ -1,6 +1,6 @@
 //! Skmsg programs.
 
-use std::os::fd::AsRawFd;
+use std::os::fd::{AsFd as _, AsRawFd as _};
 
 use crate::{
     generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
@@ -79,7 +79,9 @@ impl SkMsg {
     ///
     /// The returned value can be used to detach, see [SkMsg::detach].
     pub fn attach(&mut self, map: SockMapFd) -> Result<SkMsgLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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)| {

+ 7 - 2
aya/src/programs/sk_skb.rs

@@ -1,6 +1,9 @@
 //! Skskb programs.
 
-use std::{os::fd::AsRawFd, path::Path};
+use std::{
+    os::fd::{AsFd as _, AsRawFd as _},
+    path::Path,
+};
 
 use crate::{
     generated::{
@@ -72,7 +75,9 @@ impl SkSkb {
     ///
     /// The returned value can be used to detach, see [SkSkb::detach].
     pub fn attach(&mut self, map: SockMapFd) -> Result<SkSkbLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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 {

+ 4 - 2
aya/src/programs/sock_ops.rs

@@ -1,5 +1,5 @@
 //! Socket option programs.
-use std::os::fd::AsRawFd;
+use std::os::fd::{AsFd as _, AsRawFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS},
@@ -59,7 +59,9 @@ impl SockOps {
     ///
     /// The returned value can be used to detach, see [SockOps::detach].
     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<SockOpsLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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)| {

+ 4 - 2
aya/src/programs/socket_filter.rs

@@ -2,7 +2,7 @@
 use libc::{setsockopt, SOL_SOCKET};
 use std::{
     io, mem,
-    os::fd::{AsRawFd, RawFd},
+    os::fd::{AsFd as _, AsRawFd, RawFd},
 };
 use thiserror::Error;
 
@@ -73,7 +73,9 @@ impl SocketFilter {
     ///
     /// The returned value can be used to detach from the socket, see [SocketFilter::detach].
     pub fn attach<T: AsRawFd>(&mut self, socket: T) -> Result<SocketFilterLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        let prog_fd = self.fd()?;
+        let prog_fd = prog_fd.as_fd();
+        let prog_fd = prog_fd.as_raw_fd();
         let socket = socket.as_raw_fd();
 
         let ret = unsafe {

+ 4 - 1
aya/src/programs/tc.rs

@@ -4,6 +4,7 @@ use thiserror::Error;
 use std::{
     ffi::{CStr, CString},
     io,
+    os::fd::{AsFd as _, AsRawFd as _},
     path::Path,
 };
 
@@ -152,7 +153,9 @@ impl SchedClassifier {
         attach_type: TcAttachType,
         options: TcOptions,
     ) -> Result<SchedClassifierLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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 {

+ 9 - 2
aya/src/programs/trace_point.rs

@@ -1,5 +1,9 @@
 //! Tracepoint programs.
-use std::{fs, io, os::fd::AsFd as _, path::Path};
+use std::{
+    fs, io,
+    os::fd::{AsFd as _, AsRawFd as _},
+    path::Path,
+};
 use thiserror::Error;
 
 use crate::{
@@ -78,6 +82,9 @@ impl TracePoint {
     ///
     /// The returned value can be used to detach, see [TracePoint::detach].
     pub fn attach(&mut self, category: &str, name: &str) -> Result<TracePointLinkId, ProgramError> {
+        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 =
@@ -86,7 +93,7 @@ impl TracePoint {
                 io_error,
             })?;
 
-        let link = perf_attach(self.data.fd_or_err()?, fd)?;
+        let link = perf_attach(prog_fd, fd)?;
         self.data.links.insert(TracePointLink::new(link))
     }
 

+ 4 - 3
aya/src/programs/utils.rs

@@ -3,7 +3,7 @@ use std::{
     ffi::CStr,
     fs::File,
     io::{self, BufRead, BufReader},
-    os::fd::{AsRawFd as _, BorrowedFd},
+    os::fd::{AsFd as _, AsRawFd as _, BorrowedFd},
     path::Path,
     time::{Duration, SystemTime, UNIX_EPOCH},
 };
@@ -18,8 +18,9 @@ pub(crate) fn attach_raw_tracepoint<T: Link + From<FdLink>>(
     program_data: &mut ProgramData<T>,
     tp_name: Option<&CStr>,
 ) -> Result<T::Id, ProgramError> {
-    let prog_fd = program_data.fd_or_err()?;
-
+    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",

+ 7 - 3
aya/src/programs/xdp.rs

@@ -8,7 +8,7 @@ use std::{
     ffi::CString,
     hash::Hash,
     io,
-    os::fd::{AsFd as _, RawFd},
+    os::fd::{AsFd as _, AsRawFd as _, RawFd},
 };
 use thiserror::Error;
 
@@ -128,7 +128,9 @@ impl Xdp {
         if_index: u32,
         flags: XdpFlags,
     ) -> Result<XdpLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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) {
@@ -174,7 +176,9 @@ impl Xdp {
     ///
     /// Ownership of the link will transfer to this program.
     pub fn attach_to_link(&mut self, link: XdpLink) -> Result<XdpLinkId, ProgramError> {
-        let prog_fd = self.data.fd_or_err()?;
+        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;

+ 5 - 5
aya/src/sys/bpf.rs

@@ -3,7 +3,7 @@ use std::{
     ffi::{CStr, CString},
     io, iter,
     mem::{self, MaybeUninit},
-    os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd},
+    os::fd::{AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd},
     slice,
 };
 
@@ -132,7 +132,7 @@ pub(crate) fn bpf_load_program(
     aya_attr: &BpfLoadProgramAttrs,
     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_3 };
@@ -190,7 +190,8 @@ pub(crate) fn bpf_load_program(
     if let Some(v) = aya_attr.attach_btf_id {
         u.attach_btf_id = v;
     }
-    sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr)
+    // SAFETY: BPF_PROG_LOAD returns a new file descriptor.
+    unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) }
 }
 
 fn lookup<K: Pod, V: Pod>(
@@ -506,10 +507,9 @@ fn bpf_obj_get_info_by_fd<T, F: FnOnce(&mut T)>(
 }
 
 pub(crate) fn bpf_prog_get_info_by_fd(
-    fd: RawFd,
+    fd: BorrowedFd<'_>,
     map_ids: &mut [u32],
 ) -> Result<bpf_prog_info, SyscallError> {
-    let fd = unsafe { BorrowedFd::borrow_raw(fd) };
     bpf_obj_get_info_by_fd(fd, |info: &mut bpf_prog_info| {
         info.nr_map_ids = map_ids.len() as _;
         info.map_ids = map_ids.as_mut_ptr() as _;

+ 56 - 59
xtask/public-api/aya.txt

@@ -91,7 +91,7 @@ impl<T: core::borrow::Borrow<aya::maps::MapData>> aya::maps::ProgramArray<T>
 pub fn aya::maps::ProgramArray<T>::indices(&self) -> aya::maps::MapKeys<'_, u32>
 impl<T: core::borrow::BorrowMut<aya::maps::MapData>> aya::maps::ProgramArray<T>
 pub fn aya::maps::ProgramArray<T>::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError>
-pub fn aya::maps::ProgramArray<T>::set(&mut self, index: u32, program: aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError>
+pub fn aya::maps::ProgramArray<T>::set(&mut self, index: u32, program: &aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError>
 impl core::convert::TryFrom<aya::maps::Map> for aya::maps::ProgramArray<aya::maps::MapData>
 pub type aya::maps::ProgramArray<aya::maps::MapData>::Error = aya::maps::MapError
 pub fn aya::maps::ProgramArray<aya::maps::MapData>::try_from(map: aya::maps::Map) -> core::result::Result<aya::maps::ProgramArray<aya::maps::MapData>, aya::maps::MapError>
@@ -1502,7 +1502,7 @@ impl<T: core::borrow::Borrow<aya::maps::MapData>> aya::maps::ProgramArray<T>
 pub fn aya::maps::ProgramArray<T>::indices(&self) -> aya::maps::MapKeys<'_, u32>
 impl<T: core::borrow::BorrowMut<aya::maps::MapData>> aya::maps::ProgramArray<T>
 pub fn aya::maps::ProgramArray<T>::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError>
-pub fn aya::maps::ProgramArray<T>::set(&mut self, index: u32, program: aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError>
+pub fn aya::maps::ProgramArray<T>::set(&mut self, index: u32, program: &aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError>
 impl core::convert::TryFrom<aya::maps::Map> for aya::maps::ProgramArray<aya::maps::MapData>
 pub type aya::maps::ProgramArray<aya::maps::MapData>::Error = aya::maps::MapError
 pub fn aya::maps::ProgramArray<aya::maps::MapData>::try_from(map: aya::maps::Map) -> core::result::Result<aya::maps::ProgramArray<aya::maps::MapData>, aya::maps::MapError>
@@ -1804,7 +1804,7 @@ pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: ay
 pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::take_link(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_device::CgroupDevice
-pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_device::CgroupDevice
 pub fn aya::programs::cgroup_device::CgroupDevice::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::cgroup_device::CgroupDevice
@@ -1949,7 +1949,7 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin<P: core::convert::AsRef<st
 pub fn aya::programs::cgroup_skb::CgroupSkb::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_skb::CgroupSkb
-pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_skb::CgroupSkb
 pub fn aya::programs::cgroup_skb::CgroupSkb::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -2059,7 +2059,7 @@ pub fn aya::programs::cgroup_sock::CgroupSock::from_pin<P: core::convert::AsRef<
 pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock::CgroupSock
-pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock::CgroupSock
 pub fn aya::programs::cgroup_sock::CgroupSock::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -2169,7 +2169,7 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin<P: core::conver
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
-pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -2279,7 +2279,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin<P: core::convert::
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sockopt::CgroupSockopt
-pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sockopt::CgroupSockopt
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -2387,7 +2387,7 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: ay
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sysctl::CgroupSysctl
-pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sysctl::CgroupSysctl
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::cgroup_sysctl::CgroupSysctl
@@ -2527,12 +2527,12 @@ pub fn aya::programs::extension::ExtensionError::from(t: T) -> T
 pub struct aya::programs::extension::Extension
 impl aya::programs::extension::Extension
 pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result<aya::programs::extension::ExtensionLinkId, aya::programs::ProgramError>
-pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<aya::programs::extension::ExtensionLinkId, aya::programs::ProgramError>
+pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<aya::programs::extension::ExtensionLinkId, aya::programs::ProgramError>
 pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError>
-pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError>
+pub fn aya::programs::extension::Extension::load(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<aya::programs::extension::ExtensionLink, aya::programs::ProgramError>
 impl aya::programs::extension::Extension
-pub fn aya::programs::extension::Extension::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::extension::Extension
 pub fn aya::programs::extension::Extension::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::extension::Extension
@@ -2646,7 +2646,7 @@ pub fn aya::programs::fentry::FEntry::detach(&mut self, link_id: aya::programs::
 pub fn aya::programs::fentry::FEntry::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::fentry::FEntry::take_link(&mut self, link_id: aya::programs::fentry::FEntryLinkId) -> core::result::Result<aya::programs::fentry::FEntryLink, aya::programs::ProgramError>
 impl aya::programs::fentry::FEntry
-pub fn aya::programs::fentry::FEntry::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::fentry::FEntry
 pub fn aya::programs::fentry::FEntry::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::fentry::FEntry
@@ -2760,7 +2760,7 @@ pub fn aya::programs::fexit::FExit::detach(&mut self, link_id: aya::programs::fe
 pub fn aya::programs::fexit::FExit::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::fexit::FExit::take_link(&mut self, link_id: aya::programs::fexit::FExitLinkId) -> core::result::Result<aya::programs::fexit::FExitLink, aya::programs::ProgramError>
 impl aya::programs::fexit::FExit
-pub fn aya::programs::fexit::FExit::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::fexit::FExit
 pub fn aya::programs::fexit::FExit::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::fexit::FExit
@@ -2913,7 +2913,7 @@ pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind
 pub fn aya::programs::kprobe::KProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result<aya::programs::kprobe::KProbeLink, aya::programs::ProgramError>
 impl aya::programs::kprobe::KProbe
-pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::kprobe::KProbe
 pub fn aya::programs::kprobe::KProbe::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -3413,7 +3413,7 @@ pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Re
 pub fn aya::programs::lirc_mode2::LircMode2::query<T: std::os::fd::raw::AsRawFd>(target_fd: T) -> core::result::Result<alloc::vec::Vec<aya::programs::lirc_mode2::LircLink>, aya::programs::ProgramError>
 pub fn aya::programs::lirc_mode2::LircMode2::take_link(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result<aya::programs::lirc_mode2::LircLink, aya::programs::ProgramError>
 impl aya::programs::lirc_mode2::LircMode2
-pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::lirc_mode2::LircMode2
 pub fn aya::programs::lirc_mode2::LircMode2::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::lirc_mode2::LircMode2
@@ -3462,7 +3462,7 @@ pub fn aya::programs::lsm::Lsm::detach(&mut self, link_id: aya::programs::lsm::L
 pub fn aya::programs::lsm::Lsm::load(&mut self, lsm_hook_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::lsm::Lsm::take_link(&mut self, link_id: aya::programs::lsm::LsmLinkId) -> core::result::Result<aya::programs::lsm::LsmLink, aya::programs::ProgramError>
 impl aya::programs::lsm::Lsm
-pub fn aya::programs::lsm::Lsm::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::lsm::Lsm
 pub fn aya::programs::lsm::Lsm::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::lsm::Lsm
@@ -3749,7 +3749,7 @@ pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::pro
 pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::perf_event::PerfEvent::take_link(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result<aya::programs::perf_event::PerfEventLink, aya::programs::ProgramError>
 impl aya::programs::perf_event::PerfEvent
-pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::perf_event::PerfEvent
 pub fn aya::programs::perf_event::PerfEvent::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::perf_event::PerfEvent
@@ -3945,7 +3945,7 @@ pub fn aya::programs::tc::SchedClassifier::from_pin<P: core::convert::AsRef<std:
 pub fn aya::programs::tc::SchedClassifier::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result<aya::programs::tc::SchedClassifierLink, aya::programs::ProgramError>
 impl aya::programs::tc::SchedClassifier
-pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::tc::SchedClassifier
 pub fn aya::programs::tc::SchedClassifier::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -4085,7 +4085,7 @@ pub fn aya::programs::tp_btf::BtfTracePoint::detach(&mut self, link_id: aya::pro
 pub fn aya::programs::tp_btf::BtfTracePoint::load(&mut self, tracepoint: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::tp_btf::BtfTracePoint::take_link(&mut self, link_id: aya::programs::tp_btf::BtfTracePointLinkId) -> core::result::Result<aya::programs::tp_btf::BtfTracePointLink, aya::programs::ProgramError>
 impl aya::programs::tp_btf::BtfTracePoint
-pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::tp_btf::BtfTracePoint
 pub fn aya::programs::tp_btf::BtfTracePoint::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::tp_btf::BtfTracePoint
@@ -4236,7 +4236,7 @@ pub fn aya::programs::trace_point::TracePoint::detach(&mut self, link_id: aya::p
 pub fn aya::programs::trace_point::TracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::trace_point::TracePoint::take_link(&mut self, link_id: aya::programs::trace_point::TracePointLinkId) -> core::result::Result<aya::programs::trace_point::TracePointLink, aya::programs::ProgramError>
 impl aya::programs::trace_point::TracePoint
-pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::trace_point::TracePoint
 pub fn aya::programs::trace_point::TracePoint::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::trace_point::TracePoint
@@ -4398,7 +4398,7 @@ pub fn aya::programs::uprobe::UProbe::kind(&self) -> aya::programs::ProbeKind
 pub fn aya::programs::uprobe::UProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::programs::uprobe::UProbeLinkId) -> core::result::Result<aya::programs::uprobe::UProbeLink, aya::programs::ProgramError>
 impl aya::programs::uprobe::UProbe
-pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::uprobe::UProbe
 pub fn aya::programs::uprobe::UProbe::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -4550,7 +4550,7 @@ pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::X
 pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result<aya::programs::xdp::XdpLink, aya::programs::ProgramError>
 impl aya::programs::xdp::Xdp
-pub fn aya::programs::xdp::Xdp::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::xdp::Xdp
 pub fn aya::programs::xdp::Xdp::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::xdp::Xdp
@@ -5009,7 +5009,7 @@ pub aya::programs::Program::TracePoint(aya::programs::trace_point::TracePoint)
 pub aya::programs::Program::UProbe(aya::programs::uprobe::UProbe)
 pub aya::programs::Program::Xdp(aya::programs::xdp::Xdp)
 impl aya::programs::Program
-pub fn aya::programs::Program::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::Program::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 pub fn aya::programs::Program::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::Program::prog_type(&self) -> aya_obj::generated::linux_bindings_x86_64::bpf_prog_type
 pub fn aya::programs::Program::unload(self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -5560,7 +5560,7 @@ pub fn aya::programs::tp_btf::BtfTracePoint::detach(&mut self, link_id: aya::pro
 pub fn aya::programs::tp_btf::BtfTracePoint::load(&mut self, tracepoint: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::tp_btf::BtfTracePoint::take_link(&mut self, link_id: aya::programs::tp_btf::BtfTracePointLinkId) -> core::result::Result<aya::programs::tp_btf::BtfTracePointLink, aya::programs::ProgramError>
 impl aya::programs::tp_btf::BtfTracePoint
-pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::tp_btf::BtfTracePoint
 pub fn aya::programs::tp_btf::BtfTracePoint::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::tp_btf::BtfTracePoint
@@ -5608,7 +5608,7 @@ pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: ay
 pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::take_link(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_device::CgroupDevice
-pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_device::CgroupDevice
 pub fn aya::programs::cgroup_device::CgroupDevice::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::cgroup_device::CgroupDevice
@@ -5658,7 +5658,7 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin<P: core::convert::AsRef<st
 pub fn aya::programs::cgroup_skb::CgroupSkb::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_skb::CgroupSkb
-pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_skb::CgroupSkb
 pub fn aya::programs::cgroup_skb::CgroupSkb::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -5705,7 +5705,7 @@ pub fn aya::programs::cgroup_sock::CgroupSock::from_pin<P: core::convert::AsRef<
 pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock::CgroupSock
-pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock::CgroupSock
 pub fn aya::programs::cgroup_sock::CgroupSock::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -5752,7 +5752,7 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin<P: core::conver
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
-pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -5799,7 +5799,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin<P: core::convert::
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sockopt::CgroupSockopt
-pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sockopt::CgroupSockopt
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -5845,7 +5845,7 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: ay
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLink, aya::programs::ProgramError>
 impl aya::programs::cgroup_sysctl::CgroupSysctl
-pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::cgroup_sysctl::CgroupSysctl
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::cgroup_sysctl::CgroupSysctl
@@ -5889,12 +5889,12 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from(t: T) -> T
 pub struct aya::programs::Extension
 impl aya::programs::extension::Extension
 pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result<aya::programs::extension::ExtensionLinkId, aya::programs::ProgramError>
-pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<aya::programs::extension::ExtensionLinkId, aya::programs::ProgramError>
+pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<aya::programs::extension::ExtensionLinkId, aya::programs::ProgramError>
 pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError>
-pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError>
+pub fn aya::programs::extension::Extension::load(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<aya::programs::extension::ExtensionLink, aya::programs::ProgramError>
 impl aya::programs::extension::Extension
-pub fn aya::programs::extension::Extension::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::extension::Extension
 pub fn aya::programs::extension::Extension::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::extension::Extension
@@ -5942,7 +5942,7 @@ pub fn aya::programs::fentry::FEntry::detach(&mut self, link_id: aya::programs::
 pub fn aya::programs::fentry::FEntry::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::fentry::FEntry::take_link(&mut self, link_id: aya::programs::fentry::FEntryLinkId) -> core::result::Result<aya::programs::fentry::FEntryLink, aya::programs::ProgramError>
 impl aya::programs::fentry::FEntry
-pub fn aya::programs::fentry::FEntry::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::fentry::FEntry
 pub fn aya::programs::fentry::FEntry::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::fentry::FEntry
@@ -5990,7 +5990,7 @@ pub fn aya::programs::fexit::FExit::detach(&mut self, link_id: aya::programs::fe
 pub fn aya::programs::fexit::FExit::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::fexit::FExit::take_link(&mut self, link_id: aya::programs::fexit::FExitLinkId) -> core::result::Result<aya::programs::fexit::FExitLink, aya::programs::ProgramError>
 impl aya::programs::fexit::FExit
-pub fn aya::programs::fexit::FExit::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::fexit::FExit
 pub fn aya::programs::fexit::FExit::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::fexit::FExit
@@ -6040,7 +6040,7 @@ pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind
 pub fn aya::programs::kprobe::KProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result<aya::programs::kprobe::KProbeLink, aya::programs::ProgramError>
 impl aya::programs::kprobe::KProbe
-pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::kprobe::KProbe
 pub fn aya::programs::kprobe::KProbe::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -6087,7 +6087,7 @@ pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Re
 pub fn aya::programs::lirc_mode2::LircMode2::query<T: std::os::fd::raw::AsRawFd>(target_fd: T) -> core::result::Result<alloc::vec::Vec<aya::programs::lirc_mode2::LircLink>, aya::programs::ProgramError>
 pub fn aya::programs::lirc_mode2::LircMode2::take_link(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result<aya::programs::lirc_mode2::LircLink, aya::programs::ProgramError>
 impl aya::programs::lirc_mode2::LircMode2
-pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::lirc_mode2::LircMode2
 pub fn aya::programs::lirc_mode2::LircMode2::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::lirc_mode2::LircMode2
@@ -6135,7 +6135,7 @@ pub fn aya::programs::lsm::Lsm::detach(&mut self, link_id: aya::programs::lsm::L
 pub fn aya::programs::lsm::Lsm::load(&mut self, lsm_hook_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::lsm::Lsm::take_link(&mut self, link_id: aya::programs::lsm::LsmLinkId) -> core::result::Result<aya::programs::lsm::LsmLink, aya::programs::ProgramError>
 impl aya::programs::lsm::Lsm
-pub fn aya::programs::lsm::Lsm::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::lsm::Lsm
 pub fn aya::programs::lsm::Lsm::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::lsm::Lsm
@@ -6183,7 +6183,7 @@ pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::pro
 pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::perf_event::PerfEvent::take_link(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result<aya::programs::perf_event::PerfEventLink, aya::programs::ProgramError>
 impl aya::programs::perf_event::PerfEvent
-pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::perf_event::PerfEvent
 pub fn aya::programs::perf_event::PerfEvent::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::perf_event::PerfEvent
@@ -6225,11 +6225,12 @@ pub fn aya::programs::perf_event::PerfEvent::borrow_mut(&mut self) -> &mut T
 impl<T> core::convert::From<T> for aya::programs::perf_event::PerfEvent
 pub fn aya::programs::perf_event::PerfEvent::from(t: T) -> T
 pub struct aya::programs::ProgramFd(_)
-impl std::os::fd::raw::AsRawFd for aya::programs::ProgramFd
-pub fn aya::programs::ProgramFd::as_raw_fd(&self) -> std::os::fd::raw::RawFd
-impl core::clone::Clone for aya::programs::ProgramFd
-pub fn aya::programs::ProgramFd::clone(&self) -> aya::programs::ProgramFd
-impl core::marker::Copy for aya::programs::ProgramFd
+impl aya::programs::ProgramFd
+pub fn aya::programs::ProgramFd::try_clone(&self) -> core::result::Result<Self, aya::programs::ProgramError>
+impl std::os::fd::owned::AsFd for aya::programs::ProgramFd
+pub fn aya::programs::ProgramFd::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_>
+impl core::fmt::Debug for aya::programs::ProgramFd
+pub fn aya::programs::ProgramFd::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
 impl core::marker::Send for aya::programs::ProgramFd
 impl core::marker::Sync for aya::programs::ProgramFd
 impl core::marker::Unpin for aya::programs::ProgramFd
@@ -6243,10 +6244,6 @@ pub fn aya::programs::ProgramFd::try_from(value: U) -> core::result::Result<T, <
 impl<T, U> core::convert::TryInto<U> for aya::programs::ProgramFd where U: core::convert::TryFrom<T>
 pub type aya::programs::ProgramFd::Error = <U as core::convert::TryFrom<T>>::Error
 pub fn aya::programs::ProgramFd::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
-impl<T> alloc::borrow::ToOwned for aya::programs::ProgramFd where T: core::clone::Clone
-pub type aya::programs::ProgramFd::Owned = T
-pub fn aya::programs::ProgramFd::clone_into(&self, target: &mut T)
-pub fn aya::programs::ProgramFd::to_owned(&self) -> T
 impl<T> core::any::Any for aya::programs::ProgramFd where T: 'static + core::marker::Sized
 pub fn aya::programs::ProgramFd::type_id(&self) -> core::any::TypeId
 impl<T> core::borrow::Borrow<T> for aya::programs::ProgramFd where T: core::marker::Sized
@@ -6258,7 +6255,7 @@ pub fn aya::programs::ProgramFd::from(t: T) -> T
 pub struct aya::programs::ProgramInfo(_)
 impl aya::programs::ProgramInfo
 pub fn aya::programs::ProgramInfo::btf_id(&self) -> core::option::Option<core::num::nonzero::NonZeroU32>
-pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result<std::os::fd::owned::OwnedFd, aya::programs::ProgramError>
+pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result<aya::programs::ProgramFd, aya::programs::ProgramError>
 pub fn aya::programs::ProgramInfo::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<aya::programs::ProgramInfo, aya::programs::ProgramError>
 pub fn aya::programs::ProgramInfo::gpl_compatible(&self) -> bool
 pub fn aya::programs::ProgramInfo::id(&self) -> u32
@@ -6302,7 +6299,7 @@ pub fn aya::programs::RawTracePoint::detach(&mut self, link_id: RawTracePointLin
 pub fn aya::programs::RawTracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::RawTracePoint::take_link(&mut self, link_id: RawTracePointLinkId) -> core::result::Result<RawTracePointLink, aya::programs::ProgramError>
 impl aya::programs::RawTracePoint
-pub fn aya::programs::RawTracePoint::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::RawTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::RawTracePoint
 pub fn aya::programs::RawTracePoint::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::RawTracePoint
@@ -6352,7 +6349,7 @@ pub fn aya::programs::tc::SchedClassifier::from_pin<P: core::convert::AsRef<std:
 pub fn aya::programs::tc::SchedClassifier::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result<aya::programs::tc::SchedClassifierLink, aya::programs::ProgramError>
 impl aya::programs::tc::SchedClassifier
-pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::tc::SchedClassifier
 pub fn aya::programs::tc::SchedClassifier::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -6398,7 +6395,7 @@ pub fn aya::programs::SkLookup::detach(&mut self, link_id: SkLookupLinkId) -> co
 pub fn aya::programs::SkLookup::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::SkLookup::take_link(&mut self, link_id: SkLookupLinkId) -> core::result::Result<SkLookupLink, aya::programs::ProgramError>
 impl aya::programs::SkLookup
-pub fn aya::programs::SkLookup::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::SkLookup::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::SkLookup
 pub fn aya::programs::SkLookup::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::SkLookup
@@ -6446,7 +6443,7 @@ pub fn aya::programs::SkMsg::detach(&mut self, link_id: SkMsgLinkId) -> core::re
 pub fn aya::programs::SkMsg::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::SkMsg::take_link(&mut self, link_id: SkMsgLinkId) -> core::result::Result<SkMsgLink, aya::programs::ProgramError>
 impl aya::programs::SkMsg
-pub fn aya::programs::SkMsg::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::SkMsg::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::SkMsg
 pub fn aya::programs::SkMsg::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::SkMsg
@@ -6495,7 +6492,7 @@ pub fn aya::programs::SkSkb::from_pin<P: core::convert::AsRef<std::path::Path>>(
 pub fn aya::programs::SkSkb::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::SkSkb::take_link(&mut self, link_id: SkSkbLinkId) -> core::result::Result<SkSkbLink, aya::programs::ProgramError>
 impl aya::programs::SkSkb
-pub fn aya::programs::SkSkb::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::SkSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::SkSkb
 pub fn aya::programs::SkSkb::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::SkSkb::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -6541,7 +6538,7 @@ pub fn aya::programs::SockOps::detach(&mut self, link_id: SockOpsLinkId) -> core
 pub fn aya::programs::SockOps::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::SockOps::take_link(&mut self, link_id: SockOpsLinkId) -> core::result::Result<SockOpsLink, aya::programs::ProgramError>
 impl aya::programs::SockOps
-pub fn aya::programs::SockOps::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::SockOps::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::SockOps
 pub fn aya::programs::SockOps::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::SockOps
@@ -6589,7 +6586,7 @@ pub fn aya::programs::SocketFilter::detach(&mut self, link_id: SocketFilterLinkI
 pub fn aya::programs::SocketFilter::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::SocketFilter::take_link(&mut self, link_id: SocketFilterLinkId) -> core::result::Result<SocketFilterLink, aya::programs::ProgramError>
 impl aya::programs::SocketFilter
-pub fn aya::programs::SocketFilter::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::SocketFilter::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::SocketFilter
 pub fn aya::programs::SocketFilter::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::SocketFilter
@@ -6637,7 +6634,7 @@ pub fn aya::programs::trace_point::TracePoint::detach(&mut self, link_id: aya::p
 pub fn aya::programs::trace_point::TracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::trace_point::TracePoint::take_link(&mut self, link_id: aya::programs::trace_point::TracePointLinkId) -> core::result::Result<aya::programs::trace_point::TracePointLink, aya::programs::ProgramError>
 impl aya::programs::trace_point::TracePoint
-pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::trace_point::TracePoint
 pub fn aya::programs::trace_point::TracePoint::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::trace_point::TracePoint
@@ -6687,7 +6684,7 @@ pub fn aya::programs::uprobe::UProbe::kind(&self) -> aya::programs::ProbeKind
 pub fn aya::programs::uprobe::UProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::programs::uprobe::UProbeLinkId) -> core::result::Result<aya::programs::uprobe::UProbeLink, aya::programs::ProgramError>
 impl aya::programs::uprobe::UProbe
-pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::uprobe::UProbe
 pub fn aya::programs::uprobe::UProbe::pin<P: core::convert::AsRef<std::path::Path>>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError>
 pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error>
@@ -6735,7 +6732,7 @@ pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::X
 pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result<aya::programs::xdp::XdpLink, aya::programs::ProgramError>
 impl aya::programs::xdp::Xdp
-pub fn aya::programs::xdp::Xdp::fd(&self) -> core::option::Option<aya::programs::ProgramFd>
+pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
 impl aya::programs::xdp::Xdp
 pub fn aya::programs::xdp::Xdp::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P) -> core::result::Result<Self, aya::programs::ProgramError>
 impl aya::programs::xdp::Xdp