summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/libc/net/read_sockaddr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/libc/net/read_sockaddr.rs')
-rw-r--r--vendor/rustix/src/backend/libc/net/read_sockaddr.rs81
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(),
)
}