From f65c9ab641b51f3d5cb43b35afdcd6a6acb85083 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 28 Sep 2025 20:54:12 -0400 Subject: [PATCH] use strict provenance APIs --- aya/src/lib.rs | 12 ++++++ aya/src/maps/hash_map/hash_map.rs | 19 +++++---- aya/src/maps/mod.rs | 8 ++-- aya/src/maps/ring_buf.rs | 5 ++- aya/src/programs/socket_filter.rs | 10 ++--- aya/src/programs/uprobe.rs | 10 ++--- aya/src/sys/bpf.rs | 28 +++++++------- aya/src/sys/feature_probe.rs | 2 +- aya/src/sys/netlink.rs | 64 ++++++++++++------------------- aya/src/util.rs | 5 +-- 10 files changed, 80 insertions(+), 83 deletions(-) diff --git a/aya/src/lib.rs b/aya/src/lib.rs index c9307ed6..3e72b2f8 100644 --- a/aya/src/lib.rs +++ b/aya/src/lib.rs @@ -39,11 +39,23 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![deny( clippy::all, + clippy::as_ptr_cast_mut, + //clippy::as_underscore, clippy::cast_lossless, + //clippy::cast_possible_truncation, + //clippy::cast_possible_wrap, clippy::cast_precision_loss, + //clippy::cast_sign_loss, clippy::char_lit_as_u8, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, + clippy::mut_mut, + clippy::needless_bitwise_bool, + clippy::needless_lifetimes, + clippy::no_mangle_with_rust_abi, + clippy::ptr_as_ptr, + clippy::ptr_cast_constness, + clippy::ref_as_ptr, clippy::unnecessary_cast, clippy::use_self, absolute_paths_not_starting_with_crate, diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index e8d2c463..142386d8 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -300,21 +300,24 @@ mod tests { } fn bpf_key(attr: &bpf_attr) -> Option { - match unsafe { attr.__bindgen_anon_2.key } as *const T { - p if p.is_null() => None, - p => Some(unsafe { *p }), - } + let p: *const T = + std::ptr::with_exposed_provenance(unsafe { attr.__bindgen_anon_2.key } as usize); + (!p.is_null()).then(|| unsafe { *p }) } fn set_next_key(attr: &bpf_attr, next: T) -> SysResult { - let key = unsafe { attr.__bindgen_anon_2.__bindgen_anon_1.next_key } as *const T as *mut T; - unsafe { *key = next }; + let p: *mut T = std::ptr::with_exposed_provenance_mut(unsafe { + attr.__bindgen_anon_2.__bindgen_anon_1.next_key + } as usize); + unsafe { *p = next }; Ok(0) } fn set_ret(attr: &bpf_attr, ret: T) -> SysResult { - let value = unsafe { attr.__bindgen_anon_2.__bindgen_anon_1.value } as *const T as *mut T; - unsafe { *value = ret }; + let p: *mut T = std::ptr::with_exposed_provenance_mut(unsafe { + attr.__bindgen_anon_2.__bindgen_anon_1.value + } as usize); + unsafe { *p = ret }; Ok(0) } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index d8593a40..6842cadd 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -681,7 +681,7 @@ impl MapData { pub(crate) fn finalize(&mut self) -> Result<(), MapError> { let Self { obj, fd } = self; if !obj.data().is_empty() { - bpf_map_update_elem_ptr(fd.as_fd(), &0 as *const _, obj.data_mut().as_mut_ptr(), 0) + bpf_map_update_elem_ptr(fd.as_fd(), &0, obj.data_mut().as_mut_ptr(), 0) .map_err(|io_error| SyscallError { call: "bpf_map_update_elem", io_error, @@ -1197,7 +1197,8 @@ mod tests { ); unsafe { let name_bytes = mem::transmute::<&[u8], &[c_char]>(TEST_NAME.as_bytes()); - let map_info = attr.info.info as *mut bpf_map_info; + let map_info: *mut bpf_map_info = + std::ptr::with_exposed_provenance_mut(attr.info.info as usize); map_info.write({ let mut map_info = map_info.read(); map_info.name[..name_bytes.len()].copy_from_slice(name_bytes); @@ -1240,7 +1241,8 @@ mod tests { } => { unsafe { let info = attr.info; - let map_info = info.info as *mut bpf_map_info; + let map_info: *mut bpf_map_info = + std::ptr::with_exposed_provenance_mut(info.info as usize); map_info.write({ let mut map_info = map_info.read(); map_info.id = info.bpf_fd - crate::MockableFd::mock_unsigned_fd(); diff --git a/aya/src/maps/ring_buf.rs b/aya/src/maps/ring_buf.rs index c6642411..85d3c8a8 100644 --- a/aya/src/maps/ring_buf.rs +++ b/aya/src/maps/ring_buf.rs @@ -380,8 +380,9 @@ impl ProducerData { panic!("{:?} not in {:?}", offset..offset + len, 0..data.len()) }) }; - let header_ptr = - must_get_data(offset, mem::size_of::()).as_ptr() as *const AtomicU32; + let header_ptr: *const AtomicU32 = must_get_data(offset, mem::size_of::()) + .as_ptr() + .cast(); // Pair the kernel's SeqCst write (implies Release) [1] with an Acquire load. This // ensures data written by the producer will be visible. // diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index 7db96bcc..de6e206e 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -1,6 +1,6 @@ //! Socket filter programs. use std::{ - io, mem, + io, os::fd::{AsFd, AsRawFd as _, RawFd}, }; @@ -87,8 +87,8 @@ impl SocketFilter { socket, SOL_SOCKET, SO_ATTACH_BPF as i32, - &prog_fd as *const _ as *const _, - mem::size_of::() as u32, + std::ptr::from_ref(&prog_fd).cast(), + std::mem::size_of_val(&prog_fd) as u32, ) }; if ret < 0 { @@ -144,8 +144,8 @@ impl Link for SocketFilterLink { self.socket, SOL_SOCKET, SO_DETACH_BPF as i32, - &self.prog_fd as *const _ as *const _, - mem::size_of::() as u32, + std::ptr::from_ref(&self.prog_fd).cast(), + std::mem::size_of_val(&self.prog_fd) as u32, ); } Ok(()) diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 6dcd26e7..69378b8c 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -1,7 +1,7 @@ //! User space probes. use std::{ error::Error, - ffi::{CStr, OsStr, OsString, c_char}, + ffi::{CStr, OsStr, OsString}, fs, io::{self, BufRead as _, Cursor, Read as _}, mem, @@ -549,12 +549,8 @@ impl LdSoCache { let read_str = |pos| { use std::os::unix::ffi::OsStrExt as _; OsStr::from_bytes( - unsafe { - CStr::from_ptr( - cursor.get_ref()[offset + pos..].as_ptr() as *const c_char - ) - } - .to_bytes(), + unsafe { CStr::from_ptr(cursor.get_ref()[offset + pos..].as_ptr().cast()) } + .to_bytes(), ) .to_owned() }; diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index b1df7b58..6b7270a4 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -172,12 +172,12 @@ pub(crate) fn bpf_load_program( if let Some(btf_fd) = aya_attr.prog_btf_fd { u.prog_btf_fd = btf_fd.as_raw_fd() as u32; if aya_attr.line_info_rec_size > 0 { - u.line_info = line_info_buf.as_ptr() as *const _ as u64; + u.line_info = line_info_buf.as_ptr().expose_provenance() as u64; u.line_info_cnt = aya_attr.line_info.len() as u32; u.line_info_rec_size = aya_attr.line_info_rec_size as u32; } if aya_attr.func_info_rec_size > 0 { - u.func_info = func_info_buf.as_ptr() as *const _ as u64; + u.func_info = func_info_buf.as_ptr().expose_provenance() as u64; u.func_info_cnt = aya_attr.func_info.len() as u32; u.func_info_rec_size = aya_attr.func_info_rec_size as u32; } @@ -212,9 +212,9 @@ fn lookup( let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { - u.key = key as *const _ as u64; + u.key = std::ptr::from_ref(key).expose_provenance() as u64; } - u.__bindgen_anon_1.value = &mut value as *mut _ as u64; + u.__bindgen_anon_1.value = std::ptr::from_mut(&mut value).expose_provenance() as u64; u.flags = flags; match unit_sys_bpf(cmd, &mut attr) { @@ -264,7 +264,7 @@ pub(crate) fn bpf_map_lookup_elem_ptr( let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { - u.key = key as *const _ as u64; + u.key = std::ptr::from_ref(key).expose_provenance() as u64; } u.__bindgen_anon_1.value = value as u64; u.flags = flags; @@ -287,9 +287,9 @@ pub(crate) fn bpf_map_update_elem( let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { - u.key = key as *const _ as u64; + u.key = std::ptr::from_ref(key).expose_provenance() as u64; } - u.__bindgen_anon_1.value = value as *const _ as u64; + u.__bindgen_anon_1.value = std::ptr::from_ref(value).expose_provenance() as u64; u.flags = flags; unit_sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr) @@ -304,7 +304,7 @@ pub(crate) fn bpf_map_push_elem( let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd.as_raw_fd() as u32; - u.__bindgen_anon_1.value = value as *const _ as u64; + u.__bindgen_anon_1.value = std::ptr::from_ref(value).expose_provenance() as u64; u.flags = flags; unit_sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr) @@ -342,7 +342,7 @@ pub(crate) fn bpf_map_delete_elem(fd: BorrowedFd<'_>, key: &K) -> io::Re let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd.as_raw_fd() as u32; - u.key = key as *const _ as u64; + u.key = std::ptr::from_ref(key).expose_provenance() as u64; unit_sys_bpf(bpf_cmd::BPF_MAP_DELETE_ELEM, &mut attr) } @@ -357,9 +357,9 @@ pub(crate) fn bpf_map_get_next_key( let u = unsafe { &mut attr.__bindgen_anon_2 }; u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { - u.key = key as *const _ as u64; + u.key = std::ptr::from_ref(key).expose_provenance() as u64; } - u.__bindgen_anon_1.next_key = &mut next_key as *mut _ as u64; + u.__bindgen_anon_1.next_key = std::ptr::from_mut(&mut next_key).expose_provenance() as u64; match unit_sys_bpf(bpf_cmd::BPF_MAP_GET_NEXT_KEY, &mut attr) { Ok(()) => Ok(Some(unsafe { next_key.assume_init() })), @@ -573,7 +573,7 @@ fn bpf_obj_get_info_by_fd( init(&mut info); attr.info.bpf_fd = fd.as_raw_fd() as u32; - attr.info.info = &info as *const _ as u64; + attr.info.info = std::ptr::from_ref(&info).expose_provenance() as u64; attr.info.info_len = mem::size_of_val(&info) as u32; match unit_sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { @@ -669,11 +669,11 @@ pub(crate) fn bpf_load_btf( ) -> io::Result { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_7 }; - u.btf = raw_btf.as_ptr() as *const _ as u64; + u.btf = raw_btf.as_ptr().expose_provenance() as u64; u.btf_size = mem::size_of_val(raw_btf) as u32; if !log_buf.is_empty() { u.btf_log_level = verifier_log_level.bits(); - u.btf_log_buf = log_buf.as_mut_ptr() as u64; + u.btf_log_buf = log_buf.as_mut_ptr().expose_provenance() as u64; u.btf_log_size = log_buf.len() as u32; } // SAFETY: `BPF_BTF_LOAD` returns a newly created fd. diff --git a/aya/src/sys/feature_probe.rs b/aya/src/sys/feature_probe.rs index af77d292..4276d36e 100644 --- a/aya/src/sys/feature_probe.rs +++ b/aya/src/sys/feature_probe.rs @@ -395,7 +395,7 @@ fn probe_bpf_info(fd: MockableFd, info: T) -> Result { let mut attr = unsafe { mem::zeroed::() }; attr.info.bpf_fd = fd.as_raw_fd() as u32; attr.info.info_len = mem::size_of_val(&info) as u32; - attr.info.info = &info as *const _ as u64; + attr.info.info = std::ptr::from_ref(&info).expose_provenance() as u64; let io_error = match unit_sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(()) => return Ok(true), diff --git a/aya/src/sys/netlink.rs b/aya/src/sys/netlink.rs index 85ef1bed..e703b851 100644 --- a/aya/src/sys/netlink.rs +++ b/aya/src/sys/netlink.rs @@ -373,8 +373,8 @@ impl NetlinkSocket { sock.as_raw_fd(), SOL_NETLINK, NETLINK_EXT_ACK, - &enable as *const _ as *const _, - mem::size_of::() as u32, + std::ptr::from_ref(&enable).cast(), + mem::size_of_val(&enable) as u32, ) < 0 { return Err(NetlinkErrorInternal::IoError(io::Error::last_os_error())); @@ -385,8 +385,8 @@ impl NetlinkSocket { sock.as_raw_fd(), SOL_NETLINK, NETLINK_CAP_ACK, - &enable as *const _ as *const _, - mem::size_of::() as u32, + std::ptr::from_ref(&enable).cast(), + mem::size_of_val(&enable) as u32, ) < 0 { return Err(NetlinkErrorInternal::IoError(io::Error::last_os_error())); @@ -401,8 +401,8 @@ impl NetlinkSocket { if unsafe { getsockname( sock.as_raw_fd(), - &mut addr as *mut _ as *mut _, - &mut addr_len as *mut _, + std::ptr::from_mut(&mut addr).cast(), + std::ptr::from_mut(&mut addr_len).cast(), ) } < 0 { @@ -416,15 +416,7 @@ impl NetlinkSocket { } fn send(&self, msg: &[u8]) -> Result<(), NetlinkErrorInternal> { - if unsafe { - send( - self.sock.as_raw_fd(), - msg.as_ptr() as *const _, - msg.len(), - 0, - ) - } < 0 - { + if unsafe { send(self.sock.as_raw_fd(), msg.as_ptr().cast(), msg.len(), 0) } < 0 { return Err(NetlinkErrorInternal::IoError(io::Error::last_os_error())); } Ok(()) @@ -437,14 +429,7 @@ impl NetlinkSocket { 'out: while multipart { multipart = false; // Safety: libc wrapper - let len = unsafe { - recv( - self.sock.as_raw_fd(), - buf.as_mut_ptr() as *mut _, - buf.len(), - 0, - ) - }; + let len = unsafe { recv(self.sock.as_raw_fd(), buf.as_mut_ptr().cast(), buf.len(), 0) }; if len < 0 { return Err(NetlinkErrorInternal::IoError(io::Error::last_os_error())); } @@ -505,7 +490,7 @@ impl NetlinkMessage { } // Safety: nlmsghdr is POD so read is safe - let header = unsafe { ptr::read_unaligned(buf.as_ptr() as *const nlmsghdr) }; + let header: nlmsghdr = unsafe { ptr::read_unaligned(buf.as_ptr().cast()) }; let msg_len = header.nlmsg_len as usize; if msg_len < mem::size_of::() || msg_len > buf.len() { return Err(io::Error::other("invalid nlmsg_len")); @@ -525,9 +510,7 @@ impl NetlinkMessage { ( &buf[data_offset + mem::size_of::()..msg_len], // Safety: nlmsgerr is POD so read is safe - Some(unsafe { - ptr::read_unaligned(buf[data_offset..].as_ptr() as *const nlmsgerr) - }), + Some(unsafe { ptr::read_unaligned(buf[data_offset..].as_ptr().cast()) }), ) } else { (&buf[data_offset..msg_len], None) @@ -594,8 +577,7 @@ fn write_attr( attr_type: u16, value: T, ) -> Result { - let value = - unsafe { slice::from_raw_parts(&value as *const _ as *const _, mem::size_of::()) }; + let value = bytes_of(&value); write_attr_bytes(buf, offset, attr_type, value) } @@ -617,9 +599,7 @@ fn write_attr_bytes( } fn write_attr_header(buf: &mut [u8], offset: usize, attr: nlattr) -> Result { - let attr = - unsafe { slice::from_raw_parts(&attr as *const _ as *const _, mem::size_of::()) }; - + let attr = bytes_of(&attr); write_bytes(buf, offset, attr)?; Ok(NLA_HDR_LEN) } @@ -663,7 +643,7 @@ impl<'a> Iterator for NlAttrsIterator<'a> { })); } - let attr = unsafe { ptr::read_unaligned(buf.as_ptr() as *const nlattr) }; + let attr: nlattr = unsafe { ptr::read_unaligned(buf.as_ptr().cast()) }; let len = attr.nla_len as usize; let align_len = align_to(len, NLA_ALIGNTO as usize); if len < NLA_HDR_LEN { @@ -751,28 +731,32 @@ mod tests { assert_eq!(len, nla_len); // read IFLA_XDP - let attr = unsafe { ptr::read_unaligned(buf.as_ptr() as *const nlattr) }; + let attr: nlattr = unsafe { ptr::read_unaligned(buf.as_ptr().cast()) }; assert_eq!(attr.nla_type, NLA_F_NESTED as u16 | IFLA_XDP); assert_eq!(attr.nla_len, nla_len); // read IFLA_XDP_FD + fd - let attr = unsafe { ptr::read_unaligned(buf[NLA_HDR_LEN..].as_ptr() as *const nlattr) }; + let attr: nlattr = unsafe { ptr::read_unaligned(buf[NLA_HDR_LEN..].as_ptr().cast()) }; assert_eq!(attr.nla_type, IFLA_XDP_FD as u16); assert_eq!(attr.nla_len, (NLA_HDR_LEN + mem::size_of::()) as u16); - let fd = unsafe { ptr::read_unaligned(buf[NLA_HDR_LEN * 2..].as_ptr() as *const u32) }; + let fd: u32 = unsafe { ptr::read_unaligned(buf[NLA_HDR_LEN * 2..].as_ptr().cast()) }; assert_eq!(fd, 42); // read IFLA_XDP_EXPECTED_FD + fd - let attr = unsafe { + let attr: nlattr = unsafe { ptr::read_unaligned( - buf[NLA_HDR_LEN * 2 + mem::size_of::()..].as_ptr() as *const nlattr + buf[NLA_HDR_LEN * 2 + mem::size_of::()..] + .as_ptr() + .cast(), ) }; assert_eq!(attr.nla_type, IFLA_XDP_EXPECTED_FD as u16); assert_eq!(attr.nla_len, (NLA_HDR_LEN + mem::size_of::()) as u16); - let fd = unsafe { + let fd: u32 = unsafe { ptr::read_unaligned( - buf[NLA_HDR_LEN * 3 + mem::size_of::()..].as_ptr() as *const u32 + buf[NLA_HDR_LEN * 3 + mem::size_of::()..] + .as_ptr() + .cast(), ) }; assert_eq!(fd, 24); diff --git a/aya/src/util.rs b/aya/src/util.rs index 428f1a35..670228da 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -417,8 +417,7 @@ pub(crate) fn page_size() -> usize { // bytes_of converts a to a byte slice pub(crate) unsafe fn bytes_of(val: &T) -> &[u8] { - let ptr: *const _ = val; - unsafe { slice::from_raw_parts(ptr.cast(), mem::size_of_val(val)) } + unsafe { slice::from_raw_parts(std::ptr::from_ref(val).cast(), mem::size_of_val(val)) } } pub(crate) fn bytes_of_slice(val: &[T]) -> &[u8] { @@ -436,7 +435,7 @@ pub(crate) fn bytes_of_bpf_name(bpf_name: &[core::ffi::c_char; 16]) -> &[u8] { .rposition(|ch| *ch != 0) .map(|pos| pos + 1) .unwrap_or(0); - unsafe { slice::from_raw_parts(bpf_name.as_ptr() as *const _, length) } + unsafe { slice::from_raw_parts(bpf_name.as_ptr().cast(), length) } } // MMap corresponds to a memory-mapped region.