Skip to content

Commit

Permalink
Ensure proper alignment of control message buffer in writer.
Browse files Browse the repository at this point in the history
  • Loading branch information
de-vri-es committed Nov 15, 2023
1 parent a76f11c commit ed9aabf
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Unreleased:
* Ensure proper alginment of control message buffer in the writer.

v0.7.0 - 2023-03-03:
* Fix `OwnedFileDescriptors` iteration.

Expand Down
17 changes: 17 additions & 0 deletions src/ancillary/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<libc::cmsghdr>();

/// 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
Expand All @@ -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 }
}

Expand Down Expand Up @@ -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..]
}
}
2 changes: 1 addition & 1 deletion src/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions tests/ancillary_fds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}

0 comments on commit ed9aabf

Please sign in to comment.