From b826b9af9ad163d87df27ca2935005d2dcb5dd77 Mon Sep 17 00:00:00 2001 From: Simon Davies <=simongdavies@users.noreply.github.com> Date: Mon, 11 Nov 2024 22:40:59 +0000 Subject: [PATCH] Adds support for Azure 3 --- Cargo.toml | 2 - src/hyperlight_host/Cargo.toml | 11 ++- src/hyperlight_host/build.rs | 8 +- src/hyperlight_host/src/error.rs | 6 ++ .../src/hypervisor/hyperv_linux.rs | 45 +++++++++-- src/hyperlight_host/src/mem/memory_region.rs | 74 ++++++++++++++----- 6 files changed, 115 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b73e6aff..5a33d58c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,8 +33,6 @@ repository = "https://github.com/hyperlight-dev/hyperlight" readme = "README.md" [workspace.dependencies] -mshv-bindings = { version = "=0.2.1" } -mshv-ioctls = { version = "=0.2.1" } hyperlight-common = { path = "src/hyperlight_common", version = "0.1.0", default-features = false } hyperlight-host = { path = "src/hyperlight_host", version = "0.1.0", default-features = false } diff --git a/src/hyperlight_host/Cargo.toml b/src/hyperlight_host/Cargo.toml index 97ec9530..3f2c8e42 100644 --- a/src/hyperlight_host/Cargo.toml +++ b/src/hyperlight_host/Cargo.toml @@ -71,10 +71,12 @@ windows-result = "0.2" [target.'cfg(unix)'.dependencies] seccompiler = { version = "0.4.0", optional = true } -mshv-bindings = { workspace = true, optional = true } -mshv-ioctls = { workspace = true, optional = true } kvm-bindings = { version = "0.10.0", features = ["fam-wrappers"], optional = true } kvm-ioctls = { version = "0.19.0", optional = true } +mshv-bindings2 = { package="mshv-bindings", version = "=0.2.1", optional = true } +mshv-ioctls2 = { package="mshv-ioctls", version = "=0.2.1", optional = true} +mshv-bindings3 = { package="mshv-bindings", version = "0.3.1", optional = true } +mshv-ioctls3 = { package="mshv-ioctls", version = "0.3.1", optional = true} [dev-dependencies] signal-hook-registry = "1.4.1" @@ -112,7 +114,7 @@ cfg_aliases = "0.2.1" built = { version = "0.7.0", features = ["chrono","git2"] } [features] -default = ["kvm", "mshv", "seccomp"] +default = ["kvm", "mshv2", "seccomp"] seccomp = ["dep:seccompiler"] function_call_metrics = [] executable_heap = [] @@ -122,7 +124,8 @@ print_debug = [] # the name of the file is output to stdout and logged. dump_on_crash = ["dep:tempfile"] kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"] -mshv = ["dep:mshv-bindings", "dep:mshv-ioctls"] +mshv2 = ["mshv-bindings2", "mshv-ioctls2"] +mshv3 = ["mshv-bindings3", "mshv-ioctls3"] inprocess = [] [[bench]] diff --git a/src/hyperlight_host/build.rs b/src/hyperlight_host/build.rs index f115c6e3..8639e400 100644 --- a/src/hyperlight_host/build.rs +++ b/src/hyperlight_host/build.rs @@ -18,6 +18,10 @@ use anyhow::Result; use built::write_built_file; fn main() -> Result<()> { + // mshv2 and mshv3 features are mutually exclusive. + #[cfg(all(feature = "mshv2", feature = "mshv3"))] + panic!("mshv2 and mshv3 features are mutually exclusive"); + // re-run the build if this script is changed (or deleted!), // even if the rust code is completely unchanged. println!("cargo:rerun-if-changed=build.rs"); @@ -85,12 +89,12 @@ fn main() -> Result<()> { } // Makes #[cfg(kvm)] == #[cfg(all(feature = "kvm", target_os = "linux"))] - // and #[cfg(mshv)] == #[cfg(all(feature = "mshv", target_os = "linux"))]. + // and #[cfg(mshv)] == #[cfg(all(any(feature = "mshv2", feature = "mshv3"), target_os = "linux"))]. // Essentially the kvm and mshv features are ignored on windows as long as you use #[cfg(kvm)] and not #[cfg(feature = "kvm")]. // You should never use #[cfg(feature = "kvm")] or #[cfg(feature = "mshv")] in the codebase. cfg_aliases::cfg_aliases! { kvm: { all(feature = "kvm", target_os = "linux") }, - mshv: { all(feature = "mshv", target_os = "linux") }, + mshv: { all(any(feature = "mshv2", feature = "mshv3"), target_os = "linux") }, // inprocess feature is aliased with debug_assertions to make it only available in debug-builds. // You should never use #[cfg(feature = "inprocess")] in the codebase. Use #[cfg(inprocess)] instead. inprocess: { all(feature = "inprocess", debug_assertions) }, diff --git a/src/hyperlight_host/src/error.rs b/src/hyperlight_host/src/error.rs index 702593d8..b20457a0 100644 --- a/src/hyperlight_host/src/error.rs +++ b/src/hyperlight_host/src/error.rs @@ -14,6 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(feature = "mshv2")] +extern crate mshv_ioctls2 as mshv_ioctls; + +#[cfg(feature = "mshv3")] +extern crate mshv_ioctls3 as mshv_ioctls; + use std::array::TryFromSliceError; use std::cell::{BorrowError, BorrowMutError}; use std::convert::Infallible; diff --git a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs index 4bbaef7b..3833a01d 100644 --- a/src/hyperlight_host/src/hypervisor/hyperv_linux.rs +++ b/src/hyperlight_host/src/hypervisor/hyperv_linux.rs @@ -14,16 +14,32 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(feature = "mshv2")] +extern crate mshv_bindings2 as mshv_bindings; +#[cfg(feature = "mshv2")] +extern crate mshv_ioctls2 as mshv_ioctls; + +#[cfg(feature = "mshv3")] +extern crate mshv_bindings3 as mshv_bindings; +#[cfg(feature = "mshv3")] +extern crate mshv_ioctls3 as mshv_ioctls; + use std::fmt::{Debug, Formatter}; use log::error; +#[cfg(feature = "mshv2")] +use mshv_bindings::hv_message; use mshv_bindings::{ - hv_message, hv_message_type, hv_message_type_HVMSG_GPA_INTERCEPT, - hv_message_type_HVMSG_UNMAPPED_GPA, hv_message_type_HVMSG_X64_HALT, - hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT, hv_register_assoc, + hv_message_type, hv_message_type_HVMSG_GPA_INTERCEPT, hv_message_type_HVMSG_UNMAPPED_GPA, + hv_message_type_HVMSG_X64_HALT, hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT, hv_register_assoc, hv_register_name_HV_X64_REGISTER_RIP, hv_register_value, mshv_user_mem_region, FloatingPointUnit, SegmentRegister, SpecialRegisters, StandardRegisters, }; +#[cfg(feature = "mshv3")] +use mshv_bindings::{ + hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES, + hv_partition_synthetic_processor_features, +}; use mshv_ioctls::{Mshv, VcpuFd, VmFd}; use tracing::{instrument, Span}; @@ -89,7 +105,19 @@ impl HypervLinuxDriver { } let mshv = Mshv::new()?; let pr = Default::default(); + #[cfg(feature = "mshv2")] let vm_fd = mshv.create_vm_with_config(&pr)?; + #[cfg(feature = "mshv3")] + let vm_fd = { + let vm_fd = mshv.create_vm_with_args(&pr)?; + let features: hv_partition_synthetic_processor_features = Default::default(); + vm_fd.hvcall_set_partition_property( + hv_partition_property_code_HV_PARTITION_PROPERTY_SYNTHETIC_PROC_FEATURES, + unsafe { features.as_uint64[0] }, + )?; + vm_fd + }; + let mut vcpu_fd = vm_fd.create_vcpu(0)?; mem_regions.iter().try_for_each(|region| { @@ -283,8 +311,15 @@ impl Hypervisor for HypervLinuxDriver { const UNMAPPED_GPA_MESSAGE: hv_message_type = hv_message_type_HVMSG_UNMAPPED_GPA; const INVALID_GPA_ACCESS_MESSAGE: hv_message_type = hv_message_type_HVMSG_GPA_INTERCEPT; - let hv_message: hv_message = Default::default(); - let result = match &self.vcpu_fd.run(hv_message) { + #[cfg(feature = "mshv2")] + let run_result = { + let hv_message: hv_message = Default::default(); + &self.vcpu_fd.run(hv_message) + }; + #[cfg(feature = "mshv3")] + let run_result = &self.vcpu_fd.run(); + + let result = match run_result { Ok(m) => match m.header.message_type { HALT_MESSAGE => { debug!("mshv - Halt Details : {:#?}", &self); diff --git a/src/hyperlight_host/src/mem/memory_region.rs b/src/hyperlight_host/src/mem/memory_region.rs index f8911ff6..c2cc210f 100644 --- a/src/hyperlight_host/src/mem/memory_region.rs +++ b/src/hyperlight_host/src/mem/memory_region.rs @@ -14,6 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ +#[cfg(feature = "mshv2")] +extern crate mshv_bindings2 as mshv_bindings; +#[cfg(feature = "mshv2")] +extern crate mshv_ioctls2 as mshv_ioctls; + +#[cfg(feature = "mshv3")] +extern crate mshv_bindings3 as mshv_bindings; +#[cfg(feature = "mshv3")] +extern crate mshv_ioctls3 as mshv_ioctls; + use std::ops::Range; use bitflags::bitflags; @@ -21,9 +31,14 @@ use bitflags::bitflags; use hyperlight_common::mem::PAGE_SHIFT; use hyperlight_common::mem::PAGE_SIZE_USIZE; #[cfg(mshv)] +use mshv_bindings::{hv_x64_memory_intercept_message, mshv_user_mem_region}; +#[cfg(feature = "mshv2")] +use mshv_bindings::{ + HV_MAP_GPA_EXECUTABLE, HV_MAP_GPA_PERMISSIONS_NONE, HV_MAP_GPA_READABLE, HV_MAP_GPA_WRITABLE, +}; +#[cfg(feature = "mshv3")] use mshv_bindings::{ - hv_x64_memory_intercept_message, mshv_user_mem_region, HV_MAP_GPA_EXECUTABLE, - HV_MAP_GPA_PERMISSIONS_NONE, HV_MAP_GPA_READABLE, HV_MAP_GPA_WRITABLE, + MSHV_SET_MEM_BIT_EXECUTABLE, MSHV_SET_MEM_BIT_UNMAP, MSHV_SET_MEM_BIT_WRITABLE, }; #[cfg(target_os = "windows")] use windows::Win32::System::Hypervisor::{self, WHV_MEMORY_ACCESS_TYPE}; @@ -227,22 +242,45 @@ impl From for mshv_user_mem_region { let guest_pfn = region.guest_region.start as u64 >> PAGE_SHIFT; let userspace_addr = region.host_region.start as u64; - let flags = region.flags.iter().fold(0, |acc, flag| { - let flag_value = match flag { - MemoryRegionFlags::NONE => HV_MAP_GPA_PERMISSIONS_NONE, - MemoryRegionFlags::READ => HV_MAP_GPA_READABLE, - MemoryRegionFlags::WRITE => HV_MAP_GPA_WRITABLE, - MemoryRegionFlags::EXECUTE => HV_MAP_GPA_EXECUTABLE, - _ => 0, // ignore any unknown flags - }; - acc | flag_value - }); - - mshv_user_mem_region { - guest_pfn, - size, - userspace_addr, - flags, + #[cfg(feature = "mshv2")] + { + let flags = region.flags.iter().fold(0, |acc, flag| { + let flag_value = match flag { + MemoryRegionFlags::NONE => HV_MAP_GPA_PERMISSIONS_NONE, + MemoryRegionFlags::READ => HV_MAP_GPA_READABLE, + MemoryRegionFlags::WRITE => HV_MAP_GPA_WRITABLE, + MemoryRegionFlags::EXECUTE => HV_MAP_GPA_EXECUTABLE, + _ => 0, // ignore any unknown flags + }; + acc | flag_value + }); + mshv_user_mem_region { + guest_pfn, + size, + userspace_addr, + flags, + } + } + #[cfg(feature = "mshv3")] + { + let flags: u8 = region.flags.iter().fold(0, |acc, flag| { + let flag_value = match flag { + MemoryRegionFlags::NONE => 1 << MSHV_SET_MEM_BIT_UNMAP, + MemoryRegionFlags::READ => 0, + MemoryRegionFlags::WRITE => 1 << MSHV_SET_MEM_BIT_WRITABLE, + MemoryRegionFlags::EXECUTE => 1 << MSHV_SET_MEM_BIT_EXECUTABLE, + _ => 0, // ignore any unknown flags + }; + acc | flag_value + }); + + mshv_user_mem_region { + guest_pfn, + size, + userspace_addr, + flags, + ..Default::default() + } } } }