From 7c3e19c65a607609b24dc4185a64fcef60da6c18 Mon Sep 17 00:00:00 2001 From: Bo Chen Date: Fri, 15 May 2020 11:31:35 -0700 Subject: [PATCH] vhost_user_backend, vmm: Close leaked file descriptors Explicit call to 'close()' is required on file descriptors allocated from 'epoll::create()', which is missing for the 'EpollContext' and 'VringWorker'. This patch enforces to close the file descriptors by reusing the Drop trait of the 'File' struct. Signed-off-by: Bo Chen --- vhost_user_backend/src/lib.rs | 12 +++++++----- vmm/src/lib.rs | 17 ++++++++++------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/vhost_user_backend/src/lib.rs b/vhost_user_backend/src/lib.rs index efdb77baf..9cb3f63da 100644 --- a/vhost_user_backend/src/lib.rs +++ b/vhost_user_backend/src/lib.rs @@ -333,7 +333,7 @@ enum VringWorkerError { type VringWorkerResult = std::result::Result; pub struct VringWorker { - epoll_fd: RawFd, + epoll_file: File, } impl VringWorker { @@ -342,7 +342,7 @@ impl VringWorker { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(self.epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(self.epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { @@ -396,7 +396,7 @@ impl VringWorker { data: u64, ) -> result::Result<(), io::Error> { epoll::ctl( - self.epoll_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, fd, epoll::Event::new(ev_type, data), @@ -413,7 +413,7 @@ impl VringWorker { data: u64, ) -> result::Result<(), io::Error> { epoll::ctl( - self.epoll_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_DEL, fd, epoll::Event::new(ev_type, data), @@ -486,8 +486,10 @@ impl VhostUserHandler { for (thread_id, queues_mask) in queues_per_thread.iter().enumerate() { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(VhostUserHandlerError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; - let vring_worker = Arc::new(VringWorker { epoll_fd }); + let vring_worker = Arc::new(VringWorker { epoll_file }); let worker = vring_worker.clone(); let exit_event_id = if let Some((exit_event_fd, exit_event_id)) = diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 934c7eb61..f44dc2733 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -29,8 +29,9 @@ use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::vm::{Error as VmError, Vm, VmState}; use libc::EFD_NONBLOCK; use seccomp::{SeccompFilter, SeccompLevel}; +use std::fs::File; use std::io; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::sync::mpsc::{Receiver, RecvError, SendError, Sender}; use std::sync::{Arc, Mutex}; @@ -115,13 +116,15 @@ pub enum EpollDispatch { } pub struct EpollContext { - raw_fd: RawFd, + epoll_file: File, dispatch_table: Vec>, } impl EpollContext { pub fn new() -> result::Result { - let raw_fd = epoll::create(true)?; + let epoll_fd = epoll::create(true)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Initial capacity needs to be large enough to hold: // * 1 exit event @@ -132,7 +135,7 @@ impl EpollContext { dispatch_table.push(None); Ok(EpollContext { - raw_fd, + epoll_file, dispatch_table, }) } @@ -140,7 +143,7 @@ impl EpollContext { pub fn add_stdin(&mut self) -> result::Result<(), io::Error> { let dispatch_index = self.dispatch_table.len() as u64; epoll::ctl( - self.raw_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, libc::STDIN_FILENO, epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index), @@ -157,7 +160,7 @@ impl EpollContext { { let dispatch_index = self.dispatch_table.len() as u64; epoll::ctl( - self.raw_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, fd.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index), @@ -170,7 +173,7 @@ impl EpollContext { impl AsRawFd for EpollContext { fn as_raw_fd(&self) -> RawFd { - self.raw_fd + self.epoll_file.as_raw_fd() } }