Skip to content

Commit e140467

Browse files
yang-weijiangsean-jc
authored andcommitted
KVM: x86: Enable CET virtualization for VMX and advertise to userspace
Add support for the LOAD_CET_STATE VM-Enter and VM-Exit controls, the CET XFEATURE bits in XSS, and advertise support for IBT and SHSTK to userspace. Explicitly clear IBT and SHSTK onn SVM, as additional work is needed to enable CET on SVM, e.g. to context switch S_CET and other state. Disable KVM CET feature if unrestricted_guest is unsupported/disabled as KVM does not support emulating CET, as running without Unrestricted Guest can result in KVM emulating large swaths of guest code. While it's highly unlikely any guest will trigger emulation while also utilizing IBT or SHSTK, there's zero reason to allow CET without Unrestricted Guest as that combination should only be possible when explicitly disabling unrestricted_guest for testing purposes. Disable CET if VMX_BASIC[bit56] == 0, i.e. if hardware strictly enforces the presence of an Error Code based on exception vector, as attempting to inject a #CP with an Error Code (#CP architecturally has an Error Code) will fail due to the #CP vector historically not having an Error Code. Clear S_CET and SSP-related VMCS on "reset" to emulate the architectural of CET MSRs and SSP being reset to 0 after RESET, power-up and INIT. Note, KVM already clears guest CET state that is managed via XSTATE in kvm_xstate_reset(). Signed-off-by: Yang Weijiang <weijiang.yang@intel.com> Signed-off-by: Mathias Krause <minipli@grsecurity.net> Tested-by: Mathias Krause <minipli@grsecurity.net> Tested-by: John Allen <john.allen@amd.com> Tested-by: Rick Edgecombe <rick.p.edgecombe@intel.com> Signed-off-by: Chao Gao <chao.gao@intel.com> [sean: move some bits to separate patches, massage changelog] Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com> Link: https://lore.kernel.org/r/20250919223258.1604852-29-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 343acdd commit e140467

6 files changed

Lines changed: 45 additions & 3 deletions

File tree

arch/x86/include/asm/vmx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#define VMX_BASIC_DUAL_MONITOR_TREATMENT BIT_ULL(49)
135135
#define VMX_BASIC_INOUT BIT_ULL(54)
136136
#define VMX_BASIC_TRUE_CTLS BIT_ULL(55)
137+
#define VMX_BASIC_NO_HW_ERROR_CODE_CC BIT_ULL(56)
137138

138139
static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic)
139140
{

arch/x86/kvm/cpuid.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ void kvm_set_cpu_caps(void)
946946
VENDOR_F(WAITPKG),
947947
F(SGX_LC),
948948
F(BUS_LOCK_DETECT),
949+
X86_64_F(SHSTK),
949950
);
950951

951952
/*
@@ -980,6 +981,7 @@ void kvm_set_cpu_caps(void)
980981
F(AMX_INT8),
981982
F(AMX_BF16),
982983
F(FLUSH_L1D),
984+
F(IBT),
983985
);
984986

985987
/*

arch/x86/kvm/svm/svm.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5222,6 +5222,10 @@ static __init void svm_set_cpu_caps(void)
52225222
kvm_caps.supported_perf_cap = 0;
52235223
kvm_caps.supported_xss = 0;
52245224

5225+
/* KVM doesn't yet support CET virtualization for SVM. */
5226+
kvm_cpu_cap_clear(X86_FEATURE_SHSTK);
5227+
kvm_cpu_cap_clear(X86_FEATURE_IBT);
5228+
52255229
/* CPUID 0x80000001 and 0x8000000A (SVM features) */
52265230
if (nested) {
52275231
kvm_cpu_cap_set(X86_FEATURE_SVM);

arch/x86/kvm/vmx/capabilities.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ static inline bool cpu_has_vmx_basic_inout(void)
7373
return vmcs_config.basic & VMX_BASIC_INOUT;
7474
}
7575

76+
static inline bool cpu_has_vmx_basic_no_hw_errcode_cc(void)
77+
{
78+
return vmcs_config.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC;
79+
}
80+
7681
static inline bool cpu_has_virtual_nmis(void)
7782
{
7883
return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS &&

arch/x86/kvm/vmx/vmx.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2602,6 +2602,7 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf,
26022602
{ VM_ENTRY_LOAD_IA32_EFER, VM_EXIT_LOAD_IA32_EFER },
26032603
{ VM_ENTRY_LOAD_BNDCFGS, VM_EXIT_CLEAR_BNDCFGS },
26042604
{ VM_ENTRY_LOAD_IA32_RTIT_CTL, VM_EXIT_CLEAR_IA32_RTIT_CTL },
2605+
{ VM_ENTRY_LOAD_CET_STATE, VM_EXIT_LOAD_CET_STATE },
26052606
};
26062607

26072608
memset(vmcs_conf, 0, sizeof(*vmcs_conf));
@@ -4868,6 +4869,14 @@ void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
48684869

48694870
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
48704871

