From 06efaeb48fc25f4bd6b353a600bbad334e044bd9 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 25 Nov 2022 09:16:00 +0100 Subject: [PATCH] Don't leak fds on error in UDS on Unix We do this by simply creating a fd-managing type, e.g. UnixDatagram, from the fd once it's created. Also first tries to parse the path as that can fail without doing a system call. --- src/sys/unix/uds/datagram.rs | 7 ++++--- src/sys/unix/uds/listener.rs | 16 ++++++---------- src/sys/unix/uds/stream.rs | 15 +++++---------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/sys/unix/uds/datagram.rs b/src/sys/unix/uds/datagram.rs index d3e5314f..4ed75f35 100644 --- a/src/sys/unix/uds/datagram.rs +++ b/src/sys/unix/uds/datagram.rs @@ -7,12 +7,13 @@ use std::os::unix::net; use std::path::Path; pub(crate) fn bind(path: &Path) -> io::Result { - let fd = new_socket(libc::AF_UNIX, libc::SOCK_DGRAM)?; - // Ensure the fd is closed. - let socket = unsafe { net::UnixDatagram::from_raw_fd(fd) }; let (sockaddr, socklen) = socket_addr(path)?; let sockaddr = &sockaddr as *const libc::sockaddr_un as *const _; + + let fd = new_socket(libc::AF_UNIX, libc::SOCK_DGRAM)?; + let socket = unsafe { net::UnixDatagram::from_raw_fd(fd) }; syscall!(bind(fd, sockaddr, socklen))?; + Ok(socket) } diff --git a/src/sys/unix/uds/listener.rs b/src/sys/unix/uds/listener.rs index 79bd14ee..83846826 100644 --- a/src/sys/unix/uds/listener.rs +++ b/src/sys/unix/uds/listener.rs @@ -7,19 +7,15 @@ use std::path::Path; use std::{io, mem}; pub(crate) fn bind(path: &Path) -> io::Result { - let socket = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; let (sockaddr, socklen) = socket_addr(path)?; let sockaddr = &sockaddr as *const libc::sockaddr_un as *const libc::sockaddr; - syscall!(bind(socket, sockaddr, socklen)) - .and_then(|_| syscall!(listen(socket, 1024))) - .map_err(|err| { - // Close the socket if we hit an error, ignoring the error from - // closing since we can't pass back two errors. - let _ = unsafe { libc::close(socket) }; - err - }) - .map(|_| unsafe { net::UnixListener::from_raw_fd(socket) }) + let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; + let socket = unsafe { net::UnixListener::from_raw_fd(fd) }; + syscall!(bind(fd, sockaddr, socklen))?; + syscall!(listen(fd, 1024))?; + + Ok(socket) } pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> { diff --git a/src/sys/unix/uds/stream.rs b/src/sys/unix/uds/stream.rs index 9ae4867f..461917c1 100644 --- a/src/sys/unix/uds/stream.rs +++ b/src/sys/unix/uds/stream.rs @@ -7,23 +7,18 @@ use std::os::unix::net; use std::path::Path; pub(crate) fn connect(path: &Path) -> io::Result { - let socket = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; let (sockaddr, socklen) = socket_addr(path)?; let sockaddr = &sockaddr as *const libc::sockaddr_un as *const libc::sockaddr; - match syscall!(connect(socket, sockaddr, socklen)) { + let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; + let socket = unsafe { net::UnixStream::from_raw_fd(fd) }; + match syscall!(connect(fd, sockaddr, socklen)) { Ok(_) => {} Err(ref err) if err.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => { - // Close the socket if we hit an error, ignoring the error - // from closing since we can't pass back two errors. - let _ = unsafe { libc::close(socket) }; - - return Err(e); - } + Err(e) => return Err(e), } - Ok(unsafe { net::UnixStream::from_raw_fd(socket) }) + Ok(socket) } pub(crate) fn pair() -> io::Result<(net::UnixStream, net::UnixStream)> {