Skip to content

Commit 8b8234a

Browse files
committed
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 rust-lang/rust#76915 (comment)
1 parent 6b950bd commit 8b8234a

2 files changed

Lines changed: 38 additions & 14 deletions

File tree

src/platform/unix/ipc.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,39 @@
2727
//! ```
2828
2929
use crate::{Deserializer, Object, Serializer};
30-
use nix::libc::{AF_UNIX, SOCK_CLOEXEC, SOCK_SEQPACKET};
30+
use nix::libc::{cmsghdr, AF_UNIX, SOCK_CLOEXEC, SOCK_SEQPACKET};
3131
use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result};
3232
use std::marker::PhantomData;
3333
use std::os::unix::{
3434
io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd},
3535
net::{AncillaryData, SocketAncillary, UnixStream},
3636
};
3737

38+
const fn round_to_usize(n: usize) -> usize {
39+
const ALIGNMENT: usize = std::mem::size_of::<usize>();
40+
(n + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT
41+
}
42+
3843
pub(crate) const MAX_PACKET_SIZE: usize = 16 * 1024;
44+
pub(crate) const MAX_PACKET_FDS: usize = 128;
45+
pub(crate) const ANCILLARY_BUFFER_SIZE: usize =
46+
round_to_usize(MAX_PACKET_FDS * std::mem::size_of::<i32>())
47+
+ round_to_usize(std::mem::size_of::<cmsghdr>());
48+
49+
// https://github.com/rust-lang/rust/issues/76915#issuecomment-1875845773
50+
pub(crate) struct AncillaryBuffer {
51+
_alignment: [usize; 0],
52+
pub(crate) data: [u8; ANCILLARY_BUFFER_SIZE],
53+
}
54+
55+
impl AncillaryBuffer {
56+
pub(crate) fn new() -> Self {
57+
Self {
58+
_alignment: [],
59+
data: [0u8; ANCILLARY_BUFFER_SIZE],
60+
}
61+
}
62+
}
3963

4064
/// The transmitting side of a unidirectional channel.
4165
///
@@ -91,19 +115,18 @@ fn send_on_fd<T: Object>(fd: &UnixStream, value: &T) -> Result<()> {
91115
let fds = s.drain_handles();
92116
let serialized = s.into_vec();
93117

94-
let mut ancillary_buffer = [0; 253];
95-
96118
// Send the data and pass file descriptors
97119
let mut buffer_pos: usize = 0;
98120
let mut fds_pos: usize = 0;
99121

100122
loop {
101123
let buffer_end = serialized.len().min(buffer_pos + MAX_PACKET_SIZE - 1);
102-
let fds_end = fds.len().min(fds_pos + 253);
124+
let fds_end = fds.len().min(fds_pos + MAX_PACKET_FDS);
103125

104126
let is_last = buffer_end == serialized.len() && fds_end == fds.len();
105127

106-
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer);
128+
let mut ancillary_buffer = AncillaryBuffer::new();
129+
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data);
107130
if !ancillary.add_fds(&fds[fds_pos..fds_end]) {
108131
return Err(Error::new(ErrorKind::Other, "Too many fds to pass"));
109132
}
@@ -131,14 +154,14 @@ unsafe fn recv_on_fd<T: Object>(fd: &UnixStream) -> Result<Option<T>> {
131154
let mut serialized: Vec<u8> = Vec::new();
132155
let mut buffer_pos: usize = 0;
133156

134-
let mut ancillary_buffer = [0; 253];
135157
let mut received_fds: Vec<OwnedFd> = Vec::new();
136158

137159
loop {
138160
serialized.resize(buffer_pos + MAX_PACKET_SIZE - 1, 0);
139161

140162
let mut marker = [0];
141-
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
163+
let mut ancillary_buffer = AncillaryBuffer::new();
164+
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data);
142165

143166
let n_read = fd.recv_vectored_with_ancillary(
144167
&mut [

src/platform/unix/tokio.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
//! ```
3838
3939
use crate::{
40-
entry, imp, ipc::MAX_PACKET_SIZE, subprocess, Deserializer, FnOnceObject, Object, Serializer,
40+
entry, imp,
41+
ipc::{AncillaryBuffer, MAX_PACKET_FDS, MAX_PACKET_SIZE},
42+
subprocess, Deserializer, FnOnceObject, Object, Serializer,
4143
};
4244
use nix::libc::pid_t;
4345
use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result};
@@ -105,19 +107,18 @@ async fn send_on_fd<T: Object>(fd: &UnixSeqpacket, value: &T) -> Result<()> {
105107
(s.drain_handles(), s.into_vec())
106108
};
107109

108-
let mut ancillary_buffer = [0; 253];
109-
110110
// Send the data and pass file descriptors
111111
let mut buffer_pos: usize = 0;
112112
let mut fds_pos: usize = 0;
113113

114114
loop {
115115
let buffer_end = serialized.len().min(buffer_pos + MAX_PACKET_SIZE - 1);
116-
let fds_end = fds.len().min(fds_pos + 253);
116+
let fds_end = fds.len().min(fds_pos + MAX_PACKET_FDS);
117117

118118
let is_last = buffer_end == serialized.len() && fds_end == fds.len();
119119

120-
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer);
120+
let mut ancillary_buffer = AncillaryBuffer::new();
121+
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data);
121122
if !ancillary.add_fds(&fds[fds_pos..fds_end]) {
122123
return Err(Error::new(ErrorKind::Other, "Too many fds to pass"));
123124
}
@@ -147,14 +148,14 @@ async unsafe fn recv_on_fd<T: Object>(fd: &UnixSeqpacket) -> Result<Option<T>> {
147148
let mut serialized: Vec<u8> = Vec::new();
148149
let mut buffer_pos: usize = 0;
149150

150-
let mut ancillary_buffer = [0; 253];
151151
let mut received_fds: Vec<OwnedFd> = Vec::new();
152152

153153
loop {
154154
serialized.resize(buffer_pos + MAX_PACKET_SIZE - 1, 0);
155155

156156
let mut marker = [0];
157-
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
157+
let mut ancillary_buffer = AncillaryBuffer::new();
158+
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer.data);
158159

159160
let n_read = fd
160161
.recv_vectored_with_ancillary(

0 commit comments

Comments
 (0)