diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2017-07-11 01:51:57 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2017-07-11 01:51:57 +0000 |
commit | 84901b08e3be912e7ef291d77fe7bfd7f6fbee28 (patch) | |
tree | 3bd134d4d6c26bfba9023c52a5789a9df19099e2 /src | |
parent | 386c50cf0a9c3d5c1e481fb76ee2f17a12b3fc44 (diff) | |
parent | 64815c61836ece60d6d01d1a1ecfc1877d5bb866 (diff) | |
download | nix-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.rs | 18 |
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, }; |