1
1
use super :: sa_family_t;
2
+ use cfg_if:: cfg_if;
2
3
use crate :: { Result , NixPath } ;
3
4
use crate :: errno:: Errno ;
4
5
use memoffset:: offset_of;
5
6
use std:: { fmt, mem, net, ptr, slice} ;
7
+ use std:: convert:: TryInto ;
6
8
use std:: ffi:: OsStr ;
7
9
use std:: hash:: { Hash , Hasher } ;
8
10
use std:: path:: Path ;
@@ -575,9 +577,17 @@ impl fmt::Display for Ipv6Addr {
575
577
/// A wrapper around `sockaddr_un`.
576
578
#[ derive( Clone , Copy , Debug ) ]
577
579
pub 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
579
581
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
581
591
}
582
592
583
593
// linux man page unix(7) says there are 3 kinds of unix socket:
@@ -594,8 +604,10 @@ enum UnixAddrKind<'a> {
594
604
Abstract ( & ' a [ u8 ] ) ,
595
605
}
596
606
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 {
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) ;
599
611
if path_len == 0 {
600
612
return Self :: Unnamed ;
601
613
}
@@ -605,8 +617,19 @@ impl<'a> UnixAddrKind<'a> {
605
617
slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) . add ( 1 ) as * const u8 , path_len - 1 ) ;
606
618
return Self :: Abstract ( name) ;
607
619
}
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
+ }
610
633
}
611
634
}
612
635
@@ -626,19 +649,32 @@ impl UnixAddr {
626
649
return Err ( Errno :: ENAMETOOLONG ) ;
627
650
}
628
651
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
+ }
629
665
ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) ,
630
666
ret. sun_path . as_mut_ptr ( ) as * mut u8 ,
631
667
bytes. len ( ) ) ;
632
668
633
- Ok ( UnixAddr :: from_raw_parts ( ret, bytes . len ( ) + 1 ) )
669
+ Ok ( UnixAddr :: from_raw_parts ( ret, sun_len ) )
634
670
}
635
671
} ) ?
636
672
}
637
673
638
674
/// Create a new `sockaddr_un` representing an address in the "abstract namespace".
639
675
///
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.
642
678
/// This is a Linux-specific extension, primarily used to allow chrooted
643
679
/// processes to communicate with processes having a different filesystem view.
644
680
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
@@ -653,39 +689,51 @@ impl UnixAddr {
653
689
if path. len ( ) >= ret. sun_path . len ( ) {
654
690
return Err ( Errno :: ENAMETOOLONG ) ;
655
691
}
692
+ let sun_len = ( path. len ( ) +
693
+ 1 +
694
+ offset_of ! ( libc:: sockaddr_un, sun_path) ) . try_into ( )
695
+ . unwrap ( ) ;
656
696
657
697
// Abstract addresses are represented by sun_path[0] ==
658
698
// b'\0', so copy starting one byte in.
659
699
ptr:: copy_nonoverlapping ( path. as_ptr ( ) ,
660
700
ret. sun_path . as_mut_ptr ( ) . offset ( 1 ) as * mut u8 ,
661
701
path. len ( ) ) ;
662
702
663
- Ok ( UnixAddr :: from_raw_parts ( ret, path . len ( ) + 1 ) )
703
+ Ok ( UnixAddr :: from_raw_parts ( ret, sun_len ) )
664
704
}
665
705
}
666
706
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 .
670
710
///
671
711
/// # 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}
681
730
}
682
731
}
683
- UnixAddr { sun, path_len }
684
732
}
685
733
686
734
fn kind ( & self ) -> UnixAddrKind < ' _ > {
687
735
// 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 ( ) ) }
689
737
}
690
738
691
739
/// If this address represents a filesystem path, return that path.
@@ -699,7 +747,7 @@ impl UnixAddr {
699
747
/// If this address represents an abstract socket, return its name.
700
748
///
701
749
/// 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.
703
751
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
704
752
#[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
705
753
pub fn as_abstract ( & self ) -> Option < & [ u8 ] > {
@@ -712,7 +760,7 @@ impl UnixAddr {
712
760
/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
713
761
#[ inline]
714
762
pub fn path_len ( & self ) -> usize {
715
- self . path_len
763
+ self . sun_len ( ) as usize - offset_of ! ( libc :: sockaddr_un , sun_path )
716
764
}
717
765
/// Returns a pointer to the raw `sockaddr_un` struct
718
766
#[ inline]
@@ -724,6 +772,21 @@ impl UnixAddr {
724
772
pub fn as_mut_ptr ( & mut self ) -> * mut libc:: sockaddr_un {
725
773
& mut self . sun
726
774
}
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
+ }
727
790
}
728
791
729
792
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
@@ -957,12 +1020,12 @@ impl SockAddr {
957
1020
} ,
958
1021
mem:: size_of_val ( addr) as libc:: socklen_t
959
1022
) ,
960
- SockAddr :: Unix ( UnixAddr { ref sun , path_len } ) => (
1023
+ SockAddr :: Unix ( ref unix_addr ) => (
961
1024
// This cast is always allowed in C
962
1025
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 )
964
1027
} ,
965
- ( path_len + offset_of ! ( libc :: sockaddr_un , sun_path ) ) as libc:: socklen_t
1028
+ unix_addr . sun_len ( ) as libc:: socklen_t
966
1029
) ,
967
1030
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
968
1031
SockAddr :: Netlink ( NetlinkAddr ( ref sa) ) => (
0 commit comments