Skip to content

Commit

Permalink
Merge #1763
Browse files Browse the repository at this point in the history
1763: Fix a buffer overflow in sys::socket::recvfrom r=posborne a=asomers

IPv4 and stream sockets are unaffected, but for datagram sockets of
other address types libc::recvfrom might overwrite part of the stack.

Fixes #1762

Co-authored-by: Alan Somers <asomers@gmail.com>
  • Loading branch information
bors[bot] and asomers committed Jul 14, 2022
2 parents e5f354c + e0e768e commit 2556b78
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 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
49 changes: 47 additions & 2 deletions test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ pub fn test_std_conversions() {
mod recvfrom {
use super::*;
use nix::sys::socket::*;
use nix::Result;
use nix::{errno::Errno, Result};
use std::thread;

const MSG: &[u8] = b"Hello, World!";
Expand Down Expand Up @@ -681,6 +681,51 @@ 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");
match bind(rsock, &raddr) {
Err(Errno::EADDRNOTAVAIL) => {
println!("IPv6 not available, skipping test.");
return;
}
Err(e) => panic!("bind: {}", e),
Ok(()) => (),
}
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 +1779,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 2556b78

Please sign in to comment.