From 268e5b312669dab0fc29a87d58f97ebb7bb74340 Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Sat, 28 Feb 2026 22:18:26 -0800 Subject: [PATCH] feat(tdx): restrict KVM features to a safe subset for TDX guests Restrict the KVM CPUID features exposed to TDX guests to a known-safe subset. This prevents the guest from attempting to use unsupported paravirtualization features such as kvmclock. Signed-off-by: Changyuan Lyu --- alioth/src/board/board_x86_64/board_x86_64.rs | 2 +- alioth/src/hv/hv.rs | 2 +- alioth/src/hv/kvm/kvm.rs | 12 ++++---- .../src/hv/kvm/{ => kvm_x86_64}/kvm_x86_64.rs | 30 +++++++++++++------ .../kvm/{ => kvm_x86_64}/kvm_x86_64_test.rs | 2 +- alioth/src/hv/kvm/{ => kvm_x86_64}/sev.rs | 0 alioth/src/hv/kvm/{ => kvm_x86_64}/tdx.rs | 10 ++++++- alioth/src/hv/kvm/vcpu/vcpu_x86_64/tdx.rs | 2 +- alioth/src/hv/kvm/vm/vm_x86_64/tdx.rs | 2 +- alioth/src/hv/kvm/vm/vm_x86_64/vm_x86_64.rs | 2 +- 10 files changed, 41 insertions(+), 23 deletions(-) rename alioth/src/hv/kvm/{ => kvm_x86_64}/kvm_x86_64.rs (72%) rename alioth/src/hv/kvm/{ => kvm_x86_64}/kvm_x86_64_test.rs (97%) rename alioth/src/hv/kvm/{ => kvm_x86_64}/sev.rs (100%) rename alioth/src/hv/kvm/{ => kvm_x86_64}/tdx.rs (74%) diff --git a/alioth/src/board/board_x86_64/board_x86_64.rs b/alioth/src/board/board_x86_64/board_x86_64.rs index 70c668a7..2f3f0ff3 100644 --- a/alioth/src/board/board_x86_64/board_x86_64.rs +++ b/alioth/src/board/board_x86_64/board_x86_64.rs @@ -78,7 +78,7 @@ impl ArchBoard { where H: Hypervisor, { - let mut cpuids = hv.get_supported_cpuids()?; + let mut cpuids = hv.get_supported_cpuids(config.coco.as_ref())?; let threads_per_core = 1 + config.cpu.topology.smt as u16; let threads_per_socket = config.cpu.topology.cores * threads_per_core; diff --git a/alioth/src/hv/hv.rs b/alioth/src/hv/hv.rs index 2128f2ab..c2a1501e 100644 --- a/alioth/src/hv/hv.rs +++ b/alioth/src/hv/hv.rs @@ -431,7 +431,7 @@ pub trait Hypervisor { fn create_vm(&self, config: &VmConfig) -> Result; #[cfg(target_arch = "x86_64")] - fn get_supported_cpuids(&self) -> Result>; + fn get_supported_cpuids(&self, coco: Option<&Coco>) -> Result>; } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/alioth/src/hv/kvm/kvm.rs b/alioth/src/hv/kvm/kvm.rs index 5d01f68a..b20f2f52 100644 --- a/alioth/src/hv/kvm/kvm.rs +++ b/alioth/src/hv/kvm/kvm.rs @@ -13,15 +13,11 @@ // limitations under the License. #[cfg(target_arch = "x86_64")] -#[path = "kvm_x86_64.rs"] +#[path = "kvm_x86_64/kvm_x86_64.rs"] mod x86_64; #[cfg(target_arch = "aarch64")] mod device; -#[cfg(target_arch = "x86_64")] -mod sev; -#[cfg(target_arch = "x86_64")] -mod tdx; #[path = "vcpu/vcpu.rs"] mod vcpu; #[path = "vm/vm.rs"] @@ -47,6 +43,8 @@ use snafu::{ResultExt, Snafu}; use crate::arch::cpuid::CpuidIn; use crate::errors::{DebugTrace, trace_error}; use crate::ffi; +#[cfg(target_arch = "x86_64")] +use crate::hv::Coco; use crate::hv::{Hypervisor, MemMapOption, Result, VmConfig, error}; #[cfg(target_arch = "aarch64")] use crate::sys::kvm::KvmDevType; @@ -153,8 +151,8 @@ impl Hypervisor for Kvm { } #[cfg(target_arch = "x86_64")] - fn get_supported_cpuids(&self) -> Result> { - Kvm::get_supported_cpuids(self) + fn get_supported_cpuids(&self, coco: Option<&Coco>) -> Result> { + Kvm::get_supported_cpuids(self, coco) } } diff --git a/alioth/src/hv/kvm/kvm_x86_64.rs b/alioth/src/hv/kvm/kvm_x86_64/kvm_x86_64.rs similarity index 72% rename from alioth/src/hv/kvm/kvm_x86_64.rs rename to alioth/src/hv/kvm/kvm_x86_64/kvm_x86_64.rs index 4728df5b..f3117bcf 100644 --- a/alioth/src/hv/kvm/kvm_x86_64.rs +++ b/alioth/src/hv/kvm/kvm_x86_64/kvm_x86_64.rs @@ -12,12 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub(crate) mod sev; +pub(crate) mod tdx; + use std::arch::x86_64::CpuidResult; use std::collections::HashMap; use snafu::ResultExt; use crate::arch::cpuid::CpuidIn; +#[cfg(target_arch = "x86_64")] +use crate::hv::Coco; use crate::hv::{Kvm, Result, error}; use crate::sys::kvm::{ KVM_CPUID_FEATURES, KVM_MAX_CPUID_ENTRIES, KvmCap, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2, @@ -45,7 +50,10 @@ impl From for (CpuidIn, CpuidResult) { } impl Kvm { - pub fn get_supported_cpuids(&self) -> Result> { + pub fn get_supported_cpuids( + &self, + coco: Option<&Coco>, + ) -> Result> { let mut kvm_cpuid2 = KvmCpuid2 { nent: KVM_MAX_CPUID_ENTRIES as u32, padding: 0, @@ -64,14 +72,18 @@ impl Kvm { func: KVM_CPUID_FEATURES, index: None, }; - if let Some(entry) = cpuids.get_mut(&leaf_features) - && let Ok(ext) = self.check_extension(KvmCap::X2APIC_API) - && KvmX2apicApiFlag::from_bits_retain(ext.get() as u64).contains( - KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK, - ) - { - // Enable KVM_FEATURE_MSI_EXT_DEST_ID if KVM_CAP_X2APIC_API is supported - entry.eax |= KvmCpuidFeature::MSI_EXT_DEST_ID.bits(); + if let Some(entry) = cpuids.get_mut(&leaf_features) { + if let Ok(ext) = self.check_extension(KvmCap::X2APIC_API) + && KvmX2apicApiFlag::from_bits_retain(ext.get() as u64).contains( + KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK, + ) + { + // Enable KVM_FEATURE_MSI_EXT_DEST_ID if KVM_CAP_X2APIC_API is supported + entry.eax |= KvmCpuidFeature::MSI_EXT_DEST_ID.bits(); + } + if matches!(coco, Some(Coco::IntelTdx { .. })) { + entry.eax &= tdx::SUPPORTED_KVM_FEATURES; + } } Ok(cpuids) diff --git a/alioth/src/hv/kvm/kvm_x86_64_test.rs b/alioth/src/hv/kvm/kvm_x86_64/kvm_x86_64_test.rs similarity index 97% rename from alioth/src/hv/kvm/kvm_x86_64_test.rs rename to alioth/src/hv/kvm/kvm_x86_64/kvm_x86_64_test.rs index 7d5ad346..5e7d71d1 100644 --- a/alioth/src/hv/kvm/kvm_x86_64_test.rs +++ b/alioth/src/hv/kvm/kvm_x86_64/kvm_x86_64_test.rs @@ -25,7 +25,7 @@ use crate::sys::kvm::{KVM_CPUID_SIGNATURE, KvmCpuid2Flag, KvmCpuidEntry2}; fn test_get_supported_cpuid() { let kvm = Kvm::new(KvmConfig::default()).unwrap(); let mut kvm_cpuid_exist = false; - let supported_cpuids = kvm.get_supported_cpuids().unwrap(); + let supported_cpuids = kvm.get_supported_cpuids(None).unwrap(); for (in_, out) in &supported_cpuids { if in_.func == KVM_CPUID_SIGNATURE && out.ebx.to_le_bytes() == *b"KVMK" diff --git a/alioth/src/hv/kvm/sev.rs b/alioth/src/hv/kvm/kvm_x86_64/sev.rs similarity index 100% rename from alioth/src/hv/kvm/sev.rs rename to alioth/src/hv/kvm/kvm_x86_64/sev.rs diff --git a/alioth/src/hv/kvm/tdx.rs b/alioth/src/hv/kvm/kvm_x86_64/tdx.rs similarity index 74% rename from alioth/src/hv/kvm/tdx.rs rename to alioth/src/hv/kvm/kvm_x86_64/tdx.rs index 78b18acb..7fe58306 100644 --- a/alioth/src/hv/kvm/tdx.rs +++ b/alioth/src/hv/kvm/kvm_x86_64/tdx.rs @@ -17,7 +17,7 @@ use std::os::fd::OwnedFd; use snafu::ResultExt; use crate::hv::{Result, error}; -use crate::sys::kvm::kvm_memory_encrypt_op; +use crate::sys::kvm::{KvmCpuidFeature, kvm_memory_encrypt_op}; use crate::sys::tdx::{KvmTdxCmd, KvmTdxCmdId}; pub fn tdx_op(fd: &OwnedFd, cmd: KvmTdxCmdId, flags: u32, data: Option<&mut T>) -> Result<()> { @@ -33,3 +33,11 @@ pub fn tdx_op(fd: &OwnedFd, cmd: KvmTdxCmdId, flags: u32, data: Option<&mut T } Ok(()) } + +pub const SUPPORTED_KVM_FEATURES: u32 = KvmCpuidFeature::NOP_IO_DELAY.bits() + | KvmCpuidFeature::PV_UNHALT.bits() + | KvmCpuidFeature::PV_TLB_FLUSH.bits() + | KvmCpuidFeature::PV_SEND_IPI.bits() + | KvmCpuidFeature::POLL_CONTROL.bits() + | KvmCpuidFeature::PV_SCHED_YIELD.bits() + | KvmCpuidFeature::MSI_EXT_DEST_ID.bits(); diff --git a/alioth/src/hv/kvm/vcpu/vcpu_x86_64/tdx.rs b/alioth/src/hv/kvm/vcpu/vcpu_x86_64/tdx.rs index 26345aa3..b15e09be 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu_x86_64/tdx.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu_x86_64/tdx.rs @@ -13,8 +13,8 @@ // limitations under the License. use crate::hv::Result; -use crate::hv::kvm::tdx::tdx_op; use crate::hv::kvm::vcpu::KvmVcpu; +use crate::hv::kvm::x86_64::tdx::tdx_op; use crate::sys::tdx::{KvmTdxCmdId, KvmTdxInitMemRegion, KvmTdxInitMemRegionFlag}; impl KvmVcpu { diff --git a/alioth/src/hv/kvm/vm/vm_x86_64/tdx.rs b/alioth/src/hv/kvm/vm/vm_x86_64/tdx.rs index a854b493..d640d807 100644 --- a/alioth/src/hv/kvm/vm/vm_x86_64/tdx.rs +++ b/alioth/src/hv/kvm/vm/vm_x86_64/tdx.rs @@ -19,8 +19,8 @@ use std::mem::MaybeUninit; use crate::arch::cpuid::CpuidIn; use crate::arch::tdx::TdAttr; use crate::hv::Result; -use crate::hv::kvm::tdx::tdx_op; use crate::hv::kvm::vm::KvmVm; +use crate::hv::kvm::x86_64::tdx::tdx_op; use crate::sys::kvm::{KvmCap, KvmCpuid2Flag, KvmCpuidEntry2, KvmHypercall}; use crate::sys::tdx::{KvmTdxCapabilities, KvmTdxCmdId, KvmTdxInitVm}; diff --git a/alioth/src/hv/kvm/vm/vm_x86_64/vm_x86_64.rs b/alioth/src/hv/kvm/vm/vm_x86_64/vm_x86_64.rs index 4cecbbe8..295cd249 100644 --- a/alioth/src/hv/kvm/vm/vm_x86_64/vm_x86_64.rs +++ b/alioth/src/hv/kvm/vm/vm_x86_64/vm_x86_64.rs @@ -22,7 +22,7 @@ use snafu::ResultExt; use crate::arch::intr::{MsiAddrHi, MsiAddrLo}; use crate::arch::ioapic::NUM_PINS; -use crate::hv::kvm::sev::SevFd; +use crate::hv::kvm::x86_64::sev::SevFd; use crate::hv::kvm::{KvmVm, kvm_error}; use crate::hv::{Coco, Kvm, Result, VmConfig, error}; use crate::sys::kvm::{