diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 36bef0c81..39ce4d0d0 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -35,6 +35,7 @@ use std::collections::HashMap; use std::fs::{File, OpenOptions}; use std::io::{self, sink, stdout}; use std::os::unix::fs::OpenOptionsExt; +use std::path::PathBuf; use std::result; #[cfg(feature = "pci_support")] use std::sync::Weak; @@ -399,6 +400,9 @@ pub struct DeviceManager { // The virtio devices on the system virtio_devices: Vec<(VirtioDeviceArc, bool)>, + + // The path to the VMM for self spawning + _vmm_path: PathBuf, } impl DeviceManager { @@ -409,6 +413,7 @@ impl DeviceManager { memory_manager: Arc>, _exit_evt: &EventFd, reset_evt: &EventFd, + _vmm_path: PathBuf, ) -> DeviceManagerResult { let io_bus = devices::Bus::new(); let mmio_bus = devices::Bus::new(); @@ -482,6 +487,7 @@ impl DeviceManager { migratable_devices, memory_manager, virtio_devices: Vec::new(), + _vmm_path, }; device_manager diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 46c115b38..e40e97a93 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -20,6 +20,7 @@ use crate::vm::{Error as VmError, Vm, VmState}; use libc::EFD_NONBLOCK; use std::io; use std::os::unix::io::{AsRawFd, RawFd}; +use std::path::PathBuf; use std::sync::mpsc::{Receiver, RecvError, SendError, Sender}; use std::sync::{Arc, Mutex}; use std::{result, thread}; @@ -79,6 +80,9 @@ pub enum Error { /// Cannot shut the VMM down VmmShutdown(VmError), + + // Error following "exe" link + ExePathReadLink(io::Error), } pub type Result = result::Result; @@ -159,10 +163,16 @@ pub fn start_vmm_thread( ) -> Result>> { let http_api_event = api_event.try_clone().map_err(Error::EventFdClone)?; + // Find the path that the "/proc//exe" symlink points to. Must be done before spawning + // a thread as Rust does not put the child threads in the same thread group which prevents the + // link from being followed as per PTRACE_MODE_READ_FSCREDS (see proc(5) and ptrace(2)). The + // alternative is to run always with CAP_SYS_PTRACE but that is not a good idea. + let self_path = format!("/proc/{}/exe", std::process::id()); + let vmm_path = std::fs::read_link(PathBuf::from(self_path)).map_err(Error::ExePathReadLink)?; let thread = thread::Builder::new() .name("vmm".to_string()) .spawn(move || { - let mut vmm = Vmm::new(vmm_version.to_string(), api_event)?; + let mut vmm = Vmm::new(vmm_version.to_string(), api_event, vmm_path)?; vmm.control_loop(Arc::new(api_receiver)) }) @@ -182,10 +192,11 @@ pub struct Vmm { version: String, vm: Option, vm_config: Option>>, + vmm_path: PathBuf, } impl Vmm { - fn new(vmm_version: String, api_evt: EventFd) -> Result { + fn new(vmm_version: String, api_evt: EventFd, vmm_path: PathBuf) -> 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)?; @@ -214,6 +225,7 @@ impl Vmm { version: vmm_version, vm: None, vm_config: None, + vmm_path, }) } @@ -224,7 +236,12 @@ impl Vmm { let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?; if let Some(ref vm_config) = self.vm_config { - let vm = Vm::new(Arc::clone(vm_config), exit_evt, reset_evt)?; + let vm = Vm::new( + Arc::clone(vm_config), + exit_evt, + reset_evt, + self.vmm_path.clone(), + )?; self.vm = Some(vm); } } @@ -278,7 +295,7 @@ impl Vmm { let exit_evt = self.exit_evt.try_clone().map_err(VmError::EventFdClone)?; let reset_evt = self.reset_evt.try_clone().map_err(VmError::EventFdClone)?; - self.vm = Some(Vm::new(config, exit_evt, reset_evt)?); + self.vm = Some(Vm::new(config, exit_evt, reset_evt, self.vmm_path.clone())?); } // Then we start the new VM. diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 192d6efdd..202cb4112 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -39,6 +39,7 @@ use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH}; use std::ffi::CString; use std::fs::File; use std::io; +use std::path::PathBuf; use std::sync::{Arc, Mutex, RwLock}; use std::{result, str, thread}; use vm_allocator::{GsiApic, SystemAllocator}; @@ -223,6 +224,7 @@ impl Vm { config: Arc>, exit_evt: EventFd, reset_evt: EventFd, + vmm_path: PathBuf, ) -> Result { let kvm = Kvm::new().map_err(Error::KvmNew)?; @@ -343,6 +345,7 @@ impl Vm { memory_manager.clone(), &exit_evt, &reset_evt, + vmm_path, ) .map_err(Error::DeviceManager)?;