From b04eb4770be11f9ae9937215c16a46a1ee1a1ac9 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 14 Feb 2020 09:55:19 +0000 Subject: [PATCH] vmm: Follow the "exe" symlink from the PID directory in /proc It is necessary to do this at the start of the VMM execution rather than later as it must be done in the main thread in order to satisfy the checks required by PTRACE_MODE_READ_FSCREDS (see proc(5) and ptrace(2)) The alternative is to run as CAP_SYS_PTRACE but that has its disadvantages. Signed-off-by: Rob Bradford --- vmm/src/device_manager.rs | 6 ++++++ vmm/src/lib.rs | 25 +++++++++++++++++++++---- vmm/src/vm.rs | 3 +++ 3 files changed, 30 insertions(+), 4 deletions(-) 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)?;