Skip to content

Commit ad1a41b

Browse files
committed
fixes UB for recvmmsg, simplifies function signature of recvmmsg and sendmmsg
1 parent 996db47 commit ad1a41b

File tree

4 files changed

+50
-21
lines changed

4 files changed

+50
-21
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
All notable changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](https://semver.org/).
55

6+
## [0.28.0] - YYYY-MM-DD
7+
8+
### Fixed
9+
10+
- Fixed the function signature of `recvmmsg`, potentially causing UB
11+
([#2119](https://github.com/nix-rust/nix/issues/2119))
12+
13+
### Changed
14+
15+
- Simplified the function signatures of `recvmmsg` and `sendmmsg`
16+
617
## [0.27.1] - 2023-08-28
718

819
### Fixed

src/sys/personality.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,9 @@ pub fn get() -> Result<Persona> {
8080
///
8181
/// Example:
8282
///
83-
// Disable test on aarch64 until we know why it fails.
83+
// Disable test until we know why it fails.
8484
// https://github.com/nix-rust/nix/issues/2060
85-
#[cfg_attr(target_arch = "aarch64", doc = " ```no_run")]
86-
#[cfg_attr(not(target_arch = "aarch64"), doc = " ```")]
85+
#[doc = " ```no_run"]
8786
/// # use nix::sys::personality::{self, Persona};
8887
/// let mut pers = personality::get().unwrap();
8988
/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE));

src/sys/socket/mod.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,11 +1552,11 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
15521552
flags: MsgFlags
15531553
) -> crate::Result<MultiResults<'a, S>>
15541554
where
1555-
XS: IntoIterator<Item = &'a I>,
1555+
XS: IntoIterator<Item = I>,
15561556
AS: AsRef<[Option<S>]>,
1557-
I: AsRef<[IoSlice<'a>]> + 'a,
1558-
C: AsRef<[ControlMessage<'a>]> + 'a,
1559-
S: SockaddrLike + 'a
1557+
I: AsRef<[IoSlice<'a>]>,
1558+
C: AsRef<[ControlMessage<'a>]>,
1559+
S: SockaddrLike,
15601560
{
15611561

15621562
let mut count = 0;
@@ -1583,9 +1583,16 @@ pub fn sendmmsg<'a, XS, AS, C, I, S>(
15831583
pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) };
15841584
}
15851585

1586-
count = i+1;
1586+
// Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders`
1587+
// is through the `preallocate` function, which takes an `usize` as an argument to define its size,
1588+
// which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in
1589+
// other words: `count` doesn't overflow
1590+
count = i + 1;
15871591
}
15881592

1593+
// SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the
1594+
// maximum number of messages that can be sent safely (i.e. `count` is the minimum of the sizes of `slices`,
1595+
// `data.items` and `addrs`)
15891596
let sent = Errno::result(unsafe {
15901597
libc::sendmmsg(
15911598
fd,
@@ -1711,21 +1718,28 @@ pub fn recvmmsg<'a, XS, S, I>(
17111718
mut timeout: Option<crate::sys::time::TimeSpec>,
17121719
) -> crate::Result<MultiResults<'a, S>>
17131720
where
1714-
XS: IntoIterator<Item = &'a I>,
1715-
I: AsRef<[IoSliceMut<'a>]> + 'a,
1721+
XS: IntoIterator<Item = I>,
1722+
I: AsMut<[IoSliceMut<'a>]>,
17161723
{
17171724
let mut count = 0;
1718-
for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
1725+
for (i, (mut slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
17191726
let p = &mut mmsghdr.msg_hdr;
1720-
p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec;
1721-
p.msg_iovlen = slice.as_ref().len() as _;
1727+
p.msg_iov = slice.as_mut().as_mut_ptr().cast();
1728+
p.msg_iovlen = slice.as_mut().len() as _;
1729+
1730+
// Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders`
1731+
// is through the `preallocate` function, which takes an `usize` as an argument to define its size,
1732+
// which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in
1733+
// other words: `count` doesn't overflow
17221734
count = i + 1;
17231735
}
17241736

17251737
let timeout_ptr = timeout
17261738
.as_mut()
17271739
.map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec);
17281740

1741+
// SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the
1742+
// maximum number of messages that can be received safely (i.e. `count` is the minimum of the sizes of `slices` and `data.items`)
17291743
let received = Errno::result(unsafe {
17301744
libc::recvmmsg(
17311745
fd,
@@ -1903,7 +1917,7 @@ mod test {
19031917

19041918
let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10));
19051919

1906-
let recv = super::recvmmsg(rsock.as_raw_fd(), &mut data, recv_iovs.iter(), flags, Some(t))?;
1920+
let recv = super::recvmmsg(rsock.as_raw_fd(), &mut data, recv_iovs.iter_mut(), flags, Some(t))?;
19071921

19081922
for rmsg in recv {
19091923
#[cfg(not(any(qemu, target_arch = "aarch64")))]

test/sys/test_socket.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ mod recvfrom {
565565
let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
566566
rsock.as_raw_fd(),
567567
&mut data,
568-
msgs.iter(),
568+
msgs.iter_mut(),
569569
MsgFlags::empty(),
570570
None,
571571
)
@@ -653,7 +653,7 @@ mod recvfrom {
653653
let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
654654
rsock.as_raw_fd(),
655655
&mut data,
656-
msgs.iter(),
656+
msgs.iter_mut(),
657657
MsgFlags::MSG_DONTWAIT,
658658
None,
659659
)
@@ -2329,12 +2329,17 @@ fn test_recvmmsg_timestampns() {
23292329
// Receive the message
23302330
let mut buffer = vec![0u8; message.len()];
23312331
let cmsgspace = nix::cmsg_space!(TimeSpec);
2332-
let iov = vec![[IoSliceMut::new(&mut buffer)]];
2332+
let mut iov = vec![[IoSliceMut::new(&mut buffer)]];
23332333
let mut data = MultiHeaders::preallocate(1, Some(cmsgspace));
2334-
let r: Vec<RecvMsg<()>> =
2335-
recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None)
2336-
.unwrap()
2337-
.collect();
2334+
let r: Vec<RecvMsg<()>> = recvmmsg(
2335+
in_socket.as_raw_fd(),
2336+
&mut data,
2337+
iov.iter_mut(),
2338+
flags,
2339+
None,
2340+
)
2341+
.unwrap()
2342+
.collect();
23382343
let rtime = match r[0].cmsgs().next() {
23392344
Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
23402345
Some(_) => panic!("Unexpected control message"),

0 commit comments

Comments
 (0)