Skip to content

Commit

Permalink
Fix a buffer overflow in sys::socket::recvfrom
Browse files Browse the repository at this point in the history
IPv4 and stream sockets are unaffected, but for datagram sockets of
other address types libc::recvfrom might overwrite part of the stack.

Fixes nix-rust#1762
  • Loading branch information
asomers committed Jul 14, 2022
1 parent e5f354c commit 5fe8a3f
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).

### Fixed

- Fixed buffer overflow in nix::sys::socket::recvfrom.
(#[1763](https://github.com/nix-rust/nix/pull/1763))
- Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like
operating systems.
(#[1729](https://github.com/nix-rust/nix/pull/1729))
Expand Down
9 changes: 6 additions & 3 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1912,8 +1912,8 @@ pub fn recvfrom<T:SockaddrLike>(sockfd: RawFd, buf: &mut [u8])
-> Result<(usize, Option<T>)>
{
unsafe {
let mut addr = mem::MaybeUninit::uninit();
let mut len = mem::size_of::<T>() as socklen_t;
let mut addr = mem::MaybeUninit::<T>::uninit();
let mut len = mem::size_of_val(&addr) as socklen_t;

let ret = Errno::result(libc::recvfrom(
sockfd,
Expand All @@ -1923,7 +1923,10 @@ pub fn recvfrom<T:SockaddrLike>(sockfd: RawFd, buf: &mut [u8])
addr.as_mut_ptr() as *mut libc::sockaddr,
&mut len as *mut socklen_t))? as usize;

Ok((ret, T::from_raw(&addr.assume_init(), Some(len))))
Ok((ret, T::from_raw(
addr.assume_init().as_ptr() as *const libc::sockaddr,
Some(len))
))
}
}

Expand Down
40 changes: 39 additions & 1 deletion test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,44 @@ mod recvfrom {
assert_eq!(&buf[..DATA.len()], DATA);
}
}

#[test]
pub fn udp_inet6() {
let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
let rport = 6789;
let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
let raddr = SockaddrIn6::from(rstd_sa);
let sport = 6790;
let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
let saddr = SockaddrIn6::from(sstd_sa);
let rsock = socket(
AddressFamily::Inet6,
SockType::Datagram,
SockFlag::empty(),
None,
)
.expect("receive socket failed");
bind(rsock, &raddr).unwrap();
let ssock = socket(
AddressFamily::Inet6,
SockType::Datagram,
SockFlag::empty(),
None,
)
.expect("send socket failed");
bind(ssock, &saddr).unwrap();
let from = sendrecv(
rsock,
ssock,
move |s, m, flags| sendto(s, m, &raddr, flags),
|_, _| {},
);
assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap());
let osent_addr = from.unwrap();
let sent_addr = osent_addr.as_sockaddr_in6().unwrap();
assert_eq!(sent_addr.ip(), addr);
assert_eq!(sent_addr.port(), sport);
}
}

// Test error handling of our recvmsg wrapper
Expand Down Expand Up @@ -1734,7 +1772,7 @@ pub fn test_recv_ipv6pktinfo() {
let (lo_name, lo) = match lo_ifaddr {
Some(ifaddr) => (
ifaddr.interface_name,
ifaddr.address.expect("Expect IPv4 address on interface"),
ifaddr.address.expect("Expect IPv6 address on interface"),
),
None => return,
};
Expand Down

0 comments on commit 5fe8a3f

Please sign in to comment.