From 4cb3ea6e8fa990b88c5e8a67f1c852355bc7d99a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 1 Aug 2023 11:22:29 -0400 Subject: [PATCH 1/6] sys: `sys_bpf` takes mut ref Some syscalls mutate the argument, we can't be passing an immutable reference here. --- aya/src/sys/bpf.rs | 66 +++++++++++++++++++++++----------------------- aya/src/sys/mod.rs | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index dd285d3e..ae68991e 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -90,7 +90,7 @@ pub(crate) fn bpf_create_map( .copy_from_slice(unsafe { slice::from_raw_parts(name.as_ptr(), name_len) }); } - sys_bpf(bpf_cmd::BPF_MAP_CREATE, &attr) + sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) } pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult { @@ -98,14 +98,14 @@ pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult { let u = unsafe { &mut attr.__bindgen_anon_4 }; u.bpf_fd = fd as u32; u.pathname = path.as_ptr() as u64; - sys_bpf(bpf_cmd::BPF_OBJ_PIN, &attr) + sys_bpf(bpf_cmd::BPF_OBJ_PIN, &mut attr) } pub(crate) fn bpf_get_object(path: &CStr) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_4 }; u.pathname = path.as_ptr() as u64; - sys_bpf(bpf_cmd::BPF_OBJ_GET, &attr) + sys_bpf(bpf_cmd::BPF_OBJ_GET, &mut attr) } pub(crate) struct BpfLoadProgramAttrs<'a> { @@ -188,7 +188,7 @@ 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, &attr) + sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) } fn lookup( @@ -208,7 +208,7 @@ fn lookup( u.__bindgen_anon_1.value = &mut value as *mut _ as u64; u.flags = flags; - match sys_bpf(cmd, &attr) { + match sys_bpf(cmd, &mut attr) { Ok(_) => Ok(Some(unsafe { value.assume_init() })), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err(e) => Err(e), @@ -260,7 +260,7 @@ pub(crate) fn bpf_map_lookup_elem_ptr( u.__bindgen_anon_1.value = value as u64; u.flags = flags; - match sys_bpf(bpf_cmd::BPF_MAP_LOOKUP_ELEM, &attr) { + match sys_bpf(bpf_cmd::BPF_MAP_LOOKUP_ELEM, &mut attr) { Ok(_) => Ok(Some(())), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err(e) => Err(e), @@ -283,7 +283,7 @@ pub(crate) fn bpf_map_update_elem( u.__bindgen_anon_1.value = value as *const _ as u64; u.flags = flags; - sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) + sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr) } pub(crate) fn bpf_map_push_elem(fd: RawFd, value: &V, flags: u64) -> SysResult { @@ -294,7 +294,7 @@ pub(crate) fn bpf_map_push_elem(fd: RawFd, value: &V, flags: u64) -> Sys u.__bindgen_anon_1.value = value as *const _ as u64; u.flags = flags; - sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) + sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr) } pub(crate) fn bpf_map_update_elem_ptr( @@ -311,7 +311,7 @@ pub(crate) fn bpf_map_update_elem_ptr( u.__bindgen_anon_1.value = value as u64; u.flags = flags; - sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &attr) + sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr) } pub(crate) fn bpf_map_update_elem_per_cpu( @@ -331,7 +331,7 @@ pub(crate) fn bpf_map_delete_elem(fd: RawFd, key: &K) -> SysResult( @@ -348,7 +348,7 @@ pub(crate) fn bpf_map_get_next_key( } u.__bindgen_anon_1.next_key = &mut next_key as *mut _ as u64; - match sys_bpf(bpf_cmd::BPF_MAP_GET_NEXT_KEY, &attr) { + match sys_bpf(bpf_cmd::BPF_MAP_GET_NEXT_KEY, &mut attr) { Ok(_) => Ok(Some(unsafe { next_key.assume_init() })), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err(e) => Err(e), @@ -360,7 +360,7 @@ pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd as u32; - sys_bpf(bpf_cmd::BPF_MAP_FREEZE, &attr) + sys_bpf(bpf_cmd::BPF_MAP_FREEZE, &mut attr) } // since kernel 5.7 @@ -381,7 +381,7 @@ pub(crate) fn bpf_link_create( attr.link_create.__bindgen_anon_3.target_btf_id = btf_id; } - sys_bpf(bpf_cmd::BPF_LINK_CREATE, &attr) + sys_bpf(bpf_cmd::BPF_LINK_CREATE, &mut attr) } // since kernel 5.7 @@ -402,7 +402,7 @@ pub(crate) fn bpf_link_update( attr.link_update.flags = flags; } - sys_bpf(bpf_cmd::BPF_LINK_UPDATE, &attr) + sys_bpf(bpf_cmd::BPF_LINK_UPDATE, &mut attr) } pub(crate) fn bpf_prog_attach( @@ -416,7 +416,7 @@ pub(crate) fn bpf_prog_attach( attr.__bindgen_anon_5.target_fd = target_fd as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32; - sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &attr) + sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &mut attr) } pub(crate) fn bpf_prog_detach( @@ -430,7 +430,7 @@ pub(crate) fn bpf_prog_detach( attr.__bindgen_anon_5.target_fd = map_fd as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32; - sys_bpf(bpf_cmd::BPF_PROG_DETACH, &attr) + sys_bpf(bpf_cmd::BPF_PROG_DETACH, &mut attr) } pub(crate) fn bpf_prog_query( @@ -449,7 +449,7 @@ pub(crate) fn bpf_prog_query( attr.query.prog_cnt = prog_ids.len() as u32; attr.query.prog_ids = prog_ids.as_mut_ptr() as u64; - let ret = sys_bpf(bpf_cmd::BPF_PROG_QUERY, &attr); + let ret = sys_bpf(bpf_cmd::BPF_PROG_QUERY, &mut attr); *prog_cnt = unsafe { attr.query.prog_cnt }; @@ -465,7 +465,7 @@ pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id; // SAFETY: BPF_PROG_GET_FD_BY_ID returns a new file descriptor. - unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr).map_err(|(_, e)| e) } + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &mut attr).map_err(|(_, e)| e) } } pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result { @@ -477,7 +477,7 @@ pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result() as u32; - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { + match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(_) => Ok(unsafe { info.assume_init() }), Err((_, err)) => Err(err), } @@ -492,7 +492,7 @@ pub(crate) fn bpf_map_get_info_by_fd(prog_fd: RawFd) -> Result() as u32; - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { + match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(_) => Ok(unsafe { info.assume_init() }), Err((_, err)) => Err(err), } @@ -507,7 +507,7 @@ pub(crate) fn bpf_link_get_info_by_fd(link_fd: RawFd) -> Result() as u32; - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { + match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(_) => Ok(info), Err((_, err)) => Err(err), } @@ -526,7 +526,7 @@ pub(crate) fn btf_obj_get_info_by_fd( attr.info.info = &info as *const bpf_btf_info as u64; attr.info.info_len = mem::size_of::() as u32; - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) { + match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(_) => Ok(info), Err((_, err)) => Err(err), } @@ -541,7 +541,7 @@ pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> Sy }; attr.raw_tracepoint.prog_fd = prog_fd as u32; - sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &attr) + sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &mut attr) } pub(crate) fn bpf_load_btf( @@ -559,11 +559,11 @@ pub(crate) fn bpf_load_btf( u.btf_log_size = log_buf.len() as u32; } // SAFETY: `BPF_BTF_LOAD` returns a newly created fd. - unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) } + unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_LOAD, &mut attr) } } // SAFETY: only use for bpf_cmd that return a new file descriptor on success. -unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult { +unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { let fd = sys_bpf(cmd, attr)?; let fd = fd.try_into().map_err(|_| { ( @@ -581,7 +581,7 @@ pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result { let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id; - match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &attr) { + match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &mut attr) { Ok(v) => Ok(v as RawFd), Err((_, err)) => Err(err), } @@ -612,7 +612,7 @@ pub(crate) fn is_prog_name_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { Ok(v) => { let fd = v as RawFd; unsafe { close(fd) }; @@ -643,7 +643,7 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { Ok(v) => { let fd = v as RawFd; unsafe { close(fd) }; @@ -670,7 +670,7 @@ pub(crate) fn is_perf_link_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { if let Err((_, e)) = // Uses an invalid target FD so we get EBADF if supported. bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) @@ -726,7 +726,7 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { let fd = v as RawFd; unsafe { close(fd) }; @@ -755,7 +755,7 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { Ok(v) => { let fd = v as RawFd; unsafe { close(fd) }; @@ -905,7 +905,7 @@ pub(crate) fn is_btf_type_tag_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } -pub fn sys_bpf(cmd: bpf_cmd, attr: &bpf_attr) -> SysResult { +pub fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } @@ -913,7 +913,7 @@ pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result, (c_long, io:: let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_6 }; u.__bindgen_anon_1.start_id = id; - match sys_bpf(bpf_cmd::BPF_PROG_GET_NEXT_ID, &attr) { + match sys_bpf(bpf_cmd::BPF_PROG_GET_NEXT_ID, &mut attr) { Ok(_) => Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })), Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), Err(e) => Err(e), diff --git a/aya/src/sys/mod.rs b/aya/src/sys/mod.rs index 01e33c66..b64d76b3 100644 --- a/aya/src/sys/mod.rs +++ b/aya/src/sys/mod.rs @@ -27,7 +27,7 @@ pub(crate) type SysResult = Result; pub(crate) enum Syscall<'a> { Bpf { cmd: bpf_cmd, - attr: &'a bpf_attr, + attr: &'a mut bpf_attr, }, PerfEventOpen { attr: perf_event_attr, From de8519a38083e96f9a0c34f0577657b8050db8a8 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 1 Aug 2023 12:50:42 -0400 Subject: [PATCH 2/6] sys: extract common SyscallError We currently have 4 copies of this. --- aya/src/bpf.rs | 16 +++-- aya/src/maps/array/array.rs | 11 ++- aya/src/maps/array/per_cpu_array.rs | 6 +- aya/src/maps/array/program_array.rs | 13 ++-- aya/src/maps/bloom_filter.rs | 16 ++--- aya/src/maps/hash_map/hash_map.rs | 31 ++++---- aya/src/maps/hash_map/mod.rs | 19 ++--- aya/src/maps/hash_map/per_cpu_hash_map.rs | 11 ++- aya/src/maps/lpm_trie.rs | 27 +++---- aya/src/maps/mod.rs | 49 ++++++------- aya/src/maps/queue.rs | 12 ++-- aya/src/maps/sock/sock_hash.rs | 10 ++- aya/src/maps/sock/sock_map.rs | 13 ++-- aya/src/maps/stack.rs | 6 +- aya/src/maps/stack_trace.rs | 12 ++-- aya/src/pin.rs | 13 ++-- aya/src/programs/cgroup_device.rs | 6 +- aya/src/programs/cgroup_skb.rs | 6 +- aya/src/programs/cgroup_sock.rs | 6 +- aya/src/programs/cgroup_sock_addr.rs | 6 +- aya/src/programs/cgroup_sockopt.rs | 6 +- aya/src/programs/cgroup_sysctl.rs | 6 +- aya/src/programs/extension.rs | 33 ++++----- aya/src/programs/kprobe.rs | 12 ++-- aya/src/programs/links.rs | 26 +++---- aya/src/programs/lirc_mode2.rs | 25 ++++--- aya/src/programs/mod.rs | 86 +++++++++++------------ aya/src/programs/perf_attach.rs | 8 +-- aya/src/programs/perf_event.rs | 14 ++-- aya/src/programs/probe.rs | 13 ++-- aya/src/programs/sk_lookup.rs | 4 +- aya/src/programs/sk_msg.rs | 4 +- aya/src/programs/sk_skb.rs | 10 ++- aya/src/programs/sock_ops.rs | 4 +- aya/src/programs/trace_point.rs | 19 +++-- aya/src/programs/uprobe.rs | 12 ++-- aya/src/programs/utils.rs | 9 ++- aya/src/programs/xdp.rs | 16 ++--- aya/src/sys/bpf.rs | 2 +- aya/src/sys/mod.rs | 14 +++- xtask/public-api/aya.txt | 17 ++--- 41 files changed, 300 insertions(+), 329 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index eed006d4..aea6d11e 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -42,6 +42,7 @@ use crate::{ is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, + SyscallError, }, util::{bytes_of, bytes_of_slice, possible_cpus, POSSIBLE_CPUS}, }; @@ -505,16 +506,19 @@ impl<'a> BpfLoader<'a> { }; if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss { bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0) - .map_err(|(_, io_error)| MapError::SyscallError { + .map_err(|(_, io_error)| SyscallError { call: "bpf_map_update_elem", io_error, - })?; + }) + .map_err(MapError::from)?; } if map.obj.section_kind() == BpfSectionKind::Rodata { - bpf_map_freeze(fd).map_err(|(_, io_error)| MapError::SyscallError { - call: "bpf_map_freeze", - io_error, - })?; + bpf_map_freeze(fd) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_freeze", + io_error, + }) + .map_err(MapError::from)?; } maps.insert(name, map); } diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index e219ced6..7f242ccc 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -5,7 +5,7 @@ use std::{ use crate::{ maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, - sys::{bpf_map_lookup_elem, bpf_map_update_elem}, + sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError}, Pod, }; @@ -65,12 +65,11 @@ impl, V: Pod> Array { check_bounds(data, *index)?; let fd = data.fd_or_err()?; - let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| { - MapError::SyscallError { + let value = + bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, - } - })?; + })?; value.ok_or(MapError::KeyNotFound) } @@ -93,7 +92,7 @@ impl, V: Pod> Array { check_bounds(data, index)?; let fd = data.fd_or_err()?; bpf_map_update_elem(fd, Some(&index), value.borrow(), flags).map_err(|(_, io_error)| { - MapError::SyscallError { + SyscallError { call: "bpf_map_update_elem", io_error, } diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs index a7cde3ea..7cf1116a 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -5,7 +5,7 @@ use std::{ use crate::{ maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError, PerCpuValues}, - sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, + sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu, SyscallError}, Pod, }; @@ -85,7 +85,7 @@ impl, V: Pod> PerCpuArray { let fd = data.fd_or_err()?; let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { - MapError::SyscallError { + SyscallError { call: "bpf_map_lookup_elem", io_error, } @@ -113,7 +113,7 @@ impl, V: Pod> PerCpuArray { let fd = data.fd_or_err()?; bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| { - MapError::SyscallError { + SyscallError { call: "bpf_map_update_elem", io_error, } diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index 613d7b17..b7ec75cf 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -8,7 +8,7 @@ use std::{ use crate::{ maps::{check_bounds, check_kv_size, MapData, MapError, MapKeys}, programs::ProgramFd, - sys::{bpf_map_delete_elem, bpf_map_update_elem}, + sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError}, }; /// An array of eBPF program file descriptors used as a jump table. @@ -80,7 +80,7 @@ impl> ProgramArray { let prog_fd = program.as_raw_fd(); bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| { - MapError::SyscallError { + SyscallError { call: "bpf_map_update_elem", io_error, } @@ -99,9 +99,12 @@ impl> ProgramArray { bpf_map_delete_elem(fd, index) .map(|_| ()) - .map_err(|(_, io_error)| MapError::SyscallError { - call: "bpf_map_delete_elem", - io_error, + .map_err(|(_, io_error)| { + SyscallError { + call: "bpf_map_delete_elem", + io_error, + } + .into() }) } } diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index f646c2bb..b38bccf4 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -3,7 +3,7 @@ use std::{borrow::Borrow, marker::PhantomData}; use crate::{ maps::{check_v_size, MapData, MapError}, - sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem}, + sys::{bpf_map_lookup_elem_ptr, bpf_map_push_elem, SyscallError}, Pod, }; @@ -54,7 +54,7 @@ impl, V: Pod> BloomFilter { let fd = self.inner.borrow().fd_or_err()?; bpf_map_lookup_elem_ptr::(fd, None, &mut value, flags) - .map_err(|(_, io_error)| MapError::SyscallError { + .map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, })? @@ -65,11 +65,9 @@ impl, V: Pod> BloomFilter { /// Inserts a value into the map. pub fn insert(&self, value: impl Borrow, flags: u64) -> Result<(), MapError> { let fd = self.inner.borrow().fd_or_err()?; - bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| { - MapError::SyscallError { - call: "bpf_map_push_elem", - io_error, - } + bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_push_elem", + io_error, })?; Ok(()) } @@ -212,7 +210,7 @@ mod tests { assert_matches!( bloom_filter.insert(1, 0), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_push_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_push_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } @@ -250,7 +248,7 @@ mod tests { assert_matches!( bloom_filter.contains(&1, 0), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 49cb920d..0cb8e408 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -5,7 +5,7 @@ use std::{ use crate::{ maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, - sys::bpf_map_lookup_elem, + sys::{bpf_map_lookup_elem, SyscallError}, Pod, }; @@ -54,11 +54,9 @@ impl, K: Pod, V: Pod> HashMap { /// Returns a copy of the value associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result { let fd = self.inner.borrow().fd_or_err()?; - let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { - MapError::SyscallError { - call: "bpf_map_lookup_elem", - io_error, - } + let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, })?; value.ok_or(MapError::KeyNotFound) } @@ -292,7 +290,7 @@ mod tests { assert_matches!( hm.insert(1, 42, 0), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } @@ -352,7 +350,7 @@ mod tests { assert_matches!( hm.remove(&1), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } @@ -390,7 +388,7 @@ mod tests { assert_matches!( hm.get(&1, 0), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } @@ -535,7 +533,10 @@ mod tests { assert_matches!(keys.next(), Some(Ok(20))); assert_matches!( keys.next(), - Some(Err(MapError::SyscallError { call, .. })) if call == "bpf_map_get_next_key" + Some(Err(MapError::SyscallError(SyscallError { + call: "bpf_map_get_next_key", + io_error: _ + }))) ); assert_matches!(keys.next(), None); } @@ -647,7 +648,10 @@ mod tests { assert_matches!(iter.next(), Some(Ok((20, 200)))); assert_matches!( iter.next(), - Some(Err(MapError::SyscallError { call, .. })) if call == "bpf_map_get_next_key" + Some(Err(MapError::SyscallError(SyscallError { + call: "bpf_map_get_next_key", + io_error: _ + }))) ); assert_matches!(iter.next(), None); } @@ -691,7 +695,10 @@ mod tests { assert_matches!(iter.next(), Some(Ok((10, 100)))); assert_matches!( iter.next(), - Some(Err(MapError::SyscallError { call, .. })) if call == "bpf_map_lookup_elem" + Some(Err(MapError::SyscallError(SyscallError { + call: "bpf_map_lookup_elem", + io_error: _ + }))) ); assert_matches!(iter.next(), Some(Ok((30, 300)))); assert_matches!(iter.next(), None); diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs index 72d8583d..62d3fc55 100644 --- a/aya/src/maps/hash_map/mod.rs +++ b/aya/src/maps/hash_map/mod.rs @@ -1,7 +1,7 @@ //! Hash map types. use crate::{ maps::MapError, - sys::{bpf_map_delete_elem, bpf_map_update_elem}, + sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError}, Pod, }; @@ -21,11 +21,9 @@ pub(crate) fn insert( flags: u64, ) -> Result<(), MapError> { let fd = map.fd_or_err()?; - bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| { - MapError::SyscallError { - call: "bpf_map_update_elem", - io_error, - } + bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_update_elem", + io_error, })?; Ok(()) @@ -35,8 +33,11 @@ pub(crate) fn remove(map: &MapData, key: &K) -> Result<(), MapError> { let fd = map.fd_or_err()?; bpf_map_delete_elem(fd, key) .map(|_| ()) - .map_err(|(_, io_error)| MapError::SyscallError { - call: "bpf_map_delete_elem", - io_error, + .map_err(|(_, io_error)| { + SyscallError { + call: "bpf_map_delete_elem", + io_error, + } + .into() }) } diff --git a/aya/src/maps/hash_map/per_cpu_hash_map.rs b/aya/src/maps/hash_map/per_cpu_hash_map.rs index 91657f13..979970cc 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -8,7 +8,7 @@ use crate::{ maps::{ check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys, PerCpuValues, }, - sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu}, + sys::{bpf_map_lookup_elem_per_cpu, bpf_map_update_elem_per_cpu, SyscallError}, Pod, }; @@ -64,12 +64,11 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// Returns a slice of values - one for each CPU - associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result, MapError> { let fd = self.inner.borrow().fd_or_err()?; - let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| { - MapError::SyscallError { + let values = + bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, - } - })?; + })?; values.ok_or(MapError::KeyNotFound) } @@ -123,7 +122,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { ) -> Result<(), MapError> { let fd = self.inner.borrow_mut().fd_or_err()?; bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags).map_err( - |(_, io_error)| MapError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_map_update_elem", io_error, }, diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 4adb3f47..075aa558 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ maps::{check_kv_size, IterableMap, MapData, MapError, MapIter, MapKeys}, - sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem}, + sys::{bpf_map_delete_elem, bpf_map_lookup_elem, bpf_map_update_elem, SyscallError}, Pod, }; @@ -129,11 +129,9 @@ impl, K: Pod, V: Pod> LpmTrie { /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie. pub fn get(&self, key: &Key, flags: u64) -> Result { let fd = self.inner.borrow().fd_or_err()?; - let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { - MapError::SyscallError { - call: "bpf_map_lookup_elem", - io_error, - } + let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, })?; value.ok_or(MapError::KeyNotFound) } @@ -161,7 +159,7 @@ impl, K: Pod, V: Pod> LpmTrie { ) -> Result<(), MapError> { let fd = self.inner.borrow().fd_or_err()?; bpf_map_update_elem(fd, Some(key), value.borrow(), flags).map_err(|(_, io_error)| { - MapError::SyscallError { + SyscallError { call: "bpf_map_update_elem", io_error, } @@ -177,9 +175,12 @@ impl, K: Pod, V: Pod> LpmTrie { let fd = self.inner.borrow().fd_or_err()?; bpf_map_delete_elem(fd, key) .map(|_| ()) - .map_err(|(_, io_error)| MapError::SyscallError { - call: "bpf_map_delete_elem", - io_error, + .map_err(|(_, io_error)| { + SyscallError { + call: "bpf_map_delete_elem", + io_error, + } + .into() }) } } @@ -349,7 +350,7 @@ mod tests { let key = Key::new(16, u32::from(ipaddr).to_be()); assert_matches!( trie.insert(&key, 1, 0), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } @@ -391,7 +392,7 @@ mod tests { let key = Key::new(16, u32::from(ipaddr).to_be()); assert_matches!( trie.remove(&key), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } @@ -432,7 +433,7 @@ mod tests { assert_matches!( trie.get(&key, 0), - Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT) + Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) ); } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 5dce668e..27c4c7f2 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -58,7 +58,7 @@ use crate::{ pin::PinError, sys::{ bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key, - bpf_pin_object, + bpf_pin_object, SyscallError, }, util::nr_cpus, PinningType, Pod, @@ -167,13 +167,8 @@ pub enum MapError { ProgramNotLoaded, /// Syscall failed - #[error("the `{call}` syscall failed")] - SyscallError { - /// Syscall Name - call: &'static str, - /// Original io::Error - io_error: io::Error, - }, + #[error(transparent)] + SyscallError(#[from] SyscallError), /// Could not pin map by name #[error("map `{name:?}` requested pinning by name. pinning failed")] @@ -538,7 +533,7 @@ impl MapData { } let map_path = path.as_ref().join(name); let path_string = CString::new(map_path.to_str().unwrap()).unwrap(); - let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError { + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_GET", io_error, })? as RawFd; @@ -560,12 +555,12 @@ impl MapData { } })?; - let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError { + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_GET", io_error, })? as RawFd; - let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError { + let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| SyscallError { call: "BPF_MAP_GET_INFO_BY_FD", io_error, })?; @@ -584,7 +579,7 @@ impl MapData { /// This API is intended for cases where you have received a valid BPF FD from some other means. /// For example, you received an FD over Unix Domain Socket. pub fn from_fd(fd: RawFd) -> Result { - let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError { + let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| SyscallError { call: "BPF_OBJ_GET", io_error, })?; @@ -614,8 +609,8 @@ impl MapData { error: e.to_string(), } })?; - bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { - name: "BPF_OBJ_PIN", + bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError { + call: "BPF_OBJ_PIN", io_error, })?; self.pinned = true; @@ -692,21 +687,19 @@ impl Iterator for MapKeys<'_, K> { } }; - match bpf_map_get_next_key(fd, self.key.as_ref()) { - Ok(Some(key)) => { - self.key = Some(key); - Some(Ok(key)) - } - Ok(None) => { - self.key = None; - None - } - Err((_, io_error)) => { + let key = + bpf_map_get_next_key(fd, self.key.as_ref()).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_get_next_key", + io_error, + }); + match key { + Err(err) => { self.err = true; - Some(Err(MapError::SyscallError { - call: "bpf_map_get_next_key", - io_error, - })) + Some(Err(err.into())) + } + Ok(key) => { + self.key = key; + key.map(Ok) } } } diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index fc32c8b7..6b635dcb 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ maps::{check_kv_size, MapData, MapError}, - sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem}, + sys::{bpf_map_lookup_and_delete_elem, bpf_map_push_elem, SyscallError}, Pod, }; @@ -65,7 +65,7 @@ impl, V: Pod> Queue { let fd = self.inner.borrow().fd_or_err()?; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( - |(_, io_error)| MapError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_map_lookup_and_delete_elem", io_error, }, @@ -80,11 +80,9 @@ impl, V: Pod> Queue { /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. pub fn push(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { let fd = self.inner.borrow().fd_or_err()?; - bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| { - MapError::SyscallError { - call: "bpf_map_push_elem", - io_error, - } + bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_push_elem", + io_error, })?; Ok(()) } diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index be78e386..0e87aa98 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -8,7 +8,7 @@ use crate::{ maps::{ check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys, }, - sys::bpf_map_lookup_elem, + sys::{bpf_map_lookup_elem, SyscallError}, Pod, }; @@ -83,11 +83,9 @@ impl, K: Pod> SockHash { /// Returns the fd of the socket stored at the given key. pub fn get(&self, key: &K, flags: u64) -> Result { let fd = self.inner.borrow().fd_or_err()?; - let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| { - MapError::SyscallError { - call: "bpf_map_lookup_elem", - io_error, - } + let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, })?; value.ok_or(MapError::KeyNotFound) } diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index d34f658b..b6877827 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ maps::{check_bounds, check_kv_size, sock::SockMapFd, MapData, MapError, MapKeys}, - sys::{bpf_map_delete_elem, bpf_map_update_elem}, + sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError}, }; /// An array of TCP or UDP sockets. @@ -76,7 +76,7 @@ impl> SockMap { let fd = data.fd_or_err()?; check_bounds(data, index)?; bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( - |(_, io_error)| MapError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_map_update_elem", io_error, }, @@ -91,9 +91,12 @@ impl> SockMap { check_bounds(data, *index)?; bpf_map_delete_elem(fd, index) .map(|_| ()) - .map_err(|(_, io_error)| MapError::SyscallError { - call: "bpf_map_delete_elem", - io_error, + .map_err(|(_, io_error)| { + SyscallError { + call: "bpf_map_delete_elem", + io_error, + } + .into() }) } } diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index 0b75ae2c..8004e486 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ maps::{check_kv_size, MapData, MapError}, - sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem}, + sys::{bpf_map_lookup_and_delete_elem, bpf_map_update_elem, SyscallError}, Pod, }; @@ -65,7 +65,7 @@ impl, V: Pod> Stack { let fd = self.inner.borrow().fd_or_err()?; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( - |(_, io_error)| MapError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_map_lookup_and_delete_elem", io_error, }, @@ -81,7 +81,7 @@ impl, V: Pod> Stack { pub fn push(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { let fd = self.inner.borrow().fd_or_err()?; bpf_map_update_elem(fd, None::<&u32>, value.borrow(), flags).map_err(|(_, io_error)| { - MapError::SyscallError { + SyscallError { call: "bpf_map_update_elem", io_error, } diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs index eff8df47..f6900565 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -5,7 +5,7 @@ use std::{borrow::Borrow, collections::BTreeMap, fs, io, mem, path::Path, str::F use crate::{ maps::{IterableMap, MapData, MapError, MapIter, MapKeys}, - sys::bpf_map_lookup_elem_ptr, + sys::{bpf_map_lookup_elem_ptr, SyscallError}, }; /// A hash map of kernel or user space stack traces. @@ -77,11 +77,9 @@ impl> StackTraceMap { } let max_stack_depth = - sysctl::("kernel/perf_event_max_stack").map_err(|io_error| { - MapError::SyscallError { - call: "sysctl", - io_error, - } + sysctl::("kernel/perf_event_max_stack").map_err(|io_error| SyscallError { + call: "sysctl", + io_error, })?; let size = data.obj.value_size() as usize; if size > max_stack_depth * mem::size_of::() { @@ -106,7 +104,7 @@ impl> StackTraceMap { let mut frames = vec![0; self.max_stack_depth]; bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) - .map_err(|(_, io_error)| MapError::SyscallError { + .map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, })? diff --git a/aya/src/pin.rs b/aya/src/pin.rs index f47d8750..eda85bbc 100644 --- a/aya/src/pin.rs +++ b/aya/src/pin.rs @@ -1,5 +1,6 @@ //! Pinning BPF objects to the BPF filesystem. -use std::io; + +use crate::sys::SyscallError; use thiserror::Error; /// An error ocurred working with a pinned BPF object. @@ -24,12 +25,6 @@ pub enum PinError { error: String, }, /// An error ocurred making a syscall. - #[error("{name} failed")] - SyscallError { - /// The syscall name. - name: &'static str, - /// The [`io::Error`] returned by the syscall. - #[source] - io_error: io::Error, - }, + #[error(transparent)] + SyscallError(#[from] SyscallError), } diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index e3580b28..db8c3ec3 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -8,7 +8,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach}, + sys::{bpf_link_create, bpf_prog_attach, SyscallError}, }; /// A program used to watch or prevent device interaction from a cgroup. @@ -66,7 +66,7 @@ impl CgroupDevice { 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)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -78,7 +78,7 @@ impl CgroupDevice { ))) } else { bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index f67b56fe..dd0f65f4 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -15,7 +15,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach}, + sys::{bpf_link_create, bpf_prog_attach, SyscallError}, VerifierLogLevel, }; @@ -101,7 +101,7 @@ impl CgroupSkb { }; 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)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -113,7 +113,7 @@ impl CgroupSkb { )))) } else { bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index 9d66f9aa..d2427032 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -14,7 +14,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach}, + sys::{bpf_link_create, bpf_prog_attach, SyscallError}, VerifierLogLevel, }; @@ -76,7 +76,7 @@ impl CgroupSock { 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)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -88,7 +88,7 @@ impl CgroupSock { )))) } else { bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 045a40d2..a62a75dc 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -14,7 +14,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach}, + sys::{bpf_link_create, bpf_prog_attach, SyscallError}, VerifierLogLevel, }; @@ -77,7 +77,7 @@ impl CgroupSockAddr { 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)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -89,7 +89,7 @@ impl CgroupSockAddr { ))) } else { bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index 95b89dd7..328868d6 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -14,7 +14,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach}, + sys::{bpf_link_create, bpf_prog_attach, SyscallError}, VerifierLogLevel, }; @@ -74,7 +74,7 @@ impl CgroupSockopt { 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)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -86,7 +86,7 @@ impl CgroupSockopt { ))) } else { bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index 3cd20195..e7cc3e81 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -11,7 +11,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach}, + sys::{bpf_link_create, bpf_prog_attach, SyscallError}, }; /// A program used to watch for sysctl changes. @@ -68,7 +68,7 @@ impl CgroupSysctl { 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)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -80,7 +80,7 @@ impl CgroupSysctl { ))) } else { bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 682d14ad..d40221f7 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -10,7 +10,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd, }, - sys::{self, bpf_link_create}, + sys::{self, bpf_link_create, SyscallError}, Btf, }; @@ -91,7 +91,7 @@ impl Extension { 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)| ProgramError::SyscallError { + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, })? as RawFd; @@ -121,7 +121,7 @@ impl Extension { let prog_fd = self.data.fd_or_err()?; // 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)| ProgramError::SyscallError { + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, })? as RawFd; @@ -151,11 +151,10 @@ impl Extension { /// with the name `func_name` within that BTF object. fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { // retrieve program information - let info = - sys::bpf_prog_get_info_by_fd(prog_fd).map_err(|io_error| ProgramError::SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - })?; + let info = sys::bpf_prog_get_info_by_fd(prog_fd).map_err(|io_error| SyscallError { + call: "bpf_prog_get_info_by_fd", + io_error, + })?; // btf_id refers to the ID of the program btf that was loaded with bpf(BPF_BTF_LOAD) if info.btf_id == 0 { @@ -163,11 +162,10 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr } // the bpf fd of the BTF object - let btf_fd = - sys::bpf_btf_get_fd_by_id(info.btf_id).map_err(|io_error| ProgramError::SyscallError { - call: "bpf_btf_get_fd_by_id", - io_error, - })?; + let btf_fd = sys::bpf_btf_get_fd_by_id(info.btf_id).map_err(|io_error| SyscallError { + call: "bpf_btf_get_fd_by_id", + io_error, + })?; // we need to read the btf bytes into a buffer but we don't know the size ahead of time. // assume 4kb. if this is too small we can resize based on the size obtained in the response. @@ -176,18 +174,17 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr Ok(info) => { if info.btf_size > buf.len() as u32 { buf.resize(info.btf_size as usize, 0u8); - let btf_info = sys::btf_obj_get_info_by_fd(btf_fd, &buf).map_err(|io_error| { - ProgramError::SyscallError { + let btf_info = + sys::btf_obj_get_info_by_fd(btf_fd, &buf).map_err(|io_error| SyscallError { call: "bpf_prog_get_info_by_fd", io_error, - } - })?; + })?; Ok(btf_info) } else { Ok(info) } } - Err(io_error) => Err(ProgramError::SyscallError { + Err(io_error) => Err(SyscallError { call: "bpf_prog_get_info_by_fd", io_error, }), diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index a61f084f..48bcf532 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -10,7 +10,7 @@ use crate::{ probe::{attach, ProbeKind}, FdLink, LinkError, ProgramData, ProgramError, }, - sys::bpf_link_get_info_by_fd, + sys::{bpf_link_get_info_by_fd, SyscallError}, VerifierLogLevel, }; @@ -137,12 +137,10 @@ 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).map_err(|io_error| LinkError::SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - code: 0, - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| SyscallError { + call: "BPF_OBJ_GET_INFO_BY_FD", + io_error, + })?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_KPROBE_MULTI as u32) { return Ok(KProbeLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index 2e727612..21f6f626 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -14,7 +14,7 @@ use crate::{ generated::bpf_attach_type, pin::PinError, programs::ProgramError, - sys::{bpf_get_object, bpf_pin_object, bpf_prog_detach}, + sys::{bpf_get_object, bpf_pin_object, bpf_prog_detach, SyscallError}, }; /// A Link. @@ -152,8 +152,8 @@ impl FdLink { error: e.to_string(), } })?; - bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { - name: "BPF_OBJ_PIN", + bpf_pin_object(self.fd, &path_string).map_err(|(_, io_error)| SyscallError { + call: "BPF_OBJ_PIN", io_error, })?; Ok(PinnedLink::new(PathBuf::from(path.as_ref()), self)) @@ -208,12 +208,12 @@ impl PinnedLink { /// Creates a [`crate::programs::links::PinnedLink`] from a valid path on bpffs. pub fn from_pin>(path: P) -> Result { let path_string = CString::new(path.as_ref().to_string_lossy().to_string()).unwrap(); - let fd = - bpf_get_object(&path_string).map_err(|(code, io_error)| LinkError::SyscallError { + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| { + LinkError::SyscallError(SyscallError { call: "BPF_OBJ_GET", - code, io_error, - })? as RawFd; + }) + })? as RawFd; Ok(PinnedLink::new( path.as_ref().to_path_buf(), FdLink::new(fd), @@ -339,16 +339,8 @@ pub enum LinkError { #[error("Invalid link")] InvalidLink, /// Syscall failed. - #[error("the `{call}` syscall failed with code {code}")] - SyscallError { - /// Syscall Name. - call: &'static str, - /// Error code. - code: libc::c_long, - #[source] - /// Original io::Error. - io_error: io::Error, - }, + #[error(transparent)] + SyscallError(#[from] SyscallError), } #[cfg(test)] diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index ce40eaaa..f97b404e 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -4,7 +4,10 @@ use std::os::fd::{AsRawFd, IntoRawFd as _, 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, bpf_prog_get_info_by_fd}, + sys::{ + bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, + SyscallError, + }, }; use libc::{close, dup}; @@ -65,7 +68,7 @@ impl LircMode2 { let lircdev_fd = lircdev.as_raw_fd(); bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } @@ -96,7 +99,7 @@ impl LircMode2 { let mut prog_fds = Vec::with_capacity(prog_ids.len()); for id in prog_ids { - let fd = bpf_prog_get_fd_by_id(id).map_err(|io_error| ProgramError::SyscallError { + let fd = bpf_prog_get_fd_by_id(id).map_err(|io_error| SyscallError { call: "bpf_prog_get_fd_by_id", io_error, })?; @@ -132,13 +135,15 @@ impl LircLink { /// Get ProgramInfo from this link pub fn info(&self) -> Result { - match bpf_prog_get_info_by_fd(self.prog_fd) { - Ok(info) => Ok(ProgramInfo(info)), - Err(io_error) => Err(ProgramError::SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - }), - } + bpf_prog_get_info_by_fd(self.prog_fd) + .map(ProgramInfo) + .map_err(|io_error| { + SyscallError { + call: "bpf_prog_get_info_by_fd", + io_error, + } + .into() + }) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 1ea52b7c..0947c8fd 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -64,7 +64,6 @@ pub mod uprobe; mod utils; pub mod xdp; -use crate::util::KernelVersion; use libc::ENOSPC; use std::{ ffi::CString, @@ -112,8 +111,9 @@ use crate::{ sys::{ bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_get_next_id, bpf_prog_query, - retry_with_verifier_logs, BpfLoadProgramAttrs, + retry_with_verifier_logs, BpfLoadProgramAttrs, SyscallError, }, + util::KernelVersion, VerifierLogLevel, }; @@ -147,14 +147,8 @@ pub enum ProgramError { }, /// A syscall failed. - #[error("`{call}` failed")] - SyscallError { - /// The name of the syscall which failed. - call: &'static str, - /// The [`io::Error`] returned by the syscall. - #[source] - io_error: io::Error, - }, + #[error(transparent)] + SyscallError(#[from] SyscallError), /// The network interface does not exist. #[error("unknown network interface {name}")] @@ -456,12 +450,11 @@ impl ProgramData { None }; let attach_btf_obj_fd = if info.attach_btf_obj_id > 0 { - let fd = bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| { - ProgramError::SyscallError { + let fd = + bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| SyscallError { call: "bpf_btf_get_fd_by_id", io_error, - } - })?; + })?; Some(fd as u32) } else { None @@ -489,13 +482,12 @@ impl ProgramData { ) -> Result, ProgramError> { let path_string = CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap(); - let fd = - bpf_get_object(&path_string).map_err(|(_, io_error)| ProgramError::SyscallError { - call: "bpf_obj_get", - io_error, - })? as RawFd; + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { + call: "bpf_obj_get", + io_error, + })? as RawFd; - let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| ProgramError::SyscallError { + let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| SyscallError { call: "bpf_prog_get_info_by_fd", io_error, })?; @@ -537,8 +529,8 @@ fn pin_program>(data: &ProgramData, path: P) -> Resul error: e.to_string(), } })?; - bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError { - name: "BPF_OBJ_PIN", + bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError { + call: "BPF_OBJ_PIN", io_error, })?; Ok(()) @@ -665,15 +657,17 @@ pub(crate) fn query( prog_ids.resize(prog_cnt as usize, 0); return Ok(prog_ids); } - Err((_, io_error)) if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) => { - prog_ids.resize(prog_cnt as usize, 0); - retries += 1; - } Err((_, io_error)) => { - return Err(ProgramError::SyscallError { - call: "bpf_prog_query", - io_error, - }); + if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) { + prog_ids.resize(prog_cnt as usize, 0); + retries += 1; + } else { + return Err(SyscallError { + call: "bpf_prog_query", + io_error, + } + .into()); + } } } } @@ -951,24 +945,22 @@ impl ProgramInfo { /// /// The returned fd must be closed when no longer needed. pub fn fd(&self) -> Result { - let fd = - bpf_prog_get_fd_by_id(self.0.id).map_err(|io_error| ProgramError::SyscallError { - call: "bpf_prog_get_fd_by_id", - io_error, - })?; + let fd = bpf_prog_get_fd_by_id(self.0.id).map_err(|io_error| SyscallError { + call: "bpf_prog_get_fd_by_id", + io_error, + })?; Ok(fd.into_raw_fd()) } /// Loads a program from a pinned path in bpffs. pub fn from_pin>(path: P) -> Result { let path_string = CString::new(path.as_ref().to_str().unwrap()).unwrap(); - let fd = - bpf_get_object(&path_string).map_err(|(_, io_error)| ProgramError::SyscallError { - call: "BPF_OBJ_GET", - io_error, - })? as RawFd; + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { + call: "BPF_OBJ_GET", + io_error, + })? as RawFd; - let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| ProgramError::SyscallError { + let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| SyscallError { call: "bpf_prog_get_info_by_fd", io_error, })?; @@ -999,18 +991,19 @@ impl Iterator for ProgramsIter { self.current = next; Some( bpf_prog_get_fd_by_id(next) - .map_err(|io_error| ProgramError::SyscallError { + .map_err(|io_error| SyscallError { call: "bpf_prog_get_fd_by_id", io_error, }) .and_then(|fd| { bpf_prog_get_info_by_fd(fd.as_raw_fd()) - .map_err(|io_error| ProgramError::SyscallError { + .map_err(|io_error| SyscallError { call: "bpf_prog_get_info_by_fd", io_error, }) .map(ProgramInfo) - }), + }) + .map_err(Into::into), ) } Ok(None) => None, @@ -1018,10 +1011,11 @@ impl Iterator for ProgramsIter { // If getting the next program failed, we have to yield None in our next // iteration to avoid an infinite loop. self.error = true; - Some(Err(ProgramError::SyscallError { + Some(Err(SyscallError { call: "bpf_prog_get_fd_by_id", io_error, - })) + } + .into())) } } } diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index 27db311c..d709d331 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -7,7 +7,7 @@ use crate::{ probe::{detach_debug_fs, ProbeEvent}, FdLink, Link, ProgramError, }, - sys::{bpf_link_create, perf_event_ioctl, SysResult}, + sys::{bpf_link_create, perf_event_ioctl, SysResult, SyscallError}, FEATURES, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF, }; @@ -73,7 +73,7 @@ impl Link for PerfLink { pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result { if FEATURES.bpf_perf_link() { let link_fd = bpf_link_create(prog_fd, fd.as_raw_fd(), BPF_PERF_EVENT, None, 0).map_err( - |(_, io_error)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -98,13 +98,13 @@ fn perf_attach_either( event: Option, ) -> Result { perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "PERF_EVENT_IOC_SET_BPF", io_error, } })?; perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "PERF_EVENT_IOC_ENABLE", io_error, } diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index 5d104499..5122901e 100644 --- a/aya/src/programs/perf_event.rs +++ b/aya/src/programs/perf_event.rs @@ -19,7 +19,7 @@ use crate::{ perf_attach::{PerfLinkIdInner, PerfLinkInner}, FdLink, LinkError, ProgramData, ProgramError, }, - sys::{bpf_link_get_info_by_fd, perf_event_open}, + sys::{bpf_link_get_info_by_fd, perf_event_open, SyscallError}, }; /// The type of perf event @@ -165,7 +165,7 @@ impl PerfEvent { false, 0, ) - .map_err(|(_code, io_error)| ProgramError::SyscallError { + .map_err(|(_code, io_error)| SyscallError { call: "perf_event_open", io_error, })?; @@ -206,12 +206,10 @@ 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).map_err(|io_error| LinkError::SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - code: 0, - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| SyscallError { + call: "BPF_OBJ_GET_INFO_BY_FD", + io_error, + })?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_PERF_EVENT as u32) { return Ok(PerfEventLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index 5b002e7e..fa04d31d 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -15,7 +15,7 @@ use crate::{ trace_point::read_sys_fs_trace_point_id, uprobe::UProbeError, utils::find_tracefs_path, Link, ProgramData, ProgramError, }, - sys::{perf_event_open_probe, perf_event_open_trace_point}, + sys::{perf_event_open_probe, perf_event_open_trace_point, SyscallError}, }; static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0); @@ -118,10 +118,11 @@ fn create_as_probe( }; perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid).map_err(|(_code, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "perf_event_open", io_error, } + .into() }) } @@ -144,11 +145,9 @@ fn create_as_trace_point( let category = format!("{}s", kind.pmu()); let tpid = read_sys_fs_trace_point_id(tracefs, &category, &event_alias)?; - let fd = perf_event_open_trace_point(tpid, pid).map_err(|(_code, io_error)| { - ProgramError::SyscallError { - call: "perf_event_open", - io_error, - } + let fd = perf_event_open_trace_point(tpid, pid).map_err(|(_code, io_error)| SyscallError { + call: "perf_event_open", + io_error, })?; Ok((fd, event_alias)) diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index 27d60b8f..b0dd3811 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -3,7 +3,7 @@ use std::os::fd::{AsRawFd, RawFd}; 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, + sys::{bpf_link_create, SyscallError}, }; use super::links::FdLink; @@ -65,7 +65,7 @@ impl SkLookup { let netns_fd = netns.as_raw_fd(); let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err( - |(_, io_error)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index fc6202ba..93819fbe 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -9,7 +9,7 @@ use crate::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, }, - sys::bpf_prog_attach, + sys::{bpf_prog_attach, SyscallError}, }; /// A program used to intercept messages sent with `sendmsg()`/`sendfile()`. @@ -83,7 +83,7 @@ impl SkMsg { let map_fd = map.as_raw_fd(); bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index 162d74d0..70960265 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -12,7 +12,7 @@ use crate::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, }, - sys::bpf_prog_attach, + sys::{bpf_prog_attach, SyscallError}, VerifierLogLevel, }; @@ -79,11 +79,9 @@ impl SkSkb { 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)| { - ProgramError::SyscallError { - call: "bpf_prog_attach", - io_error, - } + 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, diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index fe8dccc0..16e71677 100644 --- a/aya/src/programs/sock_ops.rs +++ b/aya/src/programs/sock_ops.rs @@ -7,7 +7,7 @@ use crate::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, }, - sys::bpf_prog_attach, + sys::{bpf_prog_attach, SyscallError}, }; /// A program used to work with sockets. @@ -63,7 +63,7 @@ impl SockOps { let cgroup_fd = cgroup.as_raw_fd(); bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_prog_attach", io_error, } diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 8e4608c1..2970dc86 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -10,7 +10,7 @@ use crate::{ utils::find_tracefs_path, FdLink, LinkError, ProgramData, ProgramError, }, - sys::{bpf_link_get_info_by_fd, perf_event_open_trace_point}, + sys::{bpf_link_get_info_by_fd, perf_event_open_trace_point, SyscallError}, }; /// The type returned when attaching a [`TracePoint`] fails. @@ -80,12 +80,11 @@ impl TracePoint { pub fn attach(&mut self, category: &str, name: &str) -> Result { let tracefs = find_tracefs_path()?; let id = read_sys_fs_trace_point_id(tracefs, category, name)?; - let fd = perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| { - ProgramError::SyscallError { + let fd = + perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| SyscallError { call: "perf_event_open_trace_point", io_error, - } - })?; + })?; let link = perf_attach(self.data.fd_or_err()?, fd)?; self.data.links.insert(TracePointLink::new(link)) @@ -132,12 +131,10 @@ 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).map_err(|io_error| LinkError::SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - code: 0, - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| SyscallError { + call: "BPF_OBJ_GET_INFO_BY_FD", + io_error, + })?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { return Ok(TracePointLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index bab82d4b..c52e8101 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -21,7 +21,7 @@ use crate::{ probe::{attach, ProbeKind}, FdLink, LinkError, ProgramData, ProgramError, }, - sys::bpf_link_get_info_by_fd, + sys::{bpf_link_get_info_by_fd, SyscallError}, VerifierLogLevel, }; @@ -177,12 +177,10 @@ 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).map_err(|io_error| LinkError::SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - code: 0, - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| SyscallError { + call: "BPF_OBJ_GET_INFO_BY_FD", + io_error, + })?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { return Ok(UProbeLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/utils.rs b/aya/src/programs/utils.rs index 69fc616e..038fd24f 100644 --- a/aya/src/programs/utils.rs +++ b/aya/src/programs/utils.rs @@ -3,7 +3,7 @@ use std::{ffi::CStr, io, os::fd::RawFd, path::Path}; use crate::{ programs::{FdLink, Link, ProgramData, ProgramError}, - sys::bpf_raw_tracepoint_open, + sys::{bpf_raw_tracepoint_open, SyscallError}, }; /// Attaches the program to a raw tracepoint. @@ -13,12 +13,11 @@ pub(crate) fn attach_raw_tracepoint>( ) -> Result { let prog_fd = program_data.fd_or_err()?; - let pfd = bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| { - ProgramError::SyscallError { + let pfd = + bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| SyscallError { call: "bpf_raw_tracepoint_open", io_error, - } - })? as RawFd; + })? as RawFd; program_data.links.insert(FdLink::new(pfd).into()) } diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 9372b281..5a90e028 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -1,6 +1,6 @@ //! eXpress Data Path (XDP) programs. -use crate::util::KernelVersion; +use crate::{sys::SyscallError, util::KernelVersion}; use bitflags; use libc::if_nametoindex; use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::fd::RawFd}; @@ -127,7 +127,7 @@ impl Xdp { if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) { let link_fd = bpf_link_create(prog_fd, if_index, BPF_XDP, None, flags.bits()).map_err( - |(_, io_error)| ProgramError::SyscallError { + |(_, io_error)| SyscallError { call: "bpf_link_create", io_error, }, @@ -173,7 +173,7 @@ impl Xdp { XdpLinkInner::FdLink(fd_link) => { let link_fd = fd_link.fd; bpf_link_update(link_fd, prog_fd, None, 0).map_err(|(_, io_error)| { - ProgramError::SyscallError { + SyscallError { call: "bpf_link_update", io_error, } @@ -279,12 +279,10 @@ impl TryFrom for XdpLink { 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).map_err(|io_error| LinkError::SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - code: 0, - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| SyscallError { + call: "BPF_OBJ_GET_INFO_BY_FD", + io_error, + })?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_XDP as u32) { return Ok(XdpLink::new(XdpLinkInner::FdLink(fd_link))); } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index ae68991e..b05ea79a 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -905,7 +905,7 @@ pub(crate) fn is_btf_type_tag_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } -pub fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { +fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } diff --git a/aya/src/sys/mod.rs b/aya/src/sys/mod.rs index b64d76b3..ef2a0edf 100644 --- a/aya/src/sys/mod.rs +++ b/aya/src/sys/mod.rs @@ -5,12 +5,12 @@ mod perf_event; #[cfg(test)] mod fake; +use libc::{c_int, c_long, pid_t, SYS_bpf, SYS_perf_event_open}; use std::{ io, mem, os::fd::{AsRawFd as _, BorrowedFd}, }; - -use libc::{c_int, c_long, pid_t, SYS_bpf, SYS_perf_event_open}; +use thiserror::Error; pub(crate) use bpf::*; #[cfg(test)] @@ -43,6 +43,16 @@ pub(crate) enum Syscall<'a> { }, } +#[derive(Debug, Error)] +#[error("`{call}` failed")] +pub struct SyscallError { + /// The name of the syscall which failed. + pub(crate) call: &'static str, + /// The [`io::Error`] returned by the syscall. + #[source] + pub(crate) io_error: io::Error, +} + impl std::fmt::Debug for Syscall<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index a32ec8a5..da13c4a7 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -996,9 +996,7 @@ pub aya::maps::MapError::PinError pub aya::maps::MapError::PinError::error: aya::pin::PinError pub aya::maps::MapError::PinError::name: core::option::Option pub aya::maps::MapError::ProgramNotLoaded -pub aya::maps::MapError::SyscallError -pub aya::maps::MapError::SyscallError::call: &'static str -pub aya::maps::MapError::SyscallError::io_error: std::io::error::Error +pub aya::maps::MapError::SyscallError(crate::sys::SyscallError) pub aya::maps::MapError::Unsupported pub aya::maps::MapError::Unsupported::map_type: u32 impl core::convert::From for aya::BpfError @@ -1764,9 +1762,7 @@ pub aya::pin::PinError::InvalidPinPath pub aya::pin::PinError::InvalidPinPath::error: alloc::string::String pub aya::pin::PinError::NoFd pub aya::pin::PinError::NoFd::name: alloc::string::String -pub aya::pin::PinError::SyscallError -pub aya::pin::PinError::SyscallError::io_error: std::io::error::Error -pub aya::pin::PinError::SyscallError::name: &'static str +pub aya::pin::PinError::SyscallError(crate::sys::SyscallError) impl core::error::Error for aya::pin::PinError pub fn aya::pin::PinError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> impl core::fmt::Display for aya::pin::PinError @@ -3008,10 +3004,7 @@ pub fn aya::programs::kprobe::KProbeLinkId::from(t: T) -> T pub mod aya::programs::links pub enum aya::programs::links::LinkError pub aya::programs::links::LinkError::InvalidLink -pub aya::programs::links::LinkError::SyscallError -pub aya::programs::links::LinkError::SyscallError::call: &'static str -pub aya::programs::links::LinkError::SyscallError::code: libc::unix::linux_like::linux::gnu::b64::x86_64::not_x32::c_long -pub aya::programs::links::LinkError::SyscallError::io_error: std::io::error::Error +pub aya::programs::links::LinkError::SyscallError(crate::sys::SyscallError) impl core::error::Error for aya::programs::links::LinkError pub fn aya::programs::links::LinkError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> impl core::fmt::Display for aya::programs::links::LinkError @@ -5174,9 +5167,7 @@ pub aya::programs::ProgramError::MapError(aya::maps::MapError) pub aya::programs::ProgramError::NotAttached pub aya::programs::ProgramError::NotLoaded pub aya::programs::ProgramError::SocketFilterError(aya::programs::SocketFilterError) -pub aya::programs::ProgramError::SyscallError -pub aya::programs::ProgramError::SyscallError::call: &'static str -pub aya::programs::ProgramError::SyscallError::io_error: std::io::error::Error +pub aya::programs::ProgramError::SyscallError(crate::sys::SyscallError) pub aya::programs::ProgramError::TcError(aya::programs::tc::TcError) pub aya::programs::ProgramError::TracePointError(aya::programs::trace_point::TracePointError) pub aya::programs::ProgramError::UProbeError(aya::programs::uprobe::UProbeError) From a0af7e0b2fddaf297887c3e4c7480ef625c88ada Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 1 Aug 2023 13:20:02 -0400 Subject: [PATCH 3/6] programs: make `loaded_programs` opaque --- aya/src/programs/mod.rs | 74 ++++++++++------------------------------ aya/src/sys/bpf.rs | 39 +++++++++++++++++---- xtask/public-api/aya.txt | 33 ++---------------- 3 files changed, 53 insertions(+), 93 deletions(-) diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 0947c8fd..20eac41f 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -110,7 +110,7 @@ use crate::{ pin::PinError, sys::{ bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object, - bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_get_next_id, bpf_prog_query, + bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_query, iter_prog_ids, retry_with_verifier_logs, BpfLoadProgramAttrs, SyscallError, }, util::KernelVersion, @@ -971,56 +971,6 @@ impl ProgramInfo { } } -/// ProgramsIter is an Iterator over loaded eBPF programs. -pub struct ProgramsIter { - current: u32, - error: bool, -} - -impl Iterator for ProgramsIter { - type Item = Result; - - fn next(&mut self) -> Option { - if self.error { - return None; - } - let current = self.current; - - match bpf_prog_get_next_id(current) { - Ok(Some(next)) => { - self.current = next; - Some( - bpf_prog_get_fd_by_id(next) - .map_err(|io_error| SyscallError { - call: "bpf_prog_get_fd_by_id", - io_error, - }) - .and_then(|fd| { - bpf_prog_get_info_by_fd(fd.as_raw_fd()) - .map_err(|io_error| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - }) - .map(ProgramInfo) - }) - .map_err(Into::into), - ) - } - Ok(None) => None, - Err((_, io_error)) => { - // If getting the next program failed, we have to yield None in our next - // iteration to avoid an infinite loop. - self.error = true; - Some(Err(SyscallError { - call: "bpf_prog_get_fd_by_id", - io_error, - } - .into())) - } - } - } -} - /// Returns an iterator over all loaded bpf programs. /// /// This differs from [`crate::Bpf::programs`] since it will return all programs @@ -1044,9 +994,21 @@ impl Iterator for ProgramsIter { /// next program id, get the program fd, or the [`ProgramInfo`] fail. In cases where /// iteration can't be performed, for example the caller does not have the necessary privileges, /// a single item will be yielded containing the error that occurred. -pub fn loaded_programs() -> ProgramsIter { - ProgramsIter { - current: 0, - error: false, - } +pub fn loaded_programs() -> impl Iterator> { + iter_prog_ids() + .map(|id| { + let id = id?; + bpf_prog_get_fd_by_id(id).map_err(|io_error| SyscallError { + call: "bpf_prog_get_fd_by_id", + io_error, + }) + }) + .map(|fd| { + let fd = fd?; + bpf_prog_get_info_by_fd(fd.as_raw_fd()).map_err(|io_error| SyscallError { + call: "bpf_prog_get_info_by_fd", + io_error, + }) + }) + .map(|result| result.map(ProgramInfo).map_err(Into::into)) } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index b05ea79a..f315eacc 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -1,7 +1,7 @@ use std::{ cmp::{self, min}, ffi::{CStr, CString}, - io, + io, iter, mem::{self, MaybeUninit}, os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, @@ -28,7 +28,7 @@ use crate::{ }, copy_instructions, }, - sys::{syscall, SysResult, Syscall}, + sys::{syscall, SysResult, Syscall, SyscallError}, Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, }; @@ -909,17 +909,44 @@ fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } -pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result, (c_long, io::Error)> { +fn bpf_prog_get_next_id(id: u32) -> Result, SyscallError> { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_6 }; u.__bindgen_anon_1.start_id = id; match sys_bpf(bpf_cmd::BPF_PROG_GET_NEXT_ID, &mut attr) { - Ok(_) => Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })), - Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None), - Err(e) => Err(e), + Ok(code) => { + assert_eq!(code, 0); + Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })) + } + Err((code, io_error)) => { + assert_eq!(code, -1); + if io_error.raw_os_error() == Some(ENOENT) { + Ok(None) + } else { + Err(SyscallError { + call: "bpf_prog_get_next_id", + io_error, + }) + } + } } } +pub(crate) fn iter_prog_ids() -> impl Iterator> { + let mut current_id = Some(0); + iter::from_fn(move || { + let next_id = { + let current_id = current_id?; + bpf_prog_get_next_id(current_id).transpose() + }; + current_id = next_id.as_ref().and_then(|next_id| match next_id { + Ok(next_id) => Some(*next_id), + Err(SyscallError { .. }) => None, + }); + next_id + }) +} + pub(crate) fn retry_with_verifier_logs( max_retries: usize, f: impl Fn(&mut [u8]) -> SysResult, diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index da13c4a7..a545bd61 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -6228,35 +6228,6 @@ impl core::borrow::BorrowMut for aya::programs::ProgramInfo where T: core: pub fn aya::programs::ProgramInfo::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::programs::ProgramInfo pub fn aya::programs::ProgramInfo::from(t: T) -> T -pub struct aya::programs::ProgramsIter -impl core::iter::traits::iterator::Iterator for aya::programs::ProgramsIter -pub type aya::programs::ProgramsIter::Item = core::result::Result -pub fn aya::programs::ProgramsIter::next(&mut self) -> core::option::Option -impl core::marker::Send for aya::programs::ProgramsIter -impl core::marker::Sync for aya::programs::ProgramsIter -impl core::marker::Unpin for aya::programs::ProgramsIter -impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramsIter -impl core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramsIter -impl core::iter::traits::collect::IntoIterator for aya::programs::ProgramsIter where I: core::iter::traits::iterator::Iterator -pub type aya::programs::ProgramsIter::IntoIter = I -pub type aya::programs::ProgramsIter::Item = ::Item -pub fn aya::programs::ProgramsIter::into_iter(self) -> I -impl core::convert::Into for aya::programs::ProgramsIter where U: core::convert::From -pub fn aya::programs::ProgramsIter::into(self) -> U -impl core::convert::TryFrom for aya::programs::ProgramsIter where U: core::convert::Into -pub type aya::programs::ProgramsIter::Error = core::convert::Infallible -pub fn aya::programs::ProgramsIter::try_from(value: U) -> core::result::Result>::Error> -impl core::convert::TryInto for aya::programs::ProgramsIter where U: core::convert::TryFrom -pub type aya::programs::ProgramsIter::Error = >::Error -pub fn aya::programs::ProgramsIter::try_into(self) -> core::result::Result>::Error> -impl core::any::Any for aya::programs::ProgramsIter where T: 'static + core::marker::Sized -pub fn aya::programs::ProgramsIter::type_id(&self) -> core::any::TypeId -impl core::borrow::Borrow for aya::programs::ProgramsIter where T: core::marker::Sized -pub fn aya::programs::ProgramsIter::borrow(&self) -> &T -impl core::borrow::BorrowMut for aya::programs::ProgramsIter where T: core::marker::Sized -pub fn aya::programs::ProgramsIter::borrow_mut(&mut self) -> &mut T -impl core::convert::From for aya::programs::ProgramsIter -pub fn aya::programs::ProgramsIter::from(t: T) -> T pub struct aya::programs::RawTracePoint impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::attach(&mut self, tp_name: &str) -> core::result::Result @@ -6919,7 +6890,7 @@ impl aya::programs::links::Link for aya::programs::xdp::XdpLink pub type aya::programs::xdp::XdpLink::Id = aya::programs::xdp::XdpLinkId pub fn aya::programs::xdp::XdpLink::detach(self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::XdpLink::id(&self) -> Self::Id -pub fn aya::programs::loaded_programs() -> aya::programs::ProgramsIter +pub fn aya::programs::loaded_programs() -> impl core::iter::traits::iterator::Iterator> pub mod aya::util pub struct aya::util::KernelVersion impl aya::util::KernelVersion @@ -7250,4 +7221,4 @@ impl aya::Pod for u8 impl aya::Pod for aya::maps::lpm_trie::Key impl aya::Pod for [T; N] pub fn aya::features() -> &'static aya_obj::obj::Features -pub fn aya::loaded_programs() -> aya::programs::ProgramsIter +pub fn aya::loaded_programs() -> impl core::iter::traits::iterator::Iterator> From b1404e9a73aee4cdf93e96b44d35057ae1f6f079 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 1 Aug 2023 13:31:50 -0400 Subject: [PATCH 4/6] sys: push error construction up --- aya/src/maps/mod.rs | 10 ++---- aya/src/programs/extension.rs | 5 +-- aya/src/programs/kprobe.rs | 7 ++-- aya/src/programs/lirc_mode2.rs | 14 ++------ aya/src/programs/mod.rs | 27 ++++---------- aya/src/programs/perf_event.rs | 5 +-- aya/src/programs/trace_point.rs | 5 +-- aya/src/programs/uprobe.rs | 7 ++-- aya/src/programs/xdp.rs | 5 +-- aya/src/sys/bpf.rs | 64 ++++++++++++++++----------------- 10 files changed, 50 insertions(+), 99 deletions(-) diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 27c4c7f2..f5c7072f 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -560,10 +560,7 @@ impl MapData { io_error, })? as RawFd; - let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| SyscallError { - call: "BPF_MAP_GET_INFO_BY_FD", - io_error, - })?; + let info = bpf_map_get_info_by_fd(fd)?; Ok(MapData { obj: parse_map_info(info, PinningType::ByName), @@ -579,10 +576,7 @@ impl MapData { /// This API is intended for cases where you have received a valid BPF FD from some other means. /// For example, you received an FD over Unix Domain Socket. pub fn from_fd(fd: RawFd) -> Result { - let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| SyscallError { - call: "BPF_OBJ_GET", - io_error, - })?; + let info = bpf_map_get_info_by_fd(fd)?; Ok(MapData { obj: parse_map_info(info, PinningType::None), diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index d40221f7..60453c40 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -151,10 +151,7 @@ impl Extension { /// with the name `func_name` within that BTF object. fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { // retrieve program information - let info = sys::bpf_prog_get_info_by_fd(prog_fd).map_err(|io_error| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - })?; + let info = sys::bpf_prog_get_info_by_fd(prog_fd)?; // btf_id refers to the ID of the program btf that was loaded with bpf(BPF_BTF_LOAD) if info.btf_id == 0 { diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index 48bcf532..a0923a67 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -10,7 +10,7 @@ use crate::{ probe::{attach, ProbeKind}, FdLink, LinkError, ProgramData, ProgramError, }, - sys::{bpf_link_get_info_by_fd, SyscallError}, + sys::bpf_link_get_info_by_fd, VerifierLogLevel, }; @@ -137,10 +137,7 @@ 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).map_err(|io_error| SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd)?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_KPROBE_MULTI as u32) { return Ok(KProbeLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index f97b404e..e39bbf1a 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -99,11 +99,7 @@ impl LircMode2 { let mut prog_fds = Vec::with_capacity(prog_ids.len()); for id in prog_ids { - let fd = bpf_prog_get_fd_by_id(id).map_err(|io_error| SyscallError { - call: "bpf_prog_get_fd_by_id", - io_error, - })?; - + let fd = bpf_prog_get_fd_by_id(id)?; prog_fds.push(fd); } @@ -137,13 +133,7 @@ impl LircLink { pub fn info(&self) -> Result { bpf_prog_get_info_by_fd(self.prog_fd) .map(ProgramInfo) - .map_err(|io_error| { - SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - } - .into() - }) + .map_err(Into::into) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 20eac41f..a257427b 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -487,11 +487,7 @@ impl ProgramData { io_error, })? as RawFd; - let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - })?; - + let info = bpf_prog_get_info_by_fd(fd)?; let name = ProgramInfo(info).name_as_str().map(|s| s.to_string()); ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info, verifier_log_level) } @@ -945,10 +941,8 @@ impl ProgramInfo { /// /// The returned fd must be closed when no longer needed. pub fn fd(&self) -> Result { - let fd = bpf_prog_get_fd_by_id(self.0.id).map_err(|io_error| SyscallError { - call: "bpf_prog_get_fd_by_id", - io_error, - })?; + let Self(info) = self; + let fd = bpf_prog_get_fd_by_id(info.id)?; Ok(fd.into_raw_fd()) } @@ -960,10 +954,7 @@ impl ProgramInfo { io_error, })? as RawFd; - let info = bpf_prog_get_info_by_fd(fd).map_err(|io_error| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - })?; + let info = bpf_prog_get_info_by_fd(fd)?; unsafe { libc::close(fd); } @@ -998,17 +989,11 @@ pub fn loaded_programs() -> impl Iterator for PerfEventLink { type Error = LinkError; fn try_from(fd_link: FdLink) -> Result { - let info = bpf_link_get_info_by_fd(fd_link.fd).map_err(|io_error| SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd)?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_PERF_EVENT as u32) { return Ok(PerfEventLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 2970dc86..f52594d8 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -131,10 +131,7 @@ 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).map_err(|io_error| SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd)?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { return Ok(TracePointLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index c52e8101..c67a124d 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -21,7 +21,7 @@ use crate::{ probe::{attach, ProbeKind}, FdLink, LinkError, ProgramData, ProgramError, }, - sys::{bpf_link_get_info_by_fd, SyscallError}, + sys::bpf_link_get_info_by_fd, VerifierLogLevel, }; @@ -177,10 +177,7 @@ 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).map_err(|io_error| SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd)?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { return Ok(UProbeLink::new(PerfLinkInner::FdLink(fd_link))); } diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 5a90e028..3542e97a 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -279,10 +279,7 @@ impl TryFrom for XdpLink { 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).map_err(|io_error| SyscallError { - call: "BPF_OBJ_GET_INFO_BY_FD", - io_error, - })?; + let info = bpf_link_get_info_by_fd(fd_link.fd)?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_XDP as u32) { return Ok(XdpLink::new(XdpLinkInner::FdLink(fd_link))); } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index f315eacc..c6ee9e30 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -460,57 +460,57 @@ pub(crate) fn bpf_prog_query( ret } -pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result { +pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result { let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id; // SAFETY: BPF_PROG_GET_FD_BY_ID returns a new file descriptor. - unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &mut attr).map_err(|(_, e)| e) } + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_prog_get_fd_by_id", + io_error, + } + }) } -pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result { +fn bpf_obj_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { let mut attr = unsafe { mem::zeroed::() }; // info gets entirely populated by the kernel let info = MaybeUninit::zeroed(); - attr.info.bpf_fd = prog_fd as u32; + attr.info.bpf_fd = fd.as_raw_fd() as u32; attr.info.info = &info as *const _ as u64; - attr.info.info_len = mem::size_of::() as u32; + attr.info.info_len = mem::size_of_val(&info) as u32; match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { - Ok(_) => Ok(unsafe { info.assume_init() }), - Err((_, err)) => Err(err), + Ok(code) => { + assert_eq!(code, 0); + Ok(unsafe { info.assume_init() }) + } + Err((code, io_error)) => { + assert_eq!(code, -1); + Err(SyscallError { + call: "bpf_obj_get_info_by_fd", + io_error, + }) + } } } -pub(crate) fn bpf_map_get_info_by_fd(prog_fd: RawFd) -> Result { - let mut attr = unsafe { mem::zeroed::() }; - // info gets entirely populated by the kernel - let info = MaybeUninit::zeroed(); - - attr.info.bpf_fd = prog_fd as u32; - attr.info.info = info.as_ptr() as *const _ as u64; - attr.info.info_len = mem::size_of::() as u32; - - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { - Ok(_) => Ok(unsafe { info.assume_init() }), - Err((_, err)) => Err(err), - } +pub(crate) fn bpf_prog_get_info_by_fd(fd: RawFd) -> Result { + let fd = unsafe { BorrowedFd::borrow_raw(fd) }; + bpf_obj_get_info_by_fd::(fd) } -pub(crate) fn bpf_link_get_info_by_fd(link_fd: RawFd) -> Result { - let mut attr = unsafe { mem::zeroed::() }; - // info gets entirely populated by the kernel - let info = unsafe { MaybeUninit::zeroed().assume_init() }; - - attr.info.bpf_fd = link_fd as u32; - attr.info.info = &info as *const _ as u64; - attr.info.info_len = mem::size_of::() as u32; +pub(crate) fn bpf_map_get_info_by_fd(fd: RawFd) -> Result { + let fd = unsafe { BorrowedFd::borrow_raw(fd) }; + bpf_obj_get_info_by_fd::(fd) +} - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { - Ok(_) => Ok(info), - Err((_, err)) => Err(err), - } +pub(crate) fn bpf_link_get_info_by_fd(fd: RawFd) -> Result { + let fd = unsafe { BorrowedFd::borrow_raw(fd) }; + bpf_obj_get_info_by_fd::(fd) } pub(crate) fn btf_obj_get_info_by_fd( From 7bb9b7f5a5f03e815a5274457a93d0b20677059f Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 1 Aug 2023 13:38:07 -0400 Subject: [PATCH 5/6] programs: plug file descriptor leak This leaked a file descriptor if bpf_prog_get_info_by_fd failed. --- aya/src/programs/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index a257427b..95a45f62 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -954,10 +954,11 @@ impl ProgramInfo { io_error, })? as RawFd; - let info = bpf_prog_get_info_by_fd(fd)?; + let info = bpf_prog_get_info_by_fd(fd); unsafe { libc::close(fd); } + let info = info?; Ok(ProgramInfo(info)) } } From 30faa5f68f362b385b9ca96ff300dffcfd774033 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 1 Aug 2023 11:39:31 -0400 Subject: [PATCH 6/6] Add links iterator This is not yet exposed in documentation, but is complete enough for use in tests, removing the dependency on bpftool. Updates #645. --- aya/src/programs/mod.rs | 25 ++- aya/src/sys/bpf.rs | 39 ++++- test/README.md | 3 - test/integration-test/src/tests/load.rs | 198 ++++++++++++------------ test/run.sh | 2 - 5 files changed, 157 insertions(+), 110 deletions(-) diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 95a45f62..ed90c788 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -104,14 +104,15 @@ pub use uprobe::{UProbe, UProbeError}; pub use xdp::{Xdp, XdpError, XdpFlags}; use crate::{ - generated::{bpf_attach_type, bpf_prog_info, bpf_prog_type}, + generated::{bpf_attach_type, bpf_link_info, bpf_prog_info, bpf_prog_type}, maps::MapError, obj::{self, btf::BtfError, Function, VerifierLog}, pin::PinError, sys::{ - bpf_btf_get_fd_by_id, bpf_get_object, bpf_load_program, bpf_pin_object, - bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_query, iter_prog_ids, - retry_with_verifier_logs, BpfLoadProgramAttrs, SyscallError, + bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd, + bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, + bpf_prog_query, iter_link_ids, iter_prog_ids, retry_with_verifier_logs, + BpfLoadProgramAttrs, SyscallError, }, util::KernelVersion, VerifierLogLevel, @@ -998,3 +999,19 @@ pub fn loaded_programs() -> impl Iterator impl Iterator> { + iter_link_ids() + .map(|id| { + let id = id?; + bpf_link_get_fd_by_id(id) + }) + .map(|fd| { + let fd = fd?; + bpf_link_get_info_by_fd(fd.as_raw_fd()) + }) + .map(|result| result.map_err(Into::into)) +} diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index c6ee9e30..e88771a7 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -508,6 +508,20 @@ pub(crate) fn bpf_map_get_info_by_fd(fd: RawFd) -> Result(fd) } +pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result { + let mut attr = unsafe { mem::zeroed::() }; + + attr.__bindgen_anon_6.__bindgen_anon_1.link_id = link_id; + // SAFETY: BPF_LINK_GET_FD_BY_ID returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_LINK_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_link_get_fd_by_id", + io_error, + } + }) +} + pub(crate) fn bpf_link_get_info_by_fd(fd: RawFd) -> Result { let fd = unsafe { BorrowedFd::borrow_raw(fd) }; bpf_obj_get_info_by_fd::(fd) @@ -909,11 +923,15 @@ fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } -fn bpf_prog_get_next_id(id: u32) -> Result, SyscallError> { +fn bpf_obj_get_next_id( + id: u32, + cmd: bpf_cmd, + name: &'static str, +) -> Result, SyscallError> { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_6 }; u.__bindgen_anon_1.start_id = id; - match sys_bpf(bpf_cmd::BPF_PROG_GET_NEXT_ID, &mut attr) { + match sys_bpf(cmd, &mut attr) { Ok(code) => { assert_eq!(code, 0); Ok(Some(unsafe { attr.__bindgen_anon_6.next_id })) @@ -924,7 +942,7 @@ fn bpf_prog_get_next_id(id: u32) -> Result, SyscallError> { Ok(None) } else { Err(SyscallError { - call: "bpf_prog_get_next_id", + call: name, io_error, }) } @@ -932,12 +950,15 @@ fn bpf_prog_get_next_id(id: u32) -> Result, SyscallError> { } } -pub(crate) fn iter_prog_ids() -> impl Iterator> { +fn iter_obj_ids( + cmd: bpf_cmd, + name: &'static str, +) -> impl Iterator> { let mut current_id = Some(0); iter::from_fn(move || { let next_id = { let current_id = current_id?; - bpf_prog_get_next_id(current_id).transpose() + bpf_obj_get_next_id(current_id, cmd, name).transpose() }; current_id = next_id.as_ref().and_then(|next_id| match next_id { Ok(next_id) => Some(*next_id), @@ -947,6 +968,14 @@ pub(crate) fn iter_prog_ids() -> impl Iterator> }) } +pub(crate) fn iter_prog_ids() -> impl Iterator> { + iter_obj_ids(bpf_cmd::BPF_PROG_GET_NEXT_ID, "bpf_prog_get_next_id") +} + +pub(crate) fn iter_link_ids() -> impl Iterator> { + iter_obj_ids(bpf_cmd::BPF_LINK_GET_NEXT_ID, "bpf_link_get_next_id") +} + pub(crate) fn retry_with_verifier_logs( max_retries: usize, f: impl Fn(&mut [u8]) -> SysResult, diff --git a/test/README.md b/test/README.md index 0a6d1b84..a9521c0b 100644 --- a/test/README.md +++ b/test/README.md @@ -11,7 +11,6 @@ To run locally all you need is: 1. Rust nightly 1. `cargo install bpf-linker` -1. `bpftool` [^1] ### Other OSs @@ -52,5 +51,3 @@ Tests should follow these guidelines: - You may add a new module, or use an existing one. - Test functions should not return `anyhow::Result<()>` since this produces errors without stack traces. Prefer to `panic!` instead. - -[^1]: TODO(https://github.com/aya-rs/aya/issues/645): Remove this dependency. diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 4c366e46..ece72daf 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -1,17 +1,17 @@ -use std::{convert::TryInto as _, process::Command, thread, time}; +use std::{convert::TryInto as _, thread, time}; use aya::{ maps::Array, programs::{ links::{FdLink, PinnedLink}, - loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags, + loaded_links, loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags, }, util::KernelVersion, Bpf, }; -const MAX_RETRIES: u32 = 100; -const RETRY_DURATION_MS: u64 = 10; +const MAX_RETRIES: usize = 100; +const RETRY_DURATION: time::Duration = time::Duration::from_millis(10); #[test] fn long_name() { @@ -50,61 +50,67 @@ fn multiple_btf_maps() { assert_eq!(val_2, 42); } -fn is_linked(prog_id: &u32) -> bool { - let output = Command::new("bpftool").args(["link"]).output(); - let output = output.expect("Failed to run 'bpftool link'"); - let stdout = String::from_utf8(output.stdout).unwrap(); - stdout.contains(&prog_id.to_string()) -} - -macro_rules! assert_loaded_and_linked { - ($name:literal, $loaded:expr) => { - for i in 0..(MAX_RETRIES + 1) { +fn poll_loaded_program_id(name: &str) -> impl Iterator> + '_ { + std::iter::once(true) + .chain(std::iter::repeat(false)) + .map(|first| { + if !first { + thread::sleep(RETRY_DURATION); + } // Ignore race failures which can happen when the tests delete a // program in the middle of a `loaded_programs()` call. - let id = loaded_programs() + loaded_programs() .filter_map(|prog| prog.ok()) - .find(|prog| prog.name() == $name.as_bytes()) - .map(|prog| Some(prog.id())); - let mut linked = false; - if let Some(prog_id) = id { - linked = is_linked(&prog_id.unwrap()); - if linked == $loaded { - break; - } - } - - if i == MAX_RETRIES { - panic!( - "Expected (loaded/linked: {}) but found (id: {}, linked: {}", - $loaded, - id.is_some(), - linked - ); - } - thread::sleep(time::Duration::from_millis(RETRY_DURATION_MS)); - } - }; + .find_map(|prog| (prog.name() == name.as_bytes()).then(|| prog.id())) + }) } -macro_rules! assert_loaded { - ($name:literal, $loaded:expr) => { - for i in 0..(MAX_RETRIES + 1) { +#[track_caller] +fn assert_loaded_and_linked(name: &str) { + let (attempts_used, prog_id) = poll_loaded_program_id(name) + .take(MAX_RETRIES) + .enumerate() + .find_map(|(i, id)| id.map(|id| (i, id))) + .unwrap_or_else(|| panic!("{name} not loaded after {MAX_RETRIES}")); + let poll_loaded_link_id = std::iter::once(true) + .chain(std::iter::repeat(false)) + .map(|first| { + if !first { + thread::sleep(RETRY_DURATION); + } // Ignore race failures which can happen when the tests delete a // program in the middle of a `loaded_programs()` call. - let state = loaded_programs() - .filter_map(|prog| prog.ok()) - .any(|prog| prog.name() == $name.as_bytes()); + loaded_links() + .filter_map(|link| link.ok()) + .find_map(|link| (link.prog_id == prog_id).then_some(link.id)) + }); + assert!( + poll_loaded_link_id + .take(MAX_RETRIES) + .skip(attempts_used) + .any(|id| id.is_some()), + "{name} not linked after {MAX_RETRIES}" + ); +} - if state == $loaded { - break; - } - if i == MAX_RETRIES { - panic!("Expected loaded: {} but was loaded: {}", $loaded, state); - } - thread::sleep(time::Duration::from_millis(RETRY_DURATION_MS)); - } - }; +#[track_caller] +fn assert_loaded(name: &str) { + assert!( + poll_loaded_program_id(name) + .take(MAX_RETRIES) + .any(|id| id.is_some()), + "{name} not loaded after {MAX_RETRIES}" + ) +} + +#[track_caller] +fn assert_unloaded(name: &str) { + assert!( + poll_loaded_program_id(name) + .take(MAX_RETRIES) + .any(|id| id.is_none()), + "{name} still loaded after {MAX_RETRIES}" + ) } #[test] @@ -112,24 +118,24 @@ fn unload_xdp() { let mut bpf = Bpf::load(crate::TEST).unwrap(); let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); prog.load().unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); let link = prog.attach("lo", XdpFlags::default()).unwrap(); { let _link_owned = prog.take_link(link).unwrap(); prog.unload().unwrap(); - assert_loaded_and_linked!("pass", true); + assert_loaded_and_linked("pass"); }; - assert_loaded!("pass", false); + assert_unloaded("pass"); prog.load().unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); prog.attach("lo", XdpFlags::default()).unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); prog.unload().unwrap(); - assert_loaded!("pass", false); + assert_unloaded("pass"); } #[test] @@ -137,24 +143,24 @@ fn unload_kprobe() { let mut bpf = Bpf::load(crate::TEST).unwrap(); let prog: &mut KProbe = bpf.program_mut("test_kprobe").unwrap().try_into().unwrap(); prog.load().unwrap(); - assert_loaded!("test_kprobe", true); + assert_loaded("test_kprobe"); let link = prog.attach("try_to_wake_up", 0).unwrap(); { let _link_owned = prog.take_link(link).unwrap(); prog.unload().unwrap(); - assert_loaded_and_linked!("test_kprobe", true); + assert_loaded_and_linked("test_kprobe"); }; - assert_loaded!("test_kprobe", false); + assert_unloaded("test_kprobe"); prog.load().unwrap(); - assert_loaded!("test_kprobe", true); + assert_loaded("test_kprobe"); prog.attach("try_to_wake_up", 0).unwrap(); - assert_loaded!("test_kprobe", true); + assert_loaded("test_kprobe"); prog.unload().unwrap(); - assert_loaded!("test_kprobe", false); + assert_unloaded("test_kprobe"); } #[test] @@ -167,25 +173,25 @@ fn basic_tracepoint() { .unwrap(); prog.load().unwrap(); - assert_loaded!("test_tracepoint", true); + assert_loaded("test_tracepoint"); let link = prog.attach("syscalls", "sys_enter_kill").unwrap(); { let _link_owned = prog.take_link(link).unwrap(); prog.unload().unwrap(); - assert_loaded_and_linked!("test_tracepoint", true); + assert_loaded_and_linked("test_tracepoint"); }; - assert_loaded!("test_tracepoint", false); + assert_unloaded("test_tracepoint"); prog.load().unwrap(); - assert_loaded!("test_tracepoint", true); + assert_loaded("test_tracepoint"); prog.attach("syscalls", "sys_enter_kill").unwrap(); - assert_loaded!("test_tracepoint", true); + assert_loaded("test_tracepoint"); prog.unload().unwrap(); - assert_loaded!("test_tracepoint", false); + assert_unloaded("test_tracepoint"); } #[test] @@ -194,25 +200,25 @@ fn basic_uprobe() { let prog: &mut UProbe = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap(); prog.load().unwrap(); - assert_loaded!("test_uprobe", true); + assert_loaded("test_uprobe"); let link = prog.attach(Some("sleep"), 0, "libc", None).unwrap(); { let _link_owned = prog.take_link(link).unwrap(); prog.unload().unwrap(); - assert_loaded_and_linked!("test_uprobe", true); + assert_loaded_and_linked("test_uprobe"); }; - assert_loaded!("test_uprobe", false); + assert_unloaded("test_uprobe"); prog.load().unwrap(); - assert_loaded!("test_uprobe", true); + assert_loaded("test_uprobe"); prog.attach(Some("sleep"), 0, "libc", None).unwrap(); - assert_loaded!("test_uprobe", true); + assert_loaded("test_uprobe"); prog.unload().unwrap(); - assert_loaded!("test_uprobe", false); + assert_unloaded("test_uprobe"); } #[test] @@ -228,22 +234,22 @@ fn pin_link() { prog.load().unwrap(); let link_id = prog.attach("lo", XdpFlags::default()).unwrap(); let link = prog.take_link(link_id).unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); let fd_link: FdLink = link.try_into().unwrap(); let pinned = fd_link.pin("/sys/fs/bpf/aya-xdp-test-lo").unwrap(); // because of the pin, the program is still attached prog.unload().unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); // delete the pin, but the program is still attached let new_link = pinned.unpin().unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); // finally when new_link is dropped we're detached drop(new_link); - assert_loaded!("pass", false); + assert_unloaded("pass"); } #[test] @@ -263,7 +269,7 @@ fn pin_lifecycle() { } // should still be loaded since prog was pinned - assert_loaded!("pass", true); + assert_loaded("pass"); // 2. Load program from bpffs but don't attach it { @@ -271,7 +277,7 @@ fn pin_lifecycle() { } // should still be loaded since prog was pinned - assert_loaded!("pass", true); + assert_loaded("pass"); // 3. Load program from bpffs and attach { @@ -286,7 +292,7 @@ fn pin_lifecycle() { } // should still be loaded since link was pinned - assert_loaded_and_linked!("pass", true); + assert_loaded_and_linked("pass"); // 4. Load a new version of the program, unpin link, and atomically replace old program { @@ -299,11 +305,11 @@ fn pin_lifecycle() { .unpin() .unwrap(); prog.attach_to_link(link.try_into().unwrap()).unwrap(); - assert_loaded!("pass", true); + assert_loaded("pass"); } // program should be unloaded - assert_loaded!("pass", false); + assert_unloaded("pass"); } #[test] @@ -321,7 +327,7 @@ fn pin_lifecycle_tracepoint() { } // should still be loaded since prog was pinned - assert_loaded!("test_tracepoint", true); + assert_loaded("test_tracepoint"); // 2. Load program from bpffs but don't attach it { @@ -329,7 +335,7 @@ fn pin_lifecycle_tracepoint() { } // should still be loaded since prog was pinned - assert_loaded!("test_tracepoint", true); + assert_loaded("test_tracepoint"); // 3. Load program from bpffs and attach { @@ -346,7 +352,7 @@ fn pin_lifecycle_tracepoint() { } // should still be loaded since link was pinned - assert_loaded_and_linked!("test_tracepoint", true); + assert_loaded_and_linked("test_tracepoint"); // 4. unpin link, and make sure everything is unloaded { @@ -357,7 +363,7 @@ fn pin_lifecycle_tracepoint() { } // program should be unloaded - assert_loaded!("test_tracepoint", false); + assert_unloaded("test_tracepoint"); } #[test] @@ -371,7 +377,7 @@ fn pin_lifecycle_kprobe() { } // should still be loaded since prog was pinned - assert_loaded!("test_kprobe", true); + assert_loaded("test_kprobe"); // 2. Load program from bpffs but don't attach it { @@ -383,7 +389,7 @@ fn pin_lifecycle_kprobe() { } // should still be loaded since prog was pinned - assert_loaded!("test_kprobe", true); + assert_loaded("test_kprobe"); // 3. Load program from bpffs and attach { @@ -404,7 +410,7 @@ fn pin_lifecycle_kprobe() { } // should still be loaded since link was pinned - assert_loaded_and_linked!("test_kprobe", true); + assert_loaded_and_linked("test_kprobe"); // 4. unpin link, and make sure everything is unloaded { @@ -415,7 +421,7 @@ fn pin_lifecycle_kprobe() { } // program should be unloaded - assert_loaded!("test_kprobe", false); + assert_unloaded("test_kprobe"); } #[test] @@ -429,7 +435,7 @@ fn pin_lifecycle_uprobe() { } // should still be loaded since prog was pinned - assert_loaded!("test_uprobe", true); + assert_loaded("test_uprobe"); // 2. Load program from bpffs but don't attach it { @@ -441,7 +447,7 @@ fn pin_lifecycle_uprobe() { } // should still be loaded since prog was pinned - assert_loaded!("test_uprobe", true); + assert_loaded("test_uprobe"); // 3. Load program from bpffs and attach { @@ -462,7 +468,7 @@ fn pin_lifecycle_uprobe() { } // should still be loaded since link was pinned - assert_loaded_and_linked!("test_uprobe", true); + assert_loaded_and_linked("test_uprobe"); // 4. unpin link, and make sure everything is unloaded { @@ -473,5 +479,5 @@ fn pin_lifecycle_uprobe() { } // program should be unloaded - assert_loaded!("test_uprobe", false); + assert_unloaded("test_uprobe"); } diff --git a/test/run.sh b/test/run.sh index 4cbd48b1..26c98918 100755 --- a/test/run.sh +++ b/test/run.sh @@ -190,8 +190,6 @@ EOF echo "Enabling testing repositories" exec_vm sudo dnf config-manager --set-enabled updates-testing exec_vm sudo dnf config-manager --set-enabled updates-testing-modular - echo "Installing dependencies" - exec_vm sudo dnf install -qy bpftool } scp_vm() {