From 76fa6cb887b9004edb363c04342bedc8c871c4a6 Mon Sep 17 00:00:00 2001 From: swananan Date: Tue, 14 Apr 2026 21:51:54 +0800 Subject: [PATCH] aya: fix TryFrom link type checks Fix wrong bpf_link_type checks in TryFrom for UProbeLink, KProbeLink and TracePointLink. Consolidate all TryFrom implementations into an impl_try_from_fdlink! macro. Strengthen pin_lifecycle tests to verify the FdLink to link conversion, covering this previously untested path. Found while working on #1417. --- aya/src/programs/iter.rs | 18 ++++-------------- aya/src/programs/kprobe.rs | 21 ++++++--------------- aya/src/programs/links.rs | 20 ++++++++++++++++++++ aya/src/programs/mod.rs | 2 +- aya/src/programs/perf_event.rs | 21 +++++++-------------- aya/src/programs/tc.rs | 25 +++++++++---------------- aya/src/programs/trace_point.rs | 21 +++++++-------------- aya/src/programs/uprobe.rs | 25 +++++++------------------ aya/src/programs/xdp.rs | 22 +++++----------------- test/integration-test/src/tests/load.rs | 6 +++++- 10 files changed, 71 insertions(+), 110 deletions(-) diff --git a/aya/src/programs/iter.rs b/aya/src/programs/iter.rs index 069a9d97b..f6e347327 100644 --- a/aya/src/programs/iter.rs +++ b/aya/src/programs/iter.rs @@ -15,9 +15,10 @@ use aya_obj::{ use crate::{ programs::{ FdLink, LinkError, PerfLinkIdInner, PerfLinkInner, ProgramData, ProgramError, ProgramType, - define_link_wrapper, impl_try_into_fdlink, load_program_with_attach_type, + define_link_wrapper, impl_try_from_fdlink, impl_try_into_fdlink, + load_program_with_attach_type, }, - sys::{LinkTarget, SyscallError, bpf_create_iter, bpf_link_create, bpf_link_get_info_by_fd}, + sys::{LinkTarget, SyscallError, bpf_create_iter, bpf_link_create}, }; /// A BPF iterator which allows to dump data from the kernel-space into the @@ -103,19 +104,8 @@ impl AsFd for IterFd { } } -impl TryFrom for IterLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (BPF_LINK_TYPE_ITER as u32) { - return Ok(Self::new(PerfLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} - impl_try_into_fdlink!(IterLink, PerfLinkInner); +impl_try_from_fdlink!(IterLink, PerfLinkInner, BPF_LINK_TYPE_ITER); define_link_wrapper!(IterLink, IterLinkId, PerfLinkInner, PerfLinkIdInner, Iter); diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index 68780e711..b21d6fa51 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -3,7 +3,6 @@ use std::{ ffi::OsStr, fmt::{self, Write}, io, - os::fd::AsFd as _, path::{Path, PathBuf}, }; @@ -13,12 +12,11 @@ use thiserror::Error; use crate::{ VerifierLogLevel, programs::{ - FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, + ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink, impl_try_into_fdlink, load_program_without_attach_type, perf_attach::{PerfLinkIdInner, PerfLinkInner}, probe::{Probe, ProbeKind, attach}, }, - sys::bpf_link_get_info_by_fd, }; /// A kernel probe. @@ -146,15 +144,8 @@ pub enum KProbeError { } impl_try_into_fdlink!(KProbeLink, PerfLinkInner); - -impl TryFrom for KProbeLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (bpf_link_type::BPF_LINK_TYPE_KPROBE_MULTI as u32) { - return Ok(Self::new(PerfLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} +impl_try_from_fdlink!( + KProbeLink, + PerfLinkInner, + bpf_link_type::BPF_LINK_TYPE_PERF_EVENT +); diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index 6cf2c73a5..62f40102d 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -583,6 +583,26 @@ macro_rules! impl_try_into_fdlink { pub(crate) use impl_try_into_fdlink; +macro_rules! impl_try_from_fdlink { + ($wrapper:ident, $inner:ident, $link_type:expr) => { + impl TryFrom<$crate::programs::FdLink> for $wrapper { + type Error = $crate::programs::LinkError; + + fn try_from(fd_link: $crate::programs::FdLink) -> Result { + use std::os::fd::AsFd as _; + + let info = $crate::sys::bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; + if info.type_ == ($link_type as u32) { + return Ok(Self::new($inner::Fd(fd_link))); + } + Err($crate::programs::LinkError::InvalidLink) + } + } + }; +} + +pub(crate) use impl_try_from_fdlink; + #[derive(Error, Debug)] /// Errors from operations on links. pub enum LinkError { diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 3a894b515..9aee1f309 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -132,7 +132,7 @@ use crate::{ programs::{ links::{ FdLink, FdLinkId, LinkError, LinkInfo, Links, ProgAttachLink, ProgAttachLinkId, - define_link_wrapper, id_as_key, impl_try_into_fdlink, + define_link_wrapper, id_as_key, impl_try_from_fdlink, impl_try_into_fdlink, }, perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach, perf_attach_debugfs}, }, diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index d885d1845..0a8eb2728 100644 --- a/aya/src/programs/perf_event.rs +++ b/aya/src/programs/perf_event.rs @@ -11,12 +11,12 @@ use aya_obj::generated::{ use crate::{ programs::{ - FdLink, LinkError, ProgramData, ProgramError, ProgramType, impl_try_into_fdlink, + ProgramData, ProgramError, ProgramType, impl_try_from_fdlink, impl_try_into_fdlink, links::define_link_wrapper, load_program_without_attach_type, perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach}, }, - sys::{SyscallError, bpf_link_get_info_by_fd, perf_event_open}, + sys::{SyscallError, perf_event_open}, }; /// The type of perf event and their respective configuration. @@ -476,18 +476,11 @@ impl PerfEvent { } impl_try_into_fdlink!(PerfEventLink, PerfLinkInner); - -impl TryFrom for PerfEventLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (bpf_link_type::BPF_LINK_TYPE_PERF_EVENT as u32) { - return Ok(Self::new(PerfLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} +impl_try_from_fdlink!( + PerfEventLink, + PerfLinkInner, + bpf_link_type::BPF_LINK_TYPE_PERF_EVENT +); define_link_wrapper!( PerfEventLink, diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index 2187a287a..57a70b681 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -14,13 +14,13 @@ use crate::{ VerifierLogLevel, programs::{ Link, LinkError, LinkOrder, ProgramData, ProgramError, ProgramType, define_link_wrapper, - id_as_key, impl_try_into_fdlink, load_program_without_attach_type, query, + id_as_key, impl_try_from_fdlink, impl_try_into_fdlink, load_program_without_attach_type, + query, }, sys::{ BpfLinkCreateArgs, LinkTarget, NetlinkError, NetlinkSocket, ProgQueryTarget, SyscallError, - bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, bpf_prog_get_fd_by_id, - netlink_find_filter_with_name, netlink_qdisc_add_clsact, netlink_qdisc_attach, - netlink_qdisc_detach, + bpf_link_create, bpf_link_update, bpf_prog_get_fd_by_id, netlink_find_filter_with_name, + netlink_qdisc_add_clsact, netlink_qdisc_attach, netlink_qdisc_detach, }, util::{KernelVersion, ifindex_from_ifname, tc_handler_make}, }; @@ -488,18 +488,11 @@ impl<'a> TryFrom<&'a SchedClassifierLink> for &'a FdLink { } impl_try_into_fdlink!(SchedClassifierLink, TcLinkInner); - -impl TryFrom for SchedClassifierLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TCX as u32) { - return Ok(Self::new(TcLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} +impl_try_from_fdlink!( + SchedClassifierLink, + TcLinkInner, + bpf_link_type::BPF_LINK_TYPE_TCX +); define_link_wrapper!( SchedClassifierLink, diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 76e833656..0dad511a2 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -10,12 +10,12 @@ use thiserror::Error; use crate::{ programs::{ - FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, + ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink, impl_try_into_fdlink, load_program_without_attach_type, perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach}, utils::find_tracefs_path, }, - sys::{SyscallError, bpf_link_get_info_by_fd, perf_event_open_trace_point}, + sys::{SyscallError, perf_event_open_trace_point}, }; /// The type returned when attaching a [`TracePoint`] fails. @@ -99,18 +99,11 @@ define_link_wrapper!( ); impl_try_into_fdlink!(TracePointLink, PerfLinkInner); - -impl TryFrom for TracePointLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { - return Ok(Self::new(PerfLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} +impl_try_from_fdlink!( + TracePointLink, + PerfLinkInner, + bpf_link_type::BPF_LINK_TYPE_PERF_EVENT +); pub(crate) fn read_sys_fs_trace_point_id( tracefs: &Path, diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 05571a0fa..df581d659 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -6,10 +6,7 @@ use std::{ fmt::{self, Write}, fs, io::{self, BufRead as _, Cursor, Read as _}, - os::{ - fd::AsFd as _, - unix::ffi::{OsStrExt as _, OsStringExt as _}, - }, + os::unix::ffi::{OsStrExt as _, OsStringExt as _}, path::{Path, PathBuf}, sync::LazyLock, }; @@ -21,12 +18,11 @@ use thiserror::Error; use crate::{ VerifierLogLevel, programs::{ - FdLink, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, + ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink, impl_try_into_fdlink, load_program_without_attach_type, perf_attach::{PerfLinkIdInner, PerfLinkInner}, probe::{OsStringExt as _, Probe, ProbeKind, attach}, }, - sys::bpf_link_get_info_by_fd, util::MMap, }; @@ -228,18 +224,11 @@ define_link_wrapper!( ); impl_try_into_fdlink!(UProbeLink, PerfLinkInner); - -impl TryFrom for UProbeLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { - return Ok(Self::new(PerfLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} +impl_try_from_fdlink!( + UProbeLink, + PerfLinkInner, + bpf_link_type::BPF_LINK_TYPE_PERF_EVENT +); /// The type returned when attaching an [`UProbe`] fails. #[derive(Debug, Error)] diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index d719c2c49..c87d10e60 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -19,12 +19,12 @@ use thiserror::Error; use crate::{ VerifierLogLevel, programs::{ - FdLink, Link, LinkError, ProgramData, ProgramError, ProgramType, define_link_wrapper, - id_as_key, impl_try_into_fdlink, load_program_with_attach_type, + FdLink, Link, ProgramData, ProgramError, ProgramType, define_link_wrapper, id_as_key, + impl_try_from_fdlink, impl_try_into_fdlink, load_program_with_attach_type, }, sys::{ - LinkTarget, NetlinkError, SyscallError, bpf_link_create, bpf_link_get_info_by_fd, - bpf_link_update, netlink_set_xdp_fd, + LinkTarget, NetlinkError, SyscallError, bpf_link_create, bpf_link_update, + netlink_set_xdp_fd, }, util::KernelVersion, }; @@ -294,18 +294,6 @@ impl Link for XdpLinkInner { id_as_key!(XdpLinkInner, XdpLinkIdInner); impl_try_into_fdlink!(XdpLink, XdpLinkInner); - -impl TryFrom for XdpLink { - type Error = LinkError; - - fn try_from(fd_link: FdLink) -> Result { - // unwrap of fd_link.fd will not panic since it's only None when being dropped. - let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; - if info.type_ == (bpf_link_type::BPF_LINK_TYPE_XDP as u32) { - return Ok(Self::new(XdpLinkInner::Fd(fd_link))); - } - Err(LinkError::InvalidLink) - } -} +impl_try_from_fdlink!(XdpLink, XdpLinkInner, bpf_link_type::BPF_LINK_TYPE_XDP); define_link_wrapper!(XdpLink, XdpLinkId, XdpLinkInner, XdpLinkIdInner, Xdp); diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 8ff890975..dc288225a 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -535,7 +535,7 @@ fn run_pin_program_lifecycle_test

( expect_fd_link: bool, ) where P: UnloadProgramOps + PinProgramOps, - P::OwnedLink: TryInto, + P::OwnedLink: TryFrom + TryInto, for<'a> &'a mut Program: TryInto<&'a mut P, Error = ProgramError>, { let mut prog = { @@ -574,6 +574,10 @@ fn run_pin_program_lifecycle_test

( // 4. Load a new version of the program, unpin link, and atomically replace old program { let link = PinnedLink::from_pin(link_pin).unwrap().unpin().unwrap(); + let link: P::OwnedLink = link + .try_into() + .expect("pinned link should round-trip through FdLink"); + let link: FdLink = link.try_into().unwrap(); if let Some(attach_to_link) = attach_to_link { let mut bpf = Ebpf::load(bpf_image).unwrap(); let prog: &mut P =