Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: VMX: Emulate read and write to CET MSRs

Add emulation interface for CET MSR access. The emulation code is split
into common part and vendor specific part. The former does common checks
for MSRs, e.g., accessibility, data validity etc., then passes operation
to either XSAVE-managed MSRs via the helpers or CET VMCS fields.

SSP can only be read via RDSSP. Writing even requires destructive and
potentially faulting operations such as SAVEPREVSSP/RSTORSSP or
SETSSBSY/CLRSSBSY. Let the host use a pseudo-MSR that is just a wrapper
for the GUEST_SSP field of the VMCS.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
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: drop call to kvm_set_xstate_msr() for S_CET, consolidate code]
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-15-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

authored by

Yang Weijiang and committed by
Sean Christopherson
8b59d027 9d6812d4

+103 -2
+18
arch/x86/kvm/vmx/vmx.c
··· 2093 2093 else 2094 2094 msr_info->data = vmx->pt_desc.guest.addr_a[index / 2]; 2095 2095 break; 2096 + case MSR_IA32_S_CET: 2097 + msr_info->data = vmcs_readl(GUEST_S_CET); 2098 + break; 2099 + case MSR_KVM_INTERNAL_GUEST_SSP: 2100 + msr_info->data = vmcs_readl(GUEST_SSP); 2101 + break; 2102 + case MSR_IA32_INT_SSP_TAB: 2103 + msr_info->data = vmcs_readl(GUEST_INTR_SSP_TABLE); 2104 + break; 2096 2105 case MSR_IA32_DEBUGCTLMSR: 2097 2106 msr_info->data = vmx_guest_debugctl_read(); 2098 2107 break; ··· 2419 2410 vmx->pt_desc.guest.addr_b[index / 2] = data; 2420 2411 else 2421 2412 vmx->pt_desc.guest.addr_a[index / 2] = data; 2413 + break; 2414 + case MSR_IA32_S_CET: 2415 + vmcs_writel(GUEST_S_CET, data); 2416 + break; 2417 + case MSR_KVM_INTERNAL_GUEST_SSP: 2418 + vmcs_writel(GUEST_SSP, data); 2419 + break; 2420 + case MSR_IA32_INT_SSP_TAB: 2421 + vmcs_writel(GUEST_INTR_SSP_TABLE, data); 2422 2422 break; 2423 2423 case MSR_IA32_PERF_CAPABILITIES: 2424 2424 if (data & PERF_CAP_LBR_FMT) {
+62 -2
arch/x86/kvm/x86.c
··· 1890 1890 1891 1891 data = (u32)data; 1892 1892 break; 1893 + case MSR_IA32_U_CET: 1894 + case MSR_IA32_S_CET: 1895 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && 1896 + !guest_cpu_cap_has(vcpu, X86_FEATURE_IBT)) 1897 + return KVM_MSR_RET_UNSUPPORTED; 1898 + if (!kvm_is_valid_u_s_cet(vcpu, data)) 1899 + return 1; 1900 + break; 1901 + case MSR_KVM_INTERNAL_GUEST_SSP: 1902 + if (!host_initiated) 1903 + return 1; 1904 + fallthrough; 1905 + /* 1906 + * Note that the MSR emulation here is flawed when a vCPU 1907 + * doesn't support the Intel 64 architecture. The expected 1908 + * architectural behavior in this case is that the upper 32 1909 + * bits do not exist and should always read '0'. However, 1910 + * because the actual hardware on which the virtual CPU is 1911 + * running does support Intel 64, XRSTORS/XSAVES in the 1912 + * guest could observe behavior that violates the 1913 + * architecture. Intercepting XRSTORS/XSAVES for this 1914 + * special case isn't deemed worthwhile. 1915 + */ 1916 + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: 1917 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) 1918 + return KVM_MSR_RET_UNSUPPORTED; 1919 + /* 1920 + * MSR_IA32_INT_SSP_TAB is not present on processors that do 1921 + * not support Intel 64 architecture. 1922 + */ 1923 + if (index == MSR_IA32_INT_SSP_TAB && !guest_cpu_cap_has(vcpu, X86_FEATURE_LM)) 1924 + return KVM_MSR_RET_UNSUPPORTED; 1925 + if (is_noncanonical_msr_address(data, vcpu)) 1926 + return 1; 1927 + /* All SSP MSRs except MSR_IA32_INT_SSP_TAB must be 4-byte aligned */ 1928 + if (index != MSR_IA32_INT_SSP_TAB && !IS_ALIGNED(data, 4)) 1929 + return 1; 1930 + break; 1893 1931 } 1894 1932 1895 1933 msr.data = data; ··· 1971 1933 !guest_cpu_cap_has(vcpu, X86_FEATURE_RDTSCP) && 1972 1934 !guest_cpu_cap_has(vcpu, X86_FEATURE_RDPID)) 1973 1935 return 1; 1936 + break; 1937 + case MSR_IA32_U_CET: 1938 + case MSR_IA32_S_CET: 1939 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && 1940 + !guest_cpu_cap_has(vcpu, X86_FEATURE_IBT)) 1941 + return KVM_MSR_RET_UNSUPPORTED; 1942 + break; 1943 + case MSR_KVM_INTERNAL_GUEST_SSP: 1944 + if (!host_initiated) 1945 + return 1; 1946 + fallthrough; 1947 + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: 1948 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) 1949 + return KVM_MSR_RET_UNSUPPORTED; 1974 1950 break; 1975 1951 } 1976 1952 ··· 3917 3865 kvm_fpu_put(); 3918 3866 } 3919 3867 3920 - static __maybe_unused void kvm_set_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) 3868 + static void kvm_set_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) 3921 3869 { 3922 3870 kvm_access_xstate_msr(vcpu, msr_info, MSR_TYPE_W); 3923 3871 } 3924 3872 3925 - static __maybe_unused void kvm_get_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) 3873 + static void kvm_get_xstate_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) 3926 3874 { 3927 3875 kvm_access_xstate_msr(vcpu, msr_info, MSR_TYPE_R); 3928 3876 } ··· 4308 4256 vcpu->arch.guest_fpu.xfd_err = data; 4309 4257 break; 4310 4258 #endif 4259 + case MSR_IA32_U_CET: 4260 + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: 4261 + kvm_set_xstate_msr(vcpu, msr_info); 4262 + break; 4311 4263 default: 4312 4264 if (kvm_pmu_is_valid_msr(vcpu, msr)) 4313 4265 return kvm_pmu_set_msr(vcpu, msr_info); ··· 4661 4605 msr_info->data = vcpu->arch.guest_fpu.xfd_err; 4662 4606 break; 4663 4607 #endif 4608 + case MSR_IA32_U_CET: 4609 + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: 4610 + kvm_get_xstate_msr(vcpu, msr_info); 4611 + break; 4664 4612 default: 4665 4613 if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) 4666 4614 return kvm_pmu_get_msr(vcpu, msr_info);
+23
arch/x86/kvm/x86.h
··· 710 710 711 711 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); 712 712 713 + #define CET_US_RESERVED_BITS GENMASK(9, 6) 714 + #define CET_US_SHSTK_MASK_BITS GENMASK(1, 0) 715 + #define CET_US_IBT_MASK_BITS (GENMASK_ULL(5, 2) | GENMASK_ULL(63, 10)) 716 + #define CET_US_LEGACY_BITMAP_BASE(data) ((data) >> 12) 717 + 718 + static inline bool kvm_is_valid_u_s_cet(struct kvm_vcpu *vcpu, u64 data) 719 + { 720 + if (data & CET_US_RESERVED_BITS) 721 + return false; 722 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) && 723 + (data & CET_US_SHSTK_MASK_BITS)) 724 + return false; 725 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_IBT) && 726 + (data & CET_US_IBT_MASK_BITS)) 727 + return false; 728 + if (!IS_ALIGNED(CET_US_LEGACY_BITMAP_BASE(data), 4)) 729 + return false; 730 + /* IBT can be suppressed iff the TRACKER isn't WAIT_ENDBR. */ 731 + if ((data & CET_SUPPRESS) && (data & CET_WAIT_ENDBR)) 732 + return false; 733 + 734 + return true; 735 + } 713 736 #endif