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 <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-02-14 09:55:19 +00:00
parent 503887843f
commit b04eb4770b
3 changed files with 30 additions and 4 deletions

View File

@ -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<Mutex<MemoryManager>>,
_exit_evt: &EventFd,
reset_evt: &EventFd,
_vmm_path: PathBuf,
) -> DeviceManagerResult<Self> {
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

View File

@ -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<T> = result::Result<T, Error>;
@ -159,10 +163,16 @@ pub fn start_vmm_thread(
) -> Result<thread::JoinHandle<Result<()>>> {
let http_api_event = api_event.try_clone().map_err(Error::EventFdClone)?;
// Find the path that the "/proc/<pid>/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>,
vm_config: Option<Arc<Mutex<VmConfig>>>,
vmm_path: PathBuf,
}
impl Vmm {
fn new(vmm_version: String, api_evt: EventFd) -> Result<Self> {
fn new(vmm_version: String, api_evt: EventFd, vmm_path: PathBuf) -> Result<Self> {
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.

View File

@ -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<Mutex<VmConfig>>,
exit_evt: EventFd,
reset_evt: EventFd,
vmm_path: PathBuf,
) -> Result<Self> {
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)?;