Re: [PATCH] KVM: nVMX: Disallow access to vmcs12 fields that aren't supported by "hardware"
From: Sean Christopherson
Date: Wed Dec 17 2025 - 11:35:30 EST
On Tue, Dec 16, 2025, Xin Li wrote:
> > diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c
> > index 4233b5ca9461..78eca9399975 100644
> > --- a/arch/x86/kvm/vmx/vmcs12.c
> > +++ b/arch/x86/kvm/vmx/vmcs12.c
> > @@ -9,7 +9,7 @@
> > FIELD(number, name), \
> > [ROL16(number##_HIGH, 6)] = VMCS12_OFFSET(name) + sizeof(u32)
> >
> > -const unsigned short vmcs12_field_offsets[] = {
> > +const __initconst u16 supported_vmcs12_field_offsets[] = {
>
> I initially misunderstood "supported" to mean the VMCS fields available at
> runtime. I'm unsure if it's necessary to make its meaning more explicit.
> E.g., prefix with kvm_?
Oh, good point. Ya, will do.
> > FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id),
> > FIELD(POSTED_INTR_NV, posted_intr_nv),
> > FIELD(GUEST_ES_SELECTOR, guest_es_selector),
> > @@ -158,4 +158,55 @@ const unsigned short vmcs12_field_offsets[] = {
> > FIELD(HOST_SSP, host_ssp),
> > FIELD(HOST_INTR_SSP_TABLE, host_ssp_tbl),
> > };
> > -const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs12_field_offsets);
> > +
> > +u16 vmcs12_field_offsets[ARRAY_SIZE(supported_vmcs12_field_offsets)] __ro_after_init;
> > +unsigned int nr_vmcs12_fields __ro_after_init;
> > +
> > +#define VMCS12_CASE64(enc) case enc##_HIGH: case enc
> > +
> > +static __init bool cpu_has_vmcs12_field(unsigned int idx)
> > +{
> > + switch (VMCS12_IDX_TO_ENC(idx)) {
> > + case VIRTUAL_PROCESSOR_ID: return cpu_has_vmx_vpid();
> > + case POSTED_INTR_NV: return cpu_has_vmx_posted_intr();
> > + VMCS12_CASE64(TSC_MULTIPLIER): return cpu_has_vmx_tsc_scaling();
> > + VMCS12_CASE64(VIRTUAL_APIC_PAGE_ADDR): return cpu_has_vmx_tpr_shadow();
> > + VMCS12_CASE64(APIC_ACCESS_ADDR): return cpu_has_vmx_virtualize_apic_accesses();
> > + VMCS12_CASE64(POSTED_INTR_DESC_ADDR): return cpu_has_vmx_posted_intr();
> > + VMCS12_CASE64(VM_FUNCTION_CONTROL): return cpu_has_vmx_vmfunc();
> > + VMCS12_CASE64(EPT_POINTER): return cpu_has_vmx_ept();
> > + VMCS12_CASE64(EPTP_LIST_ADDRESS): return cpu_has_vmx_vmfunc();
> > + VMCS12_CASE64(XSS_EXIT_BITMAP): return cpu_has_vmx_xsaves();
> > + VMCS12_CASE64(ENCLS_EXITING_BITMAP): return cpu_has_vmx_encls_vmexit();
> > + VMCS12_CASE64(GUEST_IA32_PERF_GLOBAL_CTRL): return cpu_has_load_perf_global_ctrl();
> > + VMCS12_CASE64(HOST_IA32_PERF_GLOBAL_CTRL): return cpu_has_load_perf_global_ctrl();
>
> Combine the above 2 cases?
>
> > + case TPR_THRESHOLD: return cpu_has_vmx_tpr_shadow();
> > + case SECONDARY_VM_EXEC_CONTROL: return cpu_has_secondary_exec_ctrls();
> > + case GUEST_S_CET: return cpu_has_load_cet_ctrl();
> > + case GUEST_SSP: return cpu_has_load_cet_ctrl();
> > + case GUEST_INTR_SSP_TABLE: return cpu_has_load_cet_ctrl();
> > + case HOST_S_CET: return cpu_has_load_cet_ctrl();
> > + case HOST_SSP: return cpu_has_load_cet_ctrl();
> > + case HOST_INTR_SSP_TABLE: return cpu_has_load_cet_ctrl();
>
> Combine all CET cases?
Yeah, will do. I was on the fence as to whether it would be a net positive to
combine them.
Thanks!