From 4ab21dc174a8112cd2f069a2d38e0b65d5b86d7a Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Mon, 9 Aug 2021 22:45:54 -0700 Subject: [PATCH] Relax assertions in sockaddr_storage_to_addr to match the documentation. Fixes #1479 --- src/sys/socket/mod.rs | 8 ++++---- test/sys/test_socket.rs | 42 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 733bd6608b..f701a7312a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1780,21 +1780,21 @@ pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result { - assert!(len <= mem::size_of::()); + assert!(len <= mem::size_of::()); if len < mem::size_of_val(&addr.ss_family) { return Err(Error::from(Errno::ENOTCONN)); } match c_int::from(addr.ss_family) { libc::AF_INET => { - assert_eq!(len as usize, mem::size_of::()); + assert!(len as usize >= mem::size_of::()); let sin = unsafe { *(addr as *const sockaddr_storage as *const sockaddr_in) }; Ok(SockAddr::Inet(InetAddr::V4(sin))) } libc::AF_INET6 => { - assert_eq!(len as usize, mem::size_of::()); + assert!(len as usize >= mem::size_of::()); let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; @@ -1810,10 +1810,10 @@ pub fn sockaddr_storage_to_addr( #[cfg(any(target_os = "android", target_os = "linux"))] libc::AF_PACKET => { use libc::sockaddr_ll; + // Don't assert anything about the size. // Apparently the Linux kernel can return smaller sizes when // the value in the last element of sockaddr_ll (`sll_addr`) is // smaller than the declared size of that field - assert!(len as usize <= mem::size_of::()); let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 5471afe3d8..9aab15efd8 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,12 +1,13 @@ -use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname}; +use nix::sys::socket::{AddressFamily, InetAddr, SockAddr, UnixAddr, getsockname, sockaddr, sockaddr_in6, sockaddr_storage_to_addr}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; +use std::mem::{self, MaybeUninit}; use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6}; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; use std::str::FromStr; -use libc::c_char; +use libc::{c_char, sockaddr_storage}; #[cfg(any(target_os = "linux", target_os= "android"))] use crate::*; @@ -14,6 +15,7 @@ use crate::*; pub fn test_inetv4_addr_to_sock_addr() { let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); let addr = InetAddr::from_std(&actual); + let sockaddr = SockAddr::new_inet(addr); match addr { InetAddr::V4(addr) => { @@ -31,6 +33,22 @@ pub fn test_inetv4_addr_to_sock_addr() { let inet = addr.to_std(); assert_eq!(actual, inet); + + let (storage, ffi_size) = { + let mut storage = MaybeUninit::::zeroed(); + let storage_ptr = storage.as_mut_ptr().cast::(); + let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); + assert_eq!(mem::size_of::(), ffi_size as usize); + unsafe { + storage_ptr.copy_from_nonoverlapping(ffi_ptr as *const sockaddr, 1); + (storage.assume_init(), ffi_size) + } + }; + + let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); + assert_eq!(from_storage, sockaddr); + let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::()).unwrap(); + assert_eq!(from_storage, sockaddr); } #[test] @@ -42,6 +60,7 @@ pub fn test_inetv6_addr_to_sock_addr() { let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); let addr = InetAddr::from_std(&actual); + let sockaddr = SockAddr::new_inet(addr); match addr { InetAddr::V6(addr) => { @@ -53,6 +72,24 @@ pub fn test_inetv6_addr_to_sock_addr() { } assert_eq!(actual, addr.to_std()); + + let (storage, ffi_size) = { + let mut storage = MaybeUninit::::zeroed(); + let storage_ptr = storage.as_mut_ptr().cast::(); + let (ffi_ptr, ffi_size) = sockaddr.as_ffi_pair(); + // XXX this does not pass. + // assert_eq!(mem::size_of::(), ffi_size as usize); + assert_eq!(mem::size_of::(), ffi_size as usize); + unsafe { + storage_ptr.copy_from_nonoverlapping((ffi_ptr as *const sockaddr).cast::(), 1); + (storage.assume_init(), ffi_size) + } + }; + + let from_storage = sockaddr_storage_to_addr(&storage, ffi_size as usize).unwrap(); + assert_eq!(from_storage, sockaddr); + let from_storage = sockaddr_storage_to_addr(&storage, mem::size_of::()).unwrap(); + assert_eq!(from_storage, sockaddr); } #[test] @@ -1169,7 +1206,6 @@ fn loopback_address(family: AddressFamily) -> Option