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..baa1621 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(false).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..b135d11 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(false).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..cf20575 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(false).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..497772c 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(false).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..a8f0604 100644 --- a/src/backdoor.rs +++ b/src/backdoor.rs @@ -18,20 +18,20 @@ 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 { - BackdoorGuard::change_io_access(true)?; +pub fn access_backdoor(ignore_access_errors: bool) -> Result { + let changed = BackdoorGuard::change_io_access(true, ignore_access_errors)?; Ok(BackdoorGuard { - release_on_drop: true, + release_on_drop: changed, }) } /// 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 { - BackdoorGuard::change_io_access(true)?; +pub fn probe_backdoor(ignore_access_errors: bool) -> Result { + let changed = BackdoorGuard::change_io_access(true, ignore_access_errors)?; let mut guard = BackdoorGuard { - release_on_drop: true, + release_on_drop: changed, }; guard.probe_vmware_backdoor()?; Ok(guard) @@ -55,7 +55,7 @@ impl BackdoorGuard { /// Try to release backdoor access. pub fn release_access(self) -> Result<(), Self> { let mut guard = self; - if Self::change_io_access(false).is_err() { + if Self::change_io_access(false, false).is_err() { return Err(guard); } @@ -69,24 +69,45 @@ impl BackdoorGuard { EnhancedChan::open(self) } - pub(crate) fn change_io_access(acquire: bool) -> Result<(), VmwError> { + /// Try to change I/O ports access level. + /// + /// This returns whether access level was changed, so that it can + /// be reverted later on. + pub(crate) fn change_io_access( + acquire: bool, + ignore_access_errors: bool, + ) -> Result { // NOTE(lucab): `ioperm()` is not enough here, as the backdoor // protocol uses a dynamic range of I/O ports. let level = if acquire { 0b11 } else { 0b00 }; let err = unsafe { libc::iopl(level) }; if err != 0 { let err_code = errno::errno(); + + // Ignore permission errors if asked to do so (e.g. because + // of kernel_lockdown). + if ignore_access_errors && err_code.0 == libc::EPERM { + log::warn!( + "ignoring iopl failure: {} (errno: {})", + err_code, + err_code.0 + ); + return Ok(false); + } + return Err(format!("iopl failed: {} (errno: {})", err_code, err_code.0).into()); }; - Ok(()) + Ok(true) } } 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, false) { + log::error!("failed to release backdoor access: {}", e); + } } } }