From 7c25373ea35dcddb5c0a6f5db1b90a6afcc0850e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:03:55 +0100 Subject: [PATCH 01/12] Convert SocketAddrV* -> SockAddr safely --- Cargo.toml | 2 +- src/sockaddr.rs | 47 +++++++++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a1f95cc..c8bf0d96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] cfg-if = "0.1.6" -libc = "0.2.66" +libc = { version = "0.2.66", features = ["align"] } [target."cfg(target_os = \"redox\")".dependencies] redox_syscall = "0.1.38" diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 7bdf38ca..8d99fea9 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -5,10 +5,14 @@ use std::ptr; #[cfg(any(unix, target_os = "redox"))] use libc::{ - sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, - AF_INET6, + in6_addr, in_addr, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, + socklen_t, AF_INET, AF_INET6, }; #[cfg(windows)] +use winapi::shared::in6addr::IN6_ADDR as in6_addr; +#[cfg(windows)] +use winapi::shared::inaddr::IN_ADDR as in_addr; +#[cfg(windows)] use winapi::shared::ws2def::{ ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, @@ -168,22 +172,23 @@ impl SockAddr { } } -// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6 - -// check to make sure that the sizes at least match up -fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) { - unsafe { - mem::transmute::(v4); - mem::transmute::(v6); - } -} - impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { + let sin_addr = in_addr { + s_addr: u32::from_ne_bytes(addr.ip().octets()), + }; + + let sockaddr_in = sockaddr_in { + sin_family: AF_INET as sa_family_t, + sin_port: addr.port().to_be(), + sin_addr, + ..unsafe { mem::zeroed() } + }; + unsafe { SockAddr::from_raw_parts( - &addr as *const _ as *const _, - mem::size_of::() as socklen_t, + &sockaddr_in as *const _ as *const _, + mem::size_of::() as socklen_t, ) } } @@ -191,10 +196,20 @@ impl From for SockAddr { impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { + let sockaddr_in6 = sockaddr_in6 { + sin6_family: AF_INET6 as sa_family_t, + sin6_port: addr.port().to_be(), + sin6_addr: in6_addr { + s6_addr: addr.ip().octets(), + }, + sin6_flowinfo: addr.flowinfo(), + sin6_scope_id: addr.scope_id(), + ..unsafe { mem::zeroed() } + }; unsafe { SockAddr::from_raw_parts( - &addr as *const _ as *const _, - mem::size_of::() as socklen_t, + &sockaddr_in6 as *const _ as *const _, + mem::size_of::() as socklen_t, ) } } From b5627a2e649830d2ecae45c69d95a158de4e4f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:19:56 +0100 Subject: [PATCH 02/12] Convert SockAddr -> SocketAddrV* safely --- src/sockaddr.rs | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 8d99fea9..58b15548 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -1,6 +1,6 @@ use std::fmt; use std::mem::{self, MaybeUninit}; -use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::ptr; #[cfg(any(unix, target_os = "redox"))] @@ -124,33 +124,42 @@ impl SockAddr { } } - unsafe fn as_(&self, family: sa_family_t) -> Option { - if self.storage.ss_family != family { - return None; - } - - Some(mem::transmute_copy(&self.storage)) - } - /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET` /// family. pub fn as_inet(&self) -> Option { - unsafe { self.as_(AF_INET as sa_family_t) } + match self.as_std() { + Some(SocketAddr::V4(addr)) => Some(addr), + _ => None, + } } /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6` /// family. pub fn as_inet6(&self) -> Option { - unsafe { self.as_(AF_INET6 as sa_family_t) } + match self.as_std() { + Some(SocketAddr::V6(addr)) => Some(addr), + _ => None, + } } /// Returns this address as a `SocketAddr` if it is in the `AF_INET` /// or `AF_INET6` family, otherwise returns `None`. pub fn as_std(&self) -> Option { - if let Some(addr) = self.as_inet() { - Some(SocketAddr::V4(addr)) - } else if let Some(addr) = self.as_inet6() { - Some(SocketAddr::V6(addr)) + if self.storage.ss_family == AF_INET as sa_family_t { + let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) }; + let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); + let port = u16::from_be(addr.sin_port); + Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) + } else if self.storage.ss_family == AF_INET6 as sa_family_t { + let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) }; + let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); + let port = u16::from_be(addr.sin6_port); + Some(SocketAddr::V6(SocketAddrV6::new( + ip, + port, + addr.sin6_flowinfo, + addr.sin6_scope_id, + ))) } else { None } From b831b449eaa710ef24db1a4c9cf27a27b354c54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:24:30 +0100 Subject: [PATCH 03/12] cleanup --- src/sockaddr.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 58b15548..f26949b7 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -183,14 +183,12 @@ impl SockAddr { impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { - let sin_addr = in_addr { - s_addr: u32::from_ne_bytes(addr.ip().octets()), - }; - let sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), - sin_addr, + sin_addr: in_addr { + s_addr: u32::from_ne_bytes(addr.ip().octets()), + }, ..unsafe { mem::zeroed() } }; From c582e73d15209193b2889eb7ad7d283859241f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Fri, 6 Nov 2020 18:32:53 +0100 Subject: [PATCH 04/12] Convert from SocketAddrV* to SockAddr with less copying --- src/sockaddr.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index f26949b7..f4de98eb 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -183,7 +183,9 @@ impl SockAddr { impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { - let sockaddr_in = sockaddr_in { + let mut storage = MaybeUninit::::uninit(); + let sockaddr_in = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in) }; + *sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), sin_addr: in_addr { @@ -191,19 +193,18 @@ impl From for SockAddr { }, ..unsafe { mem::zeroed() } }; - - unsafe { - SockAddr::from_raw_parts( - &sockaddr_in as *const _ as *const _, - mem::size_of::() as socklen_t, - ) + SockAddr { + storage: unsafe { storage.assume_init() }, + len: mem::size_of::() as socklen_t, } } } impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { - let sockaddr_in6 = sockaddr_in6 { + let mut storage = MaybeUninit::::uninit(); + let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; + *sockaddr_in6 = sockaddr_in6 { sin6_family: AF_INET6 as sa_family_t, sin6_port: addr.port().to_be(), sin6_addr: in6_addr { @@ -213,11 +214,9 @@ impl From for SockAddr { sin6_scope_id: addr.scope_id(), ..unsafe { mem::zeroed() } }; - unsafe { - SockAddr::from_raw_parts( - &sockaddr_in6 as *const _ as *const _, - mem::size_of::() as socklen_t, - ) + SockAddr { + storage: unsafe { storage.assume_init() }, + len: mem::size_of::() as socklen_t, } } } From 738612ae237c16fa7d81888ebae945a045018355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 00:48:25 +0100 Subject: [PATCH 05/12] Adapt code to different sockaddr struct impl on Windows --- src/sockaddr.rs | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index f4de98eb..9dfcbde5 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -147,18 +147,35 @@ impl SockAddr { pub fn as_std(&self) -> Option { if self.storage.ss_family == AF_INET as sa_family_t { let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) }; + + #[cfg(unix)] let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); + #[cfg(windows)] + let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; + #[cfg(windows)] + let ip = Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]); + let port = u16::from_be(addr.sin_port); Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) } else if self.storage.ss_family == AF_INET6 as sa_family_t { let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) }; + + #[cfg(unix)] let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); + #[cfg(windows)] + let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() }); + let port = u16::from_be(addr.sin6_port); Some(SocketAddr::V6(SocketAddrV6::new( ip, port, addr.sin6_flowinfo, + #[cfg(unix)] addr.sin6_scope_id, + #[cfg(windows)] + unsafe { + *addr.u.sin6_scope_id() + }, ))) } else { None @@ -185,12 +202,19 @@ impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { let mut storage = MaybeUninit::::uninit(); let sockaddr_in = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in) }; + + #[cfg(unix)] + let sin_addr = in_addr { + s_addr: u32::from_ne_bytes(addr.ip().octets()), + }; + #[cfg(windows)] + let sin_addr = in_addr { + S_un: unsafe { mem::transmute(u32::from_ne_bytes(addr.ip().octets())) }, + }; *sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), - sin_addr: in_addr { - s_addr: u32::from_ne_bytes(addr.ip().octets()), - }, + sin_addr, ..unsafe { mem::zeroed() } }; SockAddr { @@ -204,14 +228,24 @@ impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { let mut storage = MaybeUninit::::uninit(); let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; + + #[cfg(windows)] + let sin6_addr = in6_addr { + u: unsafe { mem::transmute(addr.ip().octets()) }, + }; + #[cfg(unix)] + let sin6_addr = in6_addr { + s6_addr: addr.ip().octets(), + }; *sockaddr_in6 = sockaddr_in6 { sin6_family: AF_INET6 as sa_family_t, sin6_port: addr.port().to_be(), - sin6_addr: in6_addr { - s6_addr: addr.ip().octets(), - }, + sin6_addr, sin6_flowinfo: addr.flowinfo(), + #[cfg(unix)] sin6_scope_id: addr.scope_id(), + #[cfg(windows)] + u: unsafe { mem::transmute(addr.scope_id()) }, ..unsafe { mem::zeroed() } }; SockAddr { From 09eb49b4d2154894b96be635236c6180ccd46da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 01:18:20 +0100 Subject: [PATCH 06/12] Get rid of mem::transmute in favor of correctly init values --- src/sockaddr.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 9dfcbde5..bb6da03d 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -9,16 +9,16 @@ use libc::{ socklen_t, AF_INET, AF_INET6, }; #[cfg(windows)] -use winapi::shared::in6addr::IN6_ADDR as in6_addr; +use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR as in6_addr}; #[cfg(windows)] -use winapi::shared::inaddr::IN_ADDR as in_addr; +use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR as in_addr}; #[cfg(windows)] use winapi::shared::ws2def::{ ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, }; #[cfg(windows)] -use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; +use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH_u, SOCKADDR_IN6_LH as sockaddr_in6}; #[cfg(windows)] use winapi::um::ws2tcpip::socklen_t; @@ -151,9 +151,10 @@ impl SockAddr { #[cfg(unix)] let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); #[cfg(windows)] - let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; - #[cfg(windows)] - let ip = Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]); + let ip = { + let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; + Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]) + }; let port = u16::from_be(addr.sin_port); Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) @@ -208,8 +209,10 @@ impl From for SockAddr { s_addr: u32::from_ne_bytes(addr.ip().octets()), }; #[cfg(windows)] - let sin_addr = in_addr { - S_un: unsafe { mem::transmute(u32::from_ne_bytes(addr.ip().octets())) }, + let sin_addr = unsafe { + let mut s_un = mem::zeroed::(); + *s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets()); + in_addr { S_un: s_un } }; *sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, @@ -229,14 +232,22 @@ impl From for SockAddr { let mut storage = MaybeUninit::::uninit(); let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; - #[cfg(windows)] - let sin6_addr = in6_addr { - u: unsafe { mem::transmute(addr.ip().octets()) }, - }; #[cfg(unix)] let sin6_addr = in6_addr { s6_addr: addr.ip().octets(), }; + #[cfg(windows)] + let sin6_addr = unsafe { + let mut u = mem::zeroed::(); + *u.Byte_mut() = addr.ip().octets(); + in6_addr { u } + }; + #[cfg(windows)] + let u = unsafe { + let mut u = mem::zeroed::(); + *u.sin6_scope_id_mut() = addr.scope_id(); + u + }; *sockaddr_in6 = sockaddr_in6 { sin6_family: AF_INET6 as sa_family_t, sin6_port: addr.port().to_be(), @@ -245,7 +256,7 @@ impl From for SockAddr { #[cfg(unix)] sin6_scope_id: addr.scope_id(), #[cfg(windows)] - u: unsafe { mem::transmute(addr.scope_id()) }, + u, ..unsafe { mem::zeroed() } }; SockAddr { From 2c084f043612aeddb25a824fc394a20e32275850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 02:01:37 +0100 Subject: [PATCH 07/12] Cleanup --- src/sockaddr.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index bb6da03d..7ee357fb 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -155,7 +155,6 @@ impl SockAddr { let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]) }; - let port = u16::from_be(addr.sin_port); Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) } else if self.storage.ss_family == AF_INET6 as sa_family_t { @@ -165,7 +164,6 @@ impl SockAddr { let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); #[cfg(windows)] let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() }); - let port = u16::from_be(addr.sin6_port); Some(SocketAddr::V6(SocketAddrV6::new( ip, @@ -201,9 +199,6 @@ impl SockAddr { impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { - let mut storage = MaybeUninit::::uninit(); - let sockaddr_in = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in) }; - #[cfg(unix)] let sin_addr = in_addr { s_addr: u32::from_ne_bytes(addr.ip().octets()), @@ -214,6 +209,9 @@ impl From for SockAddr { *s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets()); in_addr { S_un: s_un } }; + + let mut storage = MaybeUninit::::uninit(); + let sockaddr_in = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in) }; *sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), @@ -229,9 +227,6 @@ impl From for SockAddr { impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { - let mut storage = MaybeUninit::::uninit(); - let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; - #[cfg(unix)] let sin6_addr = in6_addr { s6_addr: addr.ip().octets(), @@ -248,6 +243,9 @@ impl From for SockAddr { *u.sin6_scope_id_mut() = addr.scope_id(); u }; + + let mut storage = MaybeUninit::::uninit(); + let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; *sockaddr_in6 = sockaddr_in6 { sin6_family: AF_INET6 as sa_family_t, sin6_port: addr.port().to_be(), From 7cef159eeb545e40eec79cf035c601b2ac75d1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 02:04:50 +0100 Subject: [PATCH 08/12] Replace ..mem::zeroed() with conditional real fields --- src/sockaddr.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 7ee357fb..508e4d01 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -216,7 +216,16 @@ impl From for SockAddr { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), sin_addr, - ..unsafe { mem::zeroed() } + sin_zero: [0; 8], + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin_len: 0, }; SockAddr { storage: unsafe { storage.assume_init() }, @@ -255,7 +264,17 @@ impl From for SockAddr { sin6_scope_id: addr.scope_id(), #[cfg(windows)] u, - ..unsafe { mem::zeroed() } + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin6_len: 0, + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + __sin6_src_id: 0, }; SockAddr { storage: unsafe { storage.assume_init() }, From 487ceb5ce517dd39369f3d6d6028f3bcf272d443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 12:53:00 +0100 Subject: [PATCH 09/12] Add safety docs to two unsafe usages --- src/sockaddr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 508e4d01..b69278dd 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -146,6 +146,7 @@ impl SockAddr { /// or `AF_INET6` family, otherwise returns `None`. pub fn as_std(&self) -> Option { if self.storage.ss_family == AF_INET as sa_family_t { + // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) }; #[cfg(unix)] @@ -158,6 +159,7 @@ impl SockAddr { let port = u16::from_be(addr.sin_port); Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) } else if self.storage.ss_family == AF_INET6 as sa_family_t { + // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) }; #[cfg(unix)] From 36ea8a0bb98c7349491652f74b65854d4a041bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 13:01:04 +0100 Subject: [PATCH 10/12] Initialize sockaddr_storage to zero at all times --- src/sockaddr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index b69278dd..a88f5cd0 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -47,10 +47,10 @@ impl fmt::Debug for SockAddr { impl SockAddr { /// Constructs a `SockAddr` from its raw components. pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr { - let mut storage = MaybeUninit::::uninit(); + let mut storage = MaybeUninit::::zeroed(); ptr::copy_nonoverlapping( addr as *const _ as *const u8, - &mut storage as *mut _ as *mut u8, + storage.as_mut_ptr() as *mut u8, len as usize, ); @@ -212,7 +212,7 @@ impl From for SockAddr { in_addr { S_un: s_un } }; - let mut storage = MaybeUninit::::uninit(); + let mut storage = MaybeUninit::::zeroed(); let sockaddr_in = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in) }; *sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, @@ -255,7 +255,7 @@ impl From for SockAddr { u }; - let mut storage = MaybeUninit::::uninit(); + let mut storage = MaybeUninit::::zeroed(); let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; *sockaddr_in6 = sockaddr_in6 { sin6_family: AF_INET6 as sa_family_t, From eae8c9f00e2a53b324f7a3f14d5b514effb85a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 13:01:47 +0100 Subject: [PATCH 11/12] Remove redundant named struct field --- src/sockaddr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index a88f5cd0..95d7569d 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -57,7 +57,7 @@ impl SockAddr { SockAddr { // This is safe as we written the address to `storage` above. storage: storage.assume_init(), - len: len, + len, } } From 3c97dd4a098c612822bc5abd6e9eeb6958dfb1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 13:06:25 +0100 Subject: [PATCH 12/12] Much cleaner writing to uninitialized sockaddr_storage --- src/sockaddr.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 95d7569d..434163fe 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -212,9 +212,7 @@ impl From for SockAddr { in_addr { S_un: s_un } }; - let mut storage = MaybeUninit::::zeroed(); - let sockaddr_in = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in) }; - *sockaddr_in = sockaddr_in { + let sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), sin_addr, @@ -229,6 +227,9 @@ impl From for SockAddr { ))] sin_len: 0, }; + let mut storage = MaybeUninit::::zeroed(); + // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage` + unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) }; SockAddr { storage: unsafe { storage.assume_init() }, len: mem::size_of::() as socklen_t, @@ -255,9 +256,7 @@ impl From for SockAddr { u }; - let mut storage = MaybeUninit::::zeroed(); - let sockaddr_in6 = unsafe { &mut *(storage.as_mut_ptr() as *mut sockaddr_in6) }; - *sockaddr_in6 = sockaddr_in6 { + let sockaddr_in6 = sockaddr_in6 { sin6_family: AF_INET6 as sa_family_t, sin6_port: addr.port().to_be(), sin6_addr, @@ -278,6 +277,9 @@ impl From for SockAddr { #[cfg(any(target_os = "solaris", target_os = "illumos"))] __sin6_src_id: 0, }; + let mut storage = MaybeUninit::::zeroed(); + // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage` + unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) }; SockAddr { storage: unsafe { storage.assume_init() }, len: mem::size_of::() as socklen_t,