diff options
author | Matthew Gregan <kinetik@flim.org> | 2017-06-20 15:30:48 +1200 |
---|---|---|
committer | Matthew Gregan <kinetik@flim.org> | 2017-07-10 13:04:33 +1200 |
commit | 64815c61836ece60d6d01d1a1ecfc1877d5bb866 (patch) | |
tree | 3bd134d4d6c26bfba9023c52a5789a9df19099e2 | |
parent | 2e00adf804f0ebacfe982063c0f98af836efd4f1 (diff) | |
download | nix-64815c61836ece60d6d01d1a1ecfc1877d5bb866.zip |
Fix sendmsg on macOS when passing a zero entry cmsgs array.
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/sys/socket/mod.rs | 8 | ||||
-rw-r--r-- | test/sys/test_socket.rs | 39 |
3 files changed, 47 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 15f42a45..4ceae9c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `nix::ptrace` on all Linux-kernel-based platforms [#624](https://github.com/nix-rust/nix/pull/624). Previously it was only available on x86, x86-64, and ARM, and also not on Android. +- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter. + ([#623](https://github.com/nix-rust/nix/pull/623)) ## [0.8.1] 2017-04-16 diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 88fe02fe..c11b5367 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -277,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, }; diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index b5465aa0..9f9c9bf0 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -131,7 +131,7 @@ pub fn test_scm_rights() { panic!("unexpected cmsg"); } } - assert_eq!(msg.flags & (MSG_TRUNC | MSG_CTRUNC), MsgFlags::empty()); + assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC)); close(fd2).unwrap(); } @@ -145,6 +145,43 @@ pub fn test_scm_rights() { close(w).unwrap(); } +// Verify `sendmsg` builds a valid `msghdr` when passing an empty +// `cmsgs` argument. This should result in a msghdr with a nullptr +// msg_control field and a msg_controllen of 0 when calling into the +// raw `sendmsg`. +#[test] +pub fn test_sendmsg_empty_cmsgs() { + use nix::sys::uio::IoVec; + use nix::unistd::close; + use nix::sys::socket::{socketpair, sendmsg, recvmsg, + AddressFamily, SockType, SockFlag, + CmsgSpace, MsgFlags, + MSG_TRUNC, MSG_CTRUNC}; + + let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, 0, + SockFlag::empty()) + .unwrap(); + + { + let iov = [IoVec::from_slice(b"hello")]; + assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); + close(fd1).unwrap(); + } + + { + let mut buf = [0u8; 5]; + let iov = [IoVec::from_mut_slice(&mut buf[..])]; + let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new(); + let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + + for _ in msg.cmsgs() { + panic!("unexpected cmsg"); + } + assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC)); + close(fd2).unwrap(); + } +} + // Test creating and using named unix domain sockets #[test] pub fn test_unixdomain() { |