From f2cdb57b946c1f7dc07d8e944aad8d4af8cb2f17 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Sun, 23 Jan 2022 17:11:06 +0100 Subject: [PATCH 1/5] Add os::unix::net::SocketAddr::unix Creates a new SocketAddr from a path, supports both regular paths and abstract namespaces. --- library/std/src/os/unix/net/addr.rs | 69 ++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index f450e41bfea1e..b8e8e9b506d33 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -2,7 +2,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; -use crate::{ascii, fmt, io, iter, mem}; +use crate::{ascii, fmt, io, iter, mem, ptr}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -127,6 +127,73 @@ impl SocketAddr { Ok(SocketAddr { addr, len }) } + /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. + /// + /// # Errors + /// + /// Returns an error if the path is longer than `SUN_LEN`. + /// + /// # Examples + /// + /// ``` + /// #![feature(unix_socket_creation)] + /// use std::os::unix::net::SocketAddr; + /// use std::path::Path; + /// + /// # fn main() -> std::io::Result<()> { + /// let address = SocketAddr::unix("/path/to/socket")?; + /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "unix_socket_creation", issue = "65275")] + pub fn unix

(path: P) -> io::Result + where + P: AsRef, + { + // SAFETY: All zeros is a valid representation for `sockaddr_un`. + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + + let bytes = path.as_ref().as_os_str().as_bytes(); + let too_long = match bytes.first() { + None => false, + // linux abstract namespaces aren't null-terminated. + Some(&0) => bytes.len() > storage.sun_path.len(), + Some(_) => bytes.len() >= storage.sun_path.len(), + }; + if too_long { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + + storage.sun_family = libc::AF_UNIX as _; + // SAFETY: `bytes` and `addr.sun_path` are not overlapping and + // both point to valid memory. + // NOTE: We zeroed the memory above, so the path is already null + // terminated. + unsafe { + ptr::copy_nonoverlapping( + bytes.as_ptr(), + storage.sun_path.as_mut_ptr().cast(), + bytes.len(), + ) + }; + + let base = &storage as *const _ as usize; + let path = &storage.sun_path as *const _ as usize; + let sun_path_offset = path - base; + let length = sun_path_offset + + bytes.len() + + match bytes.first() { + Some(&0) | None => 0, + Some(_) => 1, + }; + + Ok(SocketAddr { addr: storage, len: length as _ }) + } + /// Returns `true` if the address is unnamed. /// /// # Examples From c1cd200922702f2ec5e30d5b5391c0443607d647 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 24 Jan 2022 18:00:23 +0100 Subject: [PATCH 2/5] Rename SocketAddr::unix to from_path And change it to disallow NULL bytes. --- library/std/src/os/unix/net/addr.rs | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index b8e8e9b506d33..7f64533cb67dc 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -131,7 +131,8 @@ impl SocketAddr { /// /// # Errors /// - /// Returns an error if the path is longer than `SUN_LEN`. + /// Returns an error if the path is longer than `SUN_LEN` or if it contains + /// NULL bytes. /// /// # Examples /// @@ -141,13 +142,22 @@ impl SocketAddr { /// use std::path::Path; /// /// # fn main() -> std::io::Result<()> { - /// let address = SocketAddr::unix("/path/to/socket")?; + /// let address = SocketAddr::from_path("/path/to/socket")?; /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); /// # Ok(()) /// # } /// ``` + /// + /// Creating a `SocketAddr` with a NULL byte results in an error. + /// + /// ``` + /// #![feature(unix_socket_creation)] + /// use std::os::unix::net::SocketAddr; + /// + /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err()); + /// ``` #[unstable(feature = "unix_socket_creation", issue = "65275")] - pub fn unix

(path: P) -> io::Result + pub fn from_path

(path: P) -> io::Result where P: AsRef, { @@ -155,13 +165,12 @@ impl SocketAddr { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; let bytes = path.as_ref().as_os_str().as_bytes(); - let too_long = match bytes.first() { - None => false, - // linux abstract namespaces aren't null-terminated. - Some(&0) => bytes.len() > storage.sun_path.len(), - Some(_) => bytes.len() >= storage.sun_path.len(), - }; - if too_long { + if bytes.contains(&b'\0') { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path can't contain null bytes", + )); + } else if bytes.len() >= storage.sun_path.len() { return Err(io::Error::new( io::ErrorKind::InvalidInput, "path must be shorter than SUN_LEN", @@ -184,12 +193,7 @@ impl SocketAddr { let base = &storage as *const _ as usize; let path = &storage.sun_path as *const _ as usize; let sun_path_offset = path - base; - let length = sun_path_offset - + bytes.len() - + match bytes.first() { - Some(&0) | None => 0, - Some(_) => 1, - }; + let length = sun_path_offset + bytes.len() + 1; Ok(SocketAddr { addr: storage, len: length as _ }) } From ca9a3c9a9fc7ec854919b2b932a21fc8c5c76d7f Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Thu, 27 Jan 2022 09:52:59 +0100 Subject: [PATCH 3/5] Make sockaddr_un safe and use copy_nonoverlapping The creation of libc::sockaddr_un is a safe operation, no need for it to be unsafe. This also uses the more performant copy_nonoverlapping instead of an iterator. --- library/std/src/os/unix/net/addr.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 7f64533cb67dc..9732a989f3610 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -2,7 +2,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; use crate::sys::cvt; -use crate::{ascii, fmt, io, iter, mem, ptr}; +use crate::{ascii, fmt, io, mem, ptr}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -22,8 +22,9 @@ fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { path - base } -pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); +pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + // SAFETY: All zeros is a valid representation for `sockaddr_un`. + let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() }; addr.sun_family = libc::AF_UNIX as libc::sa_family_t; let bytes = path.as_os_str().as_bytes(); @@ -41,11 +42,13 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, &"path must be shorter than SUN_LEN", )); } - for (dst, src) in iter::zip(&mut addr.sun_path, bytes) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct + // SAFETY: `bytes` and `addr.sun_path` are not overlapping and + // both point to valid memory. + // NOTE: We zeroed the memory above, so the path is already null + // terminated. + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len()) + }; let mut len = sun_path_offset(&addr) + bytes.len(); match bytes.get(0) { From 4acb8ac46c9ae4e28b4f9328202c4fdb93a6c6ea Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Thu, 27 Jan 2022 09:54:28 +0100 Subject: [PATCH 4/5] Use sockaddr_un in unix SocketAddr::from_path --- library/std/src/os/unix/net/addr.rs | 36 +---------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 9732a989f3610..40ee8833bbf46 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -164,41 +164,7 @@ impl SocketAddr { where P: AsRef, { - // SAFETY: All zeros is a valid representation for `sockaddr_un`. - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - - let bytes = path.as_ref().as_os_str().as_bytes(); - if bytes.contains(&b'\0') { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path can't contain null bytes", - )); - } else if bytes.len() >= storage.sun_path.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN", - )); - } - - storage.sun_family = libc::AF_UNIX as _; - // SAFETY: `bytes` and `addr.sun_path` are not overlapping and - // both point to valid memory. - // NOTE: We zeroed the memory above, so the path is already null - // terminated. - unsafe { - ptr::copy_nonoverlapping( - bytes.as_ptr(), - storage.sun_path.as_mut_ptr().cast(), - bytes.len(), - ) - }; - - let base = &storage as *const _ as usize; - let path = &storage.sun_path as *const _ as usize; - let sun_path_offset = path - base; - let length = sun_path_offset + bytes.len() + 1; - - Ok(SocketAddr { addr: storage, len: length as _ }) + sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len }) } /// Returns `true` if the address is unnamed. From 35f578fc789a14106b2e32b80846ecd62ccf9672 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 28 Jan 2022 15:00:17 +0100 Subject: [PATCH 5/5] Update tracking issue for unix_socket_creation --- library/std/src/os/unix/net/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 40ee8833bbf46..9dbd4548bc92d 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -159,7 +159,7 @@ impl SocketAddr { /// /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err()); /// ``` - #[unstable(feature = "unix_socket_creation", issue = "65275")] + #[unstable(feature = "unix_socket_creation", issue = "93423")] pub fn from_path

(path: P) -> io::Result where P: AsRef,