11use super :: sa_family_t;
2+ use cfg_if:: cfg_if;
23use crate :: { Result , NixPath } ;
34use crate :: errno:: Errno ;
45use memoffset:: offset_of;
56use std:: { fmt, mem, net, ptr, slice} ;
7+ use std:: convert:: TryInto ;
68use std:: ffi:: OsStr ;
79use std:: hash:: { Hash , Hasher } ;
810use std:: path:: Path ;
@@ -575,9 +577,17 @@ impl fmt::Display for Ipv6Addr {
575577/// A wrapper around `sockaddr_un`.
576578#[ derive( Clone , Copy , Debug ) ]
577579pub struct UnixAddr {
578- // INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts
580+ // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts
579581 sun : libc:: sockaddr_un ,
580- path_len : usize ,
582+ /// The length of the valid part of `sun`, including the sun_family field
583+ /// but excluding any trailing nul.
584+ // On the BSDs, this field is built into sun
585+ #[ cfg( any( target_os = "android" ,
586+ target_os = "fuchsia" ,
587+ target_os = "illumos" ,
588+ target_os = "linux"
589+ ) ) ]
590+ sun_len : u8
581591}
582592
583593// linux man page unix(7) says there are 3 kinds of unix socket:
@@ -594,8 +604,10 @@ enum UnixAddrKind<'a> {
594604 Abstract ( & ' a [ u8 ] ) ,
595605}
596606impl < ' a > UnixAddrKind < ' a > {
597- /// Safety: sun & path_len must be valid
598- unsafe fn get ( sun : & ' a libc:: sockaddr_un , path_len : usize ) -> Self {
607+ /// Safety: sun & sun_len must be valid
608+ unsafe fn get ( sun : & ' a libc:: sockaddr_un , sun_len : u8 ) -> Self {
609+ assert ! ( sun_len as usize >= offset_of!( libc:: sockaddr_un, sun_path) ) ;
610+ let path_len = sun_len as usize - offset_of ! ( libc:: sockaddr_un, sun_path) ;
599611 if path_len == 0 {
600612 return Self :: Unnamed ;
601613 }
@@ -605,8 +617,19 @@ impl<'a> UnixAddrKind<'a> {
605617 slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) . add ( 1 ) as * const u8 , path_len - 1 ) ;
606618 return Self :: Abstract ( name) ;
607619 }
608- let pathname = slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) as * const u8 , path_len - 1 ) ;
609- Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( pathname) ) )
620+ let pathname = slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) as * const u8 , path_len) ;
621+ if pathname. last ( ) == Some ( & 0 ) {
622+ // A trailing NUL is not considered part of the path, and it does
623+ // not need to be included in the addrlen passed to functions like
624+ // bind(). However, Linux adds a trailing NUL, even if one was not
625+ // originally present, when returning addrs from functions like
626+ // getsockname() (the BSDs do not do that). So we need to filter
627+ // out any trailing NUL here, so sockaddrs can round-trip through
628+ // the kernel and still compare equal.
629+ Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( & pathname[ 0 ..pathname. len ( ) - 1 ] ) ) )
630+ } else {
631+ Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( pathname) ) )
632+ }
610633 }
611634}
612635
@@ -626,19 +649,32 @@ impl UnixAddr {
626649 return Err ( Errno :: ENAMETOOLONG ) ;
627650 }
628651
652+ let sun_len = ( bytes. len ( ) +
653+ offset_of ! ( libc:: sockaddr_un, sun_path) ) . try_into ( )
654+ . unwrap ( ) ;
655+
656+ #[ cfg( any( target_os = "dragonfly" ,
657+ target_os = "freebsd" ,
658+ target_os = "ios" ,
659+ target_os = "macos" ,
660+ target_os = "netbsd" ,
661+ target_os = "openbsd" ) ) ]
662+ {
663+ ret. sun_len = sun_len;
664+ }
629665 ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) ,
630666 ret. sun_path . as_mut_ptr ( ) as * mut u8 ,
631667 bytes. len ( ) ) ;
632668
633- Ok ( UnixAddr :: from_raw_parts ( ret, bytes . len ( ) + 1 ) )
669+ Ok ( UnixAddr :: from_raw_parts ( ret, sun_len ) )
634670 }
635671 } ) ?
636672 }
637673
638674 /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
639675 ///
640- /// The leading null byte for the abstract namespace is automatically added;
641- /// thus the input `path` is expected to be the bare name, not null -prefixed.
676+ /// The leading nul byte for the abstract namespace is automatically added;
677+ /// thus the input `path` is expected to be the bare name, not NUL -prefixed.
642678 /// This is a Linux-specific extension, primarily used to allow chrooted
643679 /// processes to communicate with processes having a different filesystem view.
644680 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
@@ -653,39 +689,51 @@ impl UnixAddr {
653689 if path. len ( ) >= ret. sun_path . len ( ) {
654690 return Err ( Errno :: ENAMETOOLONG ) ;
655691 }
692+ let sun_len = ( path. len ( ) +
693+ 1 +
694+ offset_of ! ( libc:: sockaddr_un, sun_path) ) . try_into ( )
695+ . unwrap ( ) ;
656696
657697 // Abstract addresses are represented by sun_path[0] ==
658698 // b'\0', so copy starting one byte in.
659699 ptr:: copy_nonoverlapping ( path. as_ptr ( ) ,
660700 ret. sun_path . as_mut_ptr ( ) . offset ( 1 ) as * mut u8 ,
661701 path. len ( ) ) ;
662702
663- Ok ( UnixAddr :: from_raw_parts ( ret, path . len ( ) + 1 ) )
703+ Ok ( UnixAddr :: from_raw_parts ( ret, sun_len ) )
664704 }
665705 }
666706
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` .
707+ /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
708+ /// is the size of the valid portion of the struct, excluding any trailing
709+ /// NUL .
670710 ///
671711 /// # 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
712+ /// This pair of sockaddr_un & sun_len must be a valid unix addr, which
713+ /// means:
714+ /// - sun_len >= offset_of(sockaddr_un, sun_path)
715+ /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path)
716+ /// - if this is a unix addr with a pathname, sun.sun_path is a
717+ /// fs path, not necessarily nul-terminated.
718+ pub ( crate ) unsafe fn from_raw_parts ( sun : libc:: sockaddr_un , sun_len : u8 ) -> UnixAddr {
719+ cfg_if ! {
720+ if #[ cfg( any( target_os = "android" ,
721+ target_os = "fuchsia" ,
722+ target_os = "illumos" ,
723+ target_os = "linux"
724+ ) ) ]
725+ {
726+ UnixAddr { sun, sun_len }
727+ } else {
728+ assert_eq!( sun_len, sun. sun_len) ;
729+ UnixAddr { sun}
681730 }
682731 }
683- UnixAddr { sun, path_len }
684732 }
685733
686734 fn kind ( & self ) -> UnixAddrKind < ' _ > {
687735 // SAFETY: our sockaddr is always valid because of the invariant on the struct
688- unsafe { UnixAddrKind :: get ( & self . sun , self . path_len ) }
736+ unsafe { UnixAddrKind :: get ( & self . sun , self . sun_len ( ) ) }
689737 }
690738
691739 /// If this address represents a filesystem path, return that path.
@@ -699,7 +747,7 @@ impl UnixAddr {
699747 /// If this address represents an abstract socket, return its name.
700748 ///
701749 /// For abstract sockets only the bare name is returned, without the
702- /// leading null byte. `None` is returned for unnamed or path-backed sockets.
750+ /// leading NUL byte. `None` is returned for unnamed or path-backed sockets.
703751 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
704752 #[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
705753 pub fn as_abstract ( & self ) -> Option < & [ u8 ] > {
@@ -712,7 +760,7 @@ impl UnixAddr {
712760 /// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
713761 #[ inline]
714762 pub fn path_len ( & self ) -> usize {
715- self . path_len
763+ self . sun_len ( ) as usize - offset_of ! ( libc :: sockaddr_un , sun_path )
716764 }
717765 /// Returns a pointer to the raw `sockaddr_un` struct
718766 #[ inline]
@@ -724,6 +772,21 @@ impl UnixAddr {
724772 pub fn as_mut_ptr ( & mut self ) -> * mut libc:: sockaddr_un {
725773 & mut self . sun
726774 }
775+
776+ fn sun_len ( & self ) -> u8 {
777+ cfg_if ! {
778+ if #[ cfg( any( target_os = "android" ,
779+ target_os = "fuchsia" ,
780+ target_os = "illumos" ,
781+ target_os = "linux"
782+ ) ) ]
783+ {
784+ self . sun_len
785+ } else {
786+ self . sun. sun_len
787+ }
788+ }
789+ }
727790}
728791
729792#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
@@ -957,12 +1020,12 @@ impl SockAddr {
9571020 } ,
9581021 mem:: size_of_val ( addr) as libc:: socklen_t
9591022 ) ,
960- SockAddr :: Unix ( UnixAddr { ref sun , path_len } ) => (
1023+ SockAddr :: Unix ( ref unix_addr ) => (
9611024 // This cast is always allowed in C
9621025 unsafe {
963- & * ( sun as * const libc:: sockaddr_un as * const libc:: sockaddr )
1026+ & * ( & unix_addr . sun as * const libc:: sockaddr_un as * const libc:: sockaddr )
9641027 } ,
965- ( path_len + offset_of ! ( libc :: sockaddr_un , sun_path ) ) as libc:: socklen_t
1028+ unix_addr . sun_len ( ) as libc:: socklen_t
9661029 ) ,
9671030 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
9681031 SockAddr :: Netlink ( NetlinkAddr ( ref sa) ) => (
0 commit comments