summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2017-07-11 01:51:57 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2017-07-11 01:51:57 +0000
commit84901b08e3be912e7ef291d77fe7bfd7f6fbee28 (patch)
tree3bd134d4d6c26bfba9023c52a5789a9df19099e2 /src
parent386c50cf0a9c3d5c1e481fb76ee2f17a12b3fc44 (diff)
parent64815c61836ece60d6d01d1a1ecfc1877d5bb866 (diff)
downloadnix-84901b08e3be912e7ef291d77fe7bfd7f6fbee28.zip
Merge #623
623: Fix sendmsg on macOS when passing a zero entry cmsgs array. r=Susurrus On macOS, trying to call `sendmsg` with a zero entry cmsgs buffer, e.g.: sendmsg(fd, [IoVec::from_slice(buf)], &[], MsgFlags::empty(), None) ...fails with `EINVAL`. This occurs due to the pointer value for zero capacity `Vec`s being 0x1 rather than 0x0, to distinguish allocated-but-zero-size from nullptr. The [kernel validates](https://github.com/opensource-apple/xnu/blob/dc0628e187c3148723505cf1f1d35bb948d3195b/bsd/kern/uipc_syscalls.c#L1304) both the `msghdr.msg_control` and `msghdr.msg_controllen` fields and rejects `msghdr.msg_control == 0x1` as invalid. This doesn't show up on Linux because the [kernel validates](https://github.com/torvalds/linux/blob/9705596d08ac87c18aee32cc97f2783b7d14624e/net/core/scm.c#L139) `msghdr.msg_controllen` first and ignores the value of `msghdr.msg_control` if the length was 0.
Diffstat (limited to 'src')
-rw-r--r--src/sys/socket/mod.rs18
1 files changed, 11 insertions, 7 deletions
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index a126f8b4..c11b5367 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -258,14 +258,12 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
len += cmsg.len();
capacity += cmsg.space();
}
- // Alignment hackery. Note that capacity is guaranteed to be a
- // multiple of size_t. Note also that the resulting vector claims
- // to have length == capacity, so it's presently uninitialized.
+ // Note that the resulting vector claims to have length == capacity,
+ // so it's presently uninitialized.
let mut cmsg_buffer = unsafe {
let mut vec = Vec::<u8>::with_capacity(len);
- let ptr = vec.as_mut_ptr();
- mem::forget(vec);
- Vec::<u8>::from_raw_parts(ptr as *mut _, len, len)
+ vec.set_len(len);
+ vec
};
{
let mut ptr = &mut cmsg_buffer[..];
@@ -279,12 +277,18 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
None => (0 as *const _, 0),
};
+ let cmsg_ptr = if capacity > 0 {
+ cmsg_buffer.as_ptr() as *const c_void
+ } else {
+ ptr::null()
+ };
+
let mhdr = msghdr {
msg_name: name as *const c_void,
msg_namelen: namelen,
msg_iov: iov.as_ptr(),
msg_iovlen: iov.len() as size_t,
- msg_control: cmsg_buffer.as_ptr() as *const c_void,
+ msg_control: cmsg_ptr,
msg_controllen: capacity as size_t,
msg_flags: 0,
};