diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2023-07-17 22:26:39 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-17 22:26:39 +0000 |
commit | c375a102ac0af0d08c4942ffd81c84b6d6769d08 (patch) | |
tree | 6ebde1ce38d1646e0d1be66b5bfa09d1bd9530a6 /src/sys/socket/mod.rs | |
parent | 1d61638a72d91e5a5df03da4ab83182352a4d8e4 (diff) | |
parent | 2d60044196bbcf6c4da187f413e7ddd00f0a2ae0 (diff) | |
download | nix-c375a102ac0af0d08c4942ffd81c84b6d6769d08.zip |
Merge #2041master
2041: Set the length of a socket address when calling `recvmsg` on Linux r=asomers a=JarredAllen
# Background
I think I've found a bug with `recvmsg` on Linux where it doesn't set the length of a received socket address. I found this while working with unix datagram sockets with path `struct sockaddr_un` addresses, but I think this applies to any variable-length socket address type.
At present, the `sun_len` field of `UnixAddr` on Linux shows up as 0 whenever I call `recvmsg`. I think it's reading uninitialized memory (afaict the `recvmsg` function never initializes it before we call `MaybeUninit::assume_init`), though it's possible that it's being zero-initialized somewhere that I missed. Either way, this isn't the correct behavior, which should set it to the length of the `struct sockaddr_un` contents (or whatever other type of socket).
# Changes
I changed the `recvmsg` function to construct the returned socket address from the `struct sockaddr` and length returned by the libc `recvmsg` call (using the `from_raw` function the trait provides). Since the trait is sealed so downstream crates can't implement it, I believe this shouldn't be a breaking change.
# Validation
I've tested that my code (which failed due to this bug) now works. I also added a new test case which tests that we construct `UnixAddr`s correctly in the `recvmsg` function, which passes locally for me and fails if I cherry-pick it onto the current `master`.
I've also checked that `cargo test` and `cargo clippy` both still pass on `aarch64-apple-darwin` and on `aarch64-unknown-linux-musl` targets (the two targets I develop for/have access to). Hopefully your CI will confirm that everything else still works.
Co-authored-by: Jarred Allen <jarred@moveparallel.com>
Co-authored-by: Jarred Allen <jarredallen73@gmail.com>
Diffstat (limited to 'src/sys/socket/mod.rs')
-rw-r--r-- | src/sys/socket/mod.rs | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 06b93c6f..c304f6e3 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1613,7 +1613,7 @@ impl<S> MultiHeaders<S> { { // we will be storing pointers to addresses inside mhdr - convert it into boxed // slice so it can'be changed later by pushing anything into self.addresses - let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); + let mut addresses = vec![std::mem::MaybeUninit::<S>::uninit(); num_slices].into_boxed_slice(); let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); @@ -1918,7 +1918,7 @@ unsafe fn read_mhdr<'a, 'i, S>( mhdr: msghdr, r: isize, msg_controllen: usize, - address: S, + mut address: S, ) -> RecvMsg<'a, 'i, S> where S: SockaddrLike { @@ -1934,6 +1934,11 @@ unsafe fn read_mhdr<'a, 'i, S>( }.as_ref() }; + // Ignore errors if this socket address has statically-known length + // + // This is to ensure that unix socket addresses have their length set appropriately. + let _ = address.set_length(mhdr.msg_namelen as usize); + RecvMsg { bytes: r as usize, cmsghdr, @@ -1969,7 +1974,7 @@ unsafe fn pack_mhdr_to_receive<S>( // initialize it. let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; + (*p).msg_name = address as *mut c_void; (*p).msg_namelen = S::size(); (*p).msg_iov = iov_buffer as *mut iovec; (*p).msg_iovlen = iov_buffer_len as _; |