@@ -344,7 +344,7 @@ impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
344344 self . length = new_length;
345345
346346 // Get the last header in the buffer.
347- let last_header = leap ! ( messages:: Messages :: new( buffer) . last( ) ) ;
347+ let ( last_header, _ ) = leap ! ( messages:: Messages :: new( buffer) . last( ) ) ;
348348
349349 // Set the header fields.
350350 last_header. cmsg_len = unsafe { c:: CMSG_LEN ( source_len) } as _ ;
@@ -533,34 +533,48 @@ impl<'buf> AncillaryDrain<'buf> {
533533 }
534534 }
535535
536+ /// `space` is the number of bytes of buffer space at and after `msg`.
536537 fn advance (
537538 read_and_length : & mut Option < ( & ' buf mut usize , & ' buf mut usize ) > ,
538539 msg : & c:: cmsghdr ,
540+ space : usize ,
539541 ) -> Option < RecvAncillaryMessage < ' buf > > {
542+ // Clamp the message length to the buffer. When `recvmsg` truncates
543+ // control data to fit, Linux reduces `cmsg_len` to match what it
544+ // wrote, but macOS leaves `cmsg_len` holding the untruncated length,
545+ // so it can run past the end of the buffer.
546+ let msg_len = ( msg. cmsg_len as usize ) . min ( space) ;
547+
540548 // Advance the `read` pointer.
541549 if let Some ( ( read, length) ) = read_and_length {
542- let msg_len = msg. cmsg_len as usize ;
543550 * * read += msg_len;
544551 * * length -= msg_len;
545552 }
546553
547- Self :: cvt_msg ( msg)
554+ Self :: cvt_msg ( msg, msg_len )
548555 }
549556
550557 /// A closure that converts a message into a [`RecvAncillaryMessage`].
551- fn cvt_msg ( msg : & c:: cmsghdr ) -> Option < RecvAncillaryMessage < ' buf > > {
558+ fn cvt_msg ( msg : & c:: cmsghdr , msg_len : usize ) -> Option < RecvAncillaryMessage < ' buf > > {
552559 unsafe {
553- // Get a pointer to the payload.
560+ // Get a pointer to the payload. Use `msg_len` rather than
561+ // `msg.cmsg_len`, as the message may have been truncated to fit
562+ // in the buffer. If there isn't even a whole header, there's no
563+ // message to report.
554564 let payload = c:: CMSG_DATA ( msg) ;
555- let payload_len = msg. cmsg_len as usize - c:: CMSG_LEN ( 0 ) as usize ;
556-
557- // Get a mutable slice of the payload.
558- let payload: & ' buf mut [ u8 ] = slice:: from_raw_parts_mut ( payload, payload_len) ;
565+ let payload_len = msg_len. checked_sub ( c:: CMSG_LEN ( 0 ) as usize ) ?;
559566
560567 // Determine what type it is.
561568 let ( level, msg_type) = ( msg. cmsg_level , msg. cmsg_type ) ;
562569 match ( level as _ , msg_type as _ ) {
563570 ( c:: SOL_SOCKET , c:: SCM_RIGHTS ) => {
571+ // Truncation can leave a partial file descriptor at the
572+ // end of the payload; round down to whole descriptors.
573+ let payload_len = payload_len - payload_len % size_of :: < OwnedFd > ( ) ;
574+
575+ // Get a mutable slice of the payload.
576+ let payload: & ' buf mut [ u8 ] = slice:: from_raw_parts_mut ( payload, payload_len) ;
577+
564578 // Create an iterator that reads out the file descriptors.
565579 let fds = AncillaryIter :: new ( payload) ;
566580
@@ -569,7 +583,7 @@ impl<'buf> AncillaryDrain<'buf> {
569583 #[ cfg( linux_kernel) ]
570584 ( c:: SOL_SOCKET , c:: SCM_CREDENTIALS ) => {
571585 if payload_len >= size_of :: < UCred > ( ) {
572- let ucred = payload. as_ptr ( ) . cast :: < UCred > ( ) . read_unaligned ( ) ;
586+ let ucred = payload. cast :: < UCred > ( ) . read_unaligned ( ) ;
573587 Some ( RecvAncillaryMessage :: ScmCredentials ( ucred) )
574588 } else {
575589 None
@@ -586,7 +600,7 @@ impl<'buf> Iterator for AncillaryDrain<'buf> {
586600
587601 fn next ( & mut self ) -> Option < Self :: Item > {
588602 self . messages
589- . find_map ( |ev | Self :: advance ( & mut self . read_and_length , ev ) )
603+ . find_map ( |( msg , space ) | Self :: advance ( & mut self . read_and_length , msg , space ) )
590604 }
591605
592606 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
@@ -600,13 +614,13 @@ impl<'buf> Iterator for AncillaryDrain<'buf> {
600614 F : FnMut ( B , Self :: Item ) -> B ,
601615 {
602616 self . messages
603- . filter_map ( |ev | Self :: advance ( & mut self . read_and_length , ev ) )
617+ . filter_map ( |( msg , space ) | Self :: advance ( & mut self . read_and_length , msg , space ) )
604618 . fold ( init, f)
605619 }
606620
607621 fn count ( mut self ) -> usize {
608622 self . messages
609- . filter_map ( |ev | Self :: advance ( & mut self . read_and_length , ev ) )
623+ . filter_map ( |( msg , space ) | Self :: advance ( & mut self . read_and_length , msg , space ) )
610624 . count ( )
611625 }
612626
@@ -615,7 +629,7 @@ impl<'buf> Iterator for AncillaryDrain<'buf> {
615629 Self : Sized ,
616630 {
617631 self . messages
618- . filter_map ( |ev | Self :: advance ( & mut self . read_and_length , ev ) )
632+ . filter_map ( |( msg , space ) | Self :: advance ( & mut self . read_and_length , msg , space ) )
619633 . last ( )
620634 }
621635
@@ -624,7 +638,7 @@ impl<'buf> Iterator for AncillaryDrain<'buf> {
624638 Self : Sized ,
625639 {
626640 self . messages
627- . filter_map ( |ev | Self :: advance ( & mut self . read_and_length , ev ) )
641+ . filter_map ( |( msg , space ) | Self :: advance ( & mut self . read_and_length , msg , space ) )
628642 . collect ( )
629643 }
630644}
@@ -951,13 +965,21 @@ mod messages {
951965 }
952966
953967 impl < ' a > Iterator for Messages < ' a > {
954- type Item = & ' a mut c:: cmsghdr ;
968+ /// A message header, along with the number of bytes of buffer space
969+ /// at and after it, which is an upper bound on the size of the
970+ /// message.
971+ type Item = ( & ' a mut c:: cmsghdr , usize ) ;
955972
956973 #[ inline]
957974 fn next ( & mut self ) -> Option < Self :: Item > {
958975 // Get the current header.
959976 let header = self . header ?;
960977
978+ // Compute the number of bytes of buffer space at and after this
979+ // header.
980+ let end = ( self . msghdr . msg_control as usize ) + ( self . msghdr . msg_controllen as usize ) ;
981+ let space = end. saturating_sub ( header. as_ptr ( ) as usize ) ;
982+
961983 // Get the next header.
962984 self . header = NonNull :: new ( unsafe { c:: CMSG_NXTHDR ( & self . msghdr , header. as_ptr ( ) ) } ) ;
963985
@@ -967,7 +989,7 @@ mod messages {
967989 }
968990
969991 // SAFETY: The lifetime of `header` is tied to this.
970- Some ( unsafe { & mut * header. as_ptr ( ) } )
992+ Some ( ( unsafe { & mut * header. as_ptr ( ) } , space ) )
971993 }
972994
973995 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
0 commit comments