Skip to content

Commit 6d07477

Browse files
committed
UnixAddr: replace path_len with sun_len
Within UnixAddr, replace the path_len variable (length of the sun_path field) with sun_len (length of the whole structure). This is more similar to how other sockaddr types work, and it's the same way that the BSDs use the sun_len field. Also, don't require that sun_path be nul-terminated. The OS doesn't require it.
1 parent 7be98a4 commit 6d07477

File tree

2 files changed

+59
-29
lines changed

2 files changed

+59
-29
lines changed

src/sys/socket/addr.rs

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::{Result, NixPath};
33
use crate::errno::Errno;
44
use memoffset::offset_of;
55
use std::{fmt, mem, net, ptr, slice};
6+
use std::convert::TryInto;
67
use std::ffi::OsStr;
78
use std::hash::{Hash, Hasher};
89
use std::path::Path;
@@ -575,9 +576,11 @@ impl fmt::Display for Ipv6Addr {
575576
/// A wrapper around `sockaddr_un`.
576577
#[derive(Clone, Copy, Debug)]
577578
pub struct UnixAddr {
578-
// INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts
579+
// INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts
579580
sun: libc::sockaddr_un,
580-
path_len: usize,
581+
/// The length of the valid part of `sun`, including the sun_family field
582+
/// but excluding any trailing nul.
583+
sun_len: u8,
581584
}
582585

583586
// linux man page unix(7) says there are 3 kinds of unix socket:
@@ -594,8 +597,10 @@ enum UnixAddrKind<'a> {
594597
Abstract(&'a [u8]),
595598
}
596599
impl<'a> UnixAddrKind<'a> {
597-
/// Safety: sun & path_len must be valid
598-
unsafe fn get(sun: &'a libc::sockaddr_un, path_len: usize) -> Self {
600+
/// Safety: sun & sun_len must be valid
601+
unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
602+
assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path));
603+
let path_len = sun_len as usize - offset_of!(libc::sockaddr_un, sun_path);
599604
if path_len == 0 {
600605
return Self::Unnamed;
601606
}
@@ -605,7 +610,7 @@ impl<'a> UnixAddrKind<'a> {
605610
slice::from_raw_parts(sun.sun_path.as_ptr().add(1) as *const u8, path_len - 1);
606611
return Self::Abstract(name);
607612
}
608-
let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len - 1);
613+
let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len);
609614
Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
610615
}
611616
}
@@ -626,18 +631,32 @@ impl UnixAddr {
626631
return Err(Errno::ENAMETOOLONG);
627632
}
628633

634+
let sun_len = (bytes.len() +
635+
offset_of!(libc::sockaddr_un, sun_path)).try_into()
636+
.unwrap();
637+
638+
#[cfg(any(target_os = "dragonfly",
639+
target_os = "freebsd",
640+
target_os = "ios",
641+
target_os = "macos",
642+
target_os = "netbsd",
643+
target_os = "illumos",
644+
target_os = "openbsd"))]
645+
{
646+
ret.sun_len = sun_len;
647+
}
629648
ptr::copy_nonoverlapping(bytes.as_ptr(),
630649
ret.sun_path.as_mut_ptr() as *mut u8,
631650
bytes.len());
632651

633-
Ok(UnixAddr::from_raw_parts(ret, bytes.len() + 1))
652+
Ok(UnixAddr::from_raw_parts(ret, sun_len))
634653
}
635654
})?
636655
}
637656

638657
/// Create a new `sockaddr_un` representing an address in the "abstract namespace".
639658
///
640-
/// The leading null byte for the abstract namespace is automatically added;
659+
/// The leading nul byte for the abstract namespace is automatically added;
641660
/// thus the input `path` is expected to be the bare name, not null-prefixed.
642661
/// This is a Linux-specific extension, primarily used to allow chrooted
643662
/// processes to communicate with processes having a different filesystem view.
@@ -653,39 +672,50 @@ impl UnixAddr {
653672
if path.len() >= ret.sun_path.len() {
654673
return Err(Errno::ENAMETOOLONG);
655674
}
675+
let sun_len = (path.len() +
676+
1 +
677+
offset_of!(libc::sockaddr_un, sun_path)).try_into()
678+
.unwrap();
656679

657680
// Abstract addresses are represented by sun_path[0] ==
658681
// b'\0', so copy starting one byte in.
659682
ptr::copy_nonoverlapping(path.as_ptr(),
660683
ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
661684
path.len());
662685

663-
Ok(UnixAddr::from_raw_parts(ret, path.len() + 1))
686+
Ok(UnixAddr::from_raw_parts(ret, sun_len))
664687
}
665688
}
666689

