diff options
Diffstat (limited to 'vendor/rustix/src/backend/libc/net/read_sockaddr.rs')
-rw-r--r-- | vendor/rustix/src/backend/libc/net/read_sockaddr.rs | 81 |
1 files changed, 60 insertions, 21 deletions
diff --git a/vendor/rustix/src/backend/libc/net/read_sockaddr.rs b/vendor/rustix/src/backend/libc/net/read_sockaddr.rs index 575102c27..c3b23e8c2 100644 --- a/vendor/rustix/src/backend/libc/net/read_sockaddr.rs +++ b/vendor/rustix/src/backend/libc/net/read_sockaddr.rs @@ -1,13 +1,14 @@ -use super::super::c; +//! The BSD sockets API requires us to read the `ss_family` field before +//! we can interpret the rest of a `sockaddr` produced by the kernel. + #[cfg(unix)] use super::addr::SocketAddrUnix; use super::ext::{in6_addr_s6_addr, in_addr_s_addr, sockaddr_in6_sin6_scope_id}; +use crate::backend::c; #[cfg(not(windows))] use crate::ffi::CStr; use crate::io; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddrAny, SocketAddrV4, SocketAddrV6}; -#[cfg(not(windows))] -use alloc::vec::Vec; use core::mem::size_of; // This must match the header of `sockaddr`. @@ -46,6 +47,11 @@ pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr_stora (*storage.cast::<sockaddr_header>()).ss_family = c::AF_UNSPEC as _; } +/// Read a socket address encoded in a platform-specific format. +/// +/// # Safety +/// +/// `storage` must point to valid socket address storage. pub(crate) unsafe fn read_sockaddr( storage: *const c::sockaddr_storage, len: usize, @@ -61,7 +67,7 @@ pub(crate) unsafe fn read_sockaddr( if len < size_of::<c::sockaddr_in>() { return Err(io::Errno::INVAL); } - let decode = *storage.cast::<c::sockaddr_in>(); + let decode = &*storage.cast::<c::sockaddr_in>(); Ok(SocketAddrAny::V4(SocketAddrV4::new( Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))), u16::from_be(decode.sin_port), @@ -71,7 +77,7 @@ pub(crate) unsafe fn read_sockaddr( if len < size_of::<c::sockaddr_in6>() { return Err(io::Errno::INVAL); } - let decode = *storage.cast::<c::sockaddr_in6>(); + let decode = &*storage.cast::<c::sockaddr_in6>(); #[cfg(not(windows))] let s6_addr = decode.sin6_addr.s6_addr; #[cfg(windows)] @@ -93,20 +99,40 @@ pub(crate) unsafe fn read_sockaddr( return Err(io::Errno::INVAL); } if len == offsetof_sun_path { - Ok(SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap())) + SocketAddrUnix::new(&[][..]).map(SocketAddrAny::Unix) } else { - let decode = *storage.cast::<c::sockaddr_un>(); + let decode = &*storage.cast::<c::sockaddr_un>(); + + // On Linux check for Linux's [abstract namespace]. + // + // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html + #[cfg(linux_kernel)] + if decode.sun_path[0] == 0 { + return SocketAddrUnix::new_abstract_name(core::mem::transmute::< + &[c::c_char], + &[u8], + >( + &decode.sun_path[1..len - offsetof_sun_path], + )) + .map(SocketAddrAny::Unix); + } + + // Otherwise we expect a NUL-terminated filesystem path. // Trim off unused bytes from the end of `path_bytes`. let path_bytes = if cfg!(target_os = "freebsd") { // FreeBSD sometimes sets the length to longer than the length // of the NUL-terminated string. Find the NUL and truncate the // string accordingly. - &decode.sun_path[..decode.sun_path.iter().position(|b| *b == 0).unwrap()] + &decode.sun_path[..decode + .sun_path + .iter() + .position(|b| *b == 0) + .ok_or(io::Errno::INVAL)?] } else { // Otherwise, use the provided length. let provided_len = len - 1 - offsetof_sun_path; - if decode.sun_path[provided_len] != b'\0' as c::c_char { + if decode.sun_path[provided_len] != 0 { return Err(io::Errno::INVAL); } debug_assert_eq!( @@ -116,10 +142,8 @@ pub(crate) unsafe fn read_sockaddr( &decode.sun_path[..provided_len] }; - Ok(SocketAddrAny::Unix( - SocketAddrUnix::new(path_bytes.iter().map(|c| *c as u8).collect::<Vec<u8>>()) - .unwrap(), - )) + SocketAddrUnix::new(core::mem::transmute::<&[c::c_char], &[u8]>(path_bytes)) + .map(SocketAddrAny::Unix) } } _ => Err(io::Errno::INVAL), @@ -164,7 +188,7 @@ unsafe fn inner_read_sockaddr_os( match family { c::AF_INET => { assert!(len >= size_of::<c::sockaddr_in>()); - let decode = *storage.cast::<c::sockaddr_in>(); + let decode = &*storage.cast::<c::sockaddr_in>(); SocketAddrAny::V4(SocketAddrV4::new( Ipv4Addr::from(u32::from_be(in_addr_s_addr(decode.sin_addr))), u16::from_be(decode.sin_port), @@ -172,7 +196,7 @@ unsafe fn inner_read_sockaddr_os( } c::AF_INET6 => { assert!(len >= size_of::<c::sockaddr_in6>()); - let decode = *storage.cast::<c::sockaddr_in6>(); + let decode = &*storage.cast::<c::sockaddr_in6>(); SocketAddrAny::V6(SocketAddrV6::new( Ipv6Addr::from(in6_addr_s6_addr(decode.sin6_addr)), u16::from_be(decode.sin6_port), @@ -186,11 +210,26 @@ unsafe fn inner_read_sockaddr_os( if len == offsetof_sun_path { SocketAddrAny::Unix(SocketAddrUnix::new(&[][..]).unwrap()) } else { - let decode = *storage.cast::<c::sockaddr_un>(); - assert_eq!( - decode.sun_path[len - 1 - offsetof_sun_path], - b'\0' as c::c_char - ); + let decode = &*storage.cast::<c::sockaddr_un>(); + + // On Linux check for Linux's [abstract namespace]. + // + // [abstract namespace]: https://man7.org/linux/man-pages/man7/unix.7.html + #[cfg(linux_kernel)] + if decode.sun_path[0] == 0 { + return SocketAddrAny::Unix( + SocketAddrUnix::new_abstract_name(core::mem::transmute::< + &[c::c_char], + &[u8], + >( + &decode.sun_path[1..len - offsetof_sun_path], + )) + .unwrap(), + ); + } + + // Otherwise we expect a NUL-terminated filesystem path. + assert_eq!(decode.sun_path[len - 1 - offsetof_sun_path], 0); let path_bytes = &decode.sun_path[..len - 1 - offsetof_sun_path]; // FreeBSD sometimes sets the length to longer than the length @@ -200,7 +239,7 @@ unsafe fn inner_read_sockaddr_os( let path_bytes = &path_bytes[..path_bytes.iter().position(|b| *b == 0).unwrap()]; SocketAddrAny::Unix( - SocketAddrUnix::new(path_bytes.iter().map(|c| *c as u8).collect::<Vec<u8>>()) + SocketAddrUnix::new(core::mem::transmute::<&[c::c_char], &[u8]>(path_bytes)) .unwrap(), ) } |