Skip to content

Commit e0e768e

Browse files
committed
Fix a buffer overflow in sys::socket::recvfrom
IPv4 and stream sockets are unaffected, but for datagram sockets of other address types libc::recvfrom might overwrite part of the stack. Fixes #1762
1 parent e5f354c commit e0e768e

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
4444

4545
### Fixed
4646

47+
- Fixed buffer overflow in nix::sys::socket::recvfrom.
48+
(#[1763](https://github.com/nix-rust/nix/pull/1763))
4749
- Enabled `SockaddrStorage::{as_link_addr, as_link_addr_mut}` for Linux-like
4850
operating systems.
4951
(#[1729](https://github.com/nix-rust/nix/pull/1729))

src/sys/socket/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,8 +1912,8 @@ pub fn recvfrom<T:SockaddrLike>(sockfd: RawFd, buf: &mut [u8])
19121912
-> Result<(usize, Option<T>)>
19131913
{
19141914
unsafe {
1915-
let mut addr = mem::MaybeUninit::uninit();
1916-
let mut len = mem::size_of::<T>() as socklen_t;
1915+
let mut addr = mem::MaybeUninit::<T>::uninit();
1916+
let mut len = mem::size_of_val(&addr) as socklen_t;
19171917

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

1926-
Ok((ret, T::from_raw(&addr.assume_init(), Some(len))))
1926+
Ok((ret, T::from_raw(
1927+
addr.assume_init().as_ptr() as *const libc::sockaddr,
1928+
Some(len))
1929+
))
19271930
}
19281931
}
19291932

test/sys/test_socket.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ pub fn test_std_conversions() {
298298
mod recvfrom {
299299
use super::*;
300300
use nix::sys::socket::*;
301-
use nix::Result;
301+
use nix::{errno::Errno, Result};
302302
use std::thread;
303303

304304
const MSG: &[u8] = b"Hello, World!";
@@ -681,6 +681,51 @@ mod recvfrom {
681681
assert_eq!(&buf[..DATA.len()], DATA);
682682
}
683683
}
684+
685+
#[test]
686+
pub fn udp_inet6() {
687+
let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
688+
let rport = 6789;
689+
let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
690+
let raddr = SockaddrIn6::from(rstd_sa);
691+
let sport = 6790;
692+
let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
693+
let saddr = SockaddrIn6::from(sstd_sa);
694+
let rsock = socket(
695+
AddressFamily::Inet6,
696+
SockType::Datagram,
697+
SockFlag::empty(),
698+
None,
699+
)
700+
.expect("receive socket failed");
701+
match bind(rsock, &raddr) {
702+
Err(Errno::EADDRNOTAVAIL) => {
703+
println!("IPv6 not available, skipping test.");
704+
return;
705+
}
706+
Err(e) => panic!("bind: {}", e),
707+
Ok(()) => (),
708+
}
709+
let ssock = socket(
710+
AddressFamily::Inet6,
711+
SockType::Datagram,
712+
SockFlag::empty(),
713+
None,
714+
)
715+
.expect("send socket failed");
716+
bind(ssock, &saddr).unwrap();
717+
let from = sendrecv(
718+
rsock,
719+
ssock,
720+
move |s, m, flags| sendto(s, m, &raddr, flags),
721+
|_, _| {},
722+
);
723+
assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap());
724+
let osent_addr = from.unwrap();
725+
let sent_addr = osent_addr.as_sockaddr_in6().unwrap();
726+
assert_eq!(sent_addr.ip(), addr);
727+
assert_eq!(sent_addr.port(), sport);
728+
}
684729
}
685730

686731
// Test error handling of our recvmsg wrapper
@@ -1734,7 +1779,7 @@ pub fn test_recv_ipv6pktinfo() {
17341779
let (lo_name, lo) = match lo_ifaddr {
17351780
Some(ifaddr) => (
17361781
ifaddr.interface_name,
1737-
ifaddr.address.expect("Expect IPv4 address on interface"),
1782+
ifaddr.address.expect("Expect IPv6 address on interface"),
17381783
),
17391784
None => return,
17401785
};

0 commit comments

Comments
 (0)