@@ -3,6 +3,7 @@ use crate::{Result, NixPath};
3
3
use crate :: errno:: Errno ;
4
4
use memoffset:: offset_of;
5
5
use std:: { fmt, mem, net, ptr, slice} ;
6
+ use std:: convert:: TryInto ;
6
7
use std:: ffi:: OsStr ;
7
8
use std:: hash:: { Hash , Hasher } ;
8
9
use std:: path:: Path ;
@@ -575,9 +576,11 @@ impl fmt::Display for Ipv6Addr {
575
576
/// A wrapper around `sockaddr_un`.
576
577
#[ derive( Clone , Copy , Debug ) ]
577
578
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
579
580
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 ,
581
584
}
582
585
583
586
// linux man page unix(7) says there are 3 kinds of unix socket:
@@ -594,8 +597,10 @@ enum UnixAddrKind<'a> {
594
597
Abstract ( & ' a [ u8 ] ) ,
595
598
}
596
599
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) ;
599
604
if path_len == 0 {
600
605
return Self :: Unnamed ;
601
606
}
@@ -605,7 +610,7 @@ impl<'a> UnixAddrKind<'a> {
605
610
slice:: from_raw_parts ( sun. sun_path . as_ptr ( ) . add ( 1 ) as * const u8 , path_len - 1 ) ;
606
611
return Self :: Abstract ( name) ;
607
612
}
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) ;
609
614
Self :: Pathname ( Path :: new ( OsStr :: from_bytes ( pathname) ) )
610
615
}
611
616
}
@@ -626,18 +631,32 @@ impl UnixAddr {
626
631
return Err ( Errno :: ENAMETOOLONG ) ;
627
632
}
628
633
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
+ }
629
648
ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) ,
630
649
ret. sun_path . as_mut_ptr ( ) as * mut u8 ,
631
650
bytes. len ( ) ) ;
632
651
633
- Ok ( UnixAddr :: from_raw_parts ( ret, bytes . len ( ) + 1 ) )
652
+ Ok ( UnixAddr :: from_raw_parts ( ret, sun_len ) )
634
653
}
635
654
} ) ?
636
655
}
637
656
638
657
/// Create a new `sockaddr_un` representing an address in the "abstract namespace".
639
658
///
640
- /// The leading null byte for the abstract namespace is automatically added;
659
+ /// The leading nul byte for the abstract namespace is automatically added;
641
660
/// thus the input `path` is expected to be the bare name, not null-prefixed.
642
661
/// This is a Linux-specific extension, primarily used to allow chrooted
643
662
/// processes to communicate with processes having a different filesystem view.
@@ -653,39 +672,50 @@ impl UnixAddr {
653
672
if path. len ( ) >= ret. sun_path . len ( ) {
654
673
return Err ( Errno :: ENAMETOOLONG ) ;
655
674
}
675
+ let sun_len = ( path. len ( ) +
676
+ 1 +
677
+ offset_of ! ( libc:: sockaddr_un, sun_path) ) . try_into ( )
678
+ . unwrap ( ) ;
656
679
657
680
// Abstract addresses are represented by sun_path[0] ==
658
681
// b'\0', so copy starting one byte in.
659
682
ptr:: copy_nonoverlapping ( path. as_ptr ( ) ,
660
683
ret. sun_path . as_mut_ptr ( ) . offset ( 1 ) as * mut u8 ,
661
684
path. len ( ) ) ;
662
685
663
- Ok ( UnixAddr :: from_raw_parts ( ret, path . len ( ) + 1 ) )
686
+ Ok ( UnixAddr :: from_raw_parts ( ret, sun_len ) )
664
687
}
665
688
}
666
689
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 .
670
693
///
671
694
/// # 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) ;
682
711
}
683
- UnixAddr { sun, path_len }
712
+
713
+ UnixAddr { sun, sun_len }
684
714
}
685
715
686
716
fn kind ( & self ) -> UnixAddrKind < ' _ > {
687
717
// 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 ) }
689
719
}
690
720
691
721
/// If this address represents a filesystem path, return that path.
@@ -712,7 +742,7 @@ impl UnixAddr {
712
742
/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
713
743
#[ inline]
714
744
pub fn path_len ( & self ) -> usize {
715
- self . path_len
745
+ self . sun_len as usize - offset_of ! ( libc :: sockaddr_un , sun_path )
716
746
}
717
747
/// Returns a pointer to the raw `sockaddr_un` struct
718
748
#[ inline]
@@ -957,12 +987,12 @@ impl SockAddr {
957
987
} ,
958
988
mem:: size_of_val ( addr) as libc:: socklen_t
959
989
) ,
960
- SockAddr :: Unix ( UnixAddr { ref sun, path_len } ) => (
990
+ SockAddr :: Unix ( UnixAddr { ref sun, sun_len } ) => (
961
991
// This cast is always allowed in C
962
992
unsafe {
963
993
& * ( sun as * const libc:: sockaddr_un as * const libc:: sockaddr )
964
994
} ,
965
- ( path_len + offset_of ! ( libc :: sockaddr_un , sun_path ) ) as libc:: socklen_t
995
+ sun_len as libc:: socklen_t
966
996
) ,
967
997
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
968
998
SockAddr :: Netlink ( NetlinkAddr ( ref sa) ) => (
0 commit comments