diff --git a/changelog/2235.added.md b/changelog/2235.added.md new file mode 100644 index 0000000000..19f722f238 --- /dev/null +++ b/changelog/2235.added.md @@ -0,0 +1 @@ +Added the `SockaddrFromRaw` trait. diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 41d30b03a0..2c3bbed0f9 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -754,6 +754,14 @@ pub trait SockaddrLike: private::SockaddrLikePriv { } } +/// Checked conversion from a socket address pointer. +/// +/// **Note**: This trait is [sealed] and its functionality is hidden. +/// It cannot be implemented outside of nix. +/// +/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed +pub trait SockaddrFromRaw: private::SockaddrFromRawPriv {} + /// The error returned by [`SockaddrLike::set_length`] on an address whose length is statically /// fixed. #[derive(Copy, Clone, Debug)] @@ -1450,6 +1458,8 @@ impl PartialEq for SockaddrStorage { } pub(super) mod private { + use std::mem::MaybeUninit; + pub trait SockaddrLikePriv { /// Returns a mutable raw pointer to the inner structure. /// @@ -1463,6 +1473,52 @@ pub(super) mod private { self as *mut Self as *mut libc::sockaddr } } + + /// Checked conversion from a socket address pointer. + pub trait SockaddrFromRawPriv { + /// The libc storage type for this socket address. + type Storage: Copy + Send + Sync + 'static; + + /// Unsafe constructor from a variable length source. + /// + /// **Note**: This method must run the invalidity checks setuped by [`Self::init_storage`]. For these checks, + /// it must only access the fields that have been initialized by [`Self::init_storage`], the other fields + /// could be uninitialized. + /// + /// **Note**: Implementors should not forget that `len` can be larger than the size of + /// `Self::Storage`, so usually a bounds check on the passed length of the + /// address is mandatory, too. + /// + /// # Safety + /// + /// One of the following must be true: + /// + /// - `addr` must be dereferencable to `Self::Storage`. + /// + /// - `addr` has been initialized with `Self::init_storage`. + /// + /// - `addr` has been zeroed. + /// + /// Additionally, if `addr` is dereferencable to `Self::Storage`, then `len` must indicate + /// the actual length of the address. + unsafe fn from_raw( + addr: *const Self::Storage, + len: usize, + ) -> Self + where + Self: Sized; + + /// Initialize the storage for this socket address, such that after calling this function, + /// the memory representation of the argument is either valid or *provably* invalid for `Self`. + /// + /// Provably means that the invalidity must be detectable by only reading fields that have been + /// initialized by this function. + fn init_storage(buf: &mut MaybeUninit) { + unsafe { + buf.as_mut_ptr().write_bytes(0u8, 1); + } + } + } } #[cfg(linux_android)] diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index a145444fa2..4e413050e7 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -32,7 +32,7 @@ pub mod sockopt; * */ -pub use self::addr::{SockaddrLike, SockaddrStorage}; +pub use self::addr::{SockaddrFromRaw, SockaddrLike, SockaddrStorage}; #[cfg(solarish)] pub use self::addr::{AddressFamily, UnixAddr};