소스 검색

Merge pull request #723 from nrxus/map-program-owned-fd

File descriptor safety for program fd + prog attaching
Tamir Duberstein 1 년 전
부모
커밋
c4643b395f

+ 7 - 4
aya/src/maps/sock/mod.rs

@@ -5,14 +5,17 @@ mod sock_map;
 pub use sock_hash::SockHash;
 pub use sock_map::SockMap;
 
-use std::os::fd::{AsRawFd, RawFd};
+use std::os::fd::{AsFd, BorrowedFd, RawFd};
 
 /// A socket map file descriptor.
 #[derive(Copy, Clone)]
 pub struct SockMapFd(RawFd);
 
-impl AsRawFd for SockMapFd {
-    fn as_raw_fd(&self) -> RawFd {
-        self.0
+impl AsFd for SockMapFd {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        // SAFETY: This isn't necessarily safe, we need to find ways
+        // to enforce that the file descriptor is still
+        // valid. TODO(#612)
+        unsafe { BorrowedFd::borrow_raw(self.0) }
     }
 }

+ 19 - 19
aya/src/programs/cgroup_device.rs

@@ -1,14 +1,14 @@
 //! Cgroup device programs.
 
-use crate::util::KernelVersion;
-use std::os::fd::{AsFd as _, AsRawFd};
+use std::os::fd::AsFd;
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE},
     programs::{
         define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, bpf_prog_attach, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
+    util::KernelVersion,
 };
 
 /// A program used to watch or prevent device interaction from a cgroup.
@@ -60,35 +60,35 @@ impl CgroupDevice {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupDevice::detach]
-    pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupDeviceLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupDeviceLinkId, ProgramError> {
         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 cgroup_fd = cgroup.as_fd();
 
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, None, 0).map_err(
-                |(_, io_error)| SyscallError {
-                    call: "bpf_link_create",
-                    io_error,
-                },
-            )?;
+            let link_fd = bpf_link_create(
+                prog_fd,
+                LinkTarget::Fd(cgroup_fd),
+                BPF_CGROUP_DEVICE,
+                None,
+                0,
+            )
+            .map_err(|(_, io_error)| SyscallError {
+                call: "bpf_link_create",
+                io_error,
+            })?;
             self.data
                 .links
                 .insert(CgroupDeviceLink::new(CgroupDeviceLinkInner::Fd(
                     FdLink::new(link_fd),
                 )))
         } else {
-            bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE).map_err(|(_, io_error)| {
-                SyscallError {
-                    call: "bpf_prog_attach",
-                    io_error,
-                }
-            })?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE)?;
+
             self.data
                 .links
                 .insert(CgroupDeviceLink::new(CgroupDeviceLinkInner::ProgAttach(
-                    ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE),
+                    link,
                 )))
         }
     }

+ 10 - 23
aya/src/programs/cgroup_skb.rs

@@ -1,11 +1,6 @@
 //! Cgroup skb programs.
 
-use crate::util::KernelVersion;
-use std::{
-    hash::Hash,
-    os::fd::{AsFd as _, AsRawFd},
-    path::Path,
-};
+use std::{hash::Hash, os::fd::AsFd, path::Path};
 
 use crate::{
     generated::{
@@ -15,7 +10,8 @@ use crate::{
     programs::{
         define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, bpf_prog_attach, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
+    util::KernelVersion,
     VerifierLogLevel,
 };
 
@@ -87,45 +83,36 @@ impl CgroupSkb {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSkb::detach].
-    pub fn attach<T: AsRawFd>(
+    pub fn attach<T: AsFd>(
         &mut self,
         cgroup: T,
         attach_type: CgroupSkbAttachType,
     ) -> Result<CgroupSkbLinkId, ProgramError> {
         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 cgroup_fd = cgroup.as_fd();
 
         let attach_type = match attach_type {
             CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS,
             CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
         };
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
-                |(_, io_error)| SyscallError {
+            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
+                .map_err(|(_, io_error)| SyscallError {
                     call: "bpf_link_create",
                     io_error,
-                },
-            )?;
+                })?;
             self.data
                 .links
                 .insert(CgroupSkbLink::new(CgroupSkbLinkInner::Fd(FdLink::new(
                     link_fd,
                 ))))
         } else {
-            bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
-                SyscallError {
-                    call: "bpf_prog_attach",
-                    io_error,
-                }
-            })?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
 
             self.data
                 .links
-                .insert(CgroupSkbLink::new(CgroupSkbLinkInner::ProgAttach(
-                    ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
-                )))
+                .insert(CgroupSkbLink::new(CgroupSkbLinkInner::ProgAttach(link)))
         }
     }
 

+ 10 - 23
aya/src/programs/cgroup_sock.rs

@@ -2,19 +2,15 @@
 
 pub use aya_obj::programs::CgroupSockAttachType;
 
-use crate::util::KernelVersion;
-use std::{
-    hash::Hash,
-    os::fd::{AsFd as _, AsRawFd},
-    path::Path,
-};
+use std::{hash::Hash, os::fd::AsFd, path::Path};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK,
     programs::{
         define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, bpf_prog_attach, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
+    util::KernelVersion,
     VerifierLogLevel,
 };
 
@@ -70,37 +66,28 @@ impl CgroupSock {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSock::detach].
-    pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSockLinkId, ProgramError> {
         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 cgroup_fd = cgroup.as_fd();
         let attach_type = self.data.expected_attach_type.unwrap();
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
-                |(_, io_error)| SyscallError {
+            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
+                .map_err(|(_, io_error)| SyscallError {
                     call: "bpf_link_create",
                     io_error,
-                },
-            )?;
+                })?;
             self.data
                 .links
                 .insert(CgroupSockLink::new(CgroupSockLinkInner::Fd(FdLink::new(
                     link_fd,
                 ))))
         } else {
-            bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
-                SyscallError {
-                    call: "bpf_prog_attach",
-                    io_error,
-                }
-            })?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
 
             self.data
                 .links
