Skip to content

Commit

Permalink
CR: Don't return initial null of abstract address.
Browse files Browse the repository at this point in the history
  • Loading branch information
t4lz committed Mar 1, 2023
1 parent 8375cea commit 47acad2
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 17 deletions.
42 changes: 27 additions & 15 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,29 +690,41 @@ impl SockAddr {
})
}

/// Get the length of the path bytes of the address, not including any terminating null.
fn path_len(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> usize {
self.len() as usize - offset_of_path(storage) - if null_terminated { 1 } else { 0 }
/// Get the length of the path bytes of the address, not including the terminating or initial
/// (for abstract names) null byte.
///
/// Should not be called on unnamed addresses.
fn path_len(&self, storage: &libc::sockaddr_un) -> usize {
debug_assert!(!self.is_unnamed());
self.len() as usize - offset_of_path(storage) - 1
}

/// Get a u8 slice for the bytes of the pathname or abstract name.
fn path_bytes(&self, storage: &libc::sockaddr_un, null_terminated: bool) -> &[u8] {
let path_len = self.path_len(storage, null_terminated);
///
/// Should not be called on unnamed addresses.
fn path_bytes(&self, storage: &libc::sockaddr_un, abstract_name: bool) -> &[u8] {
debug_assert!(!self.is_unnamed());
// SAFETY: the pointed objects of type `i8` have the same memory layout as `u8`. The path is
// the last field in the storage and so it length is equal to
// TOTAL_LENGTH - OFFSET_OF_PATH -1 if the path is null-terminated.
// TOTAL_LENGTH - OFFSET_OF_PATH if the path is not null-terminated.
// the last field in the storage and so its length is equal to
// TOTAL_LENGTH - OFFSET_OF_PATH -1
// Where the 1 is either a terminating null if we have a pathname address, or the initial
// null byte, if it's an abstract name address. In the latter case, the path bytes start
// after the initial null byte, hence the `offset`.
// There is no safe way to convert a `&[i8]` ot `&[u8]`
unsafe { slice::from_raw_parts(storage.sun_path.as_ptr() as *const u8, path_len) }
unsafe {
slice::from_raw_parts(
(storage.sun_path.as_ptr() as *const u8).offset(abstract_name as isize),
self.path_len(storage),
)
}
}

/// Returns this address as a `Path` if it is an `AF_UNIX` pathname address, otherwise returns
/// `None`.
/// Returns this address as a `Path` reference if it is an `AF_UNIX` pathname address, otherwise
/// returns `None`.
pub fn as_pathname(&self) -> Option<&Path> {
self.as_sockaddr_un().and_then(|storage| {
(self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| {
// The -1 is for the terminating null.
let path_slice = self.path_bytes(storage, true);
let path_slice = self.path_bytes(storage, false);
Path::new::<OsStr>(OsStrExt::from_bytes(path_slice))
})
})
Expand All @@ -721,14 +733,14 @@ impl SockAddr {
/// Returns this address as a slice of bytes representing an abstract address if it is an
/// `AF_UNIX` abstract address, otherwise returns `None`.
///
/// Abstract addresses are a Linux extension, so this method returns None on all non-Linux
/// Abstract addresses are a Linux extension, so this method returns `None` on all non-Linux
/// platforms.
pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
#[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
{
self.as_sockaddr_un().and_then(|storage| {
(self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] == 0)
.then(|| self.path_bytes(storage, false))
.then(|| self.path_bytes(storage, true))
})
}
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "fuchsia")))]
Expand Down
8 changes: 6 additions & 2 deletions tests/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ fn socket_address_unix_unnamed() {
}

#[test]
#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "fuchsia"), feature = "all"))]
#[cfg(all(
any(target_os = "linux", target_os = "android", target_os = "fuchsia"),
feature = "all"
))]
fn socket_address_unix_abstract_namespace() {
let path = "\0h".repeat(108 / 2);
let addr = SockAddr::unix(&path).unwrap();
Expand All @@ -185,7 +188,8 @@ fn socket_address_unix_abstract_namespace() {
std::mem::size_of::<libc::sockaddr_un>()
);
assert!(!addr.is_unnamed());
assert_eq!(addr.as_abstract_namespace(), Some(path.as_bytes()));
// 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.is_unnamed());
}
Expand Down

0 comments on commit 47acad2

Please sign in to comment.