diff --git a/nel_os_kernel/src/vmm/x86_64/intel/auditor/controls.rs b/nel_os_kernel/src/vmm/x86_64/intel/auditor/controls.rs new file mode 100644 index 0000000..7d755cb --- /dev/null +++ b/nel_os_kernel/src/vmm/x86_64/intel/auditor/controls.rs @@ -0,0 +1,113 @@ +use x86::{msr, vmx::vmcs}; + +use crate::vmm::x86_64::{ + common::read_msr, + intel::{self, vmread}, +}; + +pub fn check_vmcs_control_fields() -> Result<(), &'static str> { + let msr_ia32_vmx_basic = read_msr(msr::IA32_VMX_BASIC); + let vmx_true_ctrl = msr_ia32_vmx_basic & (1 << 55) != 0; + + check_pin_based_exec_ctrl(vmx_true_ctrl)?; + check_primary_proc_based_exec_ctrl(vmx_true_ctrl)?; + + if intel::vmcs::controls::PrimaryProcessorBasedVmExecutionControls::read()? + .activate_secondary_controls() + { + check_secondary_proc_based_exec_ctrl(vmx_true_ctrl)?; + } + + Ok(()) +} + +fn check_pin_based_exec_ctrl(vmx_true_ctrl: bool) -> Result<(), &'static str> { + let msr_vmx_pin_based_exec_ctrl = if vmx_true_ctrl { + read_msr(msr::IA32_VMX_TRUE_PINBASED_CTLS) + } else { + read_msr(msr::IA32_VMX_PINBASED_CTLS) + }; + + let vmcs_pin_based_exec_ctrl = vmread(vmcs::control::PINBASED_EXEC_CONTROLS)?; + let msr_vmx_pin_based_exec_ctrl_low = (msr_vmx_pin_based_exec_ctrl & 0xFFFFFFFF) as u32; + let msr_vmx_pin_based_exec_ctrl_high = (msr_vmx_pin_based_exec_ctrl >> 32) as u32; + + if !(vmcs_pin_based_exec_ctrl & 0xFFFFFFFF) as u32 & msr_vmx_pin_based_exec_ctrl_low != 0 { + return Err( + "VMCS Pin-based execution controls field: IA32_VMX_PINBASED_CTRLS low bits not set", + ); + } + if (vmcs_pin_based_exec_ctrl >> 32) as u32 & !msr_vmx_pin_based_exec_ctrl_high != 0 { + return Err( + "VMCS Pin-based execution controls field: IA32_VMX_PINBASED_CTRLS high bits not zero", + ); + } + + Ok(()) +} + +fn check_primary_proc_based_exec_ctrl(vmx_true_ctrl: bool) -> Result<(), &'static str> { + let msr_vmx_primary_proc_based_exec_ctrl = if vmx_true_ctrl { + read_msr(msr::IA32_VMX_TRUE_PROCBASED_CTLS) + } else { + read_msr(msr::IA32_VMX_PROCBASED_CTLS) + }; + + let vmcs_primary_proc_based_exec_ctrl = vmread(vmcs::control::PRIMARY_PROCBASED_EXEC_CONTROLS)?; + let msr_vmx_primary_proc_based_exec_ctrl_low = + (msr_vmx_primary_proc_based_exec_ctrl & 0xFFFFFFFF) as u32; + let msr_vmx_primary_proc_based_exec_ctrl_high = + (msr_vmx_primary_proc_based_exec_ctrl >> 32) as u32; + + if !(vmcs_primary_proc_based_exec_ctrl & 0xFFFFFFFF) as u32 + & msr_vmx_primary_proc_based_exec_ctrl_low + != 0 + { + return Err( + "VMCS Primary processor-based execution controls field: IA32_VMX_PROCBASED_CTRLS low bits not set", + ); + } + if (vmcs_primary_proc_based_exec_ctrl >> 32) as u32 & !msr_vmx_primary_proc_based_exec_ctrl_high + != 0 + { + return Err( + "VMCS Primary processor-based execution controls field: IA32_VMX_PROCBASED_CTRLS high bits not zero", + ); + } + + Ok(()) +} + +fn check_secondary_proc_based_exec_ctrl(vmx_true_ctrl: bool) -> Result<(), &'static str> { + let msr_vmx_secondary_proc_based_exec_ctrl = if vmx_true_ctrl { + read_msr(msr::IA32_VMX_PROCBASED_CTLS2) + } else { + 0 + }; + + let vmcs_secondary_proc_based_exec_ctrl = + vmread(vmcs::control::SECONDARY_PROCBASED_EXEC_CONTROLS)?; + let msr_vmx_secondary_proc_based_exec_ctrl_low = + (msr_vmx_secondary_proc_based_exec_ctrl & 0xFFFFFFFF) as u32; + let msr_vmx_secondary_proc_based_exec_ctrl_high = + (msr_vmx_secondary_proc_based_exec_ctrl >> 32) as u32; + + if !(vmcs_secondary_proc_based_exec_ctrl & 0xFFFFFFFF) as u32 + & msr_vmx_secondary_proc_based_exec_ctrl_low + != 0 + { + return Err( + "VMCS Secondary processor-based execution controls field: IA32_VMX_PROCBASED_CTRLS2 low bits not set", + ); + } + if (vmcs_secondary_proc_based_exec_ctrl >> 32) as u32 + & !msr_vmx_secondary_proc_based_exec_ctrl_high + != 0 + { + return Err( + "VMCS Secondary processor-based execution controls field: IA32_VMX_PROCBASED_CTRLS2 high bits not zero", + ); + } + + Ok(()) +} diff --git a/nel_os_kernel/src/vmm/x86_64/intel/auditor/mod.rs b/nel_os_kernel/src/vmm/x86_64/intel/auditor/mod.rs new file mode 100644 index 0000000..1a8fe5f --- /dev/null +++ b/nel_os_kernel/src/vmm/x86_64/intel/auditor/mod.rs @@ -0,0 +1 @@ +pub mod controls; diff --git a/nel_os_kernel/src/vmm/x86_64/intel/mod.rs b/nel_os_kernel/src/vmm/x86_64/intel/mod.rs index b6d8e5d..47c66ea 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/mod.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/mod.rs @@ -1,4 +1,5 @@ pub mod asm; +mod auditor; mod controls; mod cpuid; mod ept; diff --git a/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs b/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs index 4fed84e..328eb5a 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs @@ -13,7 +13,7 @@ use crate::{ x86_64::{ common::{self, read_msr}, intel::{ - controls, cpuid, ept, + auditor, controls, cpuid, ept, msr::{self, ShadowMsr}, register::GuestRegisters, vmcs::{ @@ -123,6 +123,8 @@ impl IntelVCpu { fn vmentry(&mut self) -> Result<(), InstructionError> { msr::update_msrs(self).unwrap(); + auditor::controls::check_vmcs_control_fields().unwrap(); + let success = { let result: u16; unsafe {