diff --git a/src/addr.rs b/src/addr.rs index 033ecc6..056138c 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -242,7 +242,7 @@ impl UnixSocketAddr { let mut addr: sockaddr_un = unsafe { mem::zeroed() }; addr.sun_family = AF_UNIX as sa_family_t; UnixSocketAddr { - len: mem::size_of::() as socklen_t, + len: path_offset(), addr, } } @@ -672,16 +672,17 @@ impl UnixSocketAddr { } else if addr.is_null() { Err(io::Error::new(ErrorKind::InvalidInput, "addr is NULL")) } else if len < path_offset() { - Err(io::Error::new(ErrorKind::InvalidInput, "address length is too low")) - } else if len > path_offset() + mem::size_of_val(©.addr.sun_path) as socklen_t { + Err(io::Error::new(ErrorKind::InvalidInput, "address length is too short")) + } else if len > mem::size_of::() as socklen_t { Err(io::Error::new(ErrorKind::InvalidInput, TOO_LONG_DESC)) } else if (&*addr).sa_family != AF_UNIX as sa_family_t { Err(io::Error::new(ErrorKind::InvalidData, "not an unix socket address")) } else { let addr = addr as *const sockaddr_un; let sun_path_ptr = (&*addr).sun_path.as_ptr(); - let sun_path = slice::from_raw_parts(sun_path_ptr, len as usize); - copy.addr.sun_path.copy_from_slice(sun_path); + let path_len = (len - path_offset()) as usize; + let sun_path = slice::from_raw_parts(sun_path_ptr, path_len); + copy.addr.sun_path[..path_len].copy_from_slice(sun_path); copy.len = len; Ok(copy) } diff --git a/tests/addr.rs b/tests/addr.rs index 7c06cf9..f3a41c0 100644 --- a/tests/addr.rs +++ b/tests/addr.rs @@ -339,3 +339,87 @@ fn datagram_peek_vectored() { std::fs::remove_file("datagram_server.sock").unwrap(); let _ = std::fs::remove_file("datagram_client.sock"); } + +#[test] +fn from_raw_path() { + let path_addr = UnixSocketAddr::from_path("a/path.sock").unwrap(); + let a = unsafe { + let (raw_addr, raw_len) = path_addr.as_raw(); + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len) + }.expect("from_raw() accepts from_path()"); + assert_eq!(a, path_addr); + assert!(a.is_path()); +} + +#[test] +fn from_raw_max_len_path() { + let path = "R".repeat(UnixSocketAddr::max_path_len()); + let path_addr = UnixSocketAddr::from_path(path.as_str()).unwrap(); + let a = unsafe { + let (raw_addr, raw_len) = path_addr.as_raw(); + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len) + }.expect("from_path() is valid"); + assert_eq!(a, path_addr); + assert!(a.is_path()); +} + +#[test] +fn from_raw_too_long_path() { + #[repr(C)] + struct TooLong { + fam: libc::sa_family_t, + path: [u8; 300], + } + let path_addr = TooLong { + fam: libc::AF_UNIX as libc::sa_family_t, + path: [b'o'; 300], + }; + unsafe { + let raw_addr = &path_addr as *const TooLong as *const sockaddr; + UnixSocketAddr::from_raw(raw_addr, size_of::() as _) + }.expect_err("too long"); +} + +#[test] +fn from_raw_empty() { + let unspecified_addr = UnixSocketAddr::new_unspecified(); + let (raw_addr, raw_len) = unspecified_addr.as_raw(); + let a = unsafe { + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len) + }.expect("from_raw() accepts new_unspecified()"); + assert_eq!(a, unspecified_addr); + assert!(a.is_unnamed()); + + if !UnixSocketAddr::has_abstract_addresses() { + let a = unsafe { + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len+10) + }.expect("from_raw() accepts extra NULs"); + assert_eq!(a, unspecified_addr); + assert!(a.is_unnamed()); + } +} + +#[cfg(any(target_os="linux", target_os="android"))] +#[test] +fn from_raw_abstract() { + let abstract_addr = UnixSocketAddr::from_abstract(b"aa!").unwrap(); + let a = unsafe { + let (raw_addr, raw_len) = abstract_addr.as_raw(); + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len) + }.expect("from_raw() accepts from_abstract()"); + assert_eq!(a, abstract_addr); + assert!(a.is_abstract()); + + let max_abstract = "l".repeat(UnixSocketAddr::max_abstract_len()); + let abstract_addr = UnixSocketAddr::from_abstract(max_abstract.as_bytes()).unwrap(); + let (raw_addr, raw_len) = abstract_addr.as_raw(); + let a = unsafe { + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len) + }.expect("from_raw() accepts longest abstract"); + assert_eq!(a, abstract_addr); + assert!(a.is_abstract()); + + unsafe { + UnixSocketAddr::from_raw(raw_addr as *const sockaddr_un as *const sockaddr, raw_len+1) + }.expect_err("from_raw() rejects too long abstract"); +}