Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/sockaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ impl SockAddr {

/// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
///
/// Returns an error if the path is longer than `SUN_LEN`.
/// Returns an error if a pathname contains a null byte or the path is longer
/// than `SUN_LEN`.
#[cfg(not(target_os = "wasi"))]
pub fn unix<P>(path: P) -> io::Result<SockAddr>
where
Expand Down
13 changes: 9 additions & 4 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,12 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
"path must be shorter than SUN_LEN",
));
}
if bytes.first() != Some(&0) && bytes.contains(&0) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"path must not contain null bytes",
));
}

storage.sun_family = libc::AF_UNIX as sa_family_t;
// SAFETY: `bytes` and `addr.sun_path` are not overlapping and
Expand Down Expand Up @@ -961,12 +967,11 @@ impl SockAddr {
}

/// Returns this address as Unix `SocketAddr` if it is an `AF_UNIX` pathname
/// address, otherwise returns `None`.
/// address that can be represented by the standard library, otherwise returns
/// `None`.
pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
let path = self.as_pathname()?;
// SAFETY: we can represent this as a valid pathname, then so can the
// standard library.
Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
std::os::unix::net::SocketAddr::from_pathname(path).ok()
Comment on lines 969 to +974

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where you changed whether this conversion can fail.

}

/// Returns this address as a `Path` reference if it is an `AF_UNIX`
Expand Down
6 changes: 6 additions & 0 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,12 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result<SockAddr> {
"path must be shorter than SUN_LEN",
));
}
if bytes.first() != Some(&0) && bytes.contains(&0) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"path must not contain null bytes",
));
}

storage.sun_family = crate::sys::AF_UNIX as sa_family_t;
// SAFETY: casting `[u8]` to `[i8]` is safe.
Expand Down
51 changes: 51 additions & 0 deletions tests/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,44 @@ fn socket_address_unix() {
}
}

#[test]
#[cfg(not(target_os = "wasi"))]
fn socket_address_unix_invalid_pathname() {
for path in ["a\0b", "a\0", "a\0b\0c"] {
let err = SockAddr::unix(path).unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
}
}

#[test]
#[cfg(all(unix, not(target_os = "wasi")))]
fn socket_address_unix_padded_raw_pathname() {
let original = SockAddr::unix("socket").unwrap();
// SAFETY: a null-terminated pathname and zero padding form a valid
// sockaddr_un. Raw callers can supply the full structure length.
let (_, addr) = unsafe {
SockAddr::try_init(|storage, len| {
std::ptr::copy_nonoverlapping(original.as_ptr(), storage, 1);
*len = mem::size_of::<libc::sockaddr_un>() as _;
Ok(())
})
}
.unwrap();
assert!(addr.as_pathname().unwrap().as_os_str().len() > "socket".len());
assert!(addr.as_unix().is_none());
}

#[test]
#[cfg(all(unix, not(target_os = "wasi")))]
fn socket_address_unix_non_utf8_pathname() {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;

let path = Path::new(OsStr::from_bytes(b"socket-\xff"));
let addr = SockAddr::unix(path).unwrap();
assert_eq!(addr.as_unix().unwrap().as_pathname(), Some(path));
}

#[test]
#[cfg(not(target_os = "wasi"))]
fn socket_address_unix_unnamed() {
Expand Down Expand Up @@ -208,9 +246,22 @@ fn socket_address_unix_abstract_namespace() {
// The first byte is the opening null bytes of an abstract address, should not be included.
assert_eq!(addr.as_abstract_namespace(), Some(&path.as_bytes()[1..]));
assert!(addr.as_pathname().is_none());
assert!(addr.as_unix().is_none());
assert!(!addr.is_unnamed());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
fn socket_address_unix_abstract_null_bytes() {
for path in ["\0", "\0\0", "\0abstract\0payload"] {
let addr = SockAddr::unix(path).unwrap();
assert_eq!(addr.as_abstract_namespace(), Some(&path.as_bytes()[1..]));
assert!(addr.as_pathname().is_none());
assert!(addr.as_unix().is_none());
assert!(!addr.is_unnamed());
}
}

#[test]
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
fn socket_address_vsock() {
Expand Down
Loading