Skip to content

Commit

Permalink
backdoor: allow avoiding iopl permission errors
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lucab committed Oct 7, 2020
1 parent 999c62a commit 3b091e5
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "vmw_backdoor"
version = "0.1.4-alpha.0"
version = "0.2.0-alpha.0"
authors = ["Luca BRUNO <[email protected]>"]
edition = "2018"
license = "MIT/Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/check-backdoor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion examples/get-guestinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion examples/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion examples/report-agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
39 changes: 33 additions & 6 deletions src/backdoor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<BackdoorGuard, VmwError> {
/// 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, VmwError> {
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<BackdoorGuard, VmwError> {
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<BackdoorGuard, VmwError> {
/// 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, VmwError> {
BackdoorGuard::change_io_access(true)?;
let mut guard = BackdoorGuard {
release_on_drop: true,
Expand All @@ -37,6 +50,17 @@ pub fn probe_backdoor() -> Result<BackdoorGuard, VmwError> {
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<BackdoorGuard, VmwError> {
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
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

0 comments on commit 3b091e5

Please sign in to comment.