From ed9aabfa28b831c5e404847c7bdaacab63e9c2ae Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Nov 2023 13:44:49 +0100 Subject: [PATCH] Ensure proper alignment of control message buffer in writer. --- CHANGELOG.md | 3 +++ src/ancillary/writer.rs | 17 +++++++++++++++++ src/sys.rs | 2 +- tests/ancillary_fds.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 538cf6f..9f780dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +Unreleased: + * Ensure proper alginment of control message buffer in the writer. + v0.7.0 - 2023-03-03: * Fix `OwnedFileDescriptors` iteration. diff --git a/src/ancillary/writer.rs b/src/ancillary/writer.rs index 181d4ab..9174761 100644 --- a/src/ancillary/writer.rs +++ b/src/ancillary/writer.rs @@ -40,8 +40,14 @@ pub struct AncillaryMessageWriter<'a> { pub struct AddControlMessageError(()); impl<'a> AncillaryMessageWriter<'a> { + /// Alignment requirement for the control messages added to the buffer. + pub const BUFFER_ALIGN: usize = std::mem::align_of::(); + /// Create an ancillary data with the given buffer. /// + /// Some bytes at the start of the buffer may be left unused to enforce alignment to [`Self::BUFFER_ALIGN`]. + /// You can use [`Self::capacity()`] to check how much of the buffer can be used for control messages. + /// /// # Example /// /// ```no_run @@ -51,6 +57,7 @@ impl<'a> AncillaryMessageWriter<'a> { /// let mut ancillary = AncillaryMessageWriter::new(&mut ancillary_buffer); /// ``` pub fn new(buffer: &'a mut [u8]) -> Self { + let buffer = align_buffer_mut(buffer, Self::BUFFER_ALIGN); Self { buffer, length: 0 } } @@ -227,3 +234,13 @@ fn reserve_ancillary_data<'a>( Ok(std::slice::from_raw_parts_mut(data, additional_space)) } } + +/// Align a buffer to the given alignment. +fn align_buffer_mut(buffer: &mut [u8], align: usize) -> &mut [u8] { + let offset = buffer.as_ptr().align_offset(align); + if offset > buffer.len() { + &mut [] + } else { + &mut buffer[offset..] + } +} diff --git a/src/sys.rs b/src/sys.rs index b827909..79c5e17 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -267,7 +267,7 @@ fn path_to_sockaddr(path: &Path) -> std::io::Result<(libc::sockaddr_un, usize)> /// Get the Unix path of a socket address. /// -/// An error is retuend if the address is not a Unix address, or if it is an unnamed or abstract. +/// An error is returned if the address is not a Unix address, or if it is an unnamed or abstract. fn sockaddr_to_path(address: &libc::sockaddr_un, len: libc::socklen_t) -> std::io::Result<&std::path::Path> { use std::ffi::OsStr; use std::os::unix::ffi::OsStrExt; diff --git a/tests/ancillary_fds.rs b/tests/ancillary_fds.rs index f6f2b32..e5a99f4 100644 --- a/tests/ancillary_fds.rs +++ b/tests/ancillary_fds.rs @@ -48,3 +48,30 @@ async fn can_take_ownership_of_received_fds() { assert!(let Ok(_) = file.read_to_end(&mut contents)); assert!(contents == b"Wie dit leest is gek."); } + +#[tokio::test] +async fn pass_fd_unaligned_buffer() { + use tokio_seqpacket::ancillary::AncillaryMessageWriter; + + // Receive a file descriptor + let mut ancillary_buffer = [0; 64]; + // But use a purposefully misaligned ancillary buffer. + let align = ancillary_buffer.as_ptr().align_offset(AncillaryMessageWriter::BUFFER_ALIGN); + let ancillary = receive_file_descriptor(&mut ancillary_buffer[align + 1..]).await; + + // Check that we got exactly one control message containing file descriptors. + let mut messages = ancillary.messages(); + let_assert!(Some(AncillaryMessage::FileDescriptors(mut fds)) = messages.next()); + assert!(let None = messages.next()); + + // Check that we got exactly one file descriptor in the first control message. + let_assert!(Some(fd) = fds.next()); + assert!(let None = fds.next()); + + // Check that we can retrieve the message from the attached file. + let_assert!(Ok(fd) = fd.try_clone_to_owned()); + let mut file = std::fs::File::from(fd); + let mut contents = Vec::new(); + assert!(let Ok(_) = file.read_to_end(&mut contents)); + assert!(contents == b"Wie dit leest is gek."); +}