From 2e6ce7b6f422b1be0ded827a16ff835fc4f0008e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 9 Dec 2023 08:23:46 -0800 Subject: [PATCH] Fix `c_char` vs `u8` errors in the linux_raw backend. Fix the linux_raw backend to handle the case where linux-raw-sys defines `c_char` as `i8`. linux-raw-sys used to always define `c_char` as `u8` because it usually isn't important to match the platform `char` type, but that makes it inconvenient to work with Rust's `CStr`/`CString` types which use `c_char`, so linux-raw-sys has started defining `c_char` as `i8` on platforms which define it that way. --- src/backend/linux_raw/net/addr.rs | 22 +++++++++-- src/backend/linux_raw/net/read_sockaddr.rs | 46 ++++++++++++++-------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/backend/linux_raw/net/addr.rs b/src/backend/linux_raw/net/addr.rs index e6b307a16..85ba875bf 100644 --- a/src/backend/linux_raw/net/addr.rs +++ b/src/backend/linux_raw/net/addr.rs @@ -12,6 +12,7 @@ use crate::{io, path}; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; +use core::slice; /// `struct sockaddr_un` #[derive(Clone)] @@ -36,7 +37,7 @@ impl SocketAddrUnix { return Err(io::Errno::NAMETOOLONG); } for (i, b) in bytes.iter().enumerate() { - unix.sun_path[i] = *b; + unix.sun_path[i] = *b as _; } let len = offsetof_sun_path() + bytes.len(); let len = len.try_into().unwrap(); @@ -48,6 +49,10 @@ impl SocketAddrUnix { pub fn new_abstract_name(name: &[u8]) -> io::Result { let mut unix = Self::init(); let id = &mut unix.sun_path[1..]; + + // SAFETY: Convert `&mut [c_char]` to `&mut [u8]`. + let id = unsafe { slice::from_raw_parts_mut(id.as_mut_ptr().cast::(), id.len()) }; + if let Some(id) = id.get_mut(..name.len()) { id.copy_from_slice(name); let len = offsetof_sun_path() + 1 + name.len(); @@ -69,9 +74,13 @@ impl SocketAddrUnix { #[inline] pub fn path(&self) -> Option<&CStr> { let len = self.len(); - if len != 0 && self.unix.sun_path[0] != b'\0' { + if len != 0 && self.unix.sun_path[0] as u8 != b'\0' { let end = len as usize - offsetof_sun_path(); let bytes = &self.unix.sun_path[..end]; + + // SAFETY: Convert `&[c_char]` to `&[u8]`. + let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()) }; + // SAFETY: `from_bytes_with_nul_unchecked` since the string is // NUL-terminated. unsafe { Some(CStr::from_bytes_with_nul_unchecked(bytes)) } @@ -84,9 +93,14 @@ impl SocketAddrUnix { #[inline] pub fn abstract_name(&self) -> Option<&[u8]> { let len = self.len(); - if len != 0 && self.unix.sun_path[0] == b'\0' { + if len != 0 && self.unix.sun_path[0] as u8 == b'\0' { let end = len as usize - offsetof_sun_path(); - Some(&self.unix.sun_path[1..end]) + let bytes = &self.unix.sun_path[1..end]; + + // SAFETY: Convert `&[c_char]` to `&[u8]`. + let bytes = unsafe { slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()) }; + + Some(bytes) } else { None } diff --git a/src/backend/linux_raw/net/read_sockaddr.rs b/src/backend/linux_raw/net/read_sockaddr.rs index af7282c98..da9adfc2f 100644 --- a/src/backend/linux_raw/net/read_sockaddr.rs +++ b/src/backend/linux_raw/net/read_sockaddr.rs @@ -6,6 +6,7 @@ use crate::backend::c; use crate::io; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6}; use core::mem::size_of; +use core::slice; // This must match the header of `sockaddr`. #[repr(C)] @@ -93,17 +94,24 @@ pub(crate) unsafe fn read_sockaddr( // // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html if decode.sun_path[0] == 0 { - return SocketAddrUnix::new_abstract_name( - &decode.sun_path[1..len - offsetof_sun_path], - ) - .map(SocketAddrAny::Unix); + let bytes = &decode.sun_path[1..len - offsetof_sun_path]; + + // SAFETY: Convert `&[c_char]` to `&[u8]`. + let bytes = + unsafe { slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()) }; + + return SocketAddrUnix::new_abstract_name(bytes).map(SocketAddrAny::Unix); } // Otherwise we expect a NUL-terminated filesystem path. + let bytes = &decode.sun_path[..len - 1 - offsetof_sun_path]; + + // SAFETY: Convert `&[c_char]` to `&[u8]`. + let bytes = + unsafe { slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()) }; + assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); - Ok(SocketAddrAny::Unix(SocketAddrUnix::new( - &decode.sun_path[..len - 1 - offsetof_sun_path], - )?)) + Ok(SocketAddrAny::Unix(SocketAddrUnix::new(bytes)?)) } } _ => Err(io::Errno::NOTSUP), @@ -165,19 +173,25 @@ pub(crate) unsafe fn read_sockaddr_os(storage: *const c::sockaddr, len: usize) - // // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html if decode.sun_path[0] == 0 { - return SocketAddrAny::Unix( - SocketAddrUnix::new_abstract_name( - &decode.sun_path[1..len - offsetof_sun_path], - ) - .unwrap(), - ); + let bytes = &decode.sun_path[1..len - offsetof_sun_path]; + + // SAFETY: Convert `&[c_char]` to `&[u8]`. + let bytes = + unsafe { slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()) }; + + return SocketAddrAny::Unix(SocketAddrUnix::new_abstract_name(bytes).unwrap()); } // Otherwise we expect a NUL-terminated filesystem path. assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); - SocketAddrAny::Unix( - SocketAddrUnix::new(&decode.sun_path[..len - 1 - offsetof_sun_path]).unwrap(), - ) + + let bytes = &decode.sun_path[..len - 1 - offsetof_sun_path]; + + // SAFETY: Convert `&[c_char]` to `&[u8]`. + let bytes = + unsafe { slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()) }; + + SocketAddrAny::Unix(SocketAddrUnix::new(bytes).unwrap()) } } other => unimplemented!("{:?}", other),