diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index f4580440b..673ca9973 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -14,6 +14,7 @@ use std::collections::HashMap; use std::fs::File; use std::os::unix::io::{IntoRawFd, RawFd}; use std::os::unix::net::UnixListener; +use std::panic::AssertUnwindSafe; use std::path::PathBuf; use std::sync::mpsc::Sender; use std::sync::Arc; @@ -267,6 +268,7 @@ fn start_http_thread( api_notifier: EventFd, api_sender: Sender, seccomp_action: &SeccompAction, + exit_evt: EventFd, ) -> Result>> { // Retrieve seccomp filter for API thread let api_seccomp_filter = @@ -277,32 +279,44 @@ fn start_http_thread( .spawn(move || { // Apply seccomp filter for API thread. if !api_seccomp_filter.is_empty() { - apply_filter(&api_seccomp_filter).map_err(Error::ApplySeccompFilter)?; + apply_filter(&api_seccomp_filter) + .map_err(Error::ApplySeccompFilter) + .map_err(|e| { + error!("Error applying seccomp filter: {:?}", e); + exit_evt.write(1).ok(); + e + })?; } - server.start_server().unwrap(); - loop { - match server.requests() { - Ok(request_vec) => { - for server_request in request_vec { - server - .respond(server_request.process(|request| { + std::panic::catch_unwind(AssertUnwindSafe(move || { + server.start_server().unwrap(); + loop { + match server.requests() { + Ok(request_vec) => { + for server_request in request_vec { + if let Err(e) = server.respond(server_request.process(|request| { handle_http_request(request, &api_notifier, &api_sender) - })) - .or_else(|e| { + })) { error!("HTTP server error on response: {}", e); - Ok(()) - })?; + } + } + } + Err(e) => { + error!( + "HTTP server error on retrieving incoming request. Error: {}", + e + ); } } - Err(e) => { - error!( - "HTTP server error on retrieving incoming request. Error: {}", - e - ); - } } - } + })) + .map_err(|_| { + error!("http-server thread panicked"); + exit_evt.write(1).ok() + }) + .ok(); + + Ok(()) }) .map_err(Error::HttpThreadSpawn) } @@ -312,13 +326,14 @@ pub fn start_http_path_thread( api_notifier: EventFd, api_sender: Sender, seccomp_action: &SeccompAction, + exit_evt: EventFd, ) -> Result>> { std::fs::remove_file(path).unwrap_or_default(); let socket_path = PathBuf::from(path); let socket_fd = UnixListener::bind(socket_path).map_err(Error::CreateApiServerSocket)?; let server = HttpServer::new_from_fd(socket_fd.into_raw_fd()).map_err(Error::CreateApiServer)?; - start_http_thread(server, api_notifier, api_sender, seccomp_action) + start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt) } pub fn start_http_fd_thread( @@ -326,7 +341,8 @@ pub fn start_http_fd_thread( api_notifier: EventFd, api_sender: Sender, seccomp_action: &SeccompAction, + exit_evt: EventFd, ) -> Result>> { let server = HttpServer::new_from_fd(fd).map_err(Error::CreateApiServer)?; - start_http_thread(server, api_notifier, api_sender, seccomp_action) + start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt) } diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index a06d8ac9e..c40e35771 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -262,30 +262,47 @@ pub fn start_vmm_thread( get_seccomp_filter(seccomp_action, Thread::Vmm).map_err(Error::CreateSeccompFilter)?; let vmm_seccomp_action = seccomp_action.clone(); - let thread = thread::Builder::new() - .name("vmm".to_string()) - .spawn(move || { - // Apply seccomp filter for VMM thread. - if !vmm_seccomp_filter.is_empty() { - apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?; - } + let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?; + let thread = { + let exit_evt = exit_evt.try_clone().map_err(Error::EventFdClone)?; + thread::Builder::new() + .name("vmm".to_string()) + .spawn(move || { + // Apply seccomp filter for VMM thread. + if !vmm_seccomp_filter.is_empty() { + apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?; + } - let mut vmm = Vmm::new( - vmm_version.to_string(), - api_event, - vmm_seccomp_action, - hypervisor, - )?; + let mut vmm = Vmm::new( + vmm_version.to_string(), + api_event, + vmm_seccomp_action, + hypervisor, + exit_evt, + )?; - vmm.control_loop(Arc::new(api_receiver)) - }) - .map_err(Error::VmmThreadSpawn)?; + vmm.control_loop(Arc::new(api_receiver)) + }) + .map_err(Error::VmmThreadSpawn)? + }; // The VMM thread is started, we can start serving HTTP requests if let Some(http_path) = http_path { - api::start_http_path_thread(http_path, http_api_event, api_sender, seccomp_action)?; + api::start_http_path_thread( + http_path, + http_api_event, + api_sender, + seccomp_action, + exit_evt, + )?; } else if let Some(http_fd) = http_fd { - api::start_http_fd_thread(http_fd, http_api_event, api_sender, seccomp_action)?; + api::start_http_fd_thread( + http_fd, + http_api_event, + api_sender, + seccomp_action, + exit_evt, + )?; } Ok(thread) } @@ -316,9 +333,9 @@ impl Vmm { api_evt: EventFd, seccomp_action: SeccompAction, hypervisor: Arc, + exit_evt: EventFd, ) -> Result { let mut epoll = EpollContext::new().map_err(Error::Epoll)?; - let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?; let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?; let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;