From 8b8234a1939e5823e7b1e13e1c0a47fda6827d27 Mon Sep 17 00:00:00 2001 From: Alisa Sireneva Date: Wed, 3 Jan 2024 22:40:16 +0300 Subject: [PATCH] Rewrite suspicious code around ancillary data 253 seems to be a hardcoded value without any particular reasoning. Move it to a constant and use a rounder value of 128. There were also troubles regarding alignment: the API asks us to pass an arbitrary byte buffer and then performs unaligned reads/writes. Workaround that by aligning the buffer manually. For more information, see https://github.com/rust-lang/rust/issues/76915#issuecomment-1875845773 --- src/platform/unix/ipc.rs | 37 ++++++++++++++++++++++++++++++------- src/platform/unix/tokio.rs | 15 ++++++++------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/platform/unix/ipc.rs b/src/platform/unix/ipc.rs index 8ecb686..2b68088 100644 --- a/src/platform/unix/ipc.rs +++ b/src/platform/unix/ipc.rs @@ -27,7 +27,7 @@ //! ``` use crate::{Deserializer, Object, Serializer}; -use nix::libc::{AF_UNIX, SOCK_CLOEXEC, SOCK_SEQPACKET}; +use nix::libc::{cmsghdr, AF_UNIX, SOCK_CLOEXEC, SOCK_SEQPACKET}; use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result}; use std::marker::PhantomData; use std::os::unix::{ @@ -35,7 +35,31 @@ use std::os::unix::{ net::{AncillaryData, SocketAncillary, UnixStream}, }; +const fn round_to_usize(n: usize) -> usize { + const ALIGNMENT: usize = std::mem::size_of::(); + (n + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT +} + pub(crate) const MAX_PACKET_SIZE: usize = 16 * 1024; +pub(crate) const MAX_PACKET_FDS: usize = 128; +pub(crate) const ANCILLARY_BUFFER_SIZE: usize = + round_to_usize(MAX_PACKET_FDS * std::mem::size_of::()) + + round_to_usize(std::mem::size_of::()); + +// https://github.com/rust-lang/rust/issues/76915#issuecomment-1875845773 +pub(crate) struct AncillaryBuffer { + _alignment: [usize; 0], + pub(crate) data: [u8; ANCILLARY_BUFFER_SIZE], +} + +impl AncillaryBuffer { + pub(crate) fn new() -> Self { + Self { + _alignment: [], + data: [0u8; ANCILLARY_BUFFER_SIZE], + } + } +} /// The transmitting side of a unidirectional channel. /// @@ -91,19 +115,18 @@ fn send_on_fd(fd: &UnixStream, value: &T) -> Result<()> { let fds = s.drain_handles(); let serialized = s.into_vec(); - let mut ancillary_buffer = [0; 253]; - // Send the data and pass file descriptors let mut buffer_pos: usize = 0; let mut fds_pos: usize = 0; loop { let buffer_end = serialized.len().min(buffer_pos + MAX_PACKET_SIZE - 1); - let fds_end = fds.len().min(fds_pos + 253); + let fds_end = fds.len().min(fds_pos + MAX_PACKET_FDS); let is_last = buffer_end == serialized.len() && fds_end == fds.len(); - let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); + let mut ancillary_buffer = AncillaryBuffer::new(); + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data); if !ancillary.add_fds(&fds[fds_pos..fds_end]) { return Err(Error::new(ErrorKind::Other, "Too many fds to pass")); } @@ -131,14 +154,14 @@ unsafe fn recv_on_fd(fd: &UnixStream) -> Result> { let mut serialized: Vec = Vec::new(); let mut buffer_pos: usize = 0; - let mut ancillary_buffer = [0; 253]; let mut received_fds: Vec = Vec::new(); loop { serialized.resize(buffer_pos + MAX_PACKET_SIZE - 1, 0); let mut marker = [0]; - let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + let mut ancillary_buffer = AncillaryBuffer::new(); + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data); let n_read = fd.recv_vectored_with_ancillary( &mut [ diff --git a/src/platform/unix/tokio.rs b/src/platform/unix/tokio.rs index ba599fd..b998f59 100644 --- a/src/platform/unix/tokio.rs +++ b/src/platform/unix/tokio.rs @@ -37,7 +37,9 @@ //! ``` use crate::{ - entry, imp, ipc::MAX_PACKET_SIZE, subprocess, Deserializer, FnOnceObject, Object, Serializer, + entry, imp, + ipc::{AncillaryBuffer, MAX_PACKET_FDS, MAX_PACKET_SIZE}, + subprocess, Deserializer, FnOnceObject, Object, Serializer, }; use nix::libc::pid_t; use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result}; @@ -105,19 +107,18 @@ async fn send_on_fd(fd: &UnixSeqpacket, value: &T) -> Result<()> { (s.drain_handles(), s.into_vec()) }; - let mut ancillary_buffer = [0; 253]; - // Send the data and pass file descriptors let mut buffer_pos: usize = 0; let mut fds_pos: usize = 0; loop { let buffer_end = serialized.len().min(buffer_pos + MAX_PACKET_SIZE - 1); - let fds_end = fds.len().min(fds_pos + 253); + let fds_end = fds.len().min(fds_pos + MAX_PACKET_FDS); let is_last = buffer_end == serialized.len() && fds_end == fds.len(); - let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); + let mut ancillary_buffer = AncillaryBuffer::new(); + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data); if !ancillary.add_fds(&fds[fds_pos..fds_end]) { return Err(Error::new(ErrorKind::Other, "Too many fds to pass")); } @@ -147,14 +148,14 @@ async unsafe fn recv_on_fd(fd: &UnixSeqpacket) -> Result> { let mut serialized: Vec = Vec::new(); let mut buffer_pos: usize = 0; - let mut ancillary_buffer = [0; 253]; let mut received_fds: Vec = Vec::new(); loop { serialized.resize(buffer_pos + MAX_PACKET_SIZE - 1, 0); let mut marker = [0]; - let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + let mut ancillary_buffer = AncillaryBuffer::new(); + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data); let n_read = fd .recv_vectored_with_ancillary(