-                .insert(CgroupSockLink::new(CgroupSockLinkInner::ProgAttach(
-                    ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
-                )))
+                .insert(CgroupSockLink::new(CgroupSockLinkInner::ProgAttach(link)))
         }
     }
 

+ 10 - 25
aya/src/programs/cgroup_sock_addr.rs

@@ -2,19 +2,15 @@
 
 pub use aya_obj::programs::CgroupSockAddrAttachType;
 
-use crate::util::KernelVersion;
-use std::{
-    hash::Hash,
-    os::fd::{AsFd as _, AsRawFd},
-    path::Path,
-};
+use std::{hash::Hash, os::fd::AsFd, path::Path};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
     programs::{
         define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, bpf_prog_attach, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
+    util::KernelVersion,
     VerifierLogLevel,
 };
 
@@ -71,38 +67,27 @@ impl CgroupSockAddr {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSockAddr::detach].
-    pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockAddrLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSockAddrLinkId, ProgramError> {
         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 cgroup_fd = cgroup.as_fd();
         let attach_type = self.data.expected_attach_type.unwrap();
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
-                |(_, io_error)| SyscallError {
+            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
+                .map_err(|(_, io_error)| SyscallError {
                     call: "bpf_link_create",
                     io_error,
-                },
-            )?;
+                })?;
             self.data
                 .links
                 .insert(CgroupSockAddrLink::new(CgroupSockAddrLinkInner::Fd(
                     FdLink::new(link_fd),
                 )))
         } else {
-            bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
-                SyscallError {
-                    call: "bpf_prog_attach",
-                    io_error,
-                }
-            })?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
 
             self.data.links.insert(CgroupSockAddrLink::new(
-                CgroupSockAddrLinkInner::ProgAttach(ProgAttachLink::new(
-                    prog_fd,
-                    cgroup_fd,
-                    attach_type,
-                )),
+                CgroupSockAddrLinkInner::ProgAttach(link),
             ))
         }
     }

+ 10 - 21
aya/src/programs/cgroup_sockopt.rs

@@ -2,19 +2,15 @@
 
 pub use aya_obj::programs::CgroupSockoptAttachType;
 
-use crate::util::KernelVersion;
-use std::{
-    hash::Hash,
-    os::fd::{AsFd as _, AsRawFd},
-    path::Path,
-};
+use std::{hash::Hash, os::fd::AsFd, path::Path};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT,
     programs::{
         define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, bpf_prog_attach, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
+    util::KernelVersion,
     VerifierLogLevel,
 };
 
@@ -68,36 +64,29 @@ impl CgroupSockopt {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSockopt::detach].
-    pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockoptLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSockoptLinkId, ProgramError> {
         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 cgroup_fd = cgroup.as_fd();
         let attach_type = self.data.expected_attach_type.unwrap();
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
-                |(_, io_error)| SyscallError {
+            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
+                .map_err(|(_, io_error)| SyscallError {
                     call: "bpf_link_create",
                     io_error,
-                },
-            )?;
+                })?;
             self.data
                 .links
                 .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::Fd(
                     FdLink::new(link_fd),
                 )))
         } else {
-            bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
-                SyscallError {
-                    call: "bpf_prog_attach",
-                    io_error,
-                }
-            })?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
 
             self.data
                 .links
                 .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::ProgAttach(
-                    ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
+                    link,
                 )))
         }
     }

+ 18 - 22
aya/src/programs/cgroup_sysctl.rs

@@ -1,17 +1,14 @@
 //! Cgroup sysctl programs.
 
-use crate::util::KernelVersion;
-use std::{
-    hash::Hash,
-    os::fd::{AsFd as _, AsRawFd},
-};
+use std::{hash::Hash, os::fd::AsFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL},
     programs::{
         define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
     },
-    sys::{bpf_link_create, bpf_prog_attach, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
+    util::KernelVersion,
 };
 
 /// A program used to watch for sysctl changes.
@@ -62,36 +59,35 @@ impl CgroupSysctl {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSysctl::detach].
-    pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSysctlLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSysctlLinkId, ProgramError> {
         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 cgroup_fd = cgroup.as_fd();
 
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, None, 0).map_err(
-                |(_, io_error)| SyscallError {
-                    call: "bpf_link_create",
-                    io_error,
-                },
-            )?;
+            let link_fd = bpf_link_create(
+                prog_fd,
+                LinkTarget::Fd(cgroup_fd),
+                BPF_CGROUP_SYSCTL,
+                None,
+                0,
+            )
+            .map_err(|(_, io_error)| SyscallError {
+                call: "bpf_link_create",
+                io_error,
+            })?;
             self.data
                 .links
                 .insert(CgroupSysctlLink::new(CgroupSysctlLinkInner::Fd(
                     FdLink::new(link_fd),
                 )))
         } else {
-            bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL).map_err(|(_, io_error)| {
-                SyscallError {
-                    call: "bpf_prog_attach",
-                    io_error,
-                }
-            })?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL)?;
 
             self.data
                 .links
                 .insert(CgroupSysctlLink::new(CgroupSysctlLinkInner::ProgAttach(
-                    ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL),
+                    link,
                 )))
         }
     }

+ 16 - 12
aya/src/programs/extension.rs

@@ -1,8 +1,9 @@
 //! Extension programs.
-use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd};
-use thiserror::Error;
+
+use std::os::fd::{AsFd as _, BorrowedFd, OwnedFd};
 
 use object::Endianness;