4872+
if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) {
4873+
vmcs_writel(GUEST_SSP, 0);
4874+
vmcs_writel(GUEST_INTR_SSP_TABLE, 0);
4875+
}
4876+
if (kvm_cpu_cap_has(X86_FEATURE_IBT) ||
4877+
kvm_cpu_cap_has(X86_FEATURE_SHSTK))
4878+
vmcs_writel(GUEST_S_CET, 0);
4879+
48714880
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
48724881

48734882
vpid_sync_context(vmx->vpid);
@@ -6335,6 +6344,10 @@ void dump_vmcs(struct kvm_vcpu *vcpu)
63356344
if (vmcs_read32(VM_EXIT_MSR_STORE_COUNT) > 0)
63366345
vmx_dump_msrs("guest autostore", &vmx->msr_autostore.guest);
63376346

6347+
if (vmentry_ctl & VM_ENTRY_LOAD_CET_STATE)
6348+
pr_err("S_CET = 0x%016lx, SSP = 0x%016lx, SSP TABLE = 0x%016lx\n",
6349+
vmcs_readl(GUEST_S_CET), vmcs_readl(GUEST_SSP),
6350+
vmcs_readl(GUEST_INTR_SSP_TABLE));
63386351
pr_err("*** Host State ***\n");
63396352
pr_err("RIP = 0x%016lx RSP = 0x%016lx\n",
63406353
vmcs_readl(HOST_RIP), vmcs_readl(HOST_RSP));
@@ -6365,6 +6378,10 @@ void dump_vmcs(struct kvm_vcpu *vcpu)
63656378
vmcs_read64(HOST_IA32_PERF_GLOBAL_CTRL));
63666379
if (vmcs_read32(VM_EXIT_MSR_LOAD_COUNT) > 0)
63676380
vmx_dump_msrs("host autoload", &vmx->msr_autoload.host);
6381+
if (vmexit_ctl & VM_EXIT_LOAD_CET_STATE)
6382+
pr_err("S_CET = 0x%016lx, SSP = 0x%016lx, SSP TABLE = 0x%016lx\n",
6383+
vmcs_readl(HOST_S_CET), vmcs_readl(HOST_SSP),
6384+
vmcs_readl(HOST_INTR_SSP_TABLE));
63686385

63696386
pr_err("*** Control State ***\n");
63706387
pr_err("CPUBased=0x%08x SecondaryExec=0x%08x TertiaryExec=0x%016llx\n",
@@ -7946,7 +7963,6 @@ static __init void vmx_set_cpu_caps(void)
79467963
kvm_cpu_cap_set(X86_FEATURE_UMIP);
79477964

79487965
/* CPUID 0xD.1 */
7949-
kvm_caps.supported_xss = 0;
79507966
if (!cpu_has_vmx_xsaves())
79517967
kvm_cpu_cap_clear(X86_FEATURE_XSAVES);
79527968

@@ -7958,6 +7974,18 @@ static __init void vmx_set_cpu_caps(void)
79587974

79597975
if (cpu_has_vmx_waitpkg())
79607976
kvm_cpu_cap_check_and_set(X86_FEATURE_WAITPKG);
7977+
7978+
/*
7979+
* Disable CET if unrestricted_guest is unsupported as KVM doesn't
7980+
* enforce CET HW behaviors in emulator. On platforms with
7981+
* VMX_BASIC[bit56] == 0, inject #CP at VMX entry with error code
7982+
* fails, so disable CET in this case too.
7983+
*/
7984+
if (!cpu_has_load_cet_ctrl() || !enable_unrestricted_guest ||
7985+
!cpu_has_vmx_basic_no_hw_errcode_cc()) {
7986+
kvm_cpu_cap_clear(X86_FEATURE_SHSTK);
7987+
kvm_cpu_cap_clear(X86_FEATURE_IBT);
7988+
}
79617989
}
79627990

79637991
static bool vmx_is_io_intercepted(struct kvm_vcpu *vcpu,

arch/x86/kvm/vmx/vmx.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ static inline u8 vmx_get_rvi(void)
484484
VM_ENTRY_LOAD_IA32_EFER | \
485485
VM_ENTRY_LOAD_BNDCFGS | \
486486
VM_ENTRY_PT_CONCEAL_PIP | \
487-
VM_ENTRY_LOAD_IA32_RTIT_CTL)
487+
VM_ENTRY_LOAD_IA32_RTIT_CTL | \
488+
VM_ENTRY_LOAD_CET_STATE)
488489

489490
#define __KVM_REQUIRED_VMX_VM_EXIT_CONTROLS \
490491
(VM_EXIT_SAVE_DEBUG_CONTROLS | \
@@ -506,7 +507,8 @@ static inline u8 vmx_get_rvi(void)
506507
VM_EXIT_LOAD_IA32_EFER | \
507508
VM_EXIT_CLEAR_BNDCFGS | \
508509
VM_EXIT_PT_CONCEAL_PIP | \
509-
VM_EXIT_CLEAR_IA32_RTIT_CTL)
510+
VM_EXIT_CLEAR_IA32_RTIT_CTL | \
511+
VM_EXIT_LOAD_CET_STATE)
510512

511513
#define KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL \
512514
(PIN_BASED_EXT_INTR_MASK | \

0 commit comments

Comments
 (0)