667-
/// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `path_len` is the "addrlen"
668-
/// of this address, but minus `offsetof(struct sockaddr_un, sun_path)`. Basically the length
669-
/// of the data in `sun_path`.
690+
/// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
691+
/// is the size of the valid portion of the struct, excluding any trailing
692+
/// NUL.
670693
///
671694
/// # Safety
672-
/// This pair of sockaddr_un & path_len must be a valid unix addr, which means:
673-
/// - path_len <= sockaddr_un.sun_path.len()
674-
/// - if this is a unix addr with a pathname, sun.sun_path is a nul-terminated fs path and
675-
/// sun.sun_path[path_len - 1] == 0 || sun.sun_path[path_len] == 0
676-
pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, mut path_len: usize) -> UnixAddr {
677-
if let UnixAddrKind::Pathname(_) = UnixAddrKind::get(&sun, path_len) {
678-
if sun.sun_path[path_len - 1] != 0 {
679-
assert_eq!(sun.sun_path[path_len], 0);
680-
path_len += 1
681-
}
695+
/// This pair of sockaddr_un & sun_len must be a valid unix addr, which
696+
/// means:
697+
/// - sun_len >= offset_of(sockaddr_un, sun_path)
698+
/// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path)
699+
/// - if this is a unix addr with a pathname, sun.sun_path is a
700+
/// fs path, not necessarily nul-terminated.
701+
pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, sun_len: u8) -> UnixAddr {
702+
#[cfg(any(target_os = "dragonfly",
703+
target_os = "freebsd",
704+
target_os = "ios",
705+
target_os = "macos",
706+
target_os = "netbsd",
707+
target_os = "illumos",
708+
target_os = "openbsd"))]
709+
{
710+
assert_eq!(sun_len, sun.sun_len);
682711
}
683-
UnixAddr { sun, path_len }
712+
713+
UnixAddr { sun, sun_len }
684714
}
685715

686716
fn kind(&self) -> UnixAddrKind<'_> {
687717
// SAFETY: our sockaddr is always valid because of the invariant on the struct
688-
unsafe { UnixAddrKind::get(&self.sun, self.path_len) }
718+
unsafe { UnixAddrKind::get(&self.sun, self.sun_len) }
689719
}
690720

691721
/// If this address represents a filesystem path, return that path.
@@ -712,7 +742,7 @@ impl UnixAddr {
712742
/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
713743
#[inline]
714744
pub fn path_len(&self) -> usize {
715-
self.path_len
745+
self.sun_len as usize - offset_of!(libc::sockaddr_un, sun_path)
716746
}
717747
/// Returns a pointer to the raw `sockaddr_un` struct
718748
#[inline]
@@ -957,12 +987,12 @@ impl SockAddr {
957987
},
958988
mem::size_of_val(addr) as libc::socklen_t
959989
),
960-
SockAddr::Unix(UnixAddr { ref sun, path_len }) => (
990+
SockAddr::Unix(UnixAddr { ref sun, sun_len }) => (
961991
// This cast is always allowed in C
962992
unsafe {
963993
&*(sun as *const libc::sockaddr_un as *const libc::sockaddr)
964994
},
965-
(path_len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t
995+
sun_len as libc::socklen_t
966996
),
967997
#[cfg(any(target_os = "android", target_os = "linux"))]
968998
SockAddr::Netlink(NetlinkAddr(ref sa)) => (

src/sys/socket/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use cfg_if::cfg_if;
55
use crate::{Result, errno::Errno};
66
use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
77
CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
8-
use memoffset::offset_of;
8+
use std::convert::TryInto;
99
use std::{mem, ptr, slice};
1010
use std::os::unix::io::RawFd;
1111
#[cfg(target_os = "linux")]
@@ -1934,10 +1934,10 @@ pub fn sockaddr_storage_to_addr(
19341934
Ok(SockAddr::Inet(InetAddr::V6(sin6)))
19351935
}
19361936
libc::AF_UNIX => {
1937-
let pathlen = len - offset_of!(sockaddr_un, sun_path);
19381937
unsafe {
19391938
let sun = *(addr as *const _ as *const sockaddr_un);
1940-
Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen)))
1939+
let sun_len = len.try_into().unwrap();
1940+
Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len)))
19411941
}
19421942
}
19431943
#[cfg(any(target_os = "android", target_os = "linux"))]

0 commit comments

Comments
 (0)