+use thiserror::Error;
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_INET_INGRESS, bpf_prog_type::BPF_PROG_TYPE_EXT},
@@ -10,7 +11,7 @@ use crate::{
     programs::{
         define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd,
     },
-    sys::{self, bpf_link_create, SyscallError},
+    sys::{self, bpf_link_create, LinkTarget, SyscallError},
     Btf,
 };
 
@@ -88,21 +89,25 @@ impl Extension {
     pub fn attach(&mut self) -> Result<ExtensionLinkId, ProgramError> {
         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
             .as_ref()
             .ok_or(ProgramError::NotLoaded)?;
         let target_fd = target_fd.as_fd();
-        let target_fd = target_fd.as_raw_fd();
         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
-        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,
+            LinkTarget::Fd(target_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)))
@@ -128,11 +133,10 @@ 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,
-            target_fd.as_raw_fd(),
+            LinkTarget::Fd(target_fd),
             BPF_CGROUP_INET_INGRESS,
             Some(btf_id),
             0,

+ 29 - 11
aya/src/programs/links.rs

@@ -1,12 +1,11 @@
 //! Program links.
-use libc::{close, dup};
 use thiserror::Error;
 
 use std::{
     collections::{hash_map::Entry, HashMap},
     ffi::CString,
     io,
-    os::fd::{AsRawFd as _, OwnedFd, RawFd},
+    os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd, RawFd},
     path::{Path, PathBuf},
 };
 
@@ -14,7 +13,9 @@ use crate::{
     generated::bpf_attach_type,
     pin::PinError,
     programs::ProgramError,
-    sys::{bpf_get_object, bpf_pin_object, bpf_prog_detach, SyscallError},
+    sys::{
+        bpf_get_object, bpf_pin_object, bpf_prog_attach, bpf_prog_detach, SysResult, SyscallError,
+    },
 };
 
 /// A Link.
@@ -234,17 +235,34 @@ pub struct ProgAttachLinkId(RawFd, RawFd, bpf_attach_type);
 #[derive(Debug)]
 pub struct ProgAttachLink {
     prog_fd: RawFd,
-    target_fd: RawFd,
+    target_fd: OwnedFd,
     attach_type: bpf_attach_type,
 }
 
 impl ProgAttachLink {
-    pub(crate) fn new(prog_fd: RawFd, target_fd: RawFd, attach_type: bpf_attach_type) -> Self {
-        Self {
+    pub(crate) fn attach(
+        prog_fd: BorrowedFd<'_>,
+        target_fd: BorrowedFd<'_>,
+        attach_type: bpf_attach_type,
+    ) -> Result<Self, ProgramError> {
+        // The link is going to own this new file descriptor so we are
+        // going to need a duplicate whose lifetime we manage. Let's
+        // duplicate it prior to attaching it so the new file
+        // descriptor is closed at drop in case it fails to attach.
+        let target_fd = target_fd.try_clone_to_owned()?;
+        bpf_prog_attach(prog_fd, target_fd.as_fd(), attach_type).map_err(|(_, io_error)| {
+            SyscallError {
+                call: "bpf_prog_attach",
+                io_error,
+            }
+        })?;
+
+        let prog_fd = prog_fd.as_raw_fd();
+        Ok(Self {
             prog_fd,
-            target_fd: unsafe { dup(target_fd) },
+            target_fd,
             attach_type,
-        }
+        })
     }
 }
 
@@ -252,12 +270,12 @@ impl Link for ProgAttachLink {
     type Id = ProgAttachLinkId;
 
     fn id(&self) -> Self::Id {
-        ProgAttachLinkId(self.prog_fd, self.target_fd, self.attach_type)
+        ProgAttachLinkId(self.prog_fd, self.target_fd.as_raw_fd(), self.attach_type)
     }
 
     fn detach(self) -> Result<(), ProgramError> {
-        let _ = bpf_prog_detach(self.prog_fd, self.target_fd, self.attach_type);
-        unsafe { close(self.target_fd) };
+        let _: SysResult<_> =
+            bpf_prog_detach(self.prog_fd, self.target_fd.as_fd(), self.attach_type);
         Ok(())
     }
 }

+ 33 - 29
aya/src/programs/lirc_mode2.rs

@@ -1,14 +1,12 @@
 //! Lirc programs.
-use std::os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, RawFd};
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, IntoRawFd as _, OwnedFd, RawFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
     programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo},
-    sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, SyscallError},
+    sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, SysResult, SyscallError},
 };
 
-use libc::{close, dup};
-
 /// A program used to decode IR into key events for a lirc device.
 ///
 /// [`LircMode2`] programs can be used to inspect infrared pulses, spaces,
