@@ -38,15 +38,27 @@ impl InterfaceData {
3838 }
3939}
4040
41+ // Invariants:
42+ // self.base always contains a pointer received from libc::getifaddrs that is not NULL. The region pointed to is never modified in rust code.
43+ // self.next always contains either a pointer pointing to a valid ifaddr received from libc::getifaddrs or null.
44+ //
45+ // These invariants are setup by InterfaceIterator::new and guaranteed by drop and next, which are the only places these pointers are used.
4146struct InterfaceIterator {
4247 base : * mut libc:: ifaddrs ,
43- next : * mut libc:: ifaddrs ,
48+ next : * const libc:: ifaddrs ,
4449}
4550
4651impl InterfaceIterator {
4752 pub fn new ( ) -> std:: io:: Result < Self > {
4853 let mut addrs: * mut libc:: ifaddrs = std:: ptr:: null_mut ( ) ;
4954
55+ // Safety:
56+ // addrs lives for the duration of the call to getifaddrs.
57+ //
58+ // Invariant preservation:
59+ // we validate that the received address is not null, and
60+ // by the guarantees from getifaddrs points to a valid
61+ // ifaddr returned from getifaddrs
5062 unsafe {
5163 cerr ( libc:: getifaddrs ( & mut addrs) ) ?;
5264
@@ -62,6 +74,8 @@ impl InterfaceIterator {
6274
6375impl Drop for InterfaceIterator {
6476 fn drop ( & mut self ) {
77+ // Safety:
78+ // By the invariants, self.base is guaranteed to point to a memory region allocated by getifaddrs
6579 unsafe { libc:: freeifaddrs ( self . base ) } ;
6680 }
6781}
@@ -76,25 +90,35 @@ impl Iterator for InterfaceIterator {
7690 type Item = InterfaceDataInternal ;
7791
7892 fn next ( & mut self ) -> Option < <Self as Iterator >:: Item > {
93+ // Safety:
94+ // By the invariants, self.next is guaranteed to be a valid pointer to an ifaddrs struct or null.
7995 let ifaddr = unsafe { self . next . as_ref ( ) } ?;
8096
97+ // Invariant preservation
98+ // By the guarantees given by getifaddrs, ifaddr.ifa_next is either null or points to a valid
99+ // ifaddr.
81100 self . next = ifaddr. ifa_next ;
82101
102+ // Safety:
103+ // getifaddrs guarantees that ifa_name is not null and points to a valid C string.
83104 let ifname = unsafe { std:: ffi:: CStr :: from_ptr ( ifaddr. ifa_name ) } ;
84105 let name = match std:: str:: from_utf8 ( ifname. to_bytes ( ) ) {
85106 Err ( _) => unreachable ! ( "interface names must be ascii" ) ,
86107 Ok ( name) => InterfaceName :: from_str ( name) . expect ( "name from os" ) ,
87108 } ;
88109
89- let family = unsafe { ( * ifaddr. ifa_addr ) . sa_family } ;
110+ // Safety:
111+ // getifaddrs guarantees that ifa_addr either points to a valid address or is NULL.
112+ let family = unsafe { ifaddr. ifa_addr . as_ref ( ) } . map ( |a| a. sa_family ) ;
90113
91114 #[ allow( unused) ]
92115 let mac: Option < [ u8 ; 6 ] > = None ;
93116
94117 #[ cfg( target_os = "linux" ) ]
95- // Safety: getifaddrs ensures that all addresses are valid, and a valid address of type
96- // AF_PACKET always is reinterpret castable to sockaddr_ll
97- let mac = if family as i32 == libc:: AF_PACKET {
118+ // Safety: getifaddrs ensures that, if an address is present, it is valid. A valid address
119+ // of type AF_PACKET is always reinterpret castable to sockaddr_ll, and we know an address
120+ // is present since family is not None
121+ let mac = if family == Some ( libc:: AF_PACKET as _ ) {
98122 let sockaddr_ll: libc:: sockaddr_ll =
99123 unsafe { std:: ptr:: read_unaligned ( ifaddr. ifa_addr as * const _ ) } ;
100124
@@ -111,9 +135,10 @@ impl Iterator for InterfaceIterator {
111135 } ;
112136
113137 #[ cfg( any( target_os = "freebsd" , target_os = "macos" ) ) ]
114- let mac = if family as i32 == libc:: AF_LINK {
115- // Safety: getifaddrs ensures that all addresses are valid, and a valid address of type
116- // AF_LINK always is reinterpret castable to sockaddr_dl
138+ let mac = if family == Some ( libc:: AF_LINK as _ ) {
139+ // Safety: getifaddrs ensures that, if an address is present, it is valid. A valid address
140+ // of type AF_LINK is always reinterpret castable to sockaddr_ll, and we know an address
141+ // is present since family is not None
117142 let sockaddr_dl: libc:: sockaddr_dl =
118143 unsafe { std:: ptr:: read_unaligned ( ifaddr. ifa_addr as * const _ ) } ;
119144
@@ -138,6 +163,7 @@ impl Iterator for InterfaceIterator {
138163 None
139164 } ;
140165
166+ // Safety: ifaddr.ifa_addr is always either NULL, or by the guarantees of getifaddrs, points to a valid address.
141167 let socket_addr = unsafe { sockaddr_to_socket_addr ( ifaddr. ifa_addr ) } ;
142168
143169 let data = InterfaceDataInternal {
@@ -206,7 +232,7 @@ impl InterfaceName {
206232 pub fn get_index ( & self ) -> Option < libc:: c_uint > {
207233 // # SAFETY
208234 //
209- // The pointer is valid and null- terminated
235+ // self lives for the duration of the call, and is null terminated.
210236 match unsafe { libc:: if_nametoindex ( self . as_cstr ( ) . as_ptr ( ) ) } {
211237 0 => None ,
212238 n => Some ( n) ,
@@ -266,22 +292,25 @@ impl<'de> serde::Deserialize<'de> for InterfaceName {
266292///
267293/// # Safety
268294///
269- /// According to the posix standard, `sockaddr` does not have a defined size:
270- /// the size depends on the value of the `ss_family` field. We assume this to be
271- /// correct.
272- ///
273- /// In practice, types in rust/c need a statically-known stack size, so they
274- /// pick some value. In practice it can be (and is) larger than the
275- /// `sizeof<libc::sockaddr>` value.
295+ /// This function assumes that sockaddr is either NULL or points to a valid address.
276296unsafe fn sockaddr_to_socket_addr ( sockaddr : * const libc:: sockaddr ) -> Option < SocketAddr > {
277297 // Most (but not all) of the fields in a socket addr are in network byte
278298 // ordering. As such, when doing conversions here, we should start from the
279299 // NATIVE byte representation, as this will actualy be the big-endian
280300 // representation of the underlying value regardless of platform.
301+
302+ // Check for null pointers
303+ if sockaddr. is_null ( ) {
304+ return None ;
305+ }
306+
307+ // Safety: by the previous check, sockaddr is not NULL and hence points to a valid address
281308 match unsafe { ( * sockaddr) . sa_family as libc:: c_int } {
282309 libc:: AF_INET => {
283310 // SAFETY: we cast from a libc::sockaddr (alignment 2) to a libc::sockaddr_in (alignment 4)
284311 // that means that the pointer is now potentially unaligned. We must used read_unaligned!
312+ // However, the rest of the cast is safe as a valid AF_INET address is always reinterpret castable
313+ // as a sockaddr_in
285314 let inaddr: libc:: sockaddr_in =
286315 unsafe { std:: ptr:: read_unaligned ( sockaddr as * const libc:: sockaddr_in ) } ;
287316
@@ -295,9 +324,12 @@ unsafe fn sockaddr_to_socket_addr(sockaddr: *const libc::sockaddr) -> Option<Soc
295324 libc:: AF_INET6 => {
296325 // SAFETY: we cast from a libc::sockaddr (alignment 2) to a libc::sockaddr_in6 (alignment 4)
297326 // that means that the pointer is now potentially unaligned. We must used read_unaligned!
327+ // However, the cast is safe as a valid AF_INET6 address is always reinterpret catable as a sockaddr_in6
298328 let inaddr: libc:: sockaddr_in6 =
299329 unsafe { std:: ptr:: read_unaligned ( sockaddr as * const libc:: sockaddr_in6 ) } ;
300330
331+ // Safety:
332+ // sin_addr lives for the duration fo the call and matches type
301333 let sin_addr = inaddr. sin6_addr . s6_addr ;
302334 let segment_bytes: [ u8 ; 16 ] =
303335 unsafe { std:: ptr:: read_unaligned ( & sin_addr as * const _ as * const _ ) } ;
0 commit comments