From 0e027038c0d46b92e38ec00b42a48d812ad56f5b Mon Sep 17 00:00:00 2001 From: Luca BRUNO Date: Wed, 7 Oct 2020 10:10:26 +0000 Subject: [PATCH] backdoor: allow avoiding iopl permission errors This introduces additional methods for the backdoor-opening logic, in order to allow consuming applications to keep going when changing I/O access level is not alloewd (see kernel_lockdown(7) on Linux). In most cases the library may work without higher I/O level, and actual failures can be handled via normal error-handling on RPC methods. --- Cargo.toml | 2 +- examples/check-backdoor.rs | 2 +- examples/get-guestinfo.rs | 2 +- examples/log.rs | 2 +- examples/report-agent.rs | 2 +- src/backdoor.rs | 39 ++++++++++++++++++++++++++++++++------ src/lib.rs | 7 +++++-- 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2a374b9..0ba0215 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vmw_backdoor" -version = "0.1.4-alpha.0" +version = "0.2.0-alpha.0" authors = ["Luca BRUNO "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/examples/check-backdoor.rs b/examples/check-backdoor.rs index 1ac74f2..ccbec26 100644 --- a/examples/check-backdoor.rs +++ b/examples/check-backdoor.rs @@ -5,7 +5,7 @@ fn main() { let is_vmw = vmw::is_vmware_cpu(); println!("VMware CPU detected: {}.", is_vmw); - let mut backdoor = vmw::access_backdoor().unwrap(); + let mut backdoor = vmw::access_backdoor_privileged().unwrap(); println!("Raised I/O access to reach backdoor port."); let found = match backdoor.probe_vmware_backdoor() { diff --git a/examples/get-guestinfo.rs b/examples/get-guestinfo.rs index 448b1e9..16fa9ca 100644 --- a/examples/get-guestinfo.rs +++ b/examples/get-guestinfo.rs @@ -14,7 +14,7 @@ fn main() { panic!("Hypervisor not present"); } - let mut backdoor = vmw::probe_backdoor().unwrap(); + let mut backdoor = vmw::probe_backdoor_privileged().unwrap(); eprintln!("Got backdoor access."); let mut erpc = backdoor.open_enhanced_chan().unwrap(); diff --git a/examples/log.rs b/examples/log.rs index 06141f5..74226e1 100644 --- a/examples/log.rs +++ b/examples/log.rs @@ -14,7 +14,7 @@ fn main() { panic!("Hypervisor not present"); } - let mut backdoor = vmw::probe_backdoor().unwrap(); + let mut backdoor = vmw::probe_backdoor_privileged().unwrap(); eprintln!("Got backdoor access."); let mut erpc = backdoor.open_enhanced_chan().unwrap(); diff --git a/examples/report-agent.rs b/examples/report-agent.rs index 85f81f7..593f3e3 100644 --- a/examples/report-agent.rs +++ b/examples/report-agent.rs @@ -8,7 +8,7 @@ fn main() { panic!("Hypervisor not present"); } - let mut backdoor = vmw::probe_backdoor().unwrap(); + let mut backdoor = vmw::probe_backdoor_privileged().unwrap(); eprintln!("Got backdoor access."); let mut erpc = backdoor.open_enhanced_chan().unwrap(); diff --git a/src/backdoor.rs b/src/backdoor.rs index b62f143..8c8edb5 100644 --- a/src/backdoor.rs +++ b/src/backdoor.rs @@ -17,18 +17,31 @@ pub(crate) const COMMAND_ERPC: u32 = 0x1E; /// Try to acquire access to the backdoor, but do NOT probe its presence. /// -/// On Linux, this requires running with `CAP_SYS_RAWIO` privileges. -pub fn access_backdoor() -> Result { +/// On Linux, this tries to change I/O access level via `iopl()`. That requires +/// running with `CAP_SYS_RAWIO` capability and it is not compatible with +/// `kernel_lockdown`. +pub fn access_backdoor_privileged() -> Result { BackdoorGuard::change_io_access(true)?; Ok(BackdoorGuard { release_on_drop: true, }) } +/// Try to acquire access to the backdoor, but do NOT probe its presence. +/// +/// Wherever possible, use `access_backdoor_privileged()` instead. +pub fn access_backdoor() -> Result { + Ok(BackdoorGuard { + release_on_drop: false, + }) +} + /// Try to acquire access to the backdoor, and probe its presence. /// -/// On Linux, this requires running with `CAP_SYS_RAWIO` privileges. -pub fn probe_backdoor() -> Result { +/// On Linux, this tries to change I/O access level via `iopl()`. That requires +/// running with `CAP_SYS_RAWIO` capability and it is not compatible with +/// `kernel_lockdown`. +pub fn probe_backdoor_privileged() -> Result { BackdoorGuard::change_io_access(true)?; let mut guard = BackdoorGuard { release_on_drop: true, @@ -37,6 +50,17 @@ pub fn probe_backdoor() -> Result { Ok(guard) } +/// Try to acquire access to the backdoor, and probe its presence. +/// +/// Wherever possible, use `probe_backdoor_privileged()` instead. +pub fn probe_backdoor() -> Result { + let mut guard = BackdoorGuard { + release_on_drop: false, + }; + guard.probe_vmware_backdoor()?; + Ok(guard) +} + /// Guard for an open backdoor. /// /// This can be acquired via [`access_backdoor`](fn.access_backdoor.html) or @@ -69,6 +93,7 @@ impl BackdoorGuard { EnhancedChan::open(self) } + /// Try to change I/O ports access level. pub(crate) fn change_io_access(acquire: bool) -> Result<(), VmwError> { // NOTE(lucab): `ioperm()` is not enough here, as the backdoor // protocol uses a dynamic range of I/O ports. @@ -85,8 +110,10 @@ impl BackdoorGuard { impl Drop for BackdoorGuard { fn drop(&mut self) { - if self.release_on_drop && Self::change_io_access(false).is_err() { - log::warn!("failed to release backdoor access"); + if self.release_on_drop { + if let Err(e) = Self::change_io_access(false) { + log::error!("failed to release backdoor access: {}", e); + } } } } diff --git a/src/lib.rs b/src/lib.rs index 56513d8..48fa6d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ //! let is_vmw = vmw_backdoor::is_vmware_cpu(); //! println!("VMware CPU detected: {}.", is_vmw); //! -//! let mut guard = vmw_backdoor::access_backdoor().unwrap(); +//! let mut guard = vmw_backdoor::access_backdoor_privileged().unwrap(); //! println!("Raised I/O access to reach backdoor port."); //! //! let found = guard.probe_vmware_backdoor().unwrap_or(false); @@ -54,8 +54,11 @@ cfg_if::cfg_if! { mod erpc; mod low_bw; - pub use backdoor::{access_backdoor, probe_backdoor, BackdoorGuard}; pub use asm::is_vmware_cpu; + pub use backdoor::{ + access_backdoor, access_backdoor_privileged, probe_backdoor, probe_backdoor_privileged, + BackdoorGuard, + }; pub use erpc::EnhancedChan; } }