@@ -60,13 +58,17 @@ impl LircMode2 {
     /// Attaches the program to the given lirc device.
     ///
     /// The returned value can be used to detach, see [LircMode2::detach].
-    pub fn attach<T: AsRawFd>(&mut self, lircdev: T) -> Result<LircLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, lircdev: T) -> Result<LircLinkId, ProgramError> {
         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)| {
+        // The link is going to own this new file descriptor so we are
+        // going to need a duplicate whose lifetime we manage. Let's
+        // duplicate it prior to attaching it so the new file
+        // descriptor is closed at drop in case it fails to attach.
+        let lircdev_fd = lircdev.as_fd().try_clone_to_owned()?;
+
+        bpf_prog_attach(prog_fd, lircdev_fd.as_fd(), BPF_LIRC_MODE2).map_err(|(_, io_error)| {
             SyscallError {
                 call: "bpf_prog_attach",
                 io_error,
@@ -92,20 +94,25 @@ impl LircMode2 {
     }
 
     /// Queries the lirc device for attached programs.
-    pub fn query<T: AsRawFd>(target_fd: T) -> Result<Vec<LircLink>, ProgramError> {
-        let prog_ids = query(target_fd.as_raw_fd(), BPF_LIRC_MODE2, 0, &mut None)?;
+    pub fn query<T: AsFd>(target_fd: T) -> Result<Vec<LircLink>, ProgramError> {
+        let target_fd = target_fd.as_fd();
+        let prog_ids = query(target_fd, BPF_LIRC_MODE2, 0, &mut None)?;
 
-        let mut prog_fds = Vec::with_capacity(prog_ids.len());
-
-        for id in prog_ids {
-            let fd = bpf_prog_get_fd_by_id(id)?;
-            prog_fds.push(fd);
-        }
-
-        Ok(prog_fds
+        prog_ids
             .into_iter()
-            .map(|prog_fd| LircLink::new(prog_fd.into_raw_fd(), target_fd.as_raw_fd()))
-            .collect())
+            .map(|prog_id| {
+                let prog_fd = bpf_prog_get_fd_by_id(prog_id)?;
+                let target_fd = target_fd.try_clone_to_owned()?;
+                // SAFETY: The file descriptor will stay valid because
+                // we are leaking it. We cannot use `OwnedFd` in here
+                // because LircMode2::attach also uses LircLink::new
+                // but with a borrowed file descriptor (of the loaded
+                // program) without duplicating. TODO(#612): Fix API
+                // or internals so this file descriptor isn't leaked
+                let prog_fd = unsafe { BorrowedFd::borrow_raw(prog_fd.into_raw_fd()) };
+                Ok(LircLink::new(prog_fd, target_fd))
+            })
+            .collect()
     }
 }
 
@@ -117,15 +124,13 @@ pub struct LircLinkId(RawFd, RawFd);
 /// An LircMode2 Link
 pub struct LircLink {
     prog_fd: RawFd,
-    target_fd: RawFd,
+    target_fd: OwnedFd,
 }
 
 impl LircLink {
-    pub(crate) fn new(prog_fd: RawFd, target_fd: RawFd) -> Self {
-        Self {
-            prog_fd,
-            target_fd: unsafe { dup(target_fd) },
-        }
+    pub(crate) fn new(prog_fd: BorrowedFd<'_>, target_fd: OwnedFd) -> Self {
+        let prog_fd = prog_fd.as_raw_fd();
+        Self { prog_fd, target_fd }
     }
 
     /// Get ProgramInfo from this link
@@ -140,12 +145,11 @@ impl Link for LircLink {
     type Id = LircLinkId;
 
     fn id(&self) -> Self::Id {
-        LircLinkId(self.prog_fd, self.target_fd)
+        LircLinkId(self.prog_fd, self.target_fd.as_raw_fd())
     }
 
     fn detach(self) -> Result<(), ProgramError> {
-        let _ = bpf_prog_detach(self.prog_fd, self.target_fd, BPF_LIRC_MODE2);
-        unsafe { close(self.target_fd) };
+        let _: SysResult<_> = bpf_prog_detach(self.prog_fd, self.target_fd.as_fd(), BPF_LIRC_MODE2);
         Ok(())
     }
 }

+ 3 - 3
aya/src/programs/mod.rs

@@ -640,8 +640,8 @@ fn load_program<T: Link>(
     }
 }
 
-pub(crate) fn query<T: AsRawFd>(
-    target_fd: T,
+pub(crate) fn query(
+    target_fd: BorrowedFd<'_>,
     attach_type: bpf_attach_type,
     query_flags: u32,
     attach_flags: &mut Option<u32>,
@@ -653,7 +653,7 @@ pub(crate) fn query<T: AsRawFd>(
 
     loop {
         match bpf_prog_query(
-            target_fd.as_raw_fd(),
+            target_fd.as_fd().as_raw_fd(),
             attach_type,
             query_flags,
             attach_flags.as_mut(),

+ 15 - 13
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,
@@ -7,7 +7,7 @@ use crate::{
         probe::{detach_debug_fs, ProbeEvent},
         FdLink, Link, ProgramError,
     },
-    sys::{bpf_link_create, perf_event_ioctl, SysResult, SyscallError},
+    sys::{bpf_link_create, perf_event_ioctl, LinkTarget, SysResult, SyscallError},
     FEATURES, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF,
 };
 
@@ -70,14 +70,16 @@ impl Link for PerfLink {
     }
 }
 
-pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result<PerfLinkInner, ProgramError> {
+pub(crate) fn perf_attach(
+    prog_fd: BorrowedFd<'_>,
+    fd: OwnedFd,
+) -> Result<PerfLinkInner, ProgramError> {
     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 {
+        let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(fd.as_fd()), BPF_PERF_EVENT, None, 0)
+            .map_err(|(_, io_error)| SyscallError {
                 call: "bpf_link_create",
                 io_error,
-            },
-        )?;
+            })?;
         Ok(PerfLinkInner::FdLink(FdLink::new(link_fd)))
     } else {
         perf_attach_either(prog_fd, fd, None)
@@ -85,7 +87,7 @@ pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result<PerfLinkInner,
 }
 
 pub(crate) fn perf_attach_debugfs(
-    prog_fd: RawFd,
+    prog_fd: BorrowedFd<'_>,
     fd: OwnedFd,
     event: ProbeEvent,
 ) -> Result<PerfLinkInner, ProgramError> {
@@ -93,16 +95,16 @@ pub(crate) fn perf_attach_debugfs(
 }
 
 fn perf_attach_either(
-    prog_fd: RawFd,
+    prog_fd: BorrowedFd<'_>,
     fd: OwnedFd,
     event: Option<ProbeEvent>,
 ) -> Result<PerfLinkInner, ProgramError> {
-    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",

+ 1 - 2
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<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)),

+ 1 - 2
aya/src/programs/probe.rs

@@ -5,7 +5,7 @@ use std::{
     fmt::Write as _,
     fs::{self, OpenOptions},
     io::{self, Write},
-    os::fd::{AsFd as _, AsRawFd as _, OwnedFd},
+    os::fd::{AsFd as _, OwnedFd},
     path::{Path, PathBuf},
     process,
     sync::atomic::{AtomicUsize, Ordering},
@@ -115,7 +115,6 @@ pub(crate) fn attach<T: Link + From<PerfLinkInner>>(
     // 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 })

+ 7 - 9
aya/src/programs/sk_lookup.rs

@@ -1,9 +1,9 @@
-use std::os::fd::{AsFd as _, AsRawFd};
+use std::os::fd::AsFd;
 
 use crate::{
     generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP},
     programs::{define_link_wrapper, load_program, FdLinkId, ProgramData, ProgramError},
-    sys::{bpf_link_create, SyscallError},
+    sys::{bpf_link_create, LinkTarget, SyscallError},
 };
 
 use super::links::FdLink;
@@ -60,18 +60,16 @@ impl SkLookup {
     /// Attaches the program to the given network namespace.
     ///
     /// The returned value can be used to detach, see [SkLookup::detach].
-    pub fn attach<T: AsRawFd>(&mut self, netns: T) -> Result<SkLookupLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, netns: T) -> Result<SkLookupLinkId, ProgramError> {
         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 netns_fd = netns.as_fd();
 
-        let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err(
-            |(_, io_error)| SyscallError {
+        let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(netns_fd), BPF_SK_LOOKUP, None, 0)
+            .map_err(|(_, io_error)| SyscallError {
                 call: "bpf_link_create",
                 io_error,
-            },
-        )?;
+            })?;
         self.data
             .links
             .insert(SkLookupLink::new(FdLink::new(link_fd)))

+ 3 - 15
aya/src/programs/sk_msg.rs

@@ -1,6 +1,6 @@
 //! Skmsg programs.
 
-use std::os::fd::{AsFd as _, AsRawFd as _};
+use std::os::fd::AsFd as _;
 
 use crate::{
     generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
@@ -9,7 +9,6 @@ use crate::{
         define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
         ProgramError,
     },
-    sys::{bpf_prog_attach, SyscallError},
 };
 
 /// A program used to intercept messages sent with `sendmsg()`/`sendfile()`.
@@ -81,20 +80,9 @@ impl SkMsg {
     pub fn attach(&mut self, map: SockMapFd) -> Result<SkMsgLinkId, ProgramError> {
         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 link = ProgAttachLink::attach(prog_fd, map.as_fd(), BPF_SK_MSG_VERDICT)?;
 
-        bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| {
-            SyscallError {
-                call: "bpf_prog_attach",
-                io_error,
-            }
-        })?;
-        self.data.links.insert(SkMsgLink::new(ProgAttachLink::new(
-            prog_fd,
-            map_fd,
-            BPF_SK_MSG_VERDICT,
-        )))
+        self.data.links.insert(SkMsgLink::new(link))
     }
 
     /// Detaches the program from a sockmap.

+ 5 - 16
aya/src/programs/sk_skb.rs

@@ -1,9 +1,6 @@
 //! Skskb programs.
 
-use std::{
-    os::fd::{AsFd as _, AsRawFd as _},
-    path::Path,
-};
+use std::{os::fd::AsFd as _, path::Path};
 
 use crate::{
     generated::{
@@ -15,7 +12,6 @@ use crate::{
         define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
         ProgramError,
     },
-    sys::{bpf_prog_attach, SyscallError},
     VerifierLogLevel,
 };
 
@@ -77,22 +73,15 @@ impl SkSkb {
     pub fn attach(&mut self, map: SockMapFd) -> Result<SkSkbLinkId, ProgramError> {
         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 {
             SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER,
             SkSkbKind::StreamVerdict => BPF_SK_SKB_STREAM_VERDICT,
         };
-        bpf_prog_attach(prog_fd, map_fd, attach_type).map_err(|(_, io_error)| SyscallError {
-            call: "bpf_prog_attach",
-            io_error,
-        })?;
-        self.data.links.insert(SkSkbLink::new(ProgAttachLink::new(
-            prog_fd,
-            map_fd,
-            attach_type,
-        )))
+
+        let link = ProgAttachLink::attach(prog_fd, map.as_fd(), attach_type)?;
+
+        self.data.links.insert(SkSkbLink::new(link))
     }
 
     /// Detaches the program.

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

@@ -1,5 +1,5 @@
 //! Socket option programs.
-use std::os::fd::{AsFd as _, AsRawFd};
+use std::os::fd::AsFd;
 
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS},
@@ -7,7 +7,6 @@ use crate::{
         define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
         ProgramError,
     },
-    sys::{bpf_prog_attach, SyscallError},
 };
 
 /// A program used to work with sockets.
@@ -58,23 +57,11 @@ impl SockOps {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [SockOps::detach].
-    pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<SockOpsLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<SockOpsLinkId, ProgramError> {
         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)| {
-            SyscallError {
-                call: "bpf_prog_attach",
-                io_error,
-            }
-        })?;
-        self.data.links.insert(SockOpsLink::new(ProgAttachLink::new(
-            prog_fd,
-            cgroup_fd,
-            BPF_CGROUP_SOCK_OPS,
-        )))
+        let link = ProgAttachLink::attach(prog_fd.as_fd(), cgroup.as_fd(), BPF_CGROUP_SOCK_OPS)?;
+        self.data.links.insert(SockOpsLink::new(link))
     }
 
     /// Detaches the program.

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

@@ -2,7 +2,7 @@
 use libc::{setsockopt, SOL_SOCKET};
 use std::{
     io, mem,
-    os::fd::{AsFd as _, AsRawFd, RawFd},
+    os::fd::{AsFd, AsRawFd, RawFd},
 };
 use thiserror::Error;
 
@@ -48,13 +48,12 @@ pub enum SocketFilterError {
 /// # }
 /// # let mut bpf = aya::Bpf::load(&[])?;
 /// use std::net::TcpStream;
-/// use std::os::fd::AsRawFd;
 /// use aya::programs::SocketFilter;
 ///
 /// let mut client = TcpStream::connect("127.0.0.1:1234")?;
 /// let prog: &mut SocketFilter = bpf.program_mut("filter_packets").unwrap().try_into()?;
 /// prog.load()?;
-/// prog.attach(client.as_raw_fd())?;
+/// prog.attach(&client)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -72,10 +71,11 @@ impl SocketFilter {
     /// Attaches the filter on the given socket.
     ///
     /// 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> {
+    pub fn attach<T: AsFd>(&mut self, socket: T) -> Result<SocketFilterLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
         let prog_fd = prog_fd.as_raw_fd();
+        let socket = socket.as_fd();
         let socket = socket.as_raw_fd();
 
         let ret = unsafe {

+ 1 - 2
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,
 };
 
@@ -154,7 +154,6 @@ impl SchedClassifier {
     ) -> Result<SchedClassifierLinkId, ProgramError> {
         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 name = self.data.name.as_deref().unwrap_or_default();

+ 1 - 6
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<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.as_ref())?;
         let fd =

+ 0 - 1
aya/src/programs/utils.rs

@@ -20,7 +20,6 @@ pub(crate) fn attach_raw_tracepoint<T: Link + From<FdLink>>(
 ) -> Result<T::Id, ProgramError> {
     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",

+ 17 - 9
aya/src/programs/xdp.rs

@@ -1,6 +1,9 @@
 //! eXpress Data Path (XDP) programs.
 
-use crate::{sys::SyscallError, util::KernelVersion};
+use crate::{
+    sys::{LinkTarget, SyscallError},
+    util::KernelVersion,
+};
 use bitflags;
 use libc::if_nametoindex;
 use std::{
@@ -128,13 +131,11 @@ impl Xdp {
     ) -> Result<XdpLinkId, ProgramError> {
         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) {
             let link_fd = bpf_link_create(
                 prog_fd,
-                if_index,
+                LinkTarget::IfIndex(if_index),
                 bpf_attach_type::BPF_XDP,
                 None,
                 flags.bits(),
@@ -147,9 +148,11 @@ 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()) }
+            let if_index = if_index as i32;
+            unsafe { netlink_set_xdp_fd(if_index, Some(prog_fd), None, flags.bits()) }
                 .map_err(|io_error| XdpError::NetlinkError { io_error })?;
 
+            let prog_fd = prog_fd.as_raw_fd();
             self.data
                 .links
                 .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink {
@@ -181,7 +184,6 @@ impl Xdp {
     pub fn attach_to_link(&mut self, link: XdpLink) -> Result<XdpLinkId, ProgramError> {
         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;
@@ -202,10 +204,16 @@ 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),
+                        Some(old_prog_fd),
+                        replace_flags.bits(),
+                    )
+                    .map_err(|io_error| XdpError::NetlinkError { io_error })?;
                 }
 
+                let prog_fd = prog_fd.as_raw_fd();
                 self.data
                     .links
                     .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink {
@@ -238,7 +246,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(())
     }
 }

+ 31 - 16
aya/src/sys/bpf.rs

@@ -365,18 +365,31 @@ pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult<c_long> {
     sys_bpf(bpf_cmd::BPF_MAP_FREEZE, &mut attr)
 }
 
+pub(crate) enum LinkTarget<'f> {
+    Fd(BorrowedFd<'f>),
+    IfIndex(u32),
+}
+
 // since kernel 5.7
 pub(crate) fn bpf_link_create(
-    prog_fd: RawFd,
-    target_fd: RawFd,
+    prog_fd: BorrowedFd<'_>,
+    target: LinkTarget<'_>,
     attach_type: bpf_attach_type,
     btf_id: Option<u32>,
     flags: u32,
 ) -> SysResult<OwnedFd> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
-    attr.link_create.__bindgen_anon_1.prog_fd = prog_fd as u32;
-    attr.link_create.__bindgen_anon_2.target_fd = target_fd as u32;
+    attr.link_create.__bindgen_anon_1.prog_fd = prog_fd.as_raw_fd() as u32;
+
+    match target {
+        LinkTarget::Fd(fd) => {
+            attr.link_create.__bindgen_anon_2.target_fd = fd.as_raw_fd() as u32;
+        }
+        LinkTarget::IfIndex(ifindex) => {
+            attr.link_create.__bindgen_anon_2.target_ifindex = ifindex;
+        }
+    };
     attr.link_create.attach_type = attach_type as u32;
     attr.link_create.flags = flags;
     if let Some(btf_id) = btf_id {
@@ -390,14 +403,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<RawFd>,
     flags: u32,
 ) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     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;
@@ -409,14 +422,14 @@ pub(crate) fn bpf_link_update(
 }
 
 pub(crate) fn bpf_prog_attach(
-    prog_fd: RawFd,
-    target_fd: RawFd,
+    prog_fd: BorrowedFd<'_>,
+    target_fd: BorrowedFd<'_>,
     attach_type: bpf_attach_type,
 ) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
-    attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32;
-    attr.__bindgen_anon_5.target_fd = target_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_raw_fd() as u32;
     attr.__bindgen_anon_5.attach_type = attach_type as u32;
 
     sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &mut attr)
@@ -424,13 +437,13 @@ pub(crate) fn bpf_prog_attach(
 
 pub(crate) fn bpf_prog_detach(
     prog_fd: RawFd,
-    map_fd: RawFd,
+    target_fd: BorrowedFd<'_>,
     attach_type: bpf_attach_type,
 ) -> SysResult<c_long> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32;
-    attr.__bindgen_anon_5.target_fd = map_fd as u32;
+    attr.__bindgen_anon_5.target_fd = target_fd.as_raw_fd() as u32;
     attr.__bindgen_anon_5.attach_type = attach_type as u32;
 
     sys_bpf(bpf_cmd::BPF_PROG_DETACH, &mut attr)
@@ -547,14 +560,17 @@ pub(crate) fn btf_obj_get_info_by_fd(
     })
 }
 
-pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult<OwnedFd> {
+pub(crate) fn bpf_raw_tracepoint_open(
+    name: Option<&CStr>,
+    prog_fd: BorrowedFd<'_>,
+) -> SysResult<OwnedFd> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     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) }
@@ -678,10 +694,9 @@ pub(crate) fn is_perf_link_supported() -> bool {
 
     if let Ok(fd) = bpf_prog_load(&mut attr) {
         let fd = fd.as_fd();
-        let fd = fd.as_raw_fd();
         matches!(
             // Uses an invalid target FD so we get EBADF if supported.
-            bpf_link_create(fd, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0),
+            bpf_link_create(fd, LinkTarget::IfIndex(u32::MAX), bpf_attach_type::BPF_PERF_EVENT, None, 0),
             // Returns EINVAL if unsupported. EBADF if supported.
             Err((_, e)) if e.raw_os_error() == Some(libc::EBADF),
         )

+ 13 - 4
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::<nlattr>(), NLA_ALIGNTO as usi
 // netlink alignments
 pub(crate) unsafe fn netlink_set_xdp_fd(
     if_index: i32,
-    fd: RawFd,
+    fd: Option<BorrowedFd<'_>>,
     old_fd: Option<RawFd>,
     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,

+ 21 - 21
xtask/public-api/aya.txt

@@ -637,8 +637,8 @@ pub fn aya::maps::SockMap<T>::borrow_mut(&mut self) -> &mut T
 impl<T> core::convert::From<T> for aya::maps::SockMap<T>
 pub fn aya::maps::SockMap<T>::from(t: T) -> T
 pub struct aya::maps::sock::SockMapFd(_)
-impl std::os::fd::raw::AsRawFd for aya::maps::sock::SockMapFd
-pub fn aya::maps::sock::SockMapFd::as_raw_fd(&self) -> std::os::fd::raw::RawFd
+impl std::os::fd::owned::AsFd for aya::maps::sock::SockMapFd
+pub fn aya::maps::sock::SockMapFd::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_>
 impl core::clone::Clone for aya::maps::sock::SockMapFd
 pub fn aya::maps::sock::SockMapFd::clone(&self) -> aya::maps::sock::SockMapFd
 impl core::marker::Copy for aya::maps::sock::SockMapFd
@@ -1793,7 +1793,7 @@ pub use aya::programs::CgroupSockoptAttachType
 pub mod aya::programs::cgroup_device
 pub struct aya::programs::cgroup_device::CgroupDevice
 impl aya::programs::cgroup_device::CgroupDevice
-pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>
@@ -1936,7 +1936,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_skb::CgroupSkbAttachTyp
 pub fn aya::programs::cgroup_skb::CgroupSkbAttachType::from(t: T) -> T
 pub struct aya::programs::cgroup_skb::CgroupSkb
 impl aya::programs::cgroup_skb::CgroupSkb
-pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::detach(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::expected_attach_type(&self) -> &core::option::Option<aya::programs::cgroup_skb::CgroupSkbAttachType>
 pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, expected_attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
@@ -2047,7 +2047,7 @@ pub mod aya::programs::cgroup_sock
 pub use aya::programs::cgroup_sock::CgroupSockAttachType
 pub struct aya::programs::cgroup_sock::CgroupSock
 impl aya::programs::cgroup_sock::CgroupSock
-pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::detach(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock::CgroupSockAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -2157,7 +2157,7 @@ pub mod aya::programs::cgroup_sock_addr
 pub use aya::programs::cgroup_sock_addr::CgroupSockAddrAttachType
 pub struct aya::programs::cgroup_sock_addr::CgroupSockAddr
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
-pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::detach(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock_addr::CgroupSockAddrAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -2267,7 +2267,7 @@ pub mod aya::programs::cgroup_sockopt
 pub use aya::programs::cgroup_sockopt::CgroupSockoptAttachType
 pub struct aya::programs::cgroup_sockopt::CgroupSockopt
 impl aya::programs::cgroup_sockopt::CgroupSockopt
-pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::detach(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -2376,7 +2376,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::from(t: T) -> T
 pub mod aya::programs::cgroup_sysctl
 pub struct aya::programs::cgroup_sysctl::CgroupSysctl
 impl aya::programs::cgroup_sysctl::CgroupSysctl
-pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>
@@ -3395,10 +3395,10 @@ impl<T> core::convert::From<T> for aya::programs::lirc_mode2::LircLinkId
 pub fn aya::programs::lirc_mode2::LircLinkId::from(t: T) -> T
 pub struct aya::programs::lirc_mode2::LircMode2
 impl aya::programs::lirc_mode2::LircMode2
-pub fn aya::programs::lirc_mode2::LircMode2::attach<T: std::os::fd::raw::AsRawFd>(&mut self, lircdev: T) -> core::result::Result<aya::programs::lirc_mode2::LircLinkId, aya::programs::ProgramError>
+pub fn aya::programs::lirc_mode2::LircMode2::attach<T: std::os::fd::owned::AsFd>(&mut self, lircdev: T) -> core::result::Result<aya::programs::lirc_mode2::LircLinkId, aya::programs::ProgramError>
 pub fn aya::programs::lirc_mode2::LircMode2::detach(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
-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::query<T: std::os::fd::owned::AsFd>(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::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
@@ -5567,7 +5567,7 @@ impl<T> core::convert::From<T> for aya::programs::tp_btf::BtfTracePoint
 pub fn aya::programs::tp_btf::BtfTracePoint::from(t: T) -> T
 pub struct aya::programs::CgroupDevice
 impl aya::programs::cgroup_device::CgroupDevice
-pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>
@@ -5615,7 +5615,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_device::CgroupDevice
 pub fn aya::programs::cgroup_device::CgroupDevice::from(t: T) -> T
 pub struct aya::programs::CgroupSkb
 impl aya::programs::cgroup_skb::CgroupSkb
-pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::detach(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::expected_attach_type(&self) -> &core::option::Option<aya::programs::cgroup_skb::CgroupSkbAttachType>
 pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, expected_attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
@@ -5663,7 +5663,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_skb::CgroupSkb
 pub fn aya::programs::cgroup_skb::CgroupSkb::from(t: T) -> T
 pub struct aya::programs::CgroupSock
 impl aya::programs::cgroup_sock::CgroupSock
-pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::detach(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock::CgroupSockAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -5710,7 +5710,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_sock::CgroupSock
 pub fn aya::programs::cgroup_sock::CgroupSock::from(t: T) -> T
 pub struct aya::programs::CgroupSockAddr
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
-pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::detach(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock_addr::CgroupSockAddrAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -5757,7 +5757,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_sock_addr::CgroupSockAd
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from(t: T) -> T
 pub struct aya::programs::CgroupSockopt
 impl aya::programs::cgroup_sockopt::CgroupSockopt
-pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::detach(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -5804,7 +5804,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_sockopt::CgroupSockopt
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from(t: T) -> T
 pub struct aya::programs::CgroupSysctl
 impl aya::programs::cgroup_sysctl::CgroupSysctl
-pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>
@@ -6045,10 +6045,10 @@ impl<T> core::convert::From<T> for aya::programs::kprobe::KProbe
 pub fn aya::programs::kprobe::KProbe::from(t: T) -> T
 pub struct aya::programs::LircMode2
 impl aya::programs::lirc_mode2::LircMode2
-pub fn aya::programs::lirc_mode2::LircMode2::attach<T: std::os::fd::raw::AsRawFd>(&mut self, lircdev: T) -> core::result::Result<aya::programs::lirc_mode2::LircLinkId, aya::programs::ProgramError>
+pub fn aya::programs::lirc_mode2::LircMode2::attach<T: std::os::fd::owned::AsFd>(&mut self, lircdev: T) -> core::result::Result<aya::programs::lirc_mode2::LircLinkId, aya::programs::ProgramError>
 pub fn aya::programs::lirc_mode2::LircMode2::detach(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
-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::query<T: std::os::fd::owned::AsFd>(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::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError>
@@ -6354,7 +6354,7 @@ impl<T> core::convert::From<T> for aya::programs::tc::SchedClassifier
 pub fn aya::programs::tc::SchedClassifier::from(t: T) -> T
 pub struct aya::programs::SkLookup
 impl aya::programs::SkLookup
-pub fn aya::programs::SkLookup::attach<T: std::os::fd::raw::AsRawFd>(&mut self, netns: T) -> core::result::Result<SkLookupLinkId, aya::programs::ProgramError>
+pub fn aya::programs::SkLookup::attach<T: std::os::fd::owned::AsFd>(&mut self, netns: T) -> core::result::Result<SkLookupLinkId, aya::programs::ProgramError>
 pub fn aya::programs::SkLookup::detach(&mut self, link_id: SkLookupLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>
@@ -6497,7 +6497,7 @@ impl<T> core::convert::From<T> for aya::programs::SkSkb
 pub fn aya::programs::SkSkb::from(t: T) -> T
 pub struct aya::programs::SockOps
 impl aya::programs::SockOps
-pub fn aya::programs::SockOps::attach<T: std::os::fd::raw::AsRawFd>(&mut self, cgroup: T) -> core::result::Result<SockOpsLinkId, aya::programs::ProgramError>
+pub fn aya::programs::SockOps::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<SockOpsLinkId, aya::programs::ProgramError>
 pub fn aya::programs::SockOps::detach(&mut self, link_id: SockOpsLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>
@@ -6545,7 +6545,7 @@ impl<T> core::convert::From<T> for aya::programs::SockOps
 pub fn aya::programs::SockOps::from(t: T) -> T
 pub struct aya::programs::SocketFilter
 impl aya::programs::SocketFilter
-pub fn aya::programs::SocketFilter::attach<T: std::os::fd::raw::AsRawFd>(&mut self, socket: T) -> core::result::Result<SocketFilterLinkId, aya::programs::ProgramError>
+pub fn aya::programs::SocketFilter::attach<T: std::os::fd::owned::AsFd>(&mut self, socket: T) -> core::result::Result<SocketFilterLinkId, aya::programs::ProgramError>
 pub fn aya::programs::SocketFilter::detach(&mut self, link_id: SocketFilterLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 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>