@@ -3,6 +3,7 @@ use crate::{Result, NixPath};
33use crate :: errno:: Errno ;
44use memoffset:: offset_of;
55use std:: { fmt, mem, net, ptr, slice} ;
6+ use std:: convert:: TryInto ;
67use std:: ffi:: OsStr ;
78use std:: hash:: { Hash , Hasher } ;
89use std:: path:: Path ;
@@ -575,9 +576,11 @@ impl fmt::Display for Ipv6Addr {
575576/// A wrapper around `sockaddr_un`.
576577#[ derive( Clone , Copy , Debug ) ]
577578pub 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}
596599impl < ' 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) ) => (
0 commit comments