Enable CET Virtualization
Subsystems (4)
v5 cover Enable CET Virtualization
Control-flow Enforcement Technology (CET) is a kind of CPU feature used to prevent Return/CALL/Jump-Oriented Programming (ROP/COP/JOP) attacks. It provides two sub-features(SHSTK,IBT) to defend against ROP/COP/JOP style control-flow subversion attacks.
Shadow Stack (SHSTK):
A shadow stack is a second stack used exclusively for control transfer operations. The shadow stack is separate from the data/normal stack and can be enabled individually in user and kernel mode. When shadow stack is enabled, CALL pushes the return address on both the data and shadow stack. RET pops the return address from both stacks and compares them. If the return addresses from the two stacks do not match, the processor generates a #CP.
Indirect Branch Tracking (IBT):
IBT introduces new instruction(ENDBRANCH)to mark valid target addresses of indirect branches (CALL, JMP etc...). If an indirect branch is executed and the next instruction is _not_ an ENDBRANCH, the processor generates a #CP. These instruction behaves as a NOP on platforms that doesn't support CET.
Dependency:
--------------------------------------------------------------------------
The first 2 patches are taken over from CET native series[1] in kernel tip. They're prerequisites for this KVM patch series as CET user mode xstate and some feature bits are defined in the patches. Add this KVM series to kernel tree to build qualified host kernel to support guest CET features. Also apply QEMU CET enabling patches[2] to build qualified QEMU. These kernel dependent patches will be enclosed in KVM series until CET native series is merged in mainline tree.
Implementation:
--------------------------------------------------------------------------
This series enables full support for guest CET SHSTK/IBT register states, i.e., CET register states in below usage models are backed by KVM.
|
User SHSTK | User IBT (user mode)
--------------------------------------------------
Kernel SHSTK | Kernel IBT (kernel mode)
|
KVM cooperates with host kernel to back CET register states in each model. In this series, KVM manages guest CET kernel registers(MSRs) by itself and relies on host kernel to manage the user mode registers, thus KVM relies on capability from host XSS MSR before exposes CET features to guest.
Note, guest supervisor(kernel) SHSTK cannot be fully supported by this series, therefore guest SSS_CET bit of CPUID(0x7,1):EDX[bit18] is cleared. Check SDM (Vol 1, Section 17.2.3) for details.
CET states management:
--------------------------------------------------------------------------
CET user mode states, MSR_IA32_{U_CET,PL3_SSP}, depends on {XSAVES,XRSTORS} instructions to swap guest and host's states. On vmexit, guest user states are saved to guest fpu area and host user mode states are loaded from thread context before vCPU returns to userspace, vice-versa on vmentry. See details in kvm_{load,put}_guest_fpu(). So CET user mode states management depends on CET user mode bit(U_CET bit) set in host XSS MSR.
CET supervisor mode states are grouped into two categories : XSAVE-managed and non-XSAVE-managed, the former includes MSR_IA32_PL{0,1,2}_SSP and are controlled by CET supervisor mode bit(S_CET bit) in XSS, the later consists of MSR_IA32_S_CET and MSR_IA32_INTR_SSP_TBL.
The XSAVE-managed supervisor states theoretically can be handled by enabling S_CET bit in host XSS. But given the fact supervisor shadow stack isn't enabled in Linux kernel, enabling the control bit just like that for user mode states has global side-effects to all threads/tasks running on host, i.e.:
1) Introducing unnecessary XSAVE operation when switch context between non-vCPU userspace within current FPU framework.
2)Forcing allocating additional space for CET supervisor states in each thread context regardless whether it's vCPU thread or not.
To avoid these downsides, this series provides a KVM solution to save/reload vCPU's supervisor SHSTK states.
VMX introduces new VMCS fields, {GUEST|HOST}_{S_CET,SSP,INTR_SSP_TABL}, to facilitate guest/host non-XSAVES-managed states. When VMX CET entry/exit load bits are set, guest/host MSR_IA32_{S_CET,INTR_SSP_TBL,SSP} are loaded from equivalent fields at vm-exit/entry. With these new fields, such supervisor states require no addtional KVM save/reload actions.
Tests:
--------------------------------------------------------------------------
This series passed basic CET user shadow stack test and kernel IBT test in L1 and L2 guest.
The patch series _has_ impact to existing vmx test cases in KVM-unit-tests,the failures have been fixed in this patch[3].
All other parts of KVM unit-tests and selftests passed with this series. One new selftest app for CET MSRs is posted here[4].
Note, this series hasn't been tested on AMD platform yet.
To run user SHSTK test and kernel IBT test in guest , an CET capable platform is required, e.g., Sapphire Rapids server, and follow below steps to build host/guest kernel properly:
1. Build host kernel: Add this series to kernel tree and build kernel.
2. Build guest kernel: Add full CET _native_ series to kernel tree and opt-in CONFIG_X86_KERNEL_IBT and CONFIG_X86_USER_SHADOW_STACK options. Build with CET enabled gcc versions(>= 8.5.0).
3. Use patched QEMU to launch a guest.
Check kernel selftest test_shadow_stack_64 output:
[INFO] new_ssp = 7f8c82100ff8, *new_ssp = 7f8c82101001 [INFO] changing ssp from 7f8c82900ff0 to 7f8c82100ff8 [INFO] ssp is now 7f8c82101000 [OK] Shadow stack pivot [OK] Shadow stack faults [INFO] Corrupting shadow stack [INFO] Generated shadow stack violation successfully [OK] Shadow stack violation test [INFO] Gup read -> shstk access success [INFO] Gup write -> shstk access success [INFO] Violation from normal write [INFO] Gup read -> write access success [INFO] Violation from normal write [INFO] Gup write -> write access success [INFO] Cow gup write -> write access success [OK] Shadow gup test [INFO] Violation from shstk access [OK] mprotect() test [SKIP] Userfaultfd unavailable. [OK] 32 bit test
Check kernel IBT with dmesg | grep CET:
CET detected: Indirect Branch Tracking enabled
--------------------------------------------------------------------------
Changes in v5:
1. Consolidated CET MSR access code into one patch to make it clearer. [Chao]
2. Refined SSP handling when enter/exit SMM mode. [Chao]
3. Refined CET MSR interception to make it adaptive to enable/disable cases. [Chao]
4. Refined guest PL{0,1,2}_SSP handling to comply with exiting code logic. [Chao]
5. Other tweaks per Sean and Chao's feedback.
6. Rebased to: https://github.com/kvm-x86/linux/tree/next tag: kvm-x86-next-2023.07.28
[1]: CET native series: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/log/?h=x86/shstk
[2]: QEMU patch: https://lore.kernel.org/all/[email protected]/
[3]: KVM-unit-tests fixup: https://lore.kernel.org/all/[email protected]/
[4]: Selftests for CET MSRs: https://lore.kernel.org/all/[email protected]/
[5]: v4 patchset: https://lore.kernel.org/all/[email protected]/
Patch 1-2: Native dependent CET patches. Patch 3-5: Enable XSS support in KVM. Patch 6 : Prepare patch for XSAVE-managed MSR access Patch 7-9: Common patches to support CET on x86. Patch 10-11: Emulate CET MSR access. Patch 12: Handle SSP at entry/exit to SMM. Patch 13-17: Add CET virtualization settings. Patch 18-19: nVMX patches for CET support in nested VM.
Rick Edgecombe (2):
x86/cpufeatures: Add CPU feature flags for shadow stacks x86/fpu/xstate: Introduce CET MSR and XSAVES supervisor states
Sean Christopherson (2):
KVM:x86: Report XSS as to-be-saved if there are supported features KVM:x86: Load guest FPU state when access XSAVE-managed MSRs
Yang Weijiang (15):
KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS KVM:x86: Initialize kvm_caps.supported_xss
KVM:x86: Add fault checks for guest CR4.CET setting KVM:x86: Report KVM supported CET MSRs as to-be-saved KVM:x86: Make guest supervisor states as non-XSAVE managed KVM:VMX: Introduce CET VMCS fields and control bits KVM:VMX: Emulate read and write to CET MSRs
KVM:x86: Save and reload SSP to/from SMRAM
KVM:VMX: Set up interception for CET MSRs
KVM:VMX: Set host constant supervisor states to VMCS fields KVM:x86: Optimize CET supervisor SSP save/reload
KVM:x86: Enable CET virtualization for VMX and advertise to userspace KVM:x86: Enable guest CET supervisor xstate bit support KVM:nVMX: Refine error code injection to nested VM KVM:nVMX: Enable CET support for nested VM
arch/x86/include/asm/cpufeatures.h | 2 + arch/x86/include/asm/disabled-features.h | 8 +- arch/x86/include/asm/fpu/types.h | 16 +- arch/x86/include/asm/fpu/xstate.h | 6 +- arch/x86/include/asm/kvm_host.h | 6 +- arch/x86/include/asm/msr-index.h | 1 + arch/x86/include/asm/vmx.h | 8 + arch/x86/include/uapi/asm/kvm_para.h | 1 + arch/x86/kernel/cpu/cpuid-deps.c | 1 + arch/x86/kernel/fpu/xstate.c | 90 ++++----- arch/x86/kvm/cpuid.c | 32 ++- arch/x86/kvm/cpuid.h | 11 ++ arch/x86/kvm/smm.c | 11 ++ arch/x86/kvm/smm.h | 2 +- arch/x86/kvm/svm/svm.c | 2 + arch/x86/kvm/vmx/capabilities.h | 10 + arch/x86/kvm/vmx/nested.c | 49 ++++- arch/x86/kvm/vmx/nested.h | 7 + arch/x86/kvm/vmx/vmcs12.c | 6 + arch/x86/kvm/vmx/vmcs12.h | 14 +- arch/x86/kvm/vmx/vmx.c | 133 ++++++++++++- arch/x86/kvm/vmx/vmx.h | 6 +- arch/x86/kvm/x86.c | 242 +++++++++++++++++++++-- arch/x86/kvm/x86.h | 35 ++++ 24 files changed, 614 insertions(+), 85 deletions(-)
base-commit: d406b457840171306ada37400e4f3d3c6f0f4960
Signature · 1 line
2.27.0
PATCH v5 1/19 x86/cpufeatures: Add CPU feature flags for shadow stacks
From: Rick Edgecombe <[email protected]>
The Control-Flow Enforcement Technology contains two related features, one of which is Shadow Stacks. Future patches will utilize this feature for shadow stack support in KVM, so add a CPU feature flags for Shadow Stacks (CPUID.(EAX=7,ECX=0):ECX[bit 7]).
To protect shadow stack state from malicious modification, the registers are only accessible in supervisor mode. This implementation context-switches the registers with XSAVES. Make X86_FEATURE_SHSTK depend on XSAVES.
The shadow stack feature, enumerated by the CPUID bit described above, encompasses both supervisor and userspace support for shadow stack. In near future patches, only userspace shadow stack will be enabled. In expectation of future supervisor shadow stack support, create a software CPU capability to enumerate kernel utilization of userspace shadow stack support. This user shadow stack bit should depend on the HW "shstk" capability and that logic will be implemented in future patches.
--- arch/x86/include/asm/cpufeatures.h | 2 ++ arch/x86/include/asm/disabled-features.h | 8 +++++++- arch/x86/kernel/cpu/cpuid-deps.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-)
arch/x86/include/asm/cpufeatures.h +2 -0
@@ -308,6 +308,7 @@#define X86_FEATURE_MSR_TSX_CTRL (11*32+20)/* "" MSR IA32_TSX_CTRL (Intel) implemented */ #define X86_FEATURE_SMBA (11*32+21)/* "" Slow Memory Bandwidth Allocation */ #define X86_FEATURE_BMEC (11*32+22)/* "" Bandwidth Monitoring Event Configuration */ +#define X86_FEATURE_USER_SHSTK (11*32+23)/* Shadow stack support for user mode applications */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX_VNNI (12*32+ 4)/* AVX VNNI instructions */
@@ -380,6 +381,7 @@#define X86_FEATURE_OSPKE (16*32+ 4)/* OS Protection Keys Enable */ #define X86_FEATURE_WAITPKG (16*32+ 5)/* UMONITOR/UMWAIT/TPAUSE Instructions */ #define X86_FEATURE_AVX512_VBMI2 (16*32+ 6)/* Additional AVX512 Vector Bit Manipulation Instructions */ +#define X86_FEATURE_SHSTK (16*32+ 7)/* "" Shadow stack */ #define X86_FEATURE_GFNI (16*32+ 8)/* Galois Field New Instructions */ #define X86_FEATURE_VAES (16*32+ 9)/* Vector AES */ #define X86_FEATURE_VPCLMULQDQ (16*32+10)/* Carry-Less Multiplication Double Quadword */
arch/x86/include/asm/disabled-features.h +7 -1
@@ -105,6 +105,12 @@# define DISABLE_TDX_GUEST (1 << (X86_FEATURE_TDX_GUEST & 31))#endif +#ifdef CONFIG_X86_USER_SHADOW_STACK +#define DISABLE_USER_SHSTK 0 +#else +#define DISABLE_USER_SHSTK (1 << (X86_FEATURE_USER_SHSTK & 31)) +#endif +/* * Make sure to add features to the correct mask */
@@ -120,7 +126,7 @@#define DISABLED_MASK9 (DISABLE_SGX)#define DISABLED_MASK10 0#define DISABLED_MASK11 (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET| \ - DISABLE_CALL_DEPTH_TRACKING) + DISABLE_CALL_DEPTH_TRACKING|DISABLE_USER_SHSTK)#define DISABLED_MASK12 (DISABLE_LAM)#define DISABLED_MASK13 0#define DISABLED_MASK14 0
arch/x86/kernel/cpu/cpuid-deps.c +1 -0
@@ -81,6 +81,7 @@ static const struct cpuid_dep cpuid_deps[] = { { X86_FEATURE_XFD, X86_FEATURE_XSAVES }, { X86_FEATURE_XFD, X86_FEATURE_XGETBV1 }, { X86_FEATURE_AMX_TILE, X86_FEATURE_XFD }, + { X86_FEATURE_SHSTK, X86_FEATURE_XSAVES }, {} };
Signature · 1 line
2.27.0
PATCH v5 2/19 x86/fpu/xstate: Introduce CET MSR and XSAVES supervisor states
In reply to Yang WeijiangFrom: Rick Edgecombe <[email protected]>
Shadow stack register state can be managed with XSAVE. The registers can logically be separated into two groups:
* Registers controlling user-mode operation
* Registers controlling kernel-mode operation
The architecture has two new XSAVE state components: one for each group of those groups of registers. This lets an OS manage them separately if it chooses. Future patches for host userspace and KVM guests will only utilize the user-mode registers, so only configure XSAVE to save user-mode registers. This state will add 16 bytes to the xsave buffer size.
Future patches will use the user-mode XSAVE area to save guest user-mode CET state. However, VMCS includes new fields for guest CET supervisor states. KVM can use these to save and restore guest supervisor state, so host supervisor XSAVE support is not required.
Adding this exacerbates the already unwieldy if statement in check_xstate_against_struct() that handles warning about unimplemented xfeatures. So refactor these check's by having XCHECK_SZ() set a bool when it actually check's the xfeature. This ends up exceeding 80 chars, but was better on balance than other options explored. Pass the bool as pointer to make it clear that XCHECK_SZ() can change the variable.
While configuring user-mode XSAVE, clarify kernel-mode registers are not managed by XSAVE by defining the xfeature in XFEATURE_MASK_SUPERVISOR_UNSUPPORTED, like is done for XFEATURE_MASK_PT. This serves more of a documentation as code purpose, and functionally, only enables a few safety checks.
Both XSAVE state components are supervisor states, even the state controlling user-mode operation. This is a departure from earlier features like protection keys where the PKRU state is a normal user (non-supervisor) state. Having the user state be supervisor-managed ensures there is no direct, unprivileged access to it, making it harder for an attacker to subvert CET.
To facilitate this privileged access, define the two user-mode CET MSRs, and the bits defined in those MSRs relevant to future shadow stack enablement patches.
--- arch/x86/include/asm/fpu/types.h | 16 +++++- arch/x86/include/asm/fpu/xstate.h | 6 ++- arch/x86/kernel/fpu/xstate.c | 90 +++++++++++++++---------------- 3 files changed, 61 insertions(+), 51 deletions(-)
arch/x86/include/asm/fpu/types.h +14 -2
@@ -115,8 +115,8 @@ enum xfeature {XFEATURE_PT_UNIMPLEMENTED_SO_FAR ,XFEATURE_PKRU ,XFEATURE_PASID , -XFEATURE_RSRVD_COMP_11 , -XFEATURE_RSRVD_COMP_12 , +XFEATURE_CET_USER , +XFEATURE_CET_KERNEL_UNUSED ,XFEATURE_RSRVD_COMP_13 ,XFEATURE_RSRVD_COMP_14 , XFEATURE_LBR,
@@ -138,6 +138,8 @@ enum xfeature {#define XFEATURE_MASK_PT (1 << XFEATURE_PT_UNIMPLEMENTED_SO_FAR)#define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU)#define XFEATURE_MASK_PASID (1 << XFEATURE_PASID) +#define XFEATURE_MASK_CET_USER (1 << XFEATURE_CET_USER) +#define XFEATURE_MASK_CET_KERNEL (1 << XFEATURE_CET_KERNEL_UNUSED)#define XFEATURE_MASK_LBR (1 << XFEATURE_LBR)#define XFEATURE_MASK_XTILE_CFG (1 << XFEATURE_XTILE_CFG)#define XFEATURE_MASK_XTILE_DATA (1 << XFEATURE_XTILE_DATA)
@@ -252,6 +254,16 @@ struct pkru_state {u32 pad; } __packed; +/* +* State component 11 is Control-flow Enforcement user states +*/ +struct cet_user_state { +/* user control-flow settings */ +u64 user_cet; +/* user shadow stack pointer */ +u64 user_ssp; +}; +/* * State component 15: Architectural LBR configuration state. * The size of Arch LBR state depends on the number of LBRs (lbr_depth).
arch/x86/include/asm/fpu/xstate.h +4 -2
@@ -50,7 +50,8 @@#define XFEATURE_MASK_USER_DYNAMIC XFEATURE_MASK_XTILE_DATA/* All currently supported supervisor features */ -#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID) +#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID | \ + XFEATURE_MASK_CET_USER)/* * A supervisor state component may not always contain valuable information,
@@ -77,7 +78,8 @@* Unsupported supervisor features. When a supervisor feature in this mask is * supported in the future, move it to the supported supervisor feature mask. */ -#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT) +#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT | \ + XFEATURE_MASK_CET_KERNEL)/* All supervisor states including supported and unsupported states. */ #define XFEATURE_MASK_SUPERVISOR_ALL (XFEATURE_MASK_SUPERVISOR_SUPPORTED | \
arch/x86/kernel/fpu/xstate.c +43 -47
137 lines not on this page · raw message
Signature · 1 line
2.27.0
PATCH v5 3/19 KVM:x86: Report XSS as to-be-saved if there are supported features
In reply to Yang WeijiangFrom: Sean Christopherson <[email protected]>
Add MSR_IA32_XSS to the list of MSRs reported to userspace if supported_xss is non-zero, i.e. KVM supports at least one XSS based feature.
--- arch/x86/kvm/x86.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kvm/x86.c +5 -0
@@ -1451,6 +1451,7 @@ static const u32 msrs_to_save_base[] = {MSR_IA32_UMWAIT_CONTROL ,MSR_IA32_XFD ,MSR_IA32_XFD_ERR , + MSR_IA32_XSS, }; static const u32 msrs_to_save_pmu[] = {
@@ -7172,6 +7173,10 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!(kvm_get_arch_capabilities () &ARCH_CAP_TSX_CTRL_MSR ))return ;break ; +case MSR_IA32_XSS : +if (!kvm_caps.supported_xss) +return ; +break ;default :break ; }
Signature · 1 line
2.27.0
PATCH v5 4/19 KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
In reply to Yang WeijiangUpdate CPUID(EAX=0DH,ECX=1) when the guest's XSS is modified. CPUID(EAX=0DH,ECX=1).EBX reports required storage size of all enabled xstate features in XCR0 | XSS. Guest can allocate sufficient xsave buffer based on the info.
Note, KVM does not yet support any XSS based features, i.e. supported_xss is guaranteed to be zero at this time.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.c | 20 ++++++++++++++++++-- arch/x86/kvm/x86.c | 8 +++++--- 3 files changed, 24 insertions(+), 5 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -804,6 +804,7 @@ struct kvm_vcpu_arch {u64 xcr0;u64 guest_supported_xcr0; +u64 guest_supported_xss;struct kvm_pio_request pio;void *pio_data;
arch/x86/kvm/cpuid.c +18 -2
@@ -249,6 +249,17 @@ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; } +static u64 cpuid_get_supported_xss (struct kvm_cpuid_entry2 *entries,int nent) +{ +struct kvm_cpuid_entry2 *best; + + best =cpuid_entry2_find (entries, nent,0xd ,1 ); +if (!best) +return 0 ; + +return (best->ecx | ((u64 )best->edx <<32 )) & kvm_caps.supported_xss; +} +static void __kvm_update_cpuid_runtime (struct kvm_vcpu *vcpu,struct kvm_cpuid_entry2 *entries,int nent) {
@@ -276,8 +287,11 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e best =cpuid_entry2_find (entries, nent,0xD ,1 );if (best && (cpuid_entry_has (best,X86_FEATURE_XSAVES ) || -cpuid_entry_has (best,X86_FEATURE_XSAVEC ))) - best->ebx =xstate_required_size (vcpu->arch.xcr0, true); +cpuid_entry_has (best,X86_FEATURE_XSAVEC ))) { +u64 xstate = vcpu->arch.xcr0 | vcpu->arch.ia32_xss; + + best->ebx =xstate_required_size (xstate, true); + } best =__kvm_find_kvm_cpuid_features (vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best &&
@@ -325,6 +339,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.guest_supported_xcr0 =cpuid_get_supported_xcr0 (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); + vcpu->arch.guest_supported_xss = +cpuid_get_supported_xss (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);/* * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if
arch/x86/kvm/x86.c +5 -3
@@ -3780,10 +3780,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. */ -if (data & ~kvm_caps.supported_xss) +if (data & ~vcpu->arch.guest_supported_xss)return 1 ; - vcpu->arch.ia32_xss = data; -kvm_update_cpuid_runtime (vcpu); +if (vcpu->arch.ia32_xss != data) { + vcpu->arch.ia32_xss = data; +kvm_update_cpuid_runtime (vcpu); + }break ;case MSR_SMI_COUNT :if (!msr_info->host_initiated)
Signature · 1 line
2.27.0
Sean Christopherson
maintainerRe: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
Quoted 4 lines · Yang Weijiang
Update
CPUID(EAX=0DH,ECX=1)when the guest's XSS is modified. CPUID(EAX=0DH,ECX=1).EBX reports required storage size of all enabled xstate features in XCR0 | XSS. Guest can allocate sufficient xsave buffer based on the info.
Please wrap changelogs closer to ~75 chars. I'm pretty sure this isn't the first time I've made this request...
Quoted 47 lines
Note, KVM does not yet support any XSS based features, i.e.
supported_xssis guaranteed to be zero at this time.Co-developed-by Zhang Yi Z <[email protected]>Signed-off-by Zhang Yi Z <[email protected]>Signed-off-by Yang Weijiang <[email protected]>--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.c | 20 ++++++++++++++++++-- arch/x86/kvm/x86.c | 8 +++++--- 3 files changed, 24 insertions(+), 5 deletions(-)arch/x86/include/asm/kvm_host.h +1
-0@@ -804,6 +804,7 @@ struct kvm_vcpu_arch {u64 xcr0;u64 guest_supported_xcr0; +u64 guest_supported_xss;struct kvm_pio_request pio;void *pio_data;arch/x86/kvm/cpuid.c +11
-0@@ -249,6 +249,17 @@ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; } +static u64 cpuid_get_supported_xss (struct kvm_cpuid_entry2 *entries,int nent) +{ +struct kvm_cpuid_entry2 *best; + + best =cpuid_entry2_find (entries, nent,0xd ,1 ); +if (!best) +return 0 ; + +return (best->ecx | ((u64 )best->edx <<32 )) & kvm_caps.supported_xss; +} +static void __kvm_update_cpuid_runtime (struct kvm_vcpu *vcpu,struct kvm_cpuid_entry2 *entries,int nent) {
arch/x86/kvm/cpuid.c static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e · line 291
Quoted 7 lines
arch/x86/kvm/cpuid.c +2
-2@@ -276,8 +287,11 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e best =cpuid_entry2_find (entries, nent,0xD ,1 );if (best && (cpuid_entry_has (best,X86_FEATURE_XSAVES ) || -cpuid_entry_has (best,X86_FEATURE_XSAVEC ))) - best->ebx =xstate_required_size (vcpu->arch.xcr0, true); +cpuid_entry_has (best,X86_FEATURE_XSAVEC ))) { +u64 xstate = vcpu->arch.xcr0 | vcpu->arch.ia32_xss;
Nit, the variable should be xfeatures, not xstate. Though I vote to avoid the variable entirely,
best = cpuid_entry2_find(entries, nent, 0xD, 1); if (best && (cpuid_entry_has(best, X86_FEATURE_XSAVES) || cpuid_entry_has(best, X86_FEATURE_XSAVEC))) best->ebx = xstate_required_size(vcpu->arch.xcr0 | vcpu->arch.ia32_xss, true);
though it's only a slight preference, i.e. feel free to keep your approach if you or others feel strongly about the style.
arch/x86/kvm/cpuid.c static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) · line 343
Quoted 10 lines
arch/x86/kvm/cpuid.c +3
-0+ } best =__kvm_find_kvm_cpuid_features (vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best &&@@ -325,6 +339,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.guest_supported_xcr0 =cpuid_get_supported_xcr0 (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); + vcpu->arch.guest_supported_xss = +cpuid_get_supported_xss (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);
Blech. I tried to clean up this ugly, but Paolo disagreed[*]. Can you fold in the below (compile tested only) patch at the very beginning of this series? It implements my suggested alternative. And then this would become:
static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1);
if (!best)
return 0;
return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss;
}Quoted 9 lines
arch/x86/kvm/cpuid.c +0
-0/* * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if arch/x86/kvm/x86.c +0
-0@@ -3780,10 +3780,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs.
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 3788
Quoted 10 lines
arch/x86/kvm/x86.c +5
-3*/ -if (data & ~kvm_caps.supported_xss) +if (data & ~vcpu->arch.guest_supported_xss)return 1 ; - vcpu->arch.ia32_xss = data; -kvm_update_cpuid_runtime (vcpu); +if (vcpu->arch.ia32_xss != data) { + vcpu->arch.ia32_xss = data; +kvm_update_cpuid_runtime (vcpu); + }
Nit, I prefer this style:
if (vcpu->arch.ia32_xss == data) break; vcpu->arch.ia32_xss = data; kvm_update_cpuid_runtime(vcpu);
so that the common path isn't buried in an if-statement.
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 3791
Quoted 4 lines
arch/x86/kvm/x86.c +0
-0break ;case MSR_SMI_COUNT :if (!msr_info->host_initiated)
From: Sean Christopherson <[email protected]>
Date: Fri, 4 Aug 2023 08:48:03 -0700
Subject: [PATCH] KVM: x86: Rework cpuid_get_supported_xcr0() to operate on
vCPU data
Rework and rename cpuid_get_supported_xcr0() to explicitly operate on vCPU state, i.e. on a vCPU's CPUID state. Prior to commit 275a87244ec8 ("KVM:
x86: Don't adjust guest's CPUID.0x12.1 (allowed SGX enclave XFRM)"), KVM incorrectly fudged guest CPUID at runtime, which in turn necessitated massaging the incoming CPUID state for KVM_SET_CPUID{2} so as not to run afoul of kvm_cpuid_check_equal().
Opportunistically move the helper below kvm_update_cpuid_runtime() to make it harder to repeat the mistake of querying supported XCR0 for runtime updates.
No functional change intended.
--- arch/x86/kvm/cpuid.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)
arch/x86/kvm/cpuid.c +16 -17
@@ -234,21 +234,6 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) vcpu->arch.pv_cpuid.features = best->eax; } -/* -* Calculate guest's supported XCR0 taking into account guest CPUID data and -* KVM's supported XCR0 (comprised of host's XCR0 and KVM_SUPPORTED_XCR0). -*/ -static u64 cpuid_get_supported_xcr0 (struct kvm_cpuid_entry2 *entries,int nent) -{ -struct kvm_cpuid_entry2 *best; - - best =cpuid_entry2_find (entries, nent,0xd ,0 ); -if (!best) -return 0 ; - -return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; -} -static void __kvm_update_cpuid_runtime (struct kvm_vcpu *vcpu,struct kvm_cpuid_entry2 *entries,int nent) {
@@ -299,6 +284,21 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) }EXPORT_SYMBOL_GPL (kvm_update_cpuid_runtime); +/* +* Calculate guest's supported XCR0 taking into account guest CPUID data and +* KVM's supported XCR0 (comprised of host's XCR0 and KVM_SUPPORTED_XCR0). +*/ +static u64 vcpu_get_supported_xcr0 (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry_index (vcpu,0xd ,0 ); +if (!best) +return 0 ; + +return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; +} +static bool kvm_cpuid_has_hyperv (struct kvm_cpuid_entry2 *entries,int nent) {struct kvm_cpuid_entry2 *entry;
@@ -323,8 +323,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)kvm_apic_set_version (vcpu); } - vcpu->arch.guest_supported_xcr0 = -cpuid_get_supported_xcr0 (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); + vcpu->arch.guest_supported_xcr0 =vcpu_get_supported_xcr0 (vcpu);/* * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if
base-commit: f0147fcfab840fe9a3f03e9645d25c1326373fe6
Paolo Bonzini
maintainerRe: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
Quoted 7 lines · Sean Christopherson
Quoted 4 lines
Update
CPUID(EAX=0DH,ECX=1)when the guest's XSS is modified. CPUID(EAX=0DH,ECX=1).EBX reports required storage size of all enabled xstate features in XCR0 | XSS. Guest can allocate sufficient xsave buffer based on the info.Please wrap changelogs closer to ~75 chars. I'm pretty sure this isn't the first time I've made this request...
I suspect this is because of the long "word" CPUID(EAX=0DH,ECX=1).EBX. It would make the lengths less homogeneous if lines 1 stayed the same but lines 2-4 became longer.
Paolo
Re: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
Quoted 10 lines · Paolo Bonzini
Quoted 7 lines · Sean Christopherson
Quoted 4 lines
Update
CPUID(EAX=0DH,ECX=1)when the guest's XSS is modified. CPUID(EAX=0DH,ECX=1).EBX reports required storage size of all enabled xstate features in XCR0 | XSS. Guest can allocate sufficient xsave buffer based on the info.Please wrap changelogs closer to ~75 chars. I'm pretty sure this isn't the first time I've made this request...
I suspect this is because of the long "word" CPUID(EAX=0DH,ECX=1).EBX. It would make the lengths less homogeneous if lines 1 stayed the same but lines 2-4 became longer.
Yes, more or less, but I need to learn some "techniques" to make the wording looks trimmed and tidy. Thanks!
Quoted 2 lines
Paolo
Re: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
In reply to Sean ChristophersonQuoted 7 lines · Sean Christopherson
Quoted 4 lines · Yang Weijiang
Update
CPUID(EAX=0DH,ECX=1)when the guest's XSS is modified. CPUID(EAX=0DH,ECX=1).EBX reports required storage size of all enabled xstate features in XCR0 | XSS. Guest can allocate sufficient xsave buffer based on the info.Please wrap changelogs closer to ~75 chars. I'm pretty sure this isn't the first time I've made this request...
Thanks, will keep the changelog to 70~75 chars.
Quoted 57 lines
Quoted 47 lines
Note, KVM does not yet support any XSS based features, i.e.
supported_xssis guaranteed to be zero at this time.Co-developed-by Zhang Yi Z <[email protected]>Signed-off-by Zhang Yi Z <[email protected]>Signed-off-by Yang Weijiang <[email protected]>--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.c | 20 ++++++++++++++++++-- arch/x86/kvm/x86.c | 8 +++++--- 3 files changed, 24 insertions(+), 5 deletions(-)arch/x86/include/asm/kvm_host.h +1
-0@@ -804,6 +804,7 @@ struct kvm_vcpu_arch {u64 xcr0;u64 guest_supported_xcr0; +u64 guest_supported_xss;struct kvm_pio_request pio;void *pio_data;arch/x86/kvm/cpuid.c +11
-0@@ -249,6 +249,17 @@ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; } +static u64 cpuid_get_supported_xss (struct kvm_cpuid_entry2 *entries,int nent) +{ +struct kvm_cpuid_entry2 *best; + + best =cpuid_entry2_find (entries, nent,0xd ,1 ); +if (!best) +return 0 ; + +return (best->ecx | ((u64 )best->edx <<32 )) & kvm_caps.supported_xss; +} +static void __kvm_update_cpuid_runtime (struct kvm_vcpu *vcpu,struct kvm_cpuid_entry2 *entries,int nent) {arch/x86/kvm/cpuid.c static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e · line 291
Quoted 7 lines
arch/x86/kvm/cpuid.c +2
-2@@ -276,8 +287,11 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e best =cpuid_entry2_find (entries, nent,0xD ,1 );if (best && (cpuid_entry_has (best,X86_FEATURE_XSAVES ) || -cpuid_entry_has (best,X86_FEATURE_XSAVEC ))) - best->ebx =xstate_required_size (vcpu->arch.xcr0, true); +cpuid_entry_has (best,X86_FEATURE_XSAVEC ))) { +u64 xstate = vcpu->arch.xcr0 | vcpu->arch.ia32_xss;Nit, the variable should be xfeatures, not xstate. Though I vote to avoid the variable entirely,
Quoted 8 lines
best = cpuid_entry2_find(entries, nent, 0xD, 1); if (best && (cpuid_entry_has(best, X86_FEATURE_XSAVES) || cpuid_entry_has(best, X86_FEATURE_XSAVEC))) best->ebx = xstate_required_size(vcpu->arch.xcr0 | vcpu->arch.ia32_xss, true);though it's only a slight preference, i.e. feel free to keep your approach if you or others feel strongly about the style.
Yes, the variable is not necessary, will remove it.
Quoted 25 lines
arch/x86/kvm/cpuid.c static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) · line 343
Quoted 10 lines
arch/x86/kvm/cpuid.c +3
-0+ } best =__kvm_find_kvm_cpuid_features (vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best &&@@ -325,6 +339,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.guest_supported_xcr0 =cpuid_get_supported_xcr0 (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); + vcpu->arch.guest_supported_xss = +cpuid_get_supported_xss (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);Blech. I tried to clean up this ugly, but Paolo disagreed[*]. Can you fold in the below (compile tested only) patch at the very beginning of this series? It implements my suggested alternative. And then this would become:
static u64
vcpu_get_supported_xss(struct kvm_vcpu *vcpu){ struct kvm_cpuid_entry2 *best; best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); if (!best) return 0; return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; }
Quoted 1 line
Sure, will take it into my series, thanks!
Quoted 21 lines
Quoted 9 lines
arch/x86/kvm/cpuid.c +0
-0/* * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if arch/x86/kvm/x86.c +0
-0@@ -3780,10 +3780,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 3788
Quoted 10 lines
arch/x86/kvm/x86.c +5
-3*/ -if (data & ~kvm_caps.supported_xss) +if (data & ~vcpu->arch.guest_supported_xss)return 1 ; - vcpu->arch.ia32_xss = data; -kvm_update_cpuid_runtime (vcpu); +if (vcpu->arch.ia32_xss != data) { + vcpu->arch.ia32_xss = data; +kvm_update_cpuid_runtime (vcpu); + }Nit, I prefer this style:
Quoted 7 lines
if (vcpu->arch.ia32_xss == data) break; vcpu->arch.ia32_xss = data; kvm_update_cpuid_runtime(vcpu);so that the common path isn't buried in an if-statement.
Yeah, I feel I'm a bit awkward to make code look nicer :-)
Quoted 88 lines
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 3791
Quoted 4 lines
arch/x86/kvm/x86.c +0
-0break ;case MSR_SMI_COUNT :if (!msr_info->host_initiated)From: Sean Christopherson <[email protected]>
Date: Fri, 4 Aug 2023 08:48:03 -0700
Subject: [PATCH] KVM: x86: Reworkcpuid_get_supported_xcr0()to operate on
vCPU dataRework and rename
cpuid_get_supported_xcr0()to explicitly operate on vCPU state, i.e. on a vCPU's CPUID state. Prior to commit275a87244ec8("KVM:
x86: Don't adjust guest's CPUID.0x12.1 (allowed SGX enclave XFRM)"), KVM incorrectly fudged guest CPUID at runtime, which in turn necessitated massaging the incoming CPUID state for KVM_SET_CPUID{2} so as not to run afoul ofkvm_cpuid_check_equal().Opportunistically move the helper below
kvm_update_cpuid_runtime()to make it harder to repeat the mistake of querying supported XCR0 for runtime updates.No functional change intended.
Signed-off-by Sean Christopherson <[email protected]>--- arch/x86/kvm/cpuid.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)arch/x86/kvm/cpuid.c +16
-17@@ -234,21 +234,6 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) vcpu->arch.pv_cpuid.features = best->eax; } -/* -* Calculate guest's supported XCR0 taking into account guest CPUID data and -* KVM's supported XCR0 (comprised of host's XCR0 and KVM_SUPPORTED_XCR0). -*/ -static u64 cpuid_get_supported_xcr0 (struct kvm_cpuid_entry2 *entries,int nent) -{ -struct kvm_cpuid_entry2 *best; - - best =cpuid_entry2_find (entries, nent,0xd ,0 ); -if (!best) -return 0 ; - -return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; -} -static void __kvm_update_cpuid_runtime (struct kvm_vcpu *vcpu,struct kvm_cpuid_entry2 *entries,int nent) {@@ -299,6 +284,21 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) }EXPORT_SYMBOL_GPL (kvm_update_cpuid_runtime); +/* +* Calculate guest's supported XCR0 taking into account guest CPUID data and +* KVM's supported XCR0 (comprised of host's XCR0 and KVM_SUPPORTED_XCR0). +*/ +static u64 vcpu_get_supported_xcr0 (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry_index (vcpu,0xd ,0 ); +if (!best) +return 0 ; + +return (best->eax | ((u64 )best->edx <<32 )) & kvm_caps.supported_xcr0; +} +static bool kvm_cpuid_has_hyperv (struct kvm_cpuid_entry2 *entries,int nent) {struct kvm_cpuid_entry2 *entry;@@ -323,8 +323,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)kvm_apic_set_version (vcpu); } - vcpu->arch.guest_supported_xcr0 = -cpuid_get_supported_xcr0 (vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); + vcpu->arch.guest_supported_xcr0 =vcpu_get_supported_xcr0 (vcpu);/* * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if base-commit:
f0147fcfab840fe9a3f03e9645d25c1326373fe6
Sean Christopherson
maintainerRe: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
In reply to Yang Weijiangarch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 3783
Quoted 10 lines · Yang Weijiang
arch/x86/kvm/x86.c +1
-1@@ -3780,10 +3780,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. */ -if (data & ~kvm_caps.supported_xss) +if (data & ~vcpu->arch.guest_supported_xss)
Hmm, this is arguably wrong for userspace-initiated writes, as it would prevent userspace from restoring MSRs before CPUID.
And it would make the handling of MSR_IA32_XSS writes inconsistent just within this case statement. The initial "can this MSR be written at all" check would *not* honor guest CPUID for host writes, but then the per-bit check *would* honor guest CPUID for host writes.
But if we exempt host writes, then we'll end up with another mess, as exempting host writes for MSR_KVM_GUEST_SSP would let the guest coerce KVM into writing an illegal value by modifying SMRAM while in SMM.
Blech.
If we can get away with it, i.e. not break userspace, I think my preference is to enforce guest CPUID for host accesses to XSS, XFD, XFD_ERR, etc. I'm 99% certain we can make that change, because there are many, many MSRs that do NOT exempt host writes, i.e. the only way this would be a breaking change is if userspace is writing things like XSS before KVM_SET_CPUID2, but other MSRs after KVM_SET_CPUID2.
I'm pretty sure I've advocated for the exact opposite in the past, i.e. argued that KVM's ABI is to not enforce ordering between KVM_SET_CPUID2 and KVM_SET_MSR. But this is becoming untenable, juggling the dependencies in KVM is complex and is going to result in a nasty bug at some point.
For this series, lets just tighten the rules for XSS, i.e. drop the host_initated exemption. And in a parallel/separate series, try to do a wholesale cleanup of all the cases that essentially allow userspace to do KVM_SET_MSR before KVM_SET_CPUID2.
Paolo Bonzini
maintainerRe: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
Quoted 3 lines · Sean Christopherson
I think my preference is to enforce guest CPUID for host accesses to XSS, XFD,
XFD_ERR, etc I'm pretty sure I've advocated for the exact opposite in the past, i.e. argued that KVM's ABI is to not enforce ordering betweenKVM_SET_CPUID2andKVM_SET_MSR. But this is becoming untenable, juggling the dependencies in KVM is complex and is going
to result in a nasty bug at some point.
Fortunately, you are right now. Well, almost :) but the important part is that indeed the dependencies are too complex.
While host-side accesses must be allowed, they should only allow the default value if the CPUID bit is not set.
Paolo
Re: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
In reply to Sean ChristophersonQuoted 32 lines · Sean Christopherson
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 3783
Quoted 10 lines · Yang Weijiang
arch/x86/kvm/x86.c +1
-1@@ -3780,10 +3780,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. */ -if (data & ~kvm_caps.supported_xss) +if (data & ~vcpu->arch.guest_supported_xss)Hmm, this is arguably wrong for userspace-initiated writes, as it would prevent userspace from restoring MSRs before CPUID.
And it would make the handling of
MSR_IA32_XSSwrites inconsistent just within this case statement. The initial "can this MSR be written at all" check would *not* honor guest CPUID for host writes, but then the per-bit check *would* honor guest CPUID for host writes.But if we exempt host writes, then we'll end up with another mess, as exempting host writes for
MSR_KVM_GUEST_SSPwould let the guest coerce KVM into writing an illegal value by modifying SMRAM while in SMM.Blech.
If we can get away with it, i.e. not break userspace, I think my preference is to enforce guest CPUID for host accesses to XSS, XFD,
XFD_ERR, etc. I'm 99% certain we can make that change, because there are many, many MSRs that do NOT exempt host writes, i.e. the only way this would be a breaking change is if userspace is writing things like XSS beforeKVM_SET_CPUID2, but other MSRs afterKVM_SET_CPUID2.
Quoted 8 lines
I'm pretty sure I've advocated for the exact opposite in the past, i.e. argued that KVM's ABI is to not enforce ordering between
KVM_SET_CPUID2andKVM_SET_MSR. But this is becoming untenable, juggling the dependencies in KVM is complex and is going to result in a nasty bug at some point.For this series, lets just tighten the rules for XSS, i.e. drop the
host_initatedexemption. And in a parallel/separate series, try to do a wholesale cleanup of all the cases that essentially allow userspace to doKVM_SET_MSRbeforeKVM_SET_CPUID2.
OK, will do it for this series and investigate for other MSRs. Thanks!
Paolo Bonzini
maintainerRe: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
Quoted 10 lines · Weijiang
Quoted 8 lines
I'm pretty sure I've advocated for the exact opposite in the past, i.e. argued that KVM's ABI is to not enforce ordering between
KVM_SET_CPUID2andKVM_SET_MSR. But this is becoming untenable, juggling the dependencies in KVM is complex and is going to result in a nasty bug at some point.For this series, lets just tighten the rules for XSS, i.e. drop the
host_initatedexemption. And in a parallel/separate series, try to do a wholesale cleanup of all the cases that essentially allow userspace to doKVM_SET_MSRbeforeKVM_SET_CPUID2.OK, will do it for this series and investigate for other MSRs. Thanks!
Remember that, while the ordering between KVM_SET_CPUID2 and KVM_SET_MSR must be enforced(*), the host_initiated path must allow the default (generally 0) value.
Paolo
(*) this means that you should check guest_cpuid_has even if host_initiated == true.
Re: [PATCH v5 04/19] KVM:x86: Refresh CPUID on write to guest MSR_IA32_XSS
Quoted 6 lines · Paolo Bonzini
Quoted 5 lines · Weijiang
Quoted 5 lines
I'm pretty sure I've advocated for the exact opposite in the past, i.e. argued that KVM's ABI is to not enforce ordering between
KVM_SET_CPUID2andKVM_SET_MSR. But this is becoming untenable, juggling the dependencies in KVM is complex and is going to result in a nasty bug at some point.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
For this series, lets just tighten the rules for XSS, i.e. drop the
host_initatedexemption. And in a parallel/separate series, try to do a wholesale cleanup of all the cases that essentially allow userspace to doKVM_SET_MSRbeforeKVM_SET_CPUID2.OK, will do it for this series and investigate for other MSRs. Thanks!
Remember that, while the ordering between
KVM_SET_CPUID2andKVM_SET_MSRmust beenforced(*), thehost_initiatedpath must allow the default (generally 0) value.
Yes, will take it, thanks!
Quoted 5 lines
Paolo
(*) this means that you should check
guest_cpuid_haseven ifhost_initiated== true.
PATCH v5 5/19 KVM:x86: Initialize kvm_caps.supported_xss
In reply to Yang WeijiangSet kvm_caps.supported_xss to host_xss && KVM XSS mask. host_xss contains the host supported xstate feature bits for thread context switch, KVM_SUPPORTED_XSS includes all KVM enabled XSS feature bits, the operation result represents all KVM supported feature bits. Since the result is subset of host_xss, the related XSAVE-managed MSRs are automatically swapped for guest and host when vCPU exits to userspace.
--- arch/x86/kvm/vmx/vmx.c | 1 - arch/x86/kvm/x86.c | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/vmx.c +0 -1
@@ -7849,7 +7849,6 @@ static __init void vmx_set_cpu_caps(void)kvm_cpu_cap_set (X86_FEATURE_UMIP );/* CPUID 0xD.1 */ - kvm_caps.supported_xss =0 ;if (!cpu_has_vmx_xsaves ())kvm_cpu_cap_clear (X86_FEATURE_XSAVES );
arch/x86/kvm/x86.c +5 -1
@@ -225,6 +225,8 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) +#define KVM_SUPPORTED_XSS 0 +u64 __read_mostly host_efer;EXPORT_SYMBOL_GPL (host_efer);
@@ -9498,8 +9500,10 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)rdmsrl_safe (MSR_EFER , &host_efer); -if (boot_cpu_has (X86_FEATURE_XSAVES )) +if (boot_cpu_has (X86_FEATURE_XSAVES )) {rdmsrl (MSR_IA32_XSS , host_xss); + kvm_caps.supported_xss = host_xss &KVM_SUPPORTED_XSS ; + }kvm_init_pmu_capability (ops->pmu_ops);
Signature · 1 line
2.27.0
Sean Christopherson
maintainerRe: [PATCH v5 05/19] KVM:x86: Initialize kvm_caps.supported_xss
Quoted 19 lines · Yang Weijiang
Set kvm_caps.supported_xss to
host_xss&& KVM XSS mask.host_xsscontains the host supported xstate feature bits for thread context switch,KVM_SUPPORTED_XSSincludes all KVM enabled XSS feature bits, the operation result represents all KVM supported feature bits. Since the result is subset ofhost_xss, the related XSAVE-managed MSRs are automatically swapped for guest and host when vCPU exits to userspace.Signed-off-by Yang Weijiang <[email protected]>--- arch/x86/kvm/vmx/vmx.c | 1 - arch/x86/kvm/x86.c | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-)arch/x86/kvm/vmx/vmx.c +0
-0
arch/x86/kvm/vmx/vmx.c static __init void vmx_set_cpu_caps(void) · line 7852
Quoted 4 lines
arch/x86/kvm/vmx/vmx.c +0
-1@@ -7849,7 +7849,6 @@ static __init void vmx_set_cpu_caps(void)kvm_cpu_cap_set (X86_FEATURE_UMIP );/* CPUID 0xD.1 */ - kvm_caps.supported_xss =0 ;
Dropping this code in *this* patch is wrong, this belong in whatever patch(es) adds IBT and SHSTK support in VMX.
And that does matter because it means this common patch can be carried wih SVM support without breaking VMX.
Quoted 17 lines
arch/x86/kvm/vmx/vmx.c +0
-0if (!cpu_has_vmx_xsaves ())kvm_cpu_cap_clear (X86_FEATURE_XSAVES );arch/x86/kvm/x86.c +2
-0@@ -225,6 +225,8 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) +#define KVM_SUPPORTED_XSS 0 +u64 __read_mostly host_efer;EXPORT_SYMBOL_GPL (host_efer);
arch/x86/kvm/x86.c static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) · line 9506
Quoted 8 lines
arch/x86/kvm/x86.c +3
-1@@ -9498,8 +9500,10 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)rdmsrl_safe (MSR_EFER , &host_efer); -if (boot_cpu_has (X86_FEATURE_XSAVES )) +if (boot_cpu_has (X86_FEATURE_XSAVES )) {rdmsrl (MSR_IA32_XSS , host_xss); + kvm_caps.supported_xss = host_xss &KVM_SUPPORTED_XSS ; + }
Can you opportunistically (in this patch) hoist this above EFER so that XCR0 and XSS are colocated? I.e. end up with this:
if (boot_cpu_has(X86_FEATURE_XSAVE)) {
host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
kvm_caps.supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0;
}
if (boot_cpu_has(X86_FEATURE_XSAVES)) {
rdmsrl(MSR_IA32_XSS, host_xss);
kvm_caps.supported_xss = host_xss & KVM_SUPPORTED_XSS;
}
rdmsrl_safe(MSR_EFER, &host_efer);Re: [PATCH v5 05/19] KVM:x86: Initialize kvm_caps.supported_xss
Quoted 22 lines · Sean Christopherson
Quoted 21 lines · Yang Weijiang
Set kvm_caps.supported_xss to
host_xss&& KVM XSS mask.host_xsscontains the host supported xstate feature bits for thread context switch,KVM_SUPPORTED_XSSincludes all KVM enabled XSS feature bits, the operation result represents all KVM supported feature bits. Since the result is subset ofhost_xss, the related XSAVE-managed MSRs are automatically swapped for guest and host when vCPU exits to userspace.Signed-off-by Yang Weijiang <[email protected]>--- arch/x86/kvm/vmx/vmx.c | 1 - arch/x86/kvm/x86.c | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-)arch/x86/kvm/vmx/vmx.c +0
-0@@ -7849,7 +7849,6 @@ static __init void vmx_set_cpu_caps(void)kvm_cpu_cap_set (X86_FEATURE_UMIP );
Quoted 7 lines
arch/x86/kvm/vmx/vmx.c static __init void vmx_set_cpu_caps(void) · line 7852
Quoted 2 lines
arch/x86/kvm/vmx/vmx.c +0
-1/* CPUID 0xD.1 */ - kvm_caps.supported_xss =0 ;Dropping this code in *this* patch is wrong, this belong in whatever patch(es) adds IBT and SHSTK support in VMX.
And that does matter because it means this common patch can be carried wih SVM support without breaking VMX.
OK, I'll dropping this line for VMX/SVM in CET feature bits enabling patch.
Quoted 28 lines
Quoted 17 lines
arch/x86/kvm/vmx/vmx.c +0
-0if (!cpu_has_vmx_xsaves ())kvm_cpu_cap_clear (X86_FEATURE_XSAVES );arch/x86/kvm/x86.c +2
-0@@ -225,6 +225,8 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) +#define KVM_SUPPORTED_XSS 0 +u64 __read_mostly host_efer;EXPORT_SYMBOL_GPL (host_efer);arch/x86/kvm/x86.c static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) · line 9506
Quoted 8 lines
arch/x86/kvm/x86.c +3
-1@@ -9498,8 +9500,10 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)rdmsrl_safe (MSR_EFER , &host_efer); -if (boot_cpu_has (X86_FEATURE_XSAVES )) +if (boot_cpu_has (X86_FEATURE_XSAVES )) {rdmsrl (MSR_IA32_XSS , host_xss); + kvm_caps.supported_xss = host_xss &KVM_SUPPORTED_XSS ; + }Can you opportunistically (in this patch) hoist this above EFER so that XCR0 and XSS are colocated? I.e. end up with this:
Quoted 10 lines
if (boot_cpu_has(X86_FEATURE_XSAVE)) {
host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
kvm_caps.supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0;
}
if (boot_cpu_has(X86_FEATURE_XSAVES)) {
rdmsrl(MSR_IA32_XSS, host_xss);
kvm_caps.supported_xss = host_xss & KVM_SUPPORTED_XSS;
}
rdmsrl_safe(MSR_EFER, &host_efer);Will change it, thanks!
PATCH v5 6/19 KVM:x86: Load guest FPU state when access XSAVE-managed MSRs
In reply to Yang WeijiangFrom: Sean Christopherson <[email protected]>
Load the guest's FPU state if userspace is accessing MSRs whose values are managed by XSAVES. Two MSR access helpers, i.e., kvm_{get,set}_xsave_msr(), are designed by a later patch to facilitate access to such kind of MSRs.
If MSRs supported in kvm_caps.supported_xss are passed through to guest, the guest MSRs are swapped with host contents before vCPU exits to userspace and after it enters kernel again.
Because the modified code is also used for the KVM_GET_MSRS device ioctl(), explicitly check @vcpu is non-null before attempting to load guest state. The XSS supporting MSRs cannot be retrieved via the device ioctl() without loading guest FPU state (which doesn't exist).
Note that guest_cpuid_has() is not queried as host userspace is allowed to access MSRs that have not been exposed to the guest, e.g. it might do KVM_SET_MSRS prior to KVM_SET_CPUID2.
--- arch/x86/kvm/x86.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
arch/x86/kvm/x86.c +28 -1
@@ -132,6 +132,9 @@ static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2);static void __get_sregs2 (struct kvm_vcpu *vcpu,struct kvm_sregs2 *sregs2);static DEFINE_MUTEX (vendor_module_lock); +static void kvm_load_guest_fpu (struct kvm_vcpu *vcpu); +static void kvm_put_guest_fpu (struct kvm_vcpu *vcpu); +struct kvm_x86_ops kvm_x86_ops__read_mostly ;#define KVM_X86_OP (func) \
@@ -4345,6 +4348,21 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) }EXPORT_SYMBOL_GPL (kvm_get_msr_common); +static const u32 xstate_msrs[] = { +MSR_IA32_U_CET ,MSR_IA32_PL3_SSP , +}; + +static bool is_xstate_msr (u32 index) +{ +int i; + +for (i =0 ; i <ARRAY_SIZE (xstate_msrs); i++) { +if (index == xstate_msrs[i]) +return true; + } +return false; +} +/* * Read or write a bunch of msrs. All parameters are kernel addresses. *
@@ -4355,11 +4373,20 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,int (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data)) { +bool fpu_loaded = false;int i; -for (i =0 ; i < msrs->nmsrs; ++i) +for (i =0 ; i < msrs->nmsrs; ++i) { +if (vcpu && !fpu_loaded && kvm_caps.supported_xss && +is_xstate_msr (entries[i].index)) { +kvm_load_guest_fpu (vcpu); + fpu_loaded = true; + }if (do_msr (vcpu, entries[i].index, &entries[i].data))break ; + } +if (fpu_loaded) +kvm_put_guest_fpu (vcpu);return i; }
Signature · 1 line
2.27.0
PATCH v5 7/19 KVM:x86: Add fault checks for guest CR4.CET setting
In reply to Yang WeijiangCheck potential faults for CR4.CET setting per Intel SDM. CET can be enabled if and only if CR0.WP==1, i.e. setting CR4.CET=1 faults if CR0.WP==0 and setting CR0.WP=0 fails if CR4.CET==1.
--- arch/x86/kvm/x86.c | 6 ++++++ 1 file changed, 6 insertions(+)
arch/x86/kvm/x86.c +6 -0
@@ -993,6 +993,9 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) (is_64_bit_mode(vcpu) || kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)))return 1 ; +if (!(cr0 &X86_CR0_WP ) &&kvm_is_cr4_bit_set (vcpu,X86_CR4_CET )) +return 1 ; +static_call (kvm_x86_set_cr0)(vcpu, cr0);kvm_post_set_cr0 (vcpu, old_cr0, cr0);
@@ -1204,6 +1207,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)return 1 ; } +if ((cr4 &X86_CR4_CET ) && !kvm_is_cr0_bit_set (vcpu,X86_CR0_WP )) +return 1 ; +static_call (kvm_x86_set_cr4)(vcpu, cr4);kvm_post_set_cr4 (vcpu, old_cr4, cr4);
Signature · 1 line
2.27.0
Re: [PATCH v5 07/19] KVM:x86: Add fault checks for guest CR4.CET setting
nit: add a space betwen "KVM:" and "x86:" in the short changelog.
Quoted 8 lines · Yang Weijiang
Check potential faults for CR4.CET setting per Intel SDM. CET can be enabled if and only if CR0.WP==1, i.e. setting CR4.CET=1 faults if CR0.WP==0 and setting CR0.WP=0 fails if CR4.CET==1.
Co-developed-by Sean Christopherson <[email protected]>Signed-off-by Sean Christopherson <[email protected]>Signed-off-by Yang Weijiang <[email protected]>
PATCH v5 8/19 KVM:x86: Report KVM supported CET MSRs as to-be-saved
In reply to Yang WeijiangAdd all CET MSRs including the synthesized GUEST_SSP to report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches. MSR_IA32_U_CET and MSR_IA32_PL3_SSP are XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.
When CET IBT/SHSTK are enumerated to guest, both user and supervisor modes should be supported for architechtural integrity, i.e., two modes are supported as both or neither.
--- arch/x86/include/uapi/asm/kvm_para.h | 1 + arch/x86/kvm/x86.c | 10 ++++++++++ arch/x86/kvm/x86.h | 10 ++++++++++ 3 files changed, 21 insertions(+)
arch/x86/include/uapi/asm/kvm_para.h +1 -0
@@ -58,6 +58,7 @@#define MSR_KVM_ASYNC_PF_INT 0x4b564d06#define MSR_KVM_ASYNC_PF_ACK 0x4b564d07#define MSR_KVM_MIGRATION_CONTROL 0x4b564d08 +#define MSR_KVM_GUEST_SSP 0x4b564d09struct kvm_steal_time {__u64 steal;
arch/x86/kvm/x86.c +10 -0
@@ -1463,6 +1463,9 @@ static const u32 msrs_to_save_base[] = {MSR_IA32_XFD ,MSR_IA32_XFD_ERR ,MSR_IA32_XSS , +MSR_IA32_U_CET ,MSR_IA32_S_CET , +MSR_IA32_PL0_SSP ,MSR_IA32_PL1_SSP ,MSR_IA32_PL2_SSP , + MSR_IA32_PL3_SSP, MSR_IA32_INT_SSP_TAB, MSR_KVM_GUEST_SSP, }; static const u32 msrs_to_save_pmu[] = {
@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ()) +return ; +break ;default :break ; }
arch/x86/kvm/x86.h +10 -0
@@ -362,6 +362,16 @@ static inline bool kvm_mpx_supported(void) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); } +#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER) +/* +* Shadow Stack and Indirect Branch Tracking feature enabling depends on +* whether host side CET user xstate bit is supported or not. +*/ +static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ; +} +extern unsigned int min_timer_period_us;extern bool enable_vmware_backdoor;
Signature · 1 line
2.27.0
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 9 lines · Yang Weijiang
Add all CET MSRs including the synthesized
GUEST_SSPto report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches.MSR_IA32_U_CETandMSR_IA32_PL3_SSPare XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.When CET IBT/SHSTK are enumerated to guest, both user and supervisor modes should be supported for architechtural integrity, i.e., two modes are supported as both or neither.
I think whether MSRs are XSAVE-managed or not isn't related or important in this patch. And I don't get what's the intent of the last paragraph.
how about:
Add CET MSRs to the list of MSRs reported to userspace if the feature i.e., IBT or SHSTK, associated with the MSRs is supported by KVM.
Quoted 25 lines
Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/include/uapi/asm/kvm_para.h | 1 + arch/x86/kvm/x86.c | 10 ++++++++++ arch/x86/kvm/x86.h | 10 ++++++++++ 3 files changed, 21 insertions(+)arch/x86/include/uapi/asm/kvm_para.h +1
-0@@ -58,6 +58,7 @@#define MSR_KVM_ASYNC_PF_INT 0x4b564d06#define MSR_KVM_ASYNC_PF_ACK 0x4b564d07#define MSR_KVM_MIGRATION_CONTROL 0x4b564d08 +#define MSR_KVM_GUEST_SSP 0x4b564d09struct kvm_steal_time {__u64 steal;arch/x86/kvm/x86.c +0
-0
arch/x86/kvm/x86.c static const u32 msrs_to_save_base[] = { · line 1468
Quoted 6 lines
arch/x86/kvm/x86.c +3
-0@@ -1463,6 +1463,9 @@ static const u32 msrs_to_save_base[] = {MSR_IA32_XFD ,MSR_IA32_XFD_ERR ,MSR_IA32_XSS , +MSR_IA32_U_CET ,MSR_IA32_S_CET , +MSR_IA32_PL0_SSP ,MSR_IA32_PL1_SSP ,MSR_IA32_PL2_SSP , + MSR_IA32_PL3_SSP, MSR_IA32_INT_SSP_TAB, MSR_KVM_GUEST_SSP,
MSR_KVM_GUEST_SSP really should be added by a separate patch.
it is incorrect to put MSR_KVM_GUEST_SSP here because the rdmsr_safe() in kvm_probe_msr_to_save() will fail since hardware doesn't have this MSR.
IMO, MSR_KVM_GUEST_SSP should go to emulated_msrs_all[].
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 12 lines
arch/x86/kvm/x86.c +5
-0};static const u32 msrs_to_save_pmu[] = {@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())
shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
if yes, we should do
case MSR_IA32_U_CET: case MSR_IA32_S_CET: if (!kvm_is_cet_supported()) return; case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK)) return;
Quoted 11 lines
arch/x86/kvm/x86.c +2
-0+return ; +break ;default :break ; }arch/x86/kvm/x86.h +0
-0@@ -362,6 +362,16 @@ static inline bool kvm_mpx_supported(void) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 372
Quoted 10 lines
arch/x86/kvm/x86.h +8
-0} +#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER) +/* +* Shadow Stack and Indirect Branch Tracking feature enabling depends on +* whether host side CET user xstate bit is supported or not. +*/ +static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ;
why not just check if SHSTK or IBT is supported explicitly, i.e.,
return kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT);
this is straightforward. And strictly speaking, the support of a feature and the support of managing a feature's state via XSAVE(S) are two different things.
then patch 16 has no need to do
+ /*
+ * If SHSTK and IBT are not available in KVM, clear CET user bit in
+ * kvm_caps.supported_xss so that kvm_is_cet__supported() returns
+ * false when called.
+ */
+ if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) &&
+ !kvm_cpu_cap_has(X86_FEATURE_IBT))
+ kvm_caps.supported_xss &= ~CET_XSTATE_MASK;
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 7 lines · Chao Gao
Quoted 6 lines · Yang Weijiang
Add all CET MSRs including the synthesized
GUEST_SSPto report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches.MSR_IA32_U_CETandMSR_IA32_PL3_SSPare XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.
Quoted 5 lines
Quoted 3 lines
When CET IBT/SHSTK are enumerated to guest, both user and supervisor modes should be supported for architechtural integrity, i.e., two modes are supported as both or neither.
I think whether MSRs are XSAVE-managed or not isn't related or important in this patch. And I don't get what's the intent of the last paragraph.
I recalled the original intent to say, although kvm_is_cet_supported() only checks the host support of user mode states, but user and supervisor mode states are exposed as a bundle, i.e., both or neither. So it can enforce the same check for both user and supervisor states support.
Quoted 4 lines
how about:
Add CET MSRs to the list of MSRs reported to userspace if the feature i.e., IBT or SHSTK, associated with the MSRs is supported by KVM.
It's OK for me, thanks!
Quoted 32 lines
Quoted 24 lines
Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/include/uapi/asm/kvm_para.h | 1 + arch/x86/kvm/x86.c | 10 ++++++++++ arch/x86/kvm/x86.h | 10 ++++++++++ 3 files changed, 21 insertions(+)arch/x86/include/uapi/asm/kvm_para.h +1
-0@@ -58,6 +58,7 @@#define MSR_KVM_ASYNC_PF_INT 0x4b564d06#define MSR_KVM_ASYNC_PF_ACK 0x4b564d07#define MSR_KVM_MIGRATION_CONTROL 0x4b564d08 +#define MSR_KVM_GUEST_SSP 0x4b564d09struct kvm_steal_time {__u64 steal;arch/x86/kvm/x86.c +0
-0arch/x86/kvm/x86.c static const u32 msrs_to_save_base[] = { · line 1468
Quoted 6 lines
arch/x86/kvm/x86.c +3
-0@@ -1463,6 +1463,9 @@ static const u32 msrs_to_save_base[] = {MSR_IA32_XFD ,MSR_IA32_XFD_ERR ,MSR_IA32_XSS , +MSR_IA32_U_CET ,MSR_IA32_S_CET , +MSR_IA32_PL0_SSP ,MSR_IA32_PL1_SSP ,MSR_IA32_PL2_SSP , + MSR_IA32_PL3_SSP, MSR_IA32_INT_SSP_TAB, MSR_KVM_GUEST_SSP,
MSR_KVM_GUEST_SSPreally should be added by a separate patch.
Quoted 4 lines
it is incorrect to put
MSR_KVM_GUEST_SSPhere because therdmsr_safe()inkvm_probe_msr_to_save()will fail since hardware doesn't have this MSR.IMO,
MSR_KVM_GUEST_SSPshould go to emulated_msrs_all[].
Nice catch! Will move it to emulated_msrs_all, thanks!
Quoted 14 lines
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 12 lines
arch/x86/kvm/x86.c +5
-0};static const u32 msrs_to_save_pmu[] = {@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
Yes, but userspace should be able to access SHSTK MSRs even only IBT is exposed to guest so far as KVM can support SHSTK MSRs. And here is to advertise all the supported CET MSRs. So maybe we don't need to check specific feature support.
Quoted 34 lines
if yes, we should do
case MSR_IA32_U_CET: case MSR_IA32_S_CET: if (!kvm_is_cet_supported()) return; case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK)) return;Quoted 11 lines
arch/x86/kvm/x86.c +2
-0+return ; +break ;default :break ; }arch/x86/kvm/x86.h +0
-0@@ -362,6 +362,16 @@ static inline bool kvm_mpx_supported(void) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 372
Quoted 10 lines
arch/x86/kvm/x86.h +8
-0} +#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER) +/* +* Shadow Stack and Indirect Branch Tracking feature enabling depends on +* whether host side CET user xstate bit is supported or not. +*/ +static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ;why not just check if SHSTK or IBT is supported explicitly, i.e.,
Quoted 5 lines
return kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT);this is straightforward. And strictly speaking, the support of a feature and the support of managing a feature's state via XSAVE(S) are two different things.x
I think using exiting check implies two things:
1. Platform/KVM can support CET features.
2. CET user mode MSRs are backed by host thus are guaranteed to be valid. i.e., the purpose is to check guest CET dependencies instead of features' availability.
kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT)
only tells at least one of the CET features is supported by KVM.
Quoted 10 lines
then patch 16 has no need to do
(quoted diff) +8
-0+ /* + * If SHSTK and IBT are not available in KVM, clear CET user bit in + * kvm_caps.supported_xss so that kvm_is_cet__supported() returns + * false when called. + */ + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + kvm_caps.supported_xss &= ~CET_XSTATE_MASK;
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 11 lines · Weijiang
Quoted 11 lines
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 9 lines
arch/x86/kvm/x86.c +5
-0@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
Quoted 2 lines
Yes, but userspace should be able to access SHSTK MSRs even only IBT is exposed to guest so far as KVM can support SHSTK MSRs.
Why should userspace be allowed to access SHSTK MSRs in this case? L1 may not even enumerate SHSTK (qemu removes -shstk explicitly but keeps IBT), how KVM in L1 can allow its userspace to do that?
Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 372
Quoted 3 lines
arch/x86/kvm/x86.h +3
-0+static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ;why not just check if SHSTK or IBT is supported explicitly, i.e.,
return kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT);
Quoted 6 lines
Quoted 2 lines
this is straightforward. And strictly speaking, the support of a feature and the support of managing a feature's state via XSAVE(S) are two different things.x
I think using exiting check implies two things:
1. Platform/KVM can support CET features.
2. CET user mode MSRs are backed by host thus are guaranteed to be valid. i.e., the purpose is to check guest CET dependencies instead of features' availability.
When KVM claims a feature is supported, it should ensure all its dependencies are met. that's, KVM's support of a feature also imples all dependencies are met. Function-wise, the two approaches have no difference. I just think checking KVM's support of SHSTK/IBT is more clear because the function name is kvm_is_cet_supported() rather than e.g., kvm_is_cet_state_managed_by_xsave().
Quoted 16 lines
kvm_cpu_cap_has(X86_FEATURE_SHSTK)||kvm_cpu_cap_has(X86_FEATURE_IBT)only tells at least one of the CET features is supported by KVM.
Quoted 10 lines
then patch 16 has no need to do
(quoted diff) +8
-0+ /* + * If SHSTK and IBT are not available in KVM, clear CET user bit in + * kvm_caps.supported_xss so that kvm_is_cet__supported() returns + * false when called. + */ + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + kvm_caps.supported_xss &= ~CET_XSTATE_MASK;
Sean Christopherson
maintainerRe: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 12 lines · Chao Gao
Quoted 11 lines · Weijiang
Quoted 11 lines
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 9 lines
arch/x86/kvm/x86.c +5
-0@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
Quoted 6 lines
Quoted 2 lines
Yes, but userspace should be able to access SHSTK MSRs even only IBT is exposed to guest so far as KVM can support SHSTK MSRs.
Why should userspace be allowed to access SHSTK MSRs in this case? L1 may not even enumerate SHSTK (qemu removes -shstk explicitly but keeps IBT), how KVM in L1 can allow its userspace to do that?
+1. And specifically, this isn't about SHSTK being exposed to the guest, it's about SHSTK being _supported by KVM_. This is all about KVM telling userspace what MSRs are valid and/or need to be saved+restored. If KVM doesn't support a feature, then the MSRs are invalid and there is no reason for userspace to save+restore the MSRs on live migration.
Quoted 15 lines
Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 372
Quoted 3 lines
arch/x86/kvm/x86.h +3
-0+static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ;why not just check if SHSTK or IBT is supported explicitly, i.e.,
return kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT);Quoted 6 lines
Quoted 2 lines
this is straightforward. And strictly speaking, the support of a feature and the support of managing a feature's state via XSAVE(S) are two different things.x
I think using exiting check implies two things:
1. Platform/KVM can support CET features.
2. CET user mode MSRs are backed by host thus are guaranteed to be valid. i.e., the purpose is to check guest CET dependencies instead of features' availability.
Quoted 5 lines
When KVM claims a feature is supported, it should ensure all its dependencies are met. that's, KVM's support of a feature also imples all dependencies are met. Function-wise, the two approaches have no difference. I just think checking KVM's support of SHSTK/IBT is more clear because the function name is
kvm_is_cet_supported()rather than e.g.,kvm_is_cet_state_managed_by_xsave().
+1, one of the big reasons kvm_cpu_cap_has() came about was being KVM had a giant mess of one-off helpers.
Paolo Bonzini
maintainerRe: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 12 lines · Sean Christopherson
Quoted 11 lines
Quoted 7 lines
Quoted 4 lines
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 2 lines
arch/x86/kvm/x86.c +2
-0+ case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
Yes, but userspace should be able to access SHSTK MSRs even only IBT is exposed to guest so far as KVM can support SHSTK MSRs.
Why should userspace be allowed to access SHSTK MSRs in this case? L1 may not even enumerate SHSTK (qemu removes -shstk explicitly but keeps IBT), how KVM in L1 can allow its userspace to do that?
Quoted 5 lines
+1. And specifically, this isn't about SHSTK being exposed to the guest, it's about SHSTK being
_supportedbyKVM_. This is all about KVM telling userspace what MSRs are valid and/or need to be saved+restored. If KVM doesn't support a feature, then the MSRs are invalid and there is no reason for userspace to save+restore the MSRs on live migration.
I think you three are talking past each other.
There are four cases:
- U_CET/S_CET supported by the host and exposed (obvious).
- U_CET/S_CET supported by the host, IBT or SHSTK partially exposed. The MSRs should still be guest-accessible and bits that apply to absent features should be reserved (bits 0-1 for SHSTK, bits 2-63 for IBT).
- U_CET/S_CET supported by the host, IBT or SHSTK not exposed. The MSRs should still be host-accessible and writable to the default value. This is clearer if you think that KVM_GET_MSR_INDEX_LIST is a system ioctl. Whether to allow writing 0 from the guest is debatable.
- U_CET/S_CET not supported by the host. Then the MSRs should not be enabled and should not be in KVM_GET_MSR_INDEX_LIST, and also IBT/SHSTK should not be in KVM_GET_SUPPORTED_CPUID.
In my opinion it is reasonable to require both U_CET and S_CET to be supported from the beginning in the host in order to support CET. It is simpler and keeps the feature matrix at bay.
Paolo
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
In reply to Sean ChristophersonQuoted 15 lines · Sean Christopherson
Quoted 14 lines · Chao Gao
Quoted 13 lines · Weijiang
Quoted 11 lines
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 9 lines
arch/x86/kvm/x86.c +5
-0@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
Yes, but userspace should be able to access SHSTK MSRs even only IBT is exposed to guest so far as KVM can support SHSTK MSRs.
Quoted 8 lines
Quoted 3 lines
Why should userspace be allowed to access SHSTK MSRs in this case? L1 may not even enumerate SHSTK (qemu removes -shstk explicitly but keeps IBT), how KVM in L1 can allow its userspace to do that?
+1. And specifically, this isn't about SHSTK being exposed to the guest, it's about SHSTK being
_supportedbyKVM_. This is all about KVM telling userspace what MSRs are valid and/or need to be saved+restored. If KVM doesn't support a feature, then the MSRs are invalid and there is no reason for userspace to save+restore the MSRs on live migration.
OK, will use kvm_cpu_cap_has() to check KVM support before add CET MSRs to the lists.
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 10 lines
arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 372
Quoted 3 lines
arch/x86/kvm/x86.h +3
-0+static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ;why not just check if SHSTK or IBT is supported explicitly, i.e.,
return kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT);this is straightforward. And strictly speaking, the support of a feature and the support of managing a feature's state via XSAVE(S) are two different things.x
I think using exiting check implies two things:
1. Platform/KVM can support CET features.
2. CET user mode MSRs are backed by host thus are guaranteed to be valid. i.e., the purpose is to check guest CET dependencies instead of features' availability.
Quoted 7 lines
Quoted 5 lines
When KVM claims a feature is supported, it should ensure all its dependencies are met. that's, KVM's support of a feature also imples all dependencies are met. Function-wise, the two approaches have no difference. I just think checking KVM's support of SHSTK/IBT is more clear because the function name is
kvm_is_cet_supported()rather than e.g.,kvm_is_cet_state_managed_by_xsave().+1, one of the big reasons
kvm_cpu_cap_has()came about was being KVM had a giant mess of one-off helpers.
I see, thanks!
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
In reply to Chao GaoQuoted 12 lines · Chao Gao
Quoted 11 lines · Weijiang
Quoted 11 lines
arch/x86/kvm/x86.c static void kvm_probe_msr_to_save(u32 msr_index) · line 7224
Quoted 9 lines
arch/x86/kvm/x86.c +5
-0@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ())shall we consider the case where IBT is supported while SS isn't (e.g., in L1 guest)?
Quoted 5 lines
Quoted 2 lines
Yes, but userspace should be able to access SHSTK MSRs even only IBT is exposed to guest so far as KVM can support SHSTK MSRs.
Why should userspace be allowed to access SHSTK MSRs in this case? L1 may not even enumerate SHSTK (qemu removes -shstk explicitly but keeps IBT), how KVM in L1 can allow its userspace to do that?
Hold on until host_initiated access is finalized.
Quoted 14 lines
Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 372
Quoted 3 lines
arch/x86/kvm/x86.h +3
-0+static inline bool kvm_is_cet_supported (void ) +{ +return (kvm_caps.supported_xss &CET_XSTATE_MASK ) ==CET_XSTATE_MASK ;why not just check if SHSTK or IBT is supported explicitly, i.e.,
return kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT);Quoted 6 lines
Quoted 2 lines
this is straightforward. And strictly speaking, the support of a feature and the support of managing a feature's state via XSAVE(S) are two different things.x
I think using exiting check implies two things:
1. Platform/KVM can support CET features.
2. CET user mode MSRs are backed by host thus are guaranteed to be valid. i.e., the purpose is to check guest CET dependencies instead of features' availability.
Quoted 5 lines
When KVM claims a feature is supported, it should ensure all its dependencies are met. that's, KVM's support of a feature also imples all dependencies are met. Function-wise, the two approaches have no difference. I just think checking KVM's support of SHSTK/IBT is more clear because the function name is
kvm_is_cet_supported()rather than e.g.,kvm_is_cet_state_managed_by_xsave().
OK, maybe the helper is not necessary anymore, I will remove it, thank you!
Quoted 14 lines
Quoted 14 lines
kvm_cpu_cap_has(X86_FEATURE_SHSTK)||kvm_cpu_cap_has(X86_FEATURE_IBT)only tells at least one of the CET features is supported by KVM.
Quoted 10 lines
then patch 16 has no need to do
(quoted diff) +8
-0+ /* + * If SHSTK and IBT are not available in KVM, clear CET user bit in + * kvm_caps.supported_xss so that kvm_is_cet__supported() returns + * false when called. + */ + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + kvm_caps.supported_xss &= ~CET_XSTATE_MASK;
Sean Christopherson
maintainerRe: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
In reply to Yang WeijiangQuoted 62 lines · Yang Weijiang
Add all CET MSRs including the synthesized
GUEST_SSPto report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches.MSR_IA32_U_CETandMSR_IA32_PL3_SSPare XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.When CET IBT/SHSTK are enumerated to guest, both user and supervisor modes should be supported for architechtural integrity, i.e., two modes are supported as both or neither.
Signed-off-by Yang Weijiang <[email protected]>--- arch/x86/include/uapi/asm/kvm_para.h | 1 + arch/x86/kvm/x86.c | 10 ++++++++++ arch/x86/kvm/x86.h | 10 ++++++++++ 3 files changed, 21 insertions(+)arch/x86/include/uapi/asm/kvm_para.h +1
-0@@ -58,6 +58,7 @@#define MSR_KVM_ASYNC_PF_INT 0x4b564d06#define MSR_KVM_ASYNC_PF_ACK 0x4b564d07#define MSR_KVM_MIGRATION_CONTROL 0x4b564d08 +#define MSR_KVM_GUEST_SSP 0x4b564d09struct kvm_steal_time {__u64 steal;arch/x86/kvm/x86.c +10
-0@@ -1463,6 +1463,9 @@ static const u32 msrs_to_save_base[] = {MSR_IA32_XFD ,MSR_IA32_XFD_ERR ,MSR_IA32_XSS , +MSR_IA32_U_CET ,MSR_IA32_S_CET , +MSR_IA32_PL0_SSP ,MSR_IA32_PL1_SSP ,MSR_IA32_PL2_SSP , + MSR_IA32_PL3_SSP, MSR_IA32_INT_SSP_TAB, MSR_KVM_GUEST_SSP, }; static const u32 msrs_to_save_pmu[] = {@@ -7214,6 +7217,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)if (!kvm_caps.supported_xss)return ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_is_cet_supported ()) +return ; +break ;default :break ; }arch/x86/kvm/x86.h +0
-0
arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 365
Quoted 4 lines
arch/x86/kvm/x86.h +1
-0@@ -362,6 +362,16 @@ static inline bool kvm_mpx_supported(void) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); } +#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER)
This is funky. As of this patch, KVM reports MSR_IA32_S_CET, a supervisor MSR, but does not require XFEATURE_MASK_CET_KERNEL. That eventually comes along with "KVM:x86: Enable guest CET supervisor xstate bit support", but as of this patch KVM is busted.
The whole cpuid_count() code in that patch shouldn't exist, so the easiest thing is to just fold the KVM_SUPPORTED_XSS and CET_XSTATE_MASK changes from that patch into this one.
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 23 lines · Sean Christopherson
Quoted 13 lines · Yang Weijiang
Add all CET MSRs including the synthesized
GUEST_SSPto report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches.MSR_IA32_U_CETandMSR_IA32_PL3_SSPare XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.[...]
}arch/x86/kvm/x86.h +0
-0arch/x86/kvm/x86.h static inline bool kvm_mpx_supported(void) · line 365
Quoted 4 lines
arch/x86/kvm/x86.h +1
-0@@ -362,6 +362,16 @@ static inline bool kvm_mpx_supported(void) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); } +#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER)This is funky. As of this patch, KVM reports
MSR_IA32_S_CET, a supervisor MSR, but does not requireXFEATURE_MASK_CET_KERNEL. That eventually comes along with "KVM:x86: Enable guest CET supervisor xstate bit support", but as of this patch KVM is busted.
Quoted 3 lines
The whole
cpuid_count()code in that patch shouldn't exist, so the easiest thing is to just fold theKVM_SUPPORTED_XSSandCET_XSTATE_MASKchanges from that patch into this one.
I screwed it up when tried to make it clearer :-/
Will do it, thanks!
Paolo Bonzini
maintainerRe: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
In reply to Yang WeijiangQuoted 5 lines · Yang Weijiang
Add all CET MSRs including the synthesized
GUEST_SSPto report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches.MSR_IA32_U_CETandMSR_IA32_PL3_SSPare XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.
MSR_KVM_GUEST_SSP -> MSR_KVM_SSP
Also please add a comment,
/*
* 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.
*/
Paolo
Re: [PATCH v5 08/19] KVM:x86: Report KVM supported CET MSRs as to-be-saved
Quoted 11 lines · Paolo Bonzini
Quoted 5 lines · Yang Weijiang
Add all CET MSRs including the synthesized
GUEST_SSPto report list. PL{0,1,2}_SSP are independent to host XSAVE management with later patches.MSR_IA32_U_CETandMSR_IA32_PL3_SSPare XSAVE-managed on host side. MSR_IA32_S_CET/MSR_IA32_INT_SSP_TAB/MSR_KVM_GUEST_SSP are not XSAVE-managed.
MSR_KVM_GUEST_SSP->MSR_KVM_SSPAlso please add a comment,
Quoted 8 lines
/*
* 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 theGUEST_SSP
* field of the VMCS.
*/
OK, will take it, thanks!
Quoted 2 lines
Paolo
PATCH v5 9/19 KVM:x86: Make guest supervisor states as non-XSAVE managed
In reply to Yang WeijiangSave guest CET supervisor states, i.e.,PL{0,1,2}_SSP, when vCPU is exiting to userspace or being preempted. Reload the MSRs before vm-entry.
Embeded the helpers in {vmx,svm}_prepare_switch_to_guest() and vmx_prepare_switch_to_host()/svm_prepare_host_switch() to employ existing guest state management and optimize the invocation of the helpers.
Enabling CET supervisor state management in KVM due to:
-Introducing unnecessary XSAVE operation when switch to non-vCPU
userspace within current FPU framework.
-Forcing allocating additional space for CET supervisor states in
each thread context regardless whether it's vCPU thread or not.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.h | 11 +++++++++++ arch/x86/kvm/svm/svm.c | 2 ++ arch/x86/kvm/vmx/vmx.c | 2 ++ arch/x86/kvm/x86.c | 27 +++++++++++++++++++++++++++ arch/x86/kvm/x86.h | 3 +++ 6 files changed, 46 insertions(+)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -805,6 +805,7 @@ struct kvm_vcpu_arch {u64 xcr0;u64 guest_supported_xcr0;u64 guest_supported_xss; +u64 cet_s_ssp[3 ];struct kvm_pio_request pio;void *pio_data;
arch/x86/kvm/cpuid.h +11 -0
@@ -232,4 +232,15 @@ static __always_inline bool guest_pv_has(struct kvm_vcpu *vcpu, return vcpu->arch.pv_cpuid.features & (1u << kvm_feature); } +/* +* FIXME: When the "KVM-governed" enabling patchset is merge, rebase this +* series on top of that and add a new patch for CET to replace this helper +* with the qualified one. +*/ +static __always_inline bool guest_can_use(struct kvm_vcpu *vcpu, +unsigned int feature) +{ +return kvm_cpu_cap_has (feature) &&guest_cpuid_has (vcpu, feature); +} +#endif
arch/x86/kvm/svm/svm.c +2 -0
@@ -1515,11 +1515,13 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)if (likely (tsc_aux_uret_slot >=0 ))kvm_set_user_return_msr (tsc_aux_uret_slot, svm->tsc_aux,-1ull ); +reload_cet_supervisor_ssp (vcpu); svm->guest_state_loaded = true; }static void svm_prepare_host_switch (struct kvm_vcpu *vcpu) { +save_cet_supervisor_ssp (vcpu);to_svm (vcpu)->guest_state_loaded = false; }
arch/x86/kvm/vmx/vmx.c +2 -0
@@ -1323,6 +1323,7 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu) gs_base =segment_base (gs_sel);#endif +reload_cet_supervisor_ssp (vcpu);vmx_set_host_fs_gs (host_state, fs_sel, gs_sel, fs_base, gs_base); vmx->guest_state_loaded = true; }
@@ -1362,6 +1363,7 @@ static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx)wrmsrl (MSR_KERNEL_GS_BASE , vmx->msr_host_kernel_gs_base);#endif load_fixmap_gdt (raw_smp_processor_id ()); +save_cet_supervisor_ssp (&vmx->vcpu); vmx->guest_state_loaded = false; vmx->guest_uret_msrs_loaded = false; }
arch/x86/kvm/x86.c +27 -0
@@ -11128,6 +11128,31 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)trace_kvm_fpu (0 ); } +void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu) +{ +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) { +rdmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]); +rdmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]); +rdmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]); +/* +* Omit reset to host PL{1,2}_SSP because Linux will never use +* these MSRs. +*/ +wrmsrl (MSR_IA32_PL0_SSP ,0 ); + } +} +EXPORT_SYMBOL_GPL (save_cet_supervisor_ssp); + +void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu) +{ +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) { +wrmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]); +wrmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]); +wrmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]); + } +} +EXPORT_SYMBOL_GPL (reload_cet_supervisor_ssp); +int kvm_arch_vcpu_ioctl_run (struct kvm_vcpu *vcpu) {struct kvm_queued_exception *ex = &vcpu->arch.exception;
@@ -12133,6 +12158,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.cr3 =0 ;kvm_register_mark_dirty (vcpu,VCPU_EXREG_CR3 ); +memset (vcpu->arch.cet_s_ssp,0 ,sizeof (vcpu->arch.cet_s_ssp));/* * CR0.CD/NW are set on RESET, preserved on INIT. Note, some versions
@@ -12313,6 +12339,7 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) pmu->need_cleanup = true;kvm_make_request (KVM_REQ_PMU , vcpu); } +static_call (kvm_x86_sched_in)(vcpu, cpu); }
arch/x86/kvm/x86.h +3 -0
@@ -501,6 +501,9 @@ static inline void kvm_machine_check(void)void kvm_load_guest_xsave_state (struct kvm_vcpu *vcpu);void kvm_load_host_xsave_state (struct kvm_vcpu *vcpu); +void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu); +void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu); +int kvm_spec_ctrl_test_value (u64 value);bool __kvm_is_valid_cr4 (struct kvm_vcpu *vcpu,unsigned long cr4); int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r,
Signature · 1 line
2.27.0
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
arch/x86/kvm/x86.c static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) · line 11141
Quoted 12 lines · Yang Weijiang
arch/x86/kvm/x86.c +11
-0+void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu) +{ +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) { +rdmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]); +rdmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]); +rdmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]); +/* +* Omit reset to host PL{1,2}_SSP because Linux will never use +* these MSRs. +*/ +wrmsrl (MSR_IA32_PL0_SSP ,0 );
This wrmsrl() can be dropped because host doesn't support SSS yet.
arch/x86/kvm/x86.c static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) · line 11148
Quoted 7 lines
arch/x86/kvm/x86.c +7
-0+ } +} +EXPORT_SYMBOL_GPL (save_cet_supervisor_ssp); + +void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu) +{ +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) {
ditto
Quoted 19 lines
arch/x86/kvm/x86.c +7
-0+wrmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]); +wrmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]); +wrmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]); + } +} +EXPORT_SYMBOL_GPL (reload_cet_supervisor_ssp); +int
kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu){ struct kvm_queued_exception *ex = &vcpu->arch.exception;arch/x86/kvm/x86.c +1
-0@@ -12133,6 +12158,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.cr3 =0 ;kvm_register_mark_dirty (vcpu,VCPU_EXREG_CR3 ); +memset (vcpu->arch.cet_s_ssp,0 ,sizeof (vcpu->arch.cet_s_ssp));/* * CR0.CD/NW are set on RESET, preserved on INIT. Note, some versions
arch/x86/kvm/x86.c void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) · line 12342
Quoted 4 lines
arch/x86/kvm/x86.c +1
-0@@ -12313,6 +12339,7 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) pmu->need_cleanup = true;kvm_make_request (KVM_REQ_PMU , vcpu); } +
remove the stray newline.
arch/x86/kvm/x86.h static inline void kvm_machine_check(void) · line 505
Quoted 13 lines
arch/x86/kvm/x86.c +0
-0static_call (kvm_x86_sched_in)(vcpu, cpu); }arch/x86/kvm/x86.h +2
-0@@ -501,6 +501,9 @@ static inline void kvm_machine_check(void)void kvm_load_guest_xsave_state (struct kvm_vcpu *vcpu);void kvm_load_host_xsave_state (struct kvm_vcpu *vcpu); +void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu); +void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu);
nit: please add kvm_ prefix to the function names because they are exposed to other modules. "cet" in the names is a little redundant. I slightly prefer kvm_save/load_guest_supervisor_ssp()
Overall, this patch looks good to me. Hence,
Quoted 7 lines
arch/x86/kvm/x86.h +1
-0+int kvm_spec_ctrl_test_value (u64 value);bool __kvm_is_valid_cr4 (struct kvm_vcpu *vcpu,unsigned long cr4); int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r,Signature · 1 line
2.27.0
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 13 lines · Chao Gao
arch/x86/kvm/x86.c static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) · line 11141
Quoted 11 lines · Yang Weijiang
arch/x86/kvm/x86.c +11
-0+void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu) +{ +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) { +rdmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]); +rdmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]); +rdmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]); +/* +* Omit reset to host PL{1,2}_SSP because Linux will never use +* these MSRs. +*/ +wrmsrl (MSR_IA32_PL0_SSP ,0 );This
wrmsrl()can be dropped because host doesn't support SSS yet.
Frankly speaking, I want to remove this line of code. But that would mess up the MSR on host side, i.e., from host perspective, the MSRs could be filled with garbage data, and looks awful. Anyway, I can remove it.
Quoted 8 lines
arch/x86/kvm/x86.c static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) · line 11148
Quoted 7 lines
arch/x86/kvm/x86.c +7
-0+ } +} +EXPORT_SYMBOL_GPL (save_cet_supervisor_ssp); + +void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu) +{ +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) {ditto
Below is to reload guest supervisor SSPs instead of resetting host ones.
Quoted 16 lines
Quoted 16 lines
arch/x86/kvm/x86.c +7
-0+wrmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]); +wrmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]); +wrmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]); + } +} +EXPORT_SYMBOL_GPL (reload_cet_supervisor_ssp); +int
kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu){ struct kvm_queued_exception *ex = &vcpu->arch.exception;arch/x86/kvm/x86.c +1
-0@@ -12133,6 +12158,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.cr3 =0 ;kvm_register_mark_dirty (vcpu,VCPU_EXREG_CR3 ); +memset (vcpu->arch.cet_s_ssp,0 ,sizeof (vcpu->arch.cet_s_ssp));
Quoted 8 lines
arch/x86/kvm/x86.c void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) · line 12342
Quoted 7 lines
arch/x86/kvm/x86.c +1
-0/* * CR0.CD/NW are set on RESET, preserved on INIT. Note, some versions @@ -12313,6 +12339,7 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) pmu->need_cleanup = true;kvm_make_request (KVM_REQ_PMU , vcpu); } +remove the stray newline.
OK.
Quoted 9 lines
Quoted 9 lines
arch/x86/kvm/x86.c +0
-0static_call (kvm_x86_sched_in)(vcpu, cpu); }arch/x86/kvm/x86.h +0
-0@@ -501,6 +501,9 @@ static inline void kvm_machine_check(void)
Quoted 7 lines
arch/x86/kvm/x86.h static inline void kvm_machine_check(void) · line 505
Quoted 4 lines
arch/x86/kvm/x86.h +2
-0void kvm_load_guest_xsave_state (struct kvm_vcpu *vcpu);void kvm_load_host_xsave_state (struct kvm_vcpu *vcpu); +void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu); +void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu);nit: please add
kvm_prefix to the function names because they are exposed to other modules. "cet" in the names is a little redundant. I slightly prefer kvm_save/load_guest_supervisor_ssp()
Sure, actually I wanted to add the prefix, but at a second thought, the functions with kvm_ are mostly generic functions in KVM, but here are the CET specific functions.
Quoted 4 lines
Overall, this patch looks good to me. Hence,
Reviewed-by Chao Gao <[email protected]>
Thanks a lot for the review!
Quoted 7 lines
Quoted 7 lines
arch/x86/kvm/x86.h +1
-0+int kvm_spec_ctrl_test_value (u64 value);bool __kvm_is_valid_cr4 (struct kvm_vcpu *vcpu,unsigned long cr4); int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r,Signature · 1 line
2.27.0
Sean Christopherson
maintainerRe: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 5 lines · Weijiang Yang
Quoted 4 lines · Chao Gao
Review
Quoted 3 lines · Yang Weijiang
(quoted diff) +3
-0+void save_cet_supervisor_ssp(struct kvm_vcpu *vcpu) +{ + if (unlikely(guest_can_use(vcpu, X86_FEATURE_SHSTK))) {
Drop the unlikely, KVM should not speculate on the guest configuration or underlying hardware.
Quoted 9 lines
Quoted 9 lines
Review
Quoted 8 lines
(quoted diff) +8
-0+ rdmsrl(MSR_IA32_PL0_SSP, vcpu->arch.cet_s_ssp[0]); + rdmsrl(MSR_IA32_PL1_SSP, vcpu->arch.cet_s_ssp[1]); + rdmsrl(MSR_IA32_PL2_SSP, vcpu->arch.cet_s_ssp[2]); + /* + * Omit reset to host PL{1,2}_SSP because Linux will never use + * these MSRs. + */ + wrmsrl(MSR_IA32_PL0_SSP, 0);This
wrmsrl()can be dropped because host doesn't support SSS yet.
Quoted 3 lines
Frankly speaking, I want to remove this line of code. But that would mess up the MSR on host side, i.e., from host perspective, the MSRs could be filled with garbage data, and looks awful.
So? :-)
That's the case for all of the MSRs that KVM defers restoring until the host returns to userspace, i.e. running in the host with bogus values in hardware is nothing new.
And as I mentioned in the other thread regarding the assertion that SSS isn't enabled in the host, sanitizing hardware values for something that should never be consumed is a fools errand.
Quoted 1 line
Anyway, I can remove it.
Yes please, though it may be a moot point.
Quoted 8 lines
Quoted 8 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ } +} +EXPORT_SYMBOL_GPL(save_cet_supervisor_ssp); + +void reload_cet_supervisor_ssp(struct kvm_vcpu *vcpu) +{ + if (unlikely(guest_can_use(vcpu, X86_FEATURE_SHSTK))) {ditto
Quoted 4 lines
Below is to reload guest supervisor SSPs instead of resetting host ones.
Quoted 3 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ wrmsrl(MSR_IA32_PL0_SSP, vcpu->arch.cet_s_ssp[0]); + wrmsrl(MSR_IA32_PL1_SSP, vcpu->arch.cet_s_ssp[1]); + wrmsrl(MSR_IA32_PL2_SSP, vcpu->arch.cet_s_ssp[2]);
Pulling back in the justification from v3:
the Pros:
- Super easy to implement for KVM.
- Automatically avoids saving and restoring this data when the vmexit is handled within KVM.
the Cons:
- Unnecessarily restores XFEATURE_CET_KERNEL when switching to non-KVM task's userspace.
- Forces allocating space for this state on all tasks, whether or not they use KVM, and with likely zero users today and the near future.
- Complicates the FPU optimization thinking by including things that can have no affect on userspace in the FPU
IMO the pros far outweigh the cons. 3x RDMSR and 3x WRMSR when loading host/guest state is non-trivial overhead. That can be mitigated, e.g. by utilizing the user return MSR framework, but it's still unpalatable. It's unlikely many guests will SSS in the *near* future, but I don't want to end up with code that performs poorly in the future and needs to be rewritten.
Especially because another big negative is that not utilizing XSTATE bleeds into KVM's ABI. Userspace has to be told to manually save+restore MSRs instead of just letting KVM_{G,S}ET_XSAVE handle the state. And that will create a bit of a snafu if Linux does gain support for SSS.
On the other hand, the extra per-task memory is all of 24 bytes. AFAICT, there's literally zero effect on guest XSTATE allocations because those are vmalloc'd and thus rounded up to PAGE_SIZE, i.e. the next 4KiB. And XSTATE needs to be 64-byte aligned, so the 24 bytes is only actually meaningful if the current size is within 24 bytes of the next cahce line. And the "current" size is variable depending on which features are present and enabled, i.e. it's a roll of the dice as to whether or not using XSTATE for supervisor CET would actually increase memory usage. And _if_ it does increase memory consumption, I have a very hard time believing an extra 64 bytes in the worst case scenario is a dealbreaker.
If the performance is a concern, i.e. we don't want to eat saving/restoring the MSRs when switching to/from host FPU context, then I *think* that's simply a matter of keeping guest state resident when loading non-guest FPU state.
arch/x86/kernel/fpu/core.c +10 -0
@@ -167,6 +167,16 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask)*/ xfd_update_state (fpstate); +/* +* Leave supervisor CET state as-is when loading host state +* (kernel or userspace). Supervisor CET state is managed via +* XSTATE for KVM guests, but the host never consumes said +* state (doesn't support supervisor shadow stacks), i.e. it's +* safe to keep guest state loaded into hardware. +*/ +if (!fpstate->is_guest) + mask &= ~XFEATURE_MASK_CET_KERNEL ; +/* * Restoring state always needs to modify all features * which are in @mask even if the current task cannot use
So unless I'm missing something, NAK to this approach, at least not without trying the kernel FPU approach, i.e. I want somelike like to PeterZ or tglx to actually full on NAK the kernel approach before we consider shoving a hack into KVM.
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 3 lines · Sean Christopherson
So unless I'm missing something, NAK to this approach, at least not without trying the kernel FPU approach, i.e. I want somelike like to PeterZ or tglx to actually full on NAK the kernel approach before we consider shoving a hack into KVM.
Not having fully followed things (I'll go read up), SSS is blocked on FRED. But it is definitely on the books to do SSS once FRED is go.
So if the approach as chosen gets in the way of host kernel SS management, that is a wee problem.
Paolo Bonzini
maintainerRe: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
In reply to Sean ChristophersonQuoted 5 lines · Sean Christopherson
Quoted 3 lines
Quoted 3 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+void save_cet_supervisor_ssp(struct kvm_vcpu *vcpu) +{ + if (unlikely(guest_can_use(vcpu, X86_FEATURE_SHSTK))) {Drop the unlikely, KVM should not speculate on the guest configuration or underlying hardware.
In general unlikely() can still be a good idea if you have a fast path vs. a slow path; the extra cost of a branch will be much more visible on the fast path. That said the compiler should already be doing that.
Quoted 5 lines
the Pros:
- Super easy to implement for KVM.
- Automatically avoids saving and restoring this data when the vmexit is handled within KVM.
Quoted 7 lines
the Cons:
- Unnecessarily restoresXFEATURE_CET_KERNELwhen switching to non-KVM task's userspace.
- Forces allocating space for this state on all tasks, whether or not they use KVM, and with likely zero users today and the near future.
- Complicates the FPU optimization thinking by including things that can have no affect on userspace in the FPU
I'm not sure if Linux will ever use XFEATURE_CET_KERNEL. Linux does not use MSR_IA32_PL{1,2}_SSP; MSR_IA32_PL0_SSP probably would be per-CPU but it is not used while in ring 0 (except for SETSSBSY) and the restore can be delayed until return to userspace. It is not unlike the SYSCALL MSRs.
So I would treat the bit similar to the dynamic features even if it's not guarded by XFD, for example
#define XFEATURE_MASK_USER_DYNAMIC XFEATURE_MASK_XTILE_DATA #define XFEATURE_MASK_USER_OPTIONAL \
(XFEATURE_MASK_DYNAMIC | XFEATURE_MASK_CET_KERNEL)
where XFEATURE_MASK_USER_DYNAMIC is used for xfd-related tasks but everything else uses XFEATURE_MASK_USER_OPTIONAL.
Then you'd enable the feature by hand when allocating the guest fpstate.
Quoted 4 lines
Especially because another big negative is that not utilizing XSTATE bleeds into KVM's ABI. Userspace has to be told to manually save+restore MSRs instead of just letting KVM_{G,S}ET_XSAVE handle the state. And that will create a bit of a snafu if Linux does gain support for SSS.
I don't think this matters, we don't have any MSRs in KVM_GET/SET_XSAVE and in fact we can't even add them since the uABI uses the non-compacted format. MSRs should be retrieved and set via KVM_GET/SET_MSR and userspace will learn about the index automatically via KVM_GET_MSR_INDEX_LIST.
Paolo
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 8 lines · Paolo Bonzini
Quoted 5 lines · Sean Christopherson
Quoted 3 lines
Quoted 3 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+void save_cet_supervisor_ssp(struct kvm_vcpu *vcpu) +{ + if (unlikely(guest_can_use(vcpu, X86_FEATURE_SHSTK))) {Drop the unlikely, KVM should not speculate on the guest configuration or underlying hardware.
In general
unlikely()can still be a good idea if you have a fast path vs. a slow path; the extra cost of a branch will be much more visible on the fast path. That said the compiler should already be doing that.
This is my original assumption that compiler can help do some level of optimization with the modifier. Thanks!
Quoted 17 lines
Quoted 5 lines
the Pros:
- Super easy to implement for KVM.
- Automatically avoids saving and restoring this data when the vmexit is handled within KVM.Quoted 7 lines
the Cons:
- Unnecessarily restoresXFEATURE_CET_KERNELwhen switching to non-KVM task's userspace.
- Forces allocating space for this state on all tasks, whether or not they use KVM, and with likely zero users today and the near future.
- Complicates the FPU optimization thinking by including things that can have no affect on userspace in the FPUI'm not sure if Linux will ever use XFEATURE_CET_KERNEL. Linux does not use MSR_IA32_PL{1,2}_SSP;
MSR_IA32_PL0_SSPprobably would be per-CPU but it is not used while in ring 0 (except for SETSSBSY) and the restore can be delayed until return to userspace. It is not unlike the SYSCALL MSRs.So I would treat the bit similar to the dynamic features even if it's not guarded by XFD, for example
Quoted 7 lines
#define
XFEATURE_MASK_USER_DYNAMICXFEATURE_MASK_XTILE_DATA#defineXFEATURE_MASK_USER_OPTIONAL\
(XFEATURE_MASK_DYNAMIC |XFEATURE_MASK_CET_KERNEL)where
XFEATURE_MASK_USER_DYNAMICis used for xfd-related tasks but everything else usesXFEATURE_MASK_USER_OPTIONAL.Then you'd enable the feature by hand when allocating the guest fpstate.
Yes, this is another way to optimize the kernel-managed solution, I'll investigate it, thanks!
Quoted 8 lines
Quoted 4 lines
Especially because another big negative is that not utilizing XSTATE bleeds into KVM's ABI. Userspace has to be told to manually save+restore MSRs instead of just letting KVM_{G,S}ET_XSAVE handle the state. And that will create a bit of a snafu if Linux does gain support for SSS.
I don't think this matters, we don't have any MSRs in KVM_GET/SET_XSAVE and in fact we can't even add them since the uABI uses the non-compacted format. MSRs should be retrieved and set via KVM_GET/SET_MSR and userspace will learn about the index automatically via
KVM_GET_MSR_INDEX_LIST. Paolo
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
In reply to Sean ChristophersonQuoted 8 lines · Sean Christopherson
Quoted 5 lines · Weijiang Yang
Quoted 4 lines · Chao Gao
Review
Quoted 3 lines · Yang Weijiang
(quoted diff) +3
-0+void save_cet_supervisor_ssp(struct kvm_vcpu *vcpu) +{ + if (unlikely(guest_can_use(vcpu, X86_FEATURE_SHSTK))) {Drop the unlikely, KVM should not speculate on the guest configuration or underlying hardware.
OK.
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Review
Quoted 8 lines
(quoted diff) +8
-0+ rdmsrl(MSR_IA32_PL0_SSP, vcpu->arch.cet_s_ssp[0]); + rdmsrl(MSR_IA32_PL1_SSP, vcpu->arch.cet_s_ssp[1]); + rdmsrl(MSR_IA32_PL2_SSP, vcpu->arch.cet_s_ssp[2]); + /* + * Omit reset to host PL{1,2}_SSP because Linux will never use + * these MSRs. + */ + wrmsrl(MSR_IA32_PL0_SSP, 0);This
wrmsrl()can be dropped because host doesn't support SSS yet.
Quoted 8 lines
Quoted 3 lines
Frankly speaking, I want to remove this line of code. But that would mess up the MSR on host side, i.e., from host perspective, the MSRs could be filled with garbage data, and looks awful.
So? :-)
That's the case for all of the MSRs that KVM defers restoring until the host returns to userspace, i.e. running in the host with bogus values in hardware is nothing new.
CET PL{0,1,2}_SSP are a bit different from other MSRs, the latter will be reloaded with host values at some points after VM-Exit, but the CET MSRs are "leaked" and never be handled anywhere.
Quoted 82 lines
And as I mentioned in the other thread regarding the assertion that SSS isn't enabled in the host, sanitizing hardware values for something that should never be consumed is a fools errand.
Quoted 1 line
Anyway, I can remove it.
Yes please, though it may be a moot point.
Quoted 8 lines
Quoted 8 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ } +} +EXPORT_SYMBOL_GPL(save_cet_supervisor_ssp); + +void reload_cet_supervisor_ssp(struct kvm_vcpu *vcpu) +{ + if (unlikely(guest_can_use(vcpu, X86_FEATURE_SHSTK))) {ditto
Quoted 4 lines
Below is to reload guest supervisor SSPs instead of resetting host ones.
Quoted 3 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ wrmsrl(MSR_IA32_PL0_SSP, vcpu->arch.cet_s_ssp[0]); + wrmsrl(MSR_IA32_PL1_SSP, vcpu->arch.cet_s_ssp[1]); + wrmsrl(MSR_IA32_PL2_SSP, vcpu->arch.cet_s_ssp[2]);Pulling back in the justification from v3:
the Pros:
- Super easy to implement for KVM.
- Automatically avoids saving and restoring this data when the vmexit is handled within KVM.the Cons:
- Unnecessarily restoresXFEATURE_CET_KERNELwhen switching to non-KVM task's userspace.
- Forces allocating space for this state on all tasks, whether or not they use KVM, and with likely zero users today and the near future.
- Complicates the FPU optimization thinking by including things that can have no affect on userspace in the FPUIMO the pros far outweigh the cons. 3x RDMSR and 3x WRMSR when loading host/guest state is non-trivial overhead. That can be mitigated, e.g. by utilizing the user return MSR framework, but it's still unpalatable. It's unlikely many guests will SSS in the *near* future, but I don't want to end up with code that performs poorly in the future and needs to be rewritten.
Especially because another big negative is that not utilizing XSTATE bleeds into KVM's ABI. Userspace has to be told to manually save+restore MSRs instead of just letting KVM_{G,S}ET_XSAVE handle the state. And that will create a bit of a snafu if Linux does gain support for SSS.On the other hand, the extra per-task memory is all of 24 bytes. AFAICT, there's literally zero effect on guest XSTATE allocations because those are vmalloc'd and thus rounded up to
PAGE_SIZE, i.e. the next 4KiB. And XSTATE needs to be 64-byte aligned, so the 24 bytes is only actually meaningful if the current size is within 24 bytes of the next cahce line. And the "current" size is variable depending on which features are present and enabled, i.e. it's a roll of the dice as to whether or not using XSTATE for supervisor CET would actually increase memory usage. And _if_ it does increase memory consumption, I have a very hard time believing an extra 64 bytes in the worst case scenario is a dealbreaker.If the performance is a concern, i.e. we don't want to eat saving/restoring the MSRs when switching to/from host FPU context, then I *think* that's simply a matter of keeping guest state resident when loading non-guest FPU state.
arch/x86/kernel/fpu/core.c +10
-0@@ -167,6 +167,16 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask)*/ xfd_update_state (fpstate); +/* +* Leave supervisor CET state as-is when loading host state +* (kernel or userspace). Supervisor CET state is managed via +* XSTATE for KVM guests, but the host never consumes said +* state (doesn't support supervisor shadow stacks), i.e. it's +* safe to keep guest state loaded into hardware. +*/ +if (!fpstate->is_guest) + mask &= ~XFEATURE_MASK_CET_KERNEL ; +/* * Restoring state always needs to modify all features * which are in @mask even if the current task cannot use
Quoted 3 lines
So unless I'm missing something, NAK to this approach, at least not without trying the kernel FPU approach, i.e. I want somelike like to PeterZ or tglx to actually full on NAK the kernel approach before we consider shoving a hack into KVM.
I will discuss it with the stakeholders, and get back to this when it's clear. Thanks!
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
In reply to Sean ChristophersonHi, Dave, Thomas and Peter,
I would like to connect you to this discussion loop about CET supervisor states support in kernel so that you may directly talk to KVM maintainers, thanks!
The discussion background/problem/solution as below:
Background:
When KVM enumerates shadow stack support for guest in CPUID(0x7, 0).ECX[bit7], architecturally it claims both SS user and supervisor mode are supported. Although the latter is not supported in Linux, but in virtualization world, the guest OS could be non-Linux system, so KVM supervisor state support is necessary in this case. Two solutions are on the table:
1) Enable CET supervisor support in Linux kernel like user mode support.
2) Enable support in KVM domain.
Problem:
The Pros/Cons for each solution(my individual thoughts):
In kernel solution:
Pros:
- Avoid saving/restoring 3 supervisor MSRs(PL{0,1,2}_SSP) at vCPU execution path.
- Easy for KVM to manage guest CET xstate bits for guest.
Cons:
- Unnecessary supervisor state xsaves/xrstors operation for non-vCPU thread.
- Potentially extra storage space(24 bytes) for thread context.
KVM solution:
Pros:
- Not touch current kernel FPU management framework and logic.
- No extra space and operation for non-vCPU thread.
Cons:
- Manually saving/restoring 3 supervisor MSRs is a performance burden to KVM.
- It looks more like a hack method for KVM, and some handling logic seems a bit awkward.
KVM maintainers request it supported in kernel instead of KVM to make things streamlined.
We'd like to hear your voice of in kernel solution, favor vs. objection? Any important points we omitted?
Appreciated!
Solution:
Below is the supervisor state enabling patch in kernel, not include Sean's suggestion below.
=====================================================================
From 53f9890c76e4163a0fead3afe198d0c17136120e Mon Sep 17 00:00:00 2001
From: Yang Weijiang <[email protected]>
Date: Thu, 10 Aug 2023 00:10:55 -0400
Subject: [RFC PATCH] x86: fpu: Enable CET supervisor state support
Enable CET supervisor state support within current FPU states management framework. CET shadow stack feature is enabled with CPUID(0x7,0).ECX[bit7], if the bit is set, archchtectually both user and supervisor SHSTK should be supported, i.e., when KVM enumerates the feature bit to guest, it claims both modes are supported by the VMM.
The user mode SHSTK XSAVE states comprise of IA32_{U_CET,PL3_SSP}, and supervisor mode states inlude IA32_PL{0,1,2}_SSP. The xstate support for the former is enclosed in native user mode shadow stack series, but the latter is not supported yet.
KVM is going to support guest shadow stack which means guest's supervisor shadow stack states should also be well managed by VMM.
To make KVM fully support guest shadow stack states, there're at least two approaches, one is to enable supervisor xstate bit in kernel, which is straightforward and can fit well in all cases. The alternative is to enable the support within KVM domain and manually save/restore the states per vCPU thread, i.e., introduce addtional WRMSR/RDMSR at vCPU execution path.
This patch doesn't optimize CET supervisor state management, just follow the implementation of user mode state support.
---
arch/x86/include/asm/fpu/types.h | 14 ++++++++++++-- arch/x86/include/asm/fpu/xstate.h | 6 +++--- arch/x86/kernel/fpu/xstate.c | 6 +++++-
3 files changed, 20 insertions(+), 6 deletions(-)
arch/x86/include/asm/fpu/types.h +0 -0
@@ -116,7 +116,7 @@ enum xfeature {
XFEATURE_PKRU,
XFEATURE_PASID,
XFEATURE_CET_USER,
- XFEATURE_CET_KERNEL_UNUSED,
+ XFEATURE_CET_KERNEL,
XFEATURE_RSRVD_COMP_13,
XFEATURE_RSRVD_COMP_14,
XFEATURE_LBR,
@@ -139,7 +139,7 @@ enum xfeature {
#define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU) #define XFEATURE_MASK_PASID (1 << XFEATURE_PASID) #define XFEATURE_MASK_CET_USER (1 << XFEATURE_CET_USER) -#define XFEATURE_MASK_CET_KERNEL (1 << XFEATURE_CET_KERNEL_UNUSED) +#define XFEATURE_MASK_CET_KERNEL (1 << XFEATURE_CET_KERNEL) #define XFEATURE_MASK_LBR (1 << XFEATURE_LBR) #define XFEATURE_MASK_XTILE_CFG (1 << XFEATURE_XTILE_CFG) #define XFEATURE_MASK_XTILE_DATA (1 << XFEATURE_XTILE_DATA) @@ -264,6 +264,16 @@ struct cet_user_state {
u64 user_ssp;
};
+/*
+ * State component 12 is Control-flow Enforcement supervisor states
+ */
+struct cet_supervisor_state {
+ /* supervisor ssp pointers */
+ u64 pl0_ssp;
+ u64 pl1_ssp;
+ u64 pl2_ssp;
+};
+
/*
* State component 15: Architectural LBR configuration state.
* The size of Arch LBR state depends on the number of LBRs (lbr_depth).
arch/x86/include/asm/fpu/xstate.h +0 -0
@@ -51,7 +51,8 @@
/* All currently supported supervisor features */
#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID | \
- XFEATURE_MASK_CET_USER) + XFEATURE_MASK_CET_USER | \
+ XFEATURE_MASK_CET_KERNEL)
/*
* A supervisor state component may not always contain valuable information, @@ -78,8 +79,7 @@
* Unsupported supervisor features. When a supervisor feature in this mask is
* supported in the future, move it to the supported supervisor feature mask. */
-#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT | \
- XFEATURE_MASK_CET_KERNEL)
+#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT)
/* All supervisor states including supported and unsupported states. */ #define XFEATURE_MASK_SUPERVISOR_ALL (XFEATURE_MASK_SUPERVISOR_SUPPORTED | \
arch/x86/kernel/fpu/xstate.c +0 -0
@@ -51,7 +51,7 @@ static const char *xfeature_names[] =
"Protection Keys User registers",
"PASID state",
"Control-flow User registers",
- "Control-flow Kernel registers (unused)",
+ "Control-flow Kernel registers",
"unknown xstate feature",
"unknown xstate feature",
"unknown xstate feature",
@@ -74,6 +74,7 @@ static unsigned short xsave_cpuid_features[] __initdata = { [XFEATURE_PKRU] = X86_FEATURE_PKU, [XFEATURE_PASID] = X86_FEATURE_ENQCMD, [XFEATURE_CET_USER] = X86_FEATURE_SHSTK,
+ [XFEATURE_CET_KERNEL] = X86_FEATURE_SHSTK, [XFEATURE_XTILE_CFG] = X86_FEATURE_AMX_TILE, [XFEATURE_XTILE_DATA] = X86_FEATURE_AMX_TILE, };
@@ -278,6 +279,7 @@ static void __init print_xstate_features(void) print_xstate_feature(XFEATURE_MASK_PKRU); print_xstate_feature(XFEATURE_MASK_PASID); print_xstate_feature(XFEATURE_MASK_CET_USER);
+ print_xstate_feature(XFEATURE_MASK_CET_KERNEL); print_xstate_feature(XFEATURE_MASK_XTILE_CFG); print_xstate_feature(XFEATURE_MASK_XTILE_DATA);
}
@@ -347,6 +349,7 @@ static __init void os_xrstor_booting(struct xregs_state *xstate) XFEATURE_MASK_BNDCSR | \
XFEATURE_MASK_PASID | \
XFEATURE_MASK_CET_USER | \
+ XFEATURE_MASK_CET_KERNEL | \
XFEATURE_MASK_XTILE)
/*
@@ -547,6 +550,7 @@ static bool __init check_xstate_against_struct(int nr) case XFEATURE_PASID: return XCHECK_SZ(sz, nr, struct ia32_pasid_state); case XFEATURE_XTILE_CFG: return XCHECK_SZ(sz, nr, struct xtile_cfg); case XFEATURE_CET_USER: return XCHECK_SZ(sz, nr, struct cet_user_state); + case XFEATURE_CET_KERNEL: return XCHECK_SZ(sz, nr, struct cet_supervisor_state); case XFEATURE_XTILE_DATA: check_xtile_data_against_struct(sz); return true; default:
XSTATE_WARN_ON(1, "No structure for xstate: %d\n", nr);
--
2.27.0
Quoted 67 lines · Sean Christopherson
[...]
Pulling back in the justification from v3:the Pros:
- Super easy to implement for KVM.
- Automatically avoids saving and restoring this data when the vmexit is handled within KVM.the Cons:
- Unnecessarily restoresXFEATURE_CET_KERNELwhen switching to non-KVM task's userspace.
- Forces allocating space for this state on all tasks, whether or not they use KVM, and with likely zero users today and the near future.
- Complicates the FPU optimization thinking by including things that can have no affect on userspace in the FPUIMO the pros far outweigh the cons. 3x RDMSR and 3x WRMSR when loading host/guest state is non-trivial overhead. That can be mitigated, e.g. by utilizing the user return MSR framework, but it's still unpalatable. It's unlikely many guests will SSS in the *near* future, but I don't want to end up with code that performs poorly in the future and needs to be rewritten.
Especially because another big negative is that not utilizing XSTATE bleeds into KVM's ABI. Userspace has to be told to manually save+restore MSRs instead of just letting KVM_{G,S}ET_XSAVE handle the state. And that will create a bit of a snafu if Linux does gain support for SSS.
On the other hand, the extra per-task memory is all of 24 bytes. AFAICT, there's literally zero effect on guest XSTATE allocations because those are vmalloc'd and thus rounded up to
PAGE_SIZE, i.e. the next 4KiB. And XSTATE needs to be 64-byte aligned, so the 24 bytes is only actually meaningful if the current size is within 24 bytes of the next cahce line. And the "current" size is variable depending on which features are present and enabled, i.e. it's a roll of the dice as to whether or not using XSTATE for supervisor CET would actually increase memory usage. And _if_ it does increase memory consumption, I have a very hard time believing an extra 64 bytes in the worst case scenario is a dealbreaker.If the performance is a concern, i.e. we don't want to eat saving/restoring the MSRs when switching to/from host FPU context, then I *think* that's simply a matter of keeping guest state resident when loading non-guest FPU state.
arch/x86/kernel/fpu/core.c +10
-0@@ -167,6 +167,16 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask)*/ xfd_update_state (fpstate); +/* +* Leave supervisor CET state as-is when loading host state +* (kernel or userspace). Supervisor CET state is managed via +* XSTATE for KVM guests, but the host never consumes said +* state (doesn't support supervisor shadow stacks), i.e. it's +* safe to keep guest state loaded into hardware. +*/ +if (!fpstate->is_guest) + mask &= ~XFEATURE_MASK_CET_KERNEL ; +/* * Restoring state always needs to modify all features * which are in @mask even if the current task cannot use So unless I'm missing something, NAK to this approach, at least not without trying the kernel FPU approach, i.e. I want somelike like to PeterZ or tglx to actually full on NAK the kernel approach before we consider shoving a hack into KVM.
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
On 8/10/23 02:29, Yang, Weijiang wrote:
...
Quoted 5 lines
When KVM enumerates shadow stack support for guest in
CPUID(0x7, 0).ECX[bit7], architecturally it claims both SS user and supervisor mode are supported. Although the latter is not supported in Linux, but in virtualization world, the guest OS could be non-Linux system, so KVM supervisor state support is necessary in this case.
What actual OSes need this support?
Quoted 2 lines
Two solutions are on the table:
1) Enable CET supervisor support in Linux kernel like user mode support.
We _will_ do this eventually, but not until FRED is merged. The core kernel also probably won't be managing the MSRs on non-FRED hardware.
I think what you're really talking about here is that the kernel would enable CET_S XSAVE state management so that CET_S state could be managed by the core kernel's FPU code.
That is, frankly, *NOT* like the user mode support at all.
Quoted 12 lines
2) Enable support in KVM domain.
Problem:
The Pros/Cons for each solution(my individual thoughts):
In kernel solution:
Pros:
- Avoid saving/restoring 3 supervisorMSRs(PL{0,1,2}_SSP)at vCPU execution path.
- Easy for KVM to manage guest CET xstate bits for guest. Cons:
- Unnecessary supervisor state xsaves/xrstors operation for non-vCPU thread.
What operations would be unnecessary exactly?
Quoted 1 line
- Potentially extra storage space(24 bytes) for thread context.
Yep. This one is pretty unavoidable. But, we've kept MPX around in this state for a looooooong time and nobody really seemed to care.
Quoted 9 lines
KVM solution:
Pros:
- Not touch current kernel FPU management framework and logic.
- No extra space and operation for non-vCPU thread.
Cons:
- Manually saving/restoring 3 supervisor MSRs is a performance burden to KVM.
- It looks more like a hack method for KVM, and some handling logic seems a bit awkward.
In a perfect world, we'd just allocate space for CET_S in the KVM fpstates. The core kernel fpstates would have XSTATE_BV[13]==XCOMP_BV[13]==0. An XRSTOR of the core kernel fpstates would just set CET_S to its init state.
But I suspect that would be too much work to implement in practice. It would be akin to a new lesser kind of dynamic xstate, one that didn't interact with XFD and *NEVER* gets allocated in the core kernel fpstates, even on demand.
I want to hear more about who is going to use CET_S state under KVM in practice. I don't want to touch it if this is some kind of purely academic exercise. But it's also silly to hack some kind of temporary solution into KVM that we'll rip out in a year when real supervisor shadow stack support comes along.
If it's actually necessary, we should probably just eat the 24 bytes in the fpstates, flip the bit in IA32_XSS and move on. There shouldn't be any other meaningful impact to the core kernel.
Paolo Bonzini
maintainerRe: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 9 lines · Dave Hansen
On 8/10/23 02:29, Yang, Weijiang wrote:
...Quoted 5 lines
When KVM enumerates shadow stack support for guest in
CPUID(0x7, 0).ECX[bit7], architecturally it claims both SS user and supervisor mode are supported. Although the latter is not supported in Linux, but in virtualization world, the guest OS could be non-Linux system, so KVM supervisor state support is necessary in this case.What actual OSes need this support?
I think Xen could use it when running nested. But KVM cannot expose support for CET in CPUID, and at the same time fake support for MSR_IA32_PL{0,1,2}_SSP (e.g. inject a #GP if it's ever written to a nonzero value).
I suppose we could invent our own paravirtualized CPUID bit for "supervisor IBT works but supervisor SHSTK doesn't". Linux could check that but I don't think it's a good idea.
So... do, or do not. There is no try. :)
Quoted 9 lines
Quoted 2 lines
Two solutions are on the table:
1) Enable CET supervisor support in Linux kernel like user mode support.We _will_ do this eventually, but not until FRED is merged. The core kernel also probably won't be managing the MSRs on non-FRED hardware.
I think what you're really talking about here is that the kernel would enable
CET_SXSAVE state management so thatCET_Sstate could be managed by the core kernel's FPU code.
Yes, I understand it that way too.
Quoted 1 line
That is, frankly, *NOT* like the user mode support at all.
I agree.
Quoted 13 lines
Quoted 12 lines
2) Enable support in KVM domain.
Problem:
The Pros/Cons for each solution(my individual thoughts):
In kernel solution:
Pros:
- Avoid saving/restoring 3 supervisorMSRs(PL{0,1,2}_SSP)at vCPU execution path.
- Easy for KVM to manage guest CET xstate bits for guest. Cons:
- Unnecessary supervisor state xsaves/xrstors operation for non-vCPU thread.
Quoted 1 line
What operations would be unnecessary exactly?
Saving/restoring PL0/1/2_SSP when switching from one usermode task's fpstate to another.
Quoted 10 lines
Quoted 9 lines
KVM solution:
Pros:
- Not touch current kernel FPU management framework and logic.
- No extra space and operation for non-vCPU thread.
Cons:
- Manually saving/restoring 3 supervisor MSRs is a performance burden to KVM.
- It looks more like a hack method for KVM, and some handling logic seems a bit awkward.
Quoted 4 lines
In a perfect world, we'd just allocate space for
CET_Sin the KVM fpstates. The core kernel fpstates would have XSTATE_BV[13]==XCOMP_BV[13]==0. An XRSTOR of the core kernel fpstates would just setCET_Sto its init state.
Yep. I don't think it's a lot of work to implement. The basic idea as you point out below is something like
#define XFEATURE_MASK_USER_DYNAMIC XFEATURE_MASK_XTILE_DATA #define XFEATURE_MASK_USER_OPTIONAL \
(XFEATURE_MASK_DYNAMIC | XFEATURE_MASK_CET_KERNEL)
where XFEATURE_MASK_USER_DYNAMIC is used for xfd-related tasks (including the ARCH_GET_XCOMP_SUPP arch_prctl) but everything else uses XFEATURE_MASK_USER_OPTIONAL.
KVM would enable the feature by hand when allocating the guest fpstate. Disabled features would be cleared from EDX:EAX when calling XSAVE/XSAVEC/XSAVES.
Quoted 11 lines
But I suspect that would be too much work to implement in practice. It would be akin to a new lesser kind of dynamic xstate, one that didn't interact with XFD and *NEVER* gets allocated in the core kernel fpstates, even on demand.
I want to hear more about who is going to use
CET_Sstate under KVM in practice. I don't want to touch it if this is some kind of purely academic exercise. But it's also silly to hack some kind of temporary solution into KVM that we'll rip out in a year when real supervisor shadow stack support comes along.
Quoted 3 lines
If it's actually necessary, we should probably just eat the 24 bytes in the fpstates, flip the bit in
IA32_XSSand move on. There shouldn't be any other meaningful impact to the core kernel.
If that's good to you, why not.
Paolo
Sean Christopherson
maintainerRe: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 16 lines · Paolo Bonzini
Quoted 9 lines · Dave Hansen
On 8/10/23 02:29, Yang, Weijiang wrote:
...Quoted 5 lines
When KVM enumerates shadow stack support for guest in
CPUID(0x7, 0).ECX[bit7], architecturally it claims both SS user and supervisor mode are supported. Although the latter is not supported in Linux, but in virtualization world, the guest OS could be non-Linux system, so KVM supervisor state support is necessary in this case.What actual OSes need this support?
I think Xen could use it when running nested. But KVM cannot expose support for CET in CPUID, and at the same time fake support for MSR_IA32_PL{0,1,2}_SSP (e.g. inject a #GP if it's ever written to a nonzero value).
Quoted 11 lines
I suppose we could invent our own paravirtualized CPUID bit for "supervisor IBT works but supervisor SHSTK doesn't". Linux could check that but I don't think it's a good idea.
So... do, or do not. There is no try. :)
Quoted 5 lines
I want to hear more about who is going to use
CET_Sstate under KVM in practice. I don't want to touch it if this is some kind of purely academic exercise. But it's also silly to hack some kind of temporary solution into KVM that we'll rip out in a year when real supervisor shadow stack support comes along.
As Paolo alluded to, this is about KVM faithfully emulating the architecture. There is no combination of CPUID bits that allows KVM to advertise SHSTK for userspace without advertising SHSTK for supervisor.
Whether or not there are any users in the short term is unfortunately irrelevant from KVM's perspective.
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
In reply to Paolo BonziniQuoted 20 lines · Paolo Bonzini
Quoted 9 lines · Dave Hansen
On 8/10/23 02:29, Yang, Weijiang wrote:
...Quoted 5 lines
When KVM enumerates shadow stack support for guest in
CPUID(0x7, 0).ECX[bit7], architecturally it claims both SS user and supervisor mode are supported. Although the latter is not supported in Linux, but in virtualization world, the guest OS could be non-Linux system, so KVM supervisor state support is necessary in this case.What actual OSes need this support?
I think Xen could use it when running nested. But KVM cannot expose support for CET in CPUID, and at the same time fake support for MSR_IA32_PL{0,1,2}_SSP (e.g. inject a #GP if it's ever written to a nonzero value).
I suppose we could invent our own paravirtualized CPUID bit for "supervisor IBT works but supervisor SHSTK doesn't". Linux could check that but I don't think it's a good idea.
So... do, or do not. There is no try. :)
Quoted 3 lines
Quoted 2 lines
Two solutions are on the table:
1) Enable CET supervisor support in Linux kernel like user mode support.
Quoted 8 lines
Quoted 6 lines
We _will_ do this eventually, but not until FRED is merged. The core kernel also probably won't be managing the MSRs on non-FRED hardware.
I think what you're really talking about here is that the kernel would enable
CET_SXSAVE state management so thatCET_Sstate could be managed by the core kernel's FPU code.Yes, I understand it that way too.
Sorry for confusion, I missed the word "state" here.
Quoted 38 lines
Quoted 1 line
That is, frankly, *NOT* like the user mode support at all.
I agree.
Quoted 13 lines
Quoted 12 lines
2) Enable support in KVM domain.
Problem:
The Pros/Cons for each solution(my individual thoughts):
In kernel solution:
Pros:
- Avoid saving/restoring 3 supervisorMSRs(PL{0,1,2}_SSP)at vCPU execution path.
- Easy for KVM to manage guest CET xstate bits for guest. Cons:
- Unnecessary supervisor state xsaves/xrstors operation for non-vCPU thread.Quoted 1 line
What operations would be unnecessary exactly?
Saving/restoring PL0/1/2_SSP when switching from one usermode task's fpstate to another.
Quoted 10 lines
Quoted 9 lines
KVM solution:
Pros:
- Not touch current kernel FPU management framework and logic.
- No extra space and operation for non-vCPU thread.
Cons:
- Manually saving/restoring 3 supervisor MSRs is a performance burden to KVM.
- It looks more like a hack method for KVM, and some handling logic seems a bit awkward.Quoted 4 lines
In a perfect world, we'd just allocate space for
CET_Sin the KVM fpstates. The core kernel fpstates would have XSTATE_BV[13]==XCOMP_BV[13]==0. An XRSTOR of the core kernel fpstates would just setCET_Sto its init state.Yep. I don't think it's a lot of work to implement. The basic idea as you point out below is something like
Quoted 7 lines
#define
XFEATURE_MASK_USER_DYNAMICXFEATURE_MASK_XTILE_DATA#defineXFEATURE_MASK_USER_OPTIONAL\
(XFEATURE_MASK_DYNAMIC|XFEATURE_MASK_CET_KERNEL)where
XFEATURE_MASK_USER_DYNAMICis used for xfd-related tasks (including theARCH_GET_XCOMP_SUPParch_prctl) but everything else usesXFEATURE_MASK_USER_OPTIONAL.KVM would enable the feature by hand when allocating the guest fpstate. Disabled features would be cleared from EDX:EAX when calling XSAVE/XSAVEC/XSAVES.
OK, I'll move ahead in that direction.
Quoted 11 lines
Quoted 11 lines
But I suspect that would be too much work to implement in practice. It would be akin to a new lesser kind of dynamic xstate, one that didn't interact with XFD and *NEVER* gets allocated in the core kernel fpstates, even on demand.
I want to hear more about who is going to use
CET_Sstate under KVM in practice. I don't want to touch it if this is some kind of purely academic exercise. But it's also silly to hack some kind of temporary solution into KVM that we'll rip out in a year when real supervisor shadow stack support comes along.
Quoted 5 lines
Quoted 3 lines
If it's actually necessary, we should probably just eat the 24 bytes in the fpstates, flip the bit in
IA32_XSSand move on. There shouldn't be any other meaningful impact to the core kernel.If that's good to you, why not.
Thanks to all of you for quickly helping out!
Quoted 2 lines
Paolo
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
In reply to Paolo BonziniQuoted 8 lines · Paolo Bonzini
Quoted 1 line · Dave Hansen
What actual OSes need this support?
I think Xen could use it when running nested. But KVM cannot expose support for CET in CPUID, and at the same time fake support for MSR_IA32_PL{0,1,2}_SSP (e.g. inject a #GP if it's ever written to a nonzero value).
Quoted 5 lines
I suppose we could invent our own paravirtualized CPUID bit for "supervisor IBT works but supervisor SHSTK doesn't". Linux could check that but I don't think it's a good idea.
So... do, or do not. There is no try. :)
Ahh, that makes sense. This is needed for implementing the *architecture*, not because some OS actually wants to _do_ it.
...
Quoted 12 lines
Quoted 4 lines
In a perfect world, we'd just allocate space for
CET_Sin the KVM fpstates. The core kernel fpstates would have XSTATE_BV[13]==XCOMP_BV[13]==0. An XRSTOR of the core kernel fpstates would just setCET_Sto its init state.Yep. I don't think it's a lot of work to implement. The basic idea as you point out below is something like
#define
XFEATURE_MASK_USER_DYNAMICXFEATURE_MASK_XTILE_DATA#defineXFEATURE_MASK_USER_OPTIONAL\
(XFEATURE_MASK_DYNAMIC|XFEATURE_MASK_CET_KERNEL)
Quoted 7 lines
where
XFEATURE_MASK_USER_DYNAMICis used for xfd-related tasks (including theARCH_GET_XCOMP_SUPParch_prctl) but everything else usesXFEATURE_MASK_USER_OPTIONAL.KVM would enable the feature by hand when allocating the guest fpstate. Disabled features would be cleared from EDX:EAX when calling XSAVE/XSAVEC/XSAVES.
OK, so let's _try_ this perfect-world solution. KVM fpstates get fpstate->xfeatures[13] set, but no normal task fpstates have that bit set. Most of the infrastructure should be there to handle this without much fuss because it _should_ be looking at generic things like fpstate->size and fpstate->features.
But who knows what trouble this will turn up. It could get nasty and not worth it, but we should at least try it.
Re: [PATCH v5 09/19] KVM:x86: Make guest supervisor states as non-XSAVE managed
Quoted 35 lines · Dave Hansen
Quoted 7 lines · Paolo Bonzini
Quoted 1 line · Dave Hansen
What actual OSes need this support?
I think Xen could use it when running nested. But KVM cannot expose support for CET in CPUID, and at the same time fake support for MSR_IA32_PL{0,1,2}_SSP (e.g. inject a #GP if it's ever written to a nonzero value).
Quoted 5 lines
I suppose we could invent our own paravirtualized CPUID bit for "supervisor IBT works but supervisor SHSTK doesn't". Linux could check that but I don't think it's a good idea.
So... do, or do not. There is no try. :)
Ahh, that makes sense. This is needed for implementing the *architecture*, not because some OS actually wants to _do_ it.
...
Quoted 11 lines
Quoted 4 lines
In a perfect world, we'd just allocate space for
CET_Sin the KVM fpstates. The core kernel fpstates would have XSTATE_BV[13]==XCOMP_BV[13]==0. An XRSTOR of the core kernel fpstates would just setCET_Sto its init state.Yep. I don't think it's a lot of work to implement. The basic idea as you point out below is something like
#define
XFEATURE_MASK_USER_DYNAMICXFEATURE_MASK_XTILE_DATA#defineXFEATURE_MASK_USER_OPTIONAL\
(XFEATURE_MASK_DYNAMIC|XFEATURE_MASK_CET_KERNEL)Quoted 7 lines
where
XFEATURE_MASK_USER_DYNAMICis used for xfd-related tasks (including theARCH_GET_XCOMP_SUPParch_prctl) but everything else usesXFEATURE_MASK_USER_OPTIONAL.KVM would enable the feature by hand when allocating the guest fpstate. Disabled features would be cleared from EDX:EAX when calling XSAVE/XSAVEC/XSAVES.
Quoted 8 lines
OK, so let's _try_ this perfect-world solution. KVM fpstates get fpstate->xfeatures[13] set, but no normal task fpstates have that bit set. Most of the infrastructure should be there to handle this without much fuss because it _should_ be looking at generic things like
fpstate->sizeandfpstate->features.But who knows what trouble this will turn up. It could get nasty and not worth it, but we should at least try it.
Thanks Dave for clarity!
I'm moving in that direction...
PATCH v5 10/19 KVM:VMX: Introduce CET VMCS fields and control bits
In reply to Yang WeijiangControl-flow Enforcement Technology (CET) is a kind of CPU feature used to prevent Return/CALL/Jump-Oriented Programming (ROP/COP/JOP) attacks. It provides two sub-features(SHSTK,IBT) to defend against ROP/COP/JOP style control-flow subversion attacks.
Shadow Stack (SHSTK):
A shadow stack is a second stack used exclusively for control transfer operations. The shadow stack is separate from the data/normal stack and can be enabled individually in user and kernel mode. When shadow stack is enabled, CALL pushes the return address on both the data and shadow stack. RET pops the return address from both stacks and compares them. If the return addresses from the two stacks do not match, the processor generates a #CP.
Indirect Branch Tracking (IBT):
IBT introduces new instruction(ENDBRANCH)to mark valid target addresses of indirect branches (CALL, JMP etc...). If an indirect branch is executed and the next instruction is _not_ an ENDBRANCH, the processor generates a #CP. These instruction behaves as a NOP on platforms that doesn't support CET.
Several new CET MSRs are defined to support CET:
MSR_IA32_{U,S}_CET: CET settings for {user,supervisor} mode respectively.
MSR_IA32_PL{0,1,2,3}_SSP: SHSTK pointer linear address for CPL{0,1,2,3}.
MSR_IA32_INT_SSP_TAB: Linear address of SHSTK table,the entry is indexed
by IST of interrupt gate desc.
Two XSAVES state bits are introduced for CET:
IA32_XSS:[bit 11]: Control saving/restoring user mode CET states IA32_XSS:[bit 12]: Control saving/restoring supervisor mode CET states.
Six VMCS fields are introduced for CET:
{HOST,GUEST}_S_CET: Stores CET settings for kernel mode. {HOST,GUEST}_SSP: Stores shadow stack pointer of current active task/thread. {HOST,GUEST}_INTR_SSP_TABLE: Stores current active MSR_IA32_INT_SSP_TAB.
On Intel platforms, two additional bits are defined in VM_EXIT and VM_ENTRY control fields:
If VM_EXIT_LOAD_CET_STATE = 1, the host CET states are restored from the following VMCS fields at VM-Exit:
HOST_S_CET
HOST_SSP
HOST_INTR_SSP_TABLE
If VM_ENTRY_LOAD_CET_STATE = 1, the guest CET states are loaded from the following VMCS fields at VM-Entry:
GUEST_S_CET
GUEST_SSP
GUEST_INTR_SSP_TABLE
--- arch/x86/include/asm/vmx.h | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/include/asm/vmx.h +8 -0
@@ -104,6 +104,7 @@#define VM_EXIT_CLEAR_BNDCFGS 0x00800000#define VM_EXIT_PT_CONCEAL_PIP 0x01000000#define VM_EXIT_CLEAR_IA32_RTIT_CTL 0x02000000 +#define VM_EXIT_LOAD_CET_STATE 0x10000000#define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff
@@ -117,6 +118,7 @@#define VM_ENTRY_LOAD_BNDCFGS 0x00010000#define VM_ENTRY_PT_CONCEAL_PIP 0x00020000#define VM_ENTRY_LOAD_IA32_RTIT_CTL 0x00040000 +#define VM_ENTRY_LOAD_CET_STATE 0x00100000#define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff
@@ -345,6 +347,9 @@ enum vmcs_field {GUEST_PENDING_DBG_EXCEPTIONS =0x00006822 ,GUEST_SYSENTER_ESP =0x00006824 ,GUEST_SYSENTER_EIP =0x00006826 , +GUEST_S_CET =0x00006828 , +GUEST_SSP =0x0000682a , +GUEST_INTR_SSP_TABLE =0x0000682c ,HOST_CR0 =0x00006c00 ,HOST_CR3 =0x00006c02 , HOST_CR4 = 0x00006c04,
@@ -357,6 +362,9 @@ enum vmcs_field {HOST_IA32_SYSENTER_EIP =0x00006c12 ,HOST_RSP =0x00006c14 ,HOST_RIP =0x00006c16 , +HOST_S_CET =0x00006c18 , +HOST_SSP =0x00006c1a , + HOST_INTR_SSP_TABLE = 0x00006c1c };/*
Signature · 1 line
2.27.0
PATCH v5 11/19 KVM:VMX: Emulate read and write to CET MSRs
In reply to Yang WeijiangAdd emulation interface for CET MSR read and write. The emulation code is split into common part and vendor specific part, the former resides in x86.c to benefic different x86 CPU vendors, the latter for VMX is implemented in this patch.
--- arch/x86/kvm/vmx/vmx.c | 27 +++++++++++ arch/x86/kvm/x86.c | 104 +++++++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.h | 18 +++++++ 3 files changed, 141 insertions(+), 8 deletions(-)
arch/x86/kvm/vmx/vmx.c +27 -0
@@ -2095,6 +2095,18 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else msr_info->data = vmx->pt_desc.guest.addr_a[index /2 ];break ; +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : +case MSR_IA32_INT_SSP_TAB : +if (kvm_get_msr_common (vcpu, msr_info)) +return 1 ; +if (msr_info->index ==MSR_KVM_GUEST_SSP ) + msr_info->data =vmcs_readl (GUEST_SSP ); +else if (msr_info->index ==MSR_IA32_S_CET ) + msr_info->data =vmcs_readl (GUEST_S_CET ); +else if (msr_info->index ==MSR_IA32_INT_SSP_TAB ) + msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE ); +break ;case MSR_IA32_DEBUGCTLMSR : msr_info->data =vmcs_read64 (GUEST_IA32_DEBUGCTL );break ;
@@ -2404,6 +2416,18 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP : +case MSR_IA32_INT_SSP_TAB : +if (kvm_set_msr_common (vcpu, msr_info)) +return 1 ; +if (msr_index ==MSR_KVM_GUEST_SSP ) +vmcs_writel (GUEST_SSP , data); +else if (msr_index ==MSR_IA32_S_CET ) +vmcs_writel (GUEST_S_CET , data); +else if (msr_index ==MSR_IA32_INT_SSP_TAB ) +vmcs_writel (GUEST_INTR_SSP_TABLE , data); +break ;case MSR_IA32_PERF_CAPABILITIES :if (data && !vcpu_to_pmu (vcpu)->version)return 1 ;
@@ -4864,6 +4888,9 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)vmcs_write64 (GUEST_BNDCFGS ,0 );vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD ,0 );/* 22.2.1 */ +vmcs_writel (GUEST_SSP ,0 ); +vmcs_writel (GUEST_S_CET ,0 ); +vmcs_writel (GUEST_INTR_SSP_TABLE ,0 );kvm_make_request (KVM_REQ_APIC_PAGE_RELOAD , vcpu);
arch/x86/kvm/x86.c +96 -8
165 lines not on this page · raw message
arch/x86/kvm/x86.h +18 -0
@@ -552,4 +552,22 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port, void *data, unsigned int count, int in); +/* +* Guest xstate MSRs have been loaded in __msr_io(), disable preemption before +* access the MSRs to avoid MSR content corruption. +*/ +static inline void kvm_get_xsave_msr (struct msr_data *msr_info) +{ +kvm_fpu_get (); +rdmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +} + +static inline void kvm_set_xsave_msr (struct msr_data *msr_info) +{ +kvm_fpu_get (); +wrmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +} +#endif
Signature · 1 line
2.27.0
Re: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 21 lines · Yang Weijiang
Add emulation interface for CET MSR read and write. The emulation code is split into common part and vendor specific part, the former resides in
x86.cto benefic different x86 CPU vendors, the latter for VMX is implemented in this patch.Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/kvm/vmx/vmx.c | 27 +++++++++++ arch/x86/kvm/x86.c | 104 +++++++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.h | 18 +++++++ 3 files changed, 141 insertions(+), 8 deletions(-)arch/x86/kvm/vmx/vmx.c +1
-0@@ -2095,6 +2095,18 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else msr_info->data = vmx->pt_desc.guest.addr_a[index /2 ];break ; +case MSR_IA32_S_CET :
arch/x86/kvm/vmx/vmx.c static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2108
Quoted 10 lines
arch/x86/kvm/vmx/vmx.c +10
-0+case MSR_KVM_GUEST_SSP : +case MSR_IA32_INT_SSP_TAB : +if (kvm_get_msr_common (vcpu, msr_info)) +return 1 ; +if (msr_info->index ==MSR_KVM_GUEST_SSP ) + msr_info->data =vmcs_readl (GUEST_SSP ); +else if (msr_info->index ==MSR_IA32_S_CET ) + msr_info->data =vmcs_readl (GUEST_S_CET ); +else if (msr_info->index ==MSR_IA32_INT_SSP_TAB ) + msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE );
This if-else-if suggests that they are focibly grouped together to just share the call of kvm_get_msr_common(). For readability, I think it is better to handle them separately.
e.g.,
case MSR_IA32_S_CET: if (kvm_get_msr_common(vcpu, msr_info)) return 1; msr_info->data = vmcs_readl(GUEST_S_CET); break; case MSR_KVM_GUEST_SSP: if (kvm_get_msr_common(vcpu, msr_info)) return 1; msr_info->data = vmcs_readl(GUEST_SSP); break; ...
Quoted 9 lines
arch/x86/kvm/vmx/vmx.c +2
-0+break ;case MSR_IA32_DEBUGCTLMSR : msr_info->data =vmcs_read64 (GUEST_IA32_DEBUGCTL );break ;@@ -2404,6 +2416,18 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; +case MSR_IA32_S_CET :
arch/x86/kvm/vmx/vmx.c static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2429
Quoted 10 lines
arch/x86/kvm/vmx/vmx.c +10
-0+case MSR_KVM_GUEST_SSP : +case MSR_IA32_INT_SSP_TAB : +if (kvm_set_msr_common (vcpu, msr_info)) +return 1 ; +if (msr_index ==MSR_KVM_GUEST_SSP ) +vmcs_writel (GUEST_SSP , data); +else if (msr_index ==MSR_IA32_S_CET ) +vmcs_writel (GUEST_S_CET , data); +else if (msr_index ==MSR_IA32_INT_SSP_TAB ) +vmcs_writel (GUEST_INTR_SSP_TABLE , data);
ditto
arch/x86/kvm/vmx/vmx.c static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) · line 4893
Quoted 11 lines
arch/x86/kvm/vmx/vmx.c +4
-0+break ;case MSR_IA32_PERF_CAPABILITIES :if (data && !vcpu_to_pmu (vcpu)->version)return 1 ;@@ -4864,6 +4888,9 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)vmcs_write64 (GUEST_BNDCFGS ,0 );vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD ,0 );/* 22.2.1 */ +vmcs_writel (GUEST_SSP ,0 ); +vmcs_writel (GUEST_S_CET ,0 ); +vmcs_writel (GUEST_INTR_SSP_TABLE ,0 );
where are MSR_IA32_PL3_SSP and MSR_IA32_U_CET reset?
I thought that guest FPU would be reset in kvm_vcpu_reset(). But it turns out only MPX states are reset in KVM while other FPU states are unchanged. This is aligned with "Table 10.1 IA-32 and Intel® 64 Processor States Following Power-up, Reset, or INIT"
Could you double confirm the hardware beahavior that CET states are reset to 0 on INIT? If CET states are reset, we need to handle CET_IA32_PL3_SSP and MSR_IA32_U_CET like MPX.
Quoted 63 lines
arch/x86/kvm/vmx/vmx.c +0
-0kvm_make_request (KVM_REQ_APIC_PAGE_RELOAD , vcpu);arch/x86/kvm/x86.c +45
-0@@ -3627,6 +3627,39 @@ static bool kvm_is_msr_to_save(u32 msr_index)return false; } +static inline bool is_shadow_stack_msr (u32 msr) +{ +return msr ==MSR_IA32_PL0_SSP || + msr ==MSR_IA32_PL1_SSP || + msr ==MSR_IA32_PL2_SSP || + msr ==MSR_IA32_PL3_SSP || + msr ==MSR_IA32_INT_SSP_TAB || + msr ==MSR_KVM_GUEST_SSP ; +} + +static bool kvm_cet_is_msr_accessible (struct kvm_vcpu *vcpu, +struct msr_data *msr) +{ +if (is_shadow_stack_msr (msr->index)) { +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK )) +return false; + +if (msr->index ==MSR_KVM_GUEST_SSP ) +return msr->host_initiated; + +return msr->host_initiated || +guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); + } + +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT )) +return false; + +return msr->host_initiated || +guest_cpuid_has (vcpu,X86_FEATURE_IBT ) || +guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); +} +int kvm_set_msr_common (struct kvm_vcpu *vcpu,struct msr_data *msr_info) {u32 msr = msr_info->index;@@ -3981,6 +4014,45 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.guest_fpu.xfd_err = data;break ;#endif +#define CET_EXCLUSIVE_BITS (CET_SUPPRESS | CET_WAIT_ENDBR) +#define CET_CTRL_RESERVED_BITS GENMASK(9, 6) +#define CET_SHSTK_MASK_BITS GENMASK(1, 0) +#define CET_IBT_MASK_BITS (GENMASK_ULL(5, 2) | \ + GENMASK_ULL(63, 10)) +#define CET_LEG_BITMAP_BASE (data) ((data) >> 12) +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) +return 1 ; +if (!!(data &CET_CTRL_RESERVED_BITS )) +return 1 ;
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4038
Quoted 10 lines
arch/x86/kvm/x86.c +10
-0+if (!guest_can_use (vcpu,X86_FEATURE_SHSTK ) && + (data &CET_SHSTK_MASK_BITS )) +return 1 ; +if (!guest_can_use (vcpu,X86_FEATURE_IBT ) && + (data &CET_IBT_MASK_BITS )) +return 1 ; +if (!IS_ALIGNED (CET_LEG_BITMAP_BASE (data),4 ) || + (data &CET_EXCLUSIVE_BITS ) ==CET_EXCLUSIVE_BITS ) +return 1 ; +if (msr ==MSR_IA32_U_CET )
can you add a comment before this if() statement like?
/* MSR_IA32_S_CET is handled by vendor code */
Quoted 4 lines
arch/x86/kvm/x86.c +4
-0+case MSR_KVM_GUEST_SSP : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) +return 1 ;
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4054
Quoted 10 lines
arch/x86/kvm/x86.c +10
-0+if (is_noncanonical_address (data, vcpu)) +return 1 ; +if (!IS_ALIGNED (data,4 )) +return 1 ; +if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || + msr ==MSR_IA32_PL2_SSP ) { + vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ] = data; + }else if (msr ==MSR_IA32_PL3_SSP ) { +kvm_set_xsave_msr (msr_info); + }
brackets are not needed.
also add a comment for MSR_KVM_GUEST_SSP.
Quoted 67 lines
arch/x86/kvm/x86.c +12
-6+break ;default :if (kvm_pmu_is_valid_msr (vcpu, msr))return kvm_pmu_set_msr (vcpu, msr_info);@@ -4051,7 +4123,9 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)int kvm_get_msr_common (struct kvm_vcpu *vcpu,struct msr_data *msr_info) { -switch (msr_info->index) { +u32 msr = msr_info->index; + +switch (msr) {case MSR_IA32_PLATFORM_ID :case MSR_IA32_EBL_CR_POWERON :case MSR_IA32_LASTBRANCHFROMIP :@@ -4086,7 +4160,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3: case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1: case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1: -if (kvm_pmu_is_valid_msr (vcpu, msr_info->index)) +if (kvm_pmu_is_valid_msr (vcpu, msr))return kvm_pmu_get_msr (vcpu, msr_info); msr_info->data =0 ;break ;@@ -4137,7 +4211,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_MTRRcap: case MTRRphysBase_MSR(0) ... MSR_MTRRfix4K_F8000:case MSR_MTRRdefType: -return kvm_mtrr_get_msr (vcpu, msr_info->index, &msr_info->data); +return kvm_mtrr_get_msr (vcpu, msr, &msr_info->data);case 0xcd :/* fsb frequency */ msr_info->data =3 ;break ;@@ -4159,7 +4233,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data =kvm_get_apic_base (vcpu);break ; case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: -return kvm_x2apic_msr_read (vcpu, msr_info->index, &msr_info->data); +return kvm_x2apic_msr_read (vcpu, msr, &msr_info->data);case MSR_IA32_TSC_DEADLINE : msr_info->data =kvm_get_lapic_tscdeadline_msr (vcpu);break ;@@ -4253,7 +4327,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_IA32_MCG_STATUS : case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1: -return get_msr_mce (vcpu, msr_info->index, &msr_info->data, +return get_msr_mce (vcpu, msr, &msr_info->data, msr_info->host_initiated);case MSR_IA32_XSS : if (!msr_info->host_initiated &&@@ -4284,7 +4358,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case HV_X64_MSR_TSC_EMULATION_STATUS :case HV_X64_MSR_TSC_INVARIANT_CONTROL :return kvm_hv_get_msr_common (vcpu, - msr_info->index, &msr_info->data, + msr, &msr_info->data, msr_info->host_initiated);case MSR_IA32_BBL_CR_CTL3 :/* This legacy MSR exists but isn't fully documented in current @@ -4337,8 +4411,22 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vcpu->arch.guest_fpu.xfd_err;break ;#endif +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +case MSR_KVM_GUEST_SSP :
arch/x86/kvm/x86.c int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4426
Quoted 10 lines
arch/x86/kvm/x86.c +10
-0+ case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) +return 1 ; +if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || + msr ==MSR_IA32_PL2_SSP ) { + msr_info->data = + vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ]; + }else if (msr ==MSR_IA32_U_CET || msr ==MSR_IA32_PL3_SSP ) { +kvm_get_xsave_msr (msr_info); + }
Again, for readability and clarity, how about:
case MSR_IA32_U_CET: case MSR_IA32_PL3_SSP: if (!kvm_cet_is_msr_accessible(vcpu, msr_info)) return 1; kvm_get_xsave_msr(msr_info); break; case MSR_IA32_PL0_SSP ... MSR_IA32_PL2_SSP: if (!kvm_cet_is_msr_accessible(vcpu, msr_info)) return 1; msr_info->data = vcpu->arch.cet_s_ssp[msr - MSR_IA32_PL0_SSP]; break; case MSR_IA32_S_CET: case MSR_KVM_GUEST_SSP: if (!kvm_cet_is_msr_accessible(vcpu, msr_info)) return 1; /* Further handling in vendor code */ break;
Quoted 21 lines
arch/x86/kvm/x86.c +3
-2+break ;default : -if (kvm_pmu_is_valid_msr (vcpu, msr_info->index)) +if (kvm_pmu_is_valid_msr (vcpu, msr))return kvm_pmu_get_msr (vcpu, msr_info);/* @@ -4346,7 +4434,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)* to-be-saved, even if an MSR isn't fully supported. */ if (msr_info->host_initiated && -kvm_is_msr_to_save (msr_info->index)) { +kvm_is_msr_to_save (msr)) { msr_info->data =0 ;break ; }arch/x86/kvm/x86.h +0
-0
arch/x86/kvm/x86.h int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, · line 558
Quoted 7 lines
arch/x86/kvm/x86.h +4
-0@@ -552,4 +552,22 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port, void *data, unsigned int count, int in); +/* +* Guest xstate MSRs have been loaded in __msr_io(), disable preemption before +* access the MSRs to avoid MSR content corruption. +*/
I think it is better to describe what the function does prior to jumping into details like where guest FPU is loaded.
/*
* Lock and/or reload guest FPU and access xstate MSRs. For accesses initiated
* by host, guest FPU is loaded in __msr_io(). For accesses initiated by guest,
* guest FPU should have been loaded already.
*/
arch/x86/kvm/x86.h int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, · line 571
Quoted 13 lines
arch/x86/kvm/x86.h +13
-0+static inline void kvm_get_xsave_msr (struct msr_data *msr_info) +{ +kvm_fpu_get (); +rdmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +} + +static inline void kvm_set_xsave_msr (struct msr_data *msr_info) +{ +kvm_fpu_get (); +wrmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +}
Can you rename functions to kvm_get/set_xstate_msr() to align with the comment and patch 6? And if there is no user outside x86.c, you can just put these two functions right after the is_xstate_msr() added in patch 6.
Quoted 5 lines
arch/x86/kvm/x86.h +1
-0+#endif Signature · 1 line
2.27.0
Sean Christopherson
maintainerRe: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 38 lines · Chao Gao
Quoted 21 lines · Yang Weijiang
Add emulation interface for CET MSR read and write. The emulation code is split into common part and vendor specific part, the former resides in
x86.cto benefic different x86 CPU vendors, the latter for VMX is implemented in this patch.Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/kvm/vmx/vmx.c | 27 +++++++++++ arch/x86/kvm/x86.c | 104 +++++++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.h | 18 +++++++ 3 files changed, 141 insertions(+), 8 deletions(-)arch/x86/kvm/vmx/vmx.c +1
-0@@ -2095,6 +2095,18 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else msr_info->data = vmx->pt_desc.guest.addr_a[index /2 ];break ; +case MSR_IA32_S_CET :arch/x86/kvm/vmx/vmx.c static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2108
Quoted 10 lines
arch/x86/kvm/vmx/vmx.c +10
-0+case MSR_KVM_GUEST_SSP : +case MSR_IA32_INT_SSP_TAB : +if (kvm_get_msr_common (vcpu, msr_info)) +return 1 ; +if (msr_info->index ==MSR_KVM_GUEST_SSP ) + msr_info->data =vmcs_readl (GUEST_SSP ); +else if (msr_info->index ==MSR_IA32_S_CET ) + msr_info->data =vmcs_readl (GUEST_S_CET ); +else if (msr_info->index ==MSR_IA32_INT_SSP_TAB ) + msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE );This if-else-if suggests that they are focibly grouped together to just share the call of
kvm_get_msr_common(). For readability, I think it is better to handle them separately.e.g.,
Quoted 11 lines
case MSR_IA32_S_CET: if (kvm_get_msr_common(vcpu, msr_info)) return 1; msr_info->data = vmcs_readl(GUEST_S_CET); break; case MSR_KVM_GUEST_SSP: if (kvm_get_msr_common(vcpu, msr_info)) return 1; msr_info->data = vmcs_readl(GUEST_SSP); break;
Actually, we can do even better. We have an existing framework for these types of prechecks, I just completely forgot about it :-( (my "look at PAT" was a bad suggestion).
Handle the checks in __kvm_set_msr() and __kvm_get_msr(), i.e. *before* calling into vendor code. Then vendor code doesn't need to make weird callbacks.
Quoted 9 lines
arch/x86/kvm/vmx/vmx.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4018
Quoted 9 lines
arch/x86/kvm/vmx/vmx.c +2
-0int kvm_set_msr_common (struct kvm_vcpu *vcpu,struct msr_data *msr_info) {u32 msr = msr_info->index;@@ -3981,6 +4014,45 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.guest_fpu.xfd_err = data;break ;#endif +#define CET_EXCLUSIVE_BITS (CET_SUPPRESS | CET_WAIT_ENDBR) +#define CET_CTRL_RESERVED_BITS GENMASK(9, 6)
Please use a single namespace for these #defines, e.g. CET_CTRL_* or maybe CET_US_* for everything.
Quoted 4 lines
arch/x86/kvm/vmx/vmx.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4022
Quoted 4 lines
arch/x86/kvm/vmx/vmx.c +4
-0+#define CET_SHSTK_MASK_BITS GENMASK(1, 0) +#define CET_IBT_MASK_BITS (GENMASK_ULL(5, 2) | \ + GENMASK_ULL(63, 10)) +#define CET_LEG_BITMAP_BASE (data) ((data) >> 12)
Bah, stupid SDM. Please spell out "LEGACY", I though "LEG" was short for "LEGAL" since this looks a lot like a page shift, i.e. getting a pfn.
Quoted 13 lines
Quoted 13 lines
arch/x86/kvm/vmx/vmx.c +13
-0+static bool kvm_cet_is_msr_accessible (struct kvm_vcpu *vcpu, +struct msr_data *msr) +{ +if (is_shadow_stack_msr (msr->index)) { +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK )) +return false; + +if (msr->index ==MSR_KVM_GUEST_SSP ) +return msr->host_initiated; + +return msr->host_initiated || +guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); + }
Quoted 8 lines
arch/x86/kvm/vmx/vmx.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4043
Quoted 8 lines
arch/x86/kvm/vmx/vmx.c +8
-0+ +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT )) +return false; + +return msr->host_initiated || +guest_cpuid_has (vcpu,X86_FEATURE_IBT ) || +guest_cpuid_has (vcpu,X86_FEATURE_SHSTK );
Similar to my suggestsion for XSS, I think we drop the waiver for host_initiated accesses, i.e. require the feature to be enabled and exposed to the guest, even for the host.
Quoted 30 lines
arch/x86/kvm/x86.h int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, · line 558
Quoted 12 lines
arch/x86/kvm/x86.h +4
-0@@ -552,4 +552,22 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port, void *data, unsigned int count, int in); +/* +* Guest xstate MSRs have been loaded in __msr_io(), disable preemption before +* access the MSRs to avoid MSR content corruption. +*/ I think it is better to describe what the function does prior to jumping into details like where guest FPU is loaded.
/*
* Lock and/or reload guest FPU and access xstate MSRs. For accesses initiated
* by host, guest FPU is loaded in__msr_io(). For accesses initiated by guest,
* guest FPU should have been loaded already.
*/Quoted 9 lines
arch/x86/kvm/x86.h +9
-0+static inline void kvm_get_xsave_msr (struct msr_data *msr_info) +{ +kvm_fpu_get (); +rdmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +} + +static inline void kvm_set_xsave_msr (struct msr_data *msr_info) +{
Quoted 8 lines
arch/x86/kvm/x86.h int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, · line 571
Quoted 4 lines
arch/x86/kvm/x86.h +4
-0+kvm_fpu_get (); +wrmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +}Can you rename functions to kvm_get/set_xstate_msr() to align with the comment and patch 6? And if there is no user outside
x86.c, you can just put these two functions right after theis_xstate_msr()added in patch 6.
+1. These should also assert that (a) guest FPU state is loaded and (b) the MSR is passed through to the guest. I might be ok dropping (b) if both VMX and SVM passthrough all MSRs if they're exposed to the guest, i.e. not lazily passed through.
Sans any changes to kvm_{g,s}et_xsave_msr(), I think this? (completely untested)
--- arch/x86/kvm/vmx/vmx.c | 34 +++------- arch/x86/kvm/x86.c | 151 +++++++++++++++-------------------------- 2 files changed, 64 insertions(+), 121 deletions(-)
arch/x86/kvm/vmx/vmx.c +10 -24
@@ -2100,16 +2100,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vmx->pt_desc.guest.addr_a[index /2 ];break ;case MSR_IA32_S_CET : + msr_info->data =vmcs_readl (GUEST_S_CET ); +break ;case MSR_KVM_GUEST_SSP : + msr_info->data =vmcs_readl (GUEST_SSP ); +break ;case MSR_IA32_INT_SSP_TAB : -if (kvm_get_msr_common (vcpu, msr_info)) -return 1 ; -if (msr_info->index ==MSR_KVM_GUEST_SSP ) - msr_info->data =vmcs_readl (GUEST_SSP ); -else if (msr_info->index ==MSR_IA32_S_CET ) - msr_info->data =vmcs_readl (GUEST_S_CET ); -else if (msr_info->index ==MSR_IA32_INT_SSP_TAB ) - msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE ); + msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE );break ;case MSR_IA32_DEBUGCTLMSR : msr_info->data =vmcs_read64 (GUEST_IA32_DEBUGCTL );
@@ -2432,25 +2429,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; - case MSR_IA32_PL0_SSP ... MSR_IA32_PL2_SSP: -if (kvm_set_msr_common (vcpu, msr_info)) -return 1 ; -if (data) { -vmx_disable_write_intercept_sss_msr (vcpu); -wrmsrl (msr_index, data); - } -break ;case MSR_IA32_S_CET : +vmcs_writel (GUEST_S_CET , data); +break ;case MSR_KVM_GUEST_SSP : +vmcs_writel (GUEST_SSP , data); +break ;case MSR_IA32_INT_SSP_TAB : -if (kvm_set_msr_common (vcpu, msr_info)) -return 1 ; -if (msr_index ==MSR_KVM_GUEST_SSP ) -vmcs_writel (GUEST_SSP , data); -else if (msr_index ==MSR_IA32_S_CET ) -vmcs_writel (GUEST_S_CET , data); -else if (msr_index ==MSR_IA32_INT_SSP_TAB ) -vmcs_writel (GUEST_INTR_SSP_TABLE , data); +vmcs_writel (GUEST_INTR_SSP_TABLE , data);break ;case MSR_IA32_PERF_CAPABILITIES :if (data && !vcpu_to_pmu (vcpu)->version)
arch/x86/kvm/x86.c +54 -97
204 lines not on this page · raw message
base-commit: efb9177acd7a4df5883b844e1ec9c69ef0899c9c
Paolo Bonzini
maintainerRe: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 4 lines · Sean Christopherson
Quoted 4 lines
Quoted 4 lines
arch/x86/kvm/x86.c +4
-0+ +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT )) +return false;
Quoted 8 lines
Quoted 4 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ + return msr->host_initiated || + guest_cpuid_has(vcpu, X86_FEATURE_IBT) || + guest_cpuid_has(vcpu, X86_FEATURE_SHSTK);Similar to my suggestsion for XSS, I think we drop the waiver for
host_initiatedaccesses, i.e. require the feature to be enabled and exposed to the guest, even for the host.
No, please don't. Allowing host-initiated accesses is what makes it possible to take the list of MSR indices and pass it blindly to KVM_GET_MSR and KVM_SET_MSR. This should be documented, will send a patch.
Paolo
Sean Christopherson
maintainerRe: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 14 lines · Paolo Bonzini
Quoted 4 lines · Sean Christopherson
Quoted 4 lines
Quoted 4 lines
arch/x86/kvm/x86.c +4
-0+ +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT )) +return false;Quoted 8 lines
Quoted 4 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ + return msr->host_initiated || + guest_cpuid_has(vcpu, X86_FEATURE_IBT) || + guest_cpuid_has(vcpu, X86_FEATURE_SHSTK);Similar to my suggestsion for XSS, I think we drop the waiver for
host_initiatedaccesses, i.e. require the feature to be enabled and exposed to the guest, even for the host.
Quoted 3 lines
No, please don't. Allowing host-initiated accesses is what makes it possible to take the list of MSR indices and pass it blindly to
KVM_GET_MSRandKVM_SET_MSR.
I don't see how that can work today. Oooh, the MSRs that don't exempt host_initiated are added to the list of MSRs to save/restore, i.e. KVM "silently" supports MSR_AMD64_OSVW_ID_LENGTH and MSR_AMD64_OSVW_STATUS.
And guest_pv_has() returns true unless userspace has opted in to enforcement.
Sad panda.
That means we need to figure out a solution for KVM stuffing GUEST_SSP on RSM, which is a "host" write but a guest controlled value.
Paolo Bonzini
maintainerRe: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 1 line · Sean Christopherson
Oooh, the MSRs that don't exempt
host_initiatedare added to the list
(are *not* added)
Quoted 4 lines
of MSRs to save/restore, i.e. KVM "silently" supports
MSR_AMD64_OSVW_ID_LENGTHandMSR_AMD64_OSVW_STATUS.And
guest_pv_has()returns true unless userspace has opted in to enforcement.
Two different ways of having the same bug. The latter was introduced in the implementation of KVM_CAP_ENFORCE_PV_FEATURE_CPUID; it would become a problem if some selftests started using it.
Paolo
Re: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
In reply to Sean ChristophersonQuoted 49 lines · Sean Christopherson
Quoted 37 lines · Chao Gao
Quoted 21 lines · Yang Weijiang
Add emulation interface for CET MSR read and write. The emulation code is split into common part and vendor specific part, the former resides in
x86.cto benefic different x86 CPU vendors, the latter for VMX is implemented in this patch.Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/kvm/vmx/vmx.c | 27 +++++++++++ arch/x86/kvm/x86.c | 104 +++++++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.h | 18 +++++++ 3 files changed, 141 insertions(+), 8 deletions(-)arch/x86/kvm/vmx/vmx.c +1
-0@@ -2095,6 +2095,18 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else msr_info->data = vmx->pt_desc.guest.addr_a[index /2 ];break ; +case MSR_IA32_S_CET :arch/x86/kvm/vmx/vmx.c static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2108
Quoted 10 lines
arch/x86/kvm/vmx/vmx.c +10
-0+case MSR_KVM_GUEST_SSP : +case MSR_IA32_INT_SSP_TAB : +if (kvm_get_msr_common (vcpu, msr_info)) +return 1 ; +if (msr_info->index ==MSR_KVM_GUEST_SSP ) + msr_info->data =vmcs_readl (GUEST_SSP ); +else if (msr_info->index ==MSR_IA32_S_CET ) + msr_info->data =vmcs_readl (GUEST_S_CET ); +else if (msr_info->index ==MSR_IA32_INT_SSP_TAB ) + msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE );This if-else-if suggests that they are focibly grouped together to just share the call of
kvm_get_msr_common(). For readability, I think it is better to handle them separately.e.g.,
Quoted 11 lines
case MSR_IA32_S_CET: if (kvm_get_msr_common(vcpu, msr_info)) return 1; msr_info->data = vmcs_readl(GUEST_S_CET); break; case MSR_KVM_GUEST_SSP: if (kvm_get_msr_common(vcpu, msr_info)) return 1; msr_info->data = vmcs_readl(GUEST_SSP); break;
Quoted 6 lines
Actually, we can do even better. We have an existing framework for these types of prechecks, I just completely forgot about it :-( (my "look at PAT" was a bad suggestion).
Handle the checks in
__kvm_set_msr()and__kvm_get_msr(), i.e. *before* calling into vendor code. Then vendor code doesn't need to make weird callbacks.
I see, will change it, thank you!
Quoted 11 lines
Quoted 9 lines
arch/x86/kvm/vmx/vmx.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4018
Quoted 9 lines
arch/x86/kvm/vmx/vmx.c +2
-0int kvm_set_msr_common (struct kvm_vcpu *vcpu,struct msr_data *msr_info) {u32 msr = msr_info->index;@@ -3981,6 +4014,45 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.guest_fpu.xfd_err = data;break ;#endif +#define CET_EXCLUSIVE_BITS (CET_SUPPRESS | CET_WAIT_ENDBR) +#define CET_CTRL_RESERVED_BITS GENMASK(9, 6)Please use a single namespace for these #defines, e.g. CET_CTRL_* or maybe CET_US_* for everything.
OK.
Quoted 6 lines
Quoted 4 lines
arch/x86/kvm/vmx/vmx.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4022
Quoted 4 lines
arch/x86/kvm/vmx/vmx.c +4
-0+#define CET_SHSTK_MASK_BITS GENMASK(1, 0) +#define CET_IBT_MASK_BITS (GENMASK_ULL(5, 2) | \ + GENMASK_ULL(63, 10)) +#define CET_LEG_BITMAP_BASE (data) ((data) >> 12)Bah, stupid SDM. Please spell out "LEGACY", I though "LEG" was short for "LEGAL" since this looks a lot like a page shift, i.e. getting a pfn.
Sure :-)
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
arch/x86/kvm/vmx/vmx.c +16
-0+static bool kvm_cet_is_msr_accessible (struct kvm_vcpu *vcpu, +struct msr_data *msr) +{ +if (is_shadow_stack_msr (msr->index)) { +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK )) +return false; + +if (msr->index ==MSR_KVM_GUEST_SSP ) +return msr->host_initiated; + +return msr->host_initiated || +guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); + } + +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT ))
Quoted 8 lines
Quoted 5 lines
arch/x86/kvm/vmx/vmx.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4043
Quoted 5 lines
arch/x86/kvm/vmx/vmx.c +5
-0+return false; + +return msr->host_initiated || +guest_cpuid_has (vcpu,X86_FEATURE_IBT ) || +guest_cpuid_has (vcpu,X86_FEATURE_SHSTK );Similar to my suggestsion for XSS, I think we drop the waiver for
host_initiatedaccesses, i.e. require the feature to be enabled and exposed to the guest, even for the host.
I saw Paolo shares different opinion on this, so would hold on for a while...
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/x86.h +0
-0@@ -552,4 +552,22 @@ int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port, void *data, unsigned int count, int in);
Quoted 6 lines
Quoted 6 lines
arch/x86/kvm/x86.h int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, · line 558
Quoted 4 lines
arch/x86/kvm/x86.h +4
-0+/* +* Guest xstate MSRs have been loaded in __msr_io(), disable preemption before +* access the MSRs to avoid MSR content corruption. +*/ I think it is better to describe what the function does prior to jumping into details like where guest FPU is loaded.
OK, will do it, thanks!
Quoted 5 lines
Quoted 5 lines
/*
* Lock and/or reload guest FPU and access xstate MSRs. For accesses initiated
* by host, guest FPU is loaded in__msr_io(). For accesses initiated by guest,
* guest FPU should have been loaded already.
*/
Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/x86.h +8
-0+static inline void kvm_get_xsave_msr (struct msr_data *msr_info) +{ +kvm_fpu_get (); +rdmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +} + +static inline void kvm_set_xsave_msr (struct msr_data *msr_info)Quoted 8 lines
arch/x86/kvm/x86.h int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size, · line 571
Quoted 5 lines
arch/x86/kvm/x86.h +5
-0+{ +kvm_fpu_get (); +wrmsrl (msr_info->index, msr_info->data); +kvm_fpu_put (); +}Can you rename functions to kvm_get/set_xstate_msr() to align with the comment and patch 6? And if there is no user outside
x86.c, you can just put these two functions right after theis_xstate_msr()added in patch 6.
OK, maybe I added the helpers in this patch duo to compilation error "function is defined but not used".
Quoted 1 line
+1. These should also assert that (a) guest FPU state is loaded and
Do you mean something like this:WARN_ON_ONCE(!vcpu->arch.guest_fpu->in_use) or KVM_BUG_ON() added in the helpers?
Quoted 4 lines
(b) the MSR
is passed through to the guest. I might be ok dropping (b) if both VMX and SVM passthrough all MSRs if they're exposed to the guest, i.e. not lazily passed through.
I'm OK to add the assert if finally all the CET MSRs are passed through directly.
Quoted 282 lines
Sans any changes to kvm_{g,s}et_xsave_msr(), I think this? (completely untested)
--- arch/x86/kvm/vmx/vmx.c | 34 +++------- arch/x86/kvm/x86.c | 151 +++++++++++++++-------------------------- 2 files changed, 64 insertions(+), 121 deletions(-)arch/x86/kvm/vmx/vmx.c +10
-24@@ -2100,16 +2100,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vmx->pt_desc.guest.addr_a[index /2 ];break ;case MSR_IA32_S_CET : + msr_info->data =vmcs_readl (GUEST_S_CET ); +break ;case MSR_KVM_GUEST_SSP : + msr_info->data =vmcs_readl (GUEST_SSP ); +break ;case MSR_IA32_INT_SSP_TAB : -if (kvm_get_msr_common (vcpu, msr_info)) -return 1 ; -if (msr_info->index ==MSR_KVM_GUEST_SSP ) - msr_info->data =vmcs_readl (GUEST_SSP ); -else if (msr_info->index ==MSR_IA32_S_CET ) - msr_info->data =vmcs_readl (GUEST_S_CET ); -else if (msr_info->index ==MSR_IA32_INT_SSP_TAB ) - msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE ); + msr_info->data =vmcs_readl (GUEST_INTR_SSP_TABLE );break ;case MSR_IA32_DEBUGCTLMSR : msr_info->data =vmcs_read64 (GUEST_IA32_DEBUGCTL );@@ -2432,25 +2429,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; - case MSR_IA32_PL0_SSP ... MSR_IA32_PL2_SSP: -if (kvm_set_msr_common (vcpu, msr_info)) -return 1 ; -if (data) { -vmx_disable_write_intercept_sss_msr (vcpu); -wrmsrl (msr_index, data); - } -break ;case MSR_IA32_S_CET : +vmcs_writel (GUEST_S_CET , data); +break ;case MSR_KVM_GUEST_SSP : +vmcs_writel (GUEST_SSP , data); +break ;case MSR_IA32_INT_SSP_TAB : -if (kvm_set_msr_common (vcpu, msr_info)) -return 1 ; -if (msr_index ==MSR_KVM_GUEST_SSP ) -vmcs_writel (GUEST_SSP , data); -else if (msr_index ==MSR_IA32_S_CET ) -vmcs_writel (GUEST_S_CET , data); -else if (msr_index ==MSR_IA32_INT_SSP_TAB ) -vmcs_writel (GUEST_INTR_SSP_TABLE , data); +vmcs_writel (GUEST_INTR_SSP_TABLE , data);break ;case MSR_IA32_PERF_CAPABILITIES :if (data && !vcpu_to_pmu (vcpu)->version)arch/x86/kvm/x86.c +54
-97@@ -1838,6 +1838,11 @@ bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type) }EXPORT_SYMBOL_GPL (kvm_msr_allowed); +#define CET_US_RESERVED_BITS GENMASK(9, 6) +#define CET_US_SHSTK_MASK_BITS GENMASK(1, 0) +#define CET_US_IBT_MASK_BITS (GENMASK_ULL(5, 2) | GENMASK_ULL(63, 10)) +#define CET_US_LEGACY_BITMAP_BASE (data) ((data) >> 12) +/* * Write @data into the MSR specified by @index. Select MSR specific fault * checks are bypassed if @host_initiated is %true. @@ -1897,6 +1902,35 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, data = (u32 )data;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +if (!guest_can_use (vcpu,X86_FEATURE_SHSTK ) && + !guest_can_use (vcpu,X86_FEATURE_IBT )) +return 1 ; +if (data &CET_US_RESERVED_BITS ) +return 1 ; +if (!guest_can_use (vcpu,X86_FEATURE_SHSTK ) && + (data &CET_US_SHSTK_MASK_BITS )) +return 1 ; +if (!guest_can_use (vcpu,X86_FEATURE_IBT ) && + (data &CET_US_IBT_MASK_BITS )) +return 1 ; +if (!IS_ALIGNED (CET_US_LEGACY_BITMAP_BASE (data),4 )) +return 1 ; + +/* IBT can be suppressed iff the TRACKER isn't WAIT_ENDR. */ +if ((data &CET_SUPPRESS ) && (data &CET_WAIT_ENDBR )) +return 1 ; +break ; + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +case MSR_KVM_GUEST_SSP : +if (!guest_can_use (vcpu,X86_FEATURE_SHSTK )) +return 1 ; +if (is_noncanonical_address (data, vcpu)) +return 1 ; +if (!IS_ALIGNED (data,4 )) +return 1 ; +break ; } msr.data = data;@@ -1940,6 +1974,17 @@ static int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, !guest_cpuid_has(vcpu, X86_FEATURE_RDPID))return 1 ;break ; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : +if (!guest_can_use (vcpu,X86_FEATURE_IBT ) && + !guest_can_use (vcpu,X86_FEATURE_SHSTK )) +return 1 ; +break ; + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +case MSR_KVM_GUEST_SSP : +if (!guest_can_use (vcpu,X86_FEATURE_SHSTK )) +return 1 ; +break ; } msr.index = index;@@ -3640,47 +3685,6 @@ static bool kvm_is_msr_to_save(u32 msr_index)return false; } -static inline bool is_shadow_stack_msr (u32 msr) -{ -return msr ==MSR_IA32_PL0_SSP || - msr ==MSR_IA32_PL1_SSP || - msr ==MSR_IA32_PL2_SSP || - msr ==MSR_IA32_PL3_SSP || - msr ==MSR_IA32_INT_SSP_TAB || - msr ==MSR_KVM_GUEST_SSP ; -} - -static bool kvm_cet_is_msr_accessible (struct kvm_vcpu *vcpu, -struct msr_data *msr) -{ -if (is_shadow_stack_msr (msr->index)) { -if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK )) -return false; - -/* -* This MSR is synthesized mainly for userspace access during -* Live Migration, it also can be accessed in SMM mode by VMM. -* Guest is not allowed to access this MSR. -*/ -if (msr->index ==MSR_KVM_GUEST_SSP ) { -if (IS_ENABLED (CONFIG_X86_64 ) &&is_smm (vcpu)) -return true; - -return msr->host_initiated; - } - -return msr->host_initiated || -guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); - } - -if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && - !kvm_cpu_cap_has (X86_FEATURE_IBT )) -return false; - -return msr->host_initiated || -guest_cpuid_has (vcpu,X86_FEATURE_IBT ) || -guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); -}int kvm_set_msr_common (struct kvm_vcpu *vcpu,struct msr_data *msr_info) {@@ -4036,46 +4040,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.guest_fpu.xfd_err = data;break ;#endif -#define CET_EXCLUSIVE_BITS (CET_SUPPRESS | CET_WAIT_ENDBR) -#define CET_CTRL_RESERVED_BITS GENMASK(9, 6) -#define CET_SHSTK_MASK_BITS GENMASK(1, 0) -#define CET_IBT_MASK_BITS (GENMASK_ULL(5, 2) | \ - GENMASK_ULL(63, 10)) -#define CET_LEG_BITMAP_BASE (data) ((data) >> 12)case MSR_IA32_U_CET : -case MSR_IA32_S_CET : -if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) -return 1 ; -if (!!(data &CET_CTRL_RESERVED_BITS )) -return 1 ; -if (!guest_can_use (vcpu,X86_FEATURE_SHSTK ) && - (data &CET_SHSTK_MASK_BITS )) -return 1 ; -if (!guest_can_use (vcpu,X86_FEATURE_IBT ) && - (data &CET_IBT_MASK_BITS )) -return 1 ; -if (!IS_ALIGNED (CET_LEG_BITMAP_BASE (data),4 ) || - (data &CET_EXCLUSIVE_BITS ) ==CET_EXCLUSIVE_BITS ) -return 1 ; -if (msr ==MSR_IA32_U_CET ) -kvm_set_xsave_msr (msr_info); -break ; -case MSR_KVM_GUEST_SSP : - case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: -if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) -return 1 ; -if (is_noncanonical_address (data, vcpu)) -return 1 ; -if (!IS_ALIGNED (data,4 )) -return 1 ; -if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || - msr ==MSR_IA32_PL2_SSP ) { - vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ] = data; -if (!vcpu->arch.cet_sss_active && data) - vcpu->arch.cet_sss_active = true; - }else if (msr ==MSR_IA32_PL3_SSP ) { -kvm_set_xsave_msr (msr_info); - } + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: +kvm_set_xsave_msr (msr_info);break ;default :if (kvm_pmu_is_valid_msr (vcpu, msr))@@ -4436,17 +4403,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)break ;#endif case MSR_IA32_U_CET : -case MSR_IA32_S_CET : -case MSR_KVM_GUEST_SSP : - case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: -if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) -return 1 ; -if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || - msr ==MSR_IA32_PL2_SSP ) { - msr_info->data = vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ]; - }else if (msr ==MSR_IA32_U_CET || msr ==MSR_IA32_PL3_SSP ) { -kvm_get_xsave_msr (msr_info); - } + case MSR_IA32_PL0_SSP ... MSR_IA32_PL3_SSP: +kvm_get_xsave_msr (msr_info);break ;default :if (kvm_pmu_is_valid_msr (vcpu, msr))@@ -7330,9 +7288,13 @@ static void kvm_probe_msr_to_save(u32 msr_index)break ;case MSR_IA32_U_CET :case MSR_IA32_S_CET : +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT )) +return ; +break ;case MSR_KVM_GUEST_SSP : case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: -if (!kvm_is_cet_supported ()) +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ))return ;break ;default :@@ -9664,13 +9626,8 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) kvm_caps.supported_xcr0 = host_xcr0 &KVM_SUPPORTED_XCR0 ; }if (boot_cpu_has (X86_FEATURE_XSAVES )) { -u32 eax, ebx, ecx, edx; - -cpuid_count (0xd ,1 , &eax, &ebx, &ecx, &edx);rdmsrl (MSR_IA32_XSS , host_xss); kvm_caps.supported_xss = host_xss &KVM_SUPPORTED_XSS ; -if (ecx &XFEATURE_MASK_CET_KERNEL ) - kvm_caps.supported_xss |=XFEATURE_MASK_CET_KERNEL ; }rdmsrl_safe (MSR_EFER , &host_efer);
Quoted 1 line
base-commit:
efb9177acd7a4df5883b844e1ec9c69ef0899c9c
The code looks good to me except the handling of MSR_KVM_GUEST_SSP, non-host-initiated read/write should be prevented.
Paolo Bonzini
maintainerRe: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 5 lines · Weijiang
Quoted 3 lines
Similar to my suggestsion for XSS, I think we drop the waiver for
host_initiatedaccesses, i.e. require the feature to be enabled and exposed to the guest, even for the host.I saw Paolo shares different opinion on this, so would hold on for a while...
It's not *so* different: the host initiated access should be allowed, but it should only allow writing zero. So, something like:
Review
Quoted 3 lines
(quoted diff) +3
-0+static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu, + struct msr_data *msr) +{
bool host_msr_reset =
msr->host_initiated && msr->data == 0;
and then below you use host_msr_reset instead of msr->host_initiated.
Review
Quoted 5 lines
(quoted diff) +5
-0+ if (msr->index == MSR_KVM_GUEST_SSP) + return msr->host_initiated; + + return msr->host_initiated || + guest_cpuid_has(vcpu, X86_FEATURE_SHSTK);
This can be unified like this:
return
(host_msr_reset || guest_cpuid_has(vcpu, X86_FEATURE_SHSTK)) && (msr->index != MSR_KVM_GUEST_SSP || msr->host_initiated);
Review
Quoted 9 lines
(quoted diff) +9
-0+ } + + if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) && + !kvm_cpu_cap_has(X86_FEATURE_IBT)) + return false; + + return msr->host_initiated || + guest_cpuid_has(vcpu, X86_FEATURE_IBT) || + guest_cpuid_has(vcpu, X86_FEATURE_SHSTK);
while this can simply use host_msr_reset.
Paolo
Re: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
In reply to Yang Weijiangarch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4048
Quoted 7 lines
arch/x86/kvm/x86.c +7
-0+ case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) +return 1 ; +if (is_noncanonical_address (data, vcpu)) +return 1 ; +if (!IS_ALIGNED (data,4 )) +return 1 ;
Why should MSR_IA32_INT_SSP_TAB be 4-byte aligned? I don't see this requirement in SDM.
IA32_INTERRUPT_SSP_TABLE_ADDR:
Linear address of a table of seven shadow
stack pointers that are selected in IA-32e
mode using the IST index (when not 0) from
the interrupt gate descriptor. (R/W)
This MSR is not present on processors that
do not support Intel 64 architecture. This
field cannot represent a non-canonical
address.
Re: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 9 lines · Chao Gao
arch/x86/kvm/x86.c int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4048
Quoted 7 lines
arch/x86/kvm/x86.c +7
-0+ case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +if (!kvm_cet_is_msr_accessible (vcpu, msr_info)) +return 1 ; +if (is_noncanonical_address (data, vcpu)) +return 1 ; +if (!IS_ALIGNED (data,4 )) +return 1 ;Why should
MSR_IA32_INT_SSP_TABbe 4-byte aligned? I don't see this requirement in SDM.
It must be something wrong in my memory, thanks for catching it!
Quoted 10 lines
IA32_INTERRUPT_SSP_TABLE_ADDR:Linear address of a table of seven shadow
stack pointers that are selected in IA-32e
mode using the IST index (when not 0) from
the interrupt gate descriptor. (R/W)
This MSR is not present on processors that
do not support Intel 64 architecture. This
field cannot represent a non-canonical
address.
Paolo Bonzini
maintainerRe: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
In reply to Yang Weijiangarch/x86/kvm/vmx/vmx.c static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2104
Quoted 2 lines · Yang Weijiang
arch/x86/kvm/vmx/vmx.c +2
-0+if (msr_info->index ==MSR_KVM_GUEST_SSP ) + msr_info->data =vmcs_readl (GUEST_SSP );
Accesses to MSR_KVM_(GUEST_)SSP must be rejected unless host-initiated.
Paolo
Re: [PATCH v5 11/19] KVM:VMX: Emulate read and write to CET MSRs
Quoted 5 lines · Paolo Bonzini
Quoted 2 lines · Yang Weijiang
+ if (
msr_info->index==MSR_KVM_GUEST_SSP) +msr_info->data=vmcs_readl(GUEST_SSP);Accesses to MSR_KVM_(GUEST_)SSP must be rejected unless host-initiated.
Yes, it's kept, in v5 it's folded in:
+static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu,
+struct msr_data *msr)
+{
+if (is_shadow_stack_msr(msr->index)) {
+if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK))
+return false;
+
+if (msr->index == MSR_KVM_GUEST_SSP)
+return msr->host_initiated;
+
+return msr->host_initiated ||
+guest_cpuid_has(vcpu, X86_FEATURE_SHSTK);
+}
+
+if (!kvm_cpu_cap_has(X86_FEATURE_SHSTK) &&
+!kvm_cpu_cap_has(X86_FEATURE_IBT))
+return false;
+
+return msr->host_initiated ||
+guest_cpuid_has(vcpu, X86_FEATURE_IBT) ||
+guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); }
+
Quoted 2 lines
Paolo
PATCH v5 12/19 KVM:x86: Save and reload SSP to/from SMRAM
In reply to Yang WeijiangSave CET SSP to SMRAM on SMI and reload it on RSM.
KVM emulates architectural behavior when guest enters/leaves SMM mode, i.e., save registers to SMRAM at the entry of SMM and reload them at the exit of SMM. Per SDM, SSP is defined as one of the fields in SMRAM for 64-bit mode, so handle the state accordingly.
Check is_smm() to determine whether kvm_cet_is_msr_accessible() is called in SMM mode so that kvm_{set,get}_msr() works in SMM mode.
--- arch/x86/kvm/smm.c | 11 +++++++++++ arch/x86/kvm/smm.h | 2 +- arch/x86/kvm/x86.c | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-)
arch/x86/kvm/smm.c +11 -0
@@ -309,6 +309,12 @@ void enter_smm(struct kvm_vcpu *vcpu)kvm_smm_changed (vcpu, true); +#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_get_msr (vcpu,MSR_KVM_GUEST_SSP , &smram.smram64.ssp)) + goto error; +#endif +if (kvm_vcpu_write_guest (vcpu, vcpu->arch.smbase +0xfe00 , &smram,sizeof (smram))) goto error;
@@ -586,6 +592,11 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt)if ((vcpu->arch.hflags &HF_SMM_INSIDE_NMI_MASK ) ==0 )static_call (kvm_x86_set_nmi_mask)(vcpu, false); +#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_set_msr (vcpu,MSR_KVM_GUEST_SSP , smram.smram64.ssp)) +return X86EMUL_UNHANDLEABLE ; +#endif kvm_smm_changed (vcpu, false);/*
arch/x86/kvm/smm.h +1 -1
@@ -116,8 +116,8 @@ struct kvm_smram_state_64 {u32 smbase;u32 reserved4[5 ]; -/* ssp and svm_* fields below are not implemented by KVM */ u64 ssp; +/* svm_* fields below are not implemented by KVM */ u64 svm_guest_pat;u64 svm_host_efer;u64 svm_host_cr4;
arch/x86/kvm/x86.c +10 -1
@@ -3644,8 +3644,17 @@ static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu,if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ))return false; -if (msr->index ==MSR_KVM_GUEST_SSP ) +/* +* This MSR is synthesized mainly for userspace access during +* Live Migration, it also can be accessed in SMM mode by VMM. +* Guest is not allowed to access this MSR. +*/ +if (msr->index ==MSR_KVM_GUEST_SSP ) { +if (IS_ENABLED (CONFIG_X86_64 ) &&is_smm (vcpu)) +return true; +return msr->host_initiated; + }return msr->host_initiated ||guest_cpuid_has (vcpu,X86_FEATURE_SHSTK );
Signature · 1 line
2.27.0
Re: [PATCH v5 12/19] KVM:x86: Save and reload SSP to/from SMRAM
Quoted 21 lines · Yang Weijiang
Save CET SSP to SMRAM on SMI and reload it on RSM.
KVM emulates architectural behavior when guest enters/leaves SMM mode, i.e., save registers to SMRAM at the entry of SMM and reload them at the exit of SMM. Per SDM, SSP is defined as one of the fields in SMRAM for 64-bit mode, so handle the state accordingly.Check
is_smm()to determine whetherkvm_cet_is_msr_accessible()is called in SMM mode so that kvm_{set,get}_msr() works in SMM mode.Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/kvm/smm.c | 11 +++++++++++ arch/x86/kvm/smm.h | 2 +- arch/x86/kvm/x86.c | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-)arch/x86/kvm/smm.c +0
-0
arch/x86/kvm/smm.c void enter_smm(struct kvm_vcpu *vcpu) · line 316
Quoted 8 lines
arch/x86/kvm/smm.c +5
-0@@ -309,6 +309,12 @@ void enter_smm(struct kvm_vcpu *vcpu)kvm_smm_changed (vcpu, true); +#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_get_msr (vcpu,MSR_KVM_GUEST_SSP , &smram.smram64.ssp)) + goto error; +#endif
SSP save/load should go to enter_smm_save_state_64() and rsm_load_state_64(), where other fields of SMRAM are handled.
Quoted 37 lines
arch/x86/kvm/smm.c +6
-0+if (kvm_vcpu_write_guest (vcpu, vcpu->arch.smbase +0xfe00 , &smram,sizeof (smram))) goto error;@@ -586,6 +592,11 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt)if ((vcpu->arch.hflags &HF_SMM_INSIDE_NMI_MASK ) ==0 )static_call (kvm_x86_set_nmi_mask)(vcpu, false); +#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_set_msr (vcpu,MSR_KVM_GUEST_SSP , smram.smram64.ssp)) +return X86EMUL_UNHANDLEABLE ; +#endif kvm_smm_changed (vcpu, false);/* arch/x86/kvm/smm.h +1
-1@@ -116,8 +116,8 @@ struct kvm_smram_state_64 {u32 smbase;u32 reserved4[5 ]; -/* ssp and svm_* fields below are not implemented by KVM */ u64 ssp; +/* svm_* fields below are not implemented by KVM */ u64 svm_guest_pat;u64 svm_host_efer;u64 svm_host_cr4;arch/x86/kvm/x86.c +0
-0@@ -3644,8 +3644,17 @@ static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu,if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ))return false;
arch/x86/kvm/x86.c static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu, · line 3654
Quoted 10 lines
arch/x86/kvm/x86.c +8
-1-if (msr->index ==MSR_KVM_GUEST_SSP ) +/* +* This MSR is synthesized mainly for userspace access during +* Live Migration, it also can be accessed in SMM mode by VMM. +* Guest is not allowed to access this MSR. +*/ +if (msr->index ==MSR_KVM_GUEST_SSP ) { +if (IS_ENABLED (CONFIG_X86_64 ) &&is_smm (vcpu)) +return true;
On second thoughts, this is incorrect. We don't want guest in SMM mode to read/write SSP via the synthesized MSR. Right?
You can
1. move set/get guest SSP into two helper functions, e.g., kvm_set/get_ssp()
2. call kvm_set/get_ssp() for host-initiated MSR accesses and SMM transitions.
3. refuse guest accesses to the synthesized MSR.
Quoted 9 lines
arch/x86/kvm/x86.c +2
-0+return msr->host_initiated; + }return msr->host_initiated ||guest_cpuid_has (vcpu,X86_FEATURE_SHSTK );Signature · 1 line
2.27.0
Sean Christopherson
maintainerRe: [PATCH v5 12/19] KVM:x86: Save and reload SSP to/from SMRAM
Quoted 25 lines · Chao Gao
Quoted 24 lines · Yang Weijiang
Save CET SSP to SMRAM on SMI and reload it on RSM.
KVM emulates architectural behavior when guest enters/leaves SMM mode, i.e., save registers to SMRAM at the entry of SMM and reload them at the exit of SMM. Per SDM, SSP is defined as one of the fields in SMRAM for 64-bit mode, so handle the state accordingly.Check
is_smm()to determine whetherkvm_cet_is_msr_accessible()is called in SMM mode so that kvm_{set,get}_msr() works in SMM mode.Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/kvm/smm.c | 11 +++++++++++ arch/x86/kvm/smm.h | 2 +- arch/x86/kvm/x86.c | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-)arch/x86/kvm/smm.c +0
-0@@ -309,6 +309,12 @@ void enter_smm(struct kvm_vcpu *vcpu)kvm_smm_changed (vcpu, true);
Quoted 8 lines
arch/x86/kvm/smm.c void enter_smm(struct kvm_vcpu *vcpu) · line 316
Quoted 5 lines
arch/x86/kvm/smm.c +5
-0+#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_get_msr (vcpu,MSR_KVM_GUEST_SSP , &smram.smram64.ssp)) + goto error; +#endif SSP save/load should go to
enter_smm_save_state_64()andrsm_load_state_64(), where other fields of SMRAM are handled.
+1. The right way to get/set MSRs like this is to use __kvm_get_msr() and pass %true for @host_initiated. Though I would add a prep patch to provide wrappers for __kvm_get_msr() and __kvm_set_msr(). Naming will be hard, but I think we can use kvm_{read,write}_msr() to go along with the KVM-initiated register accessors/mutators, e.g. kvm_register_read(), kvm_pdptr_write(), etc.
Then you don't need to wait until after kvm_smm_changed(), and kvm_cet_is_msr_accessible() doesn't need the confusing (and broken) SMM waiver, e.g. as Chao points out below, that would allow the guest to access the synthetic MSR.
Delta patch at the bottom (would need to be split up, rebased, etc.).
Quoted 37 lines
Quoted 37 lines
arch/x86/kvm/smm.c +5
-0if (kvm_vcpu_write_guest (vcpu, vcpu->arch.smbase +0xfe00 , &smram,sizeof (smram))) goto error;@@ -586,6 +592,11 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt)if ((vcpu->arch.hflags &HF_SMM_INSIDE_NMI_MASK ) ==0 )static_call (kvm_x86_set_nmi_mask)(vcpu, false); +#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_set_msr (vcpu,MSR_KVM_GUEST_SSP , smram.smram64.ssp)) +return X86EMUL_UNHANDLEABLE ; +#endif kvm_smm_changed (vcpu, false);/* arch/x86/kvm/smm.h +1
-1@@ -116,8 +116,8 @@ struct kvm_smram_state_64 {u32 smbase;u32 reserved4[5 ]; -/* ssp and svm_* fields below are not implemented by KVM */ u64 ssp; +/* svm_* fields below are not implemented by KVM */ u64 svm_guest_pat;u64 svm_host_efer;u64 svm_host_cr4;arch/x86/kvm/x86.c +0
-0@@ -3644,8 +3644,17 @@ static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu,if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ))return false;
Quoted 12 lines
arch/x86/kvm/x86.c static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu, · line 3654
Quoted 9 lines
arch/x86/kvm/x86.c +8
-1-if (msr->index ==MSR_KVM_GUEST_SSP ) +/* +* This MSR is synthesized mainly for userspace access during +* Live Migration, it also can be accessed in SMM mode by VMM. +* Guest is not allowed to access this MSR. +*/ +if (msr->index ==MSR_KVM_GUEST_SSP ) { +if (IS_ENABLED (CONFIG_X86_64 ) &&is_smm (vcpu)) +return true;On second thoughts, this is incorrect. We don't want guest in SMM mode to read/write SSP via the synthesized MSR. Right?
It's not a guest read though, KVM is doing the read while emulating SMI/RSM.
Quoted 3 lines
You can
1. move set/get guest SSP into two helper functions, e.g., kvm_set/get_ssp()
2. call kvm_set/get_ssp() for host-initiated MSR accesses and SMM transitions.
We could, but that would largely defeat the purpose of kvm_x86_ops.{g,s}et_msr(), i.e. we already have hooks to get at MSR values that are buried in the VMCS/VMCB, the interface is just a bit kludgy.
Quoted 1 line
3. refuse guest accesses to the synthesized MSR.
--- arch/x86/include/asm/kvm_host.h | 8 +++++++- arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/smm.c | 10 ++++------ arch/x86/kvm/x86.c | 17 +++++++++++++---- 4 files changed, 25 insertions(+), 12 deletions(-)
arch/x86/include/asm/kvm_host.h +7 -1
@@ -1939,7 +1939,13 @@ void kvm_prepare_emulation_failure_exit(struct kvm_vcpu *vcpu);void kvm_enable_efer_bits (u64 );bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer); -int __kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data,bool host_initiated); + +/* +* kvm_msr_{read,write}() are KVM-internal helpers, i.e. for when KVM needs to +* get/set an MSR value when emulating CPU behavior. +*/ +int kvm_msr_read (struct kvm_vcpu *vcpu,u32 index,u64 *data); +int kvm_msr_write (struct kvm_vcpu *vcpu,u32 index,u64 *data);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,u32 index,u64 data);int kvm_emulate_rdmsr (struct kvm_vcpu *vcpu);
arch/x86/kvm/cpuid.c +1 -1
@@ -1515,7 +1515,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, *edx = entry->edx;if (function ==7 && index ==0 ) {u64 data; -if (!__kvm_get_msr (vcpu,MSR_IA32_TSX_CTRL , &data, true) && +if (!kvm_msr_read (vcpu,MSR_IA32_TSX_CTRL , &data) && (data &TSX_CTRL_CPUID_CLEAR )) *ebx &= ~(F (RTM ) |F (HLE )); }else if (function ==0x80000007 ) {
arch/x86/kvm/smm.c +4 -6
@@ -275,6 +275,10 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu,enter_smm_save_seg_64 (vcpu, &smram->gs,VCPU_SREG_GS ); smram->int_shadow =static_call (kvm_x86_get_interrupt_shadow)(vcpu); + + if (guest_can_use(vcpu, X86_FEATURE_SHSTK) +KVM_BUG_ON (kvm_msr_read (vcpu,MSR_KVM_GUEST_SSP , + &smram.smram64.ssp), vcpu->kvm)); }#endif
@@ -309,12 +313,6 @@ void enter_smm(struct kvm_vcpu *vcpu)kvm_smm_changed (vcpu, true); -#ifdef CONFIG_X86_64 -if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && -kvm_get_msr (vcpu,MSR_KVM_GUEST_SSP , &smram.smram64.ssp)) - goto error; -#endif -if (kvm_vcpu_write_guest (vcpu, vcpu->arch.smbase +0xfe00 , &smram,sizeof (smram))) goto error;
arch/x86/kvm/x86.c +13 -4
@@ -1924,8 +1924,8 @@ static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu,* Returns 0 on success, non-0 otherwise. * Assumes vcpu_load() was already called. */ -int __kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data, -bool host_initiated) +static int __kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data, +bool host_initiated) {struct msr_data msr;int ret;
@@ -1951,6 +1951,16 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data,return ret; } +int kvm_msr_write (struct kvm_vcpu *vcpu,u32 index,u64 *data) +{ +return __kvm_get_msr (vcpu, index, data, true); +} + +int kvm_msr_read (struct kvm_vcpu *vcpu,u32 index,u64 *data) +{ +return __kvm_get_msr (vcpu, index, data, true); +} +static int kvm_get_msr_ignored_check (struct kvm_vcpu *vcpu,u32 index,u64 *data,bool host_initiated) {
@@ -4433,8 +4443,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)return 1 ;if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || msr ==MSR_IA32_PL2_SSP ) { - msr_info->data = - vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ]; + msr_info->data = vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ]; }else if (msr ==MSR_IA32_U_CET || msr ==MSR_IA32_PL3_SSP ) {kvm_get_xsave_msr (msr_info); }
base-commit: 82e95ab0094bf1b823a6f9c9a07238852b375a22
Re: [PATCH v5 12/19] KVM:x86: Save and reload SSP to/from SMRAM
Quoted 39 lines · Sean Christopherson
Quoted 25 lines · Chao Gao
Quoted 24 lines · Yang Weijiang
Save CET SSP to SMRAM on SMI and reload it on RSM.
KVM emulates architectural behavior when guest enters/leaves SMM mode, i.e., save registers to SMRAM at the entry of SMM and reload them at the exit of SMM. Per SDM, SSP is defined as one of the fields in SMRAM for 64-bit mode, so handle the state accordingly.Check
is_smm()to determine whetherkvm_cet_is_msr_accessible()is called in SMM mode so that kvm_{set,get}_msr() works in SMM mode.Signed-off-by Yang Weijiang <[email protected]>---
arch/x86/kvm/smm.c | 11 +++++++++++ arch/x86/kvm/smm.h | 2 +- arch/x86/kvm/x86.c | 11 ++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-)arch/x86/kvm/smm.c +0
-0@@ -309,6 +309,12 @@ void enter_smm(struct kvm_vcpu *vcpu)kvm_smm_changed (vcpu, true);Quoted 7 lines
arch/x86/kvm/smm.c void enter_smm(struct kvm_vcpu *vcpu) · line 316
Quoted 5 lines
arch/x86/kvm/smm.c +5
-0+#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_get_msr (vcpu,MSR_KVM_GUEST_SSP , &smram.smram64.ssp)) + goto error; +#endif SSP save/load should go to
enter_smm_save_state_64()andrsm_load_state_64(), where other fields of SMRAM are handled.+1. The right way to get/set MSRs like this is to use
__kvm_get_msr()and pass %true for @host_initiated. Though I would add a prep patch to provide wrappers for__kvm_get_msr()and__kvm_set_msr(). Naming will be hard, but I think we can use kvm_{read,write}_msr() to go along with the KVM-initiated register accessors/mutators, e.g.kvm_register_read(),kvm_pdptr_write(), etc.
Quoted 5 lines
Then you don't need to wait until after
kvm_smm_changed(), andkvm_cet_is_msr_accessible()doesn't need the confusing (and broken) SMM waiver, e.g. as Chao points out below, that would allow the guest to access the synthetic MSR.Delta patch at the bottom (would need to be split up, rebased, etc.).
Thanks! Will change the related stuffs per your suggestions!
Quoted 169 lines
Quoted 37 lines
Quoted 37 lines
arch/x86/kvm/smm.c +5
-0if (kvm_vcpu_write_guest (vcpu, vcpu->arch.smbase +0xfe00 , &smram,sizeof (smram))) goto error;@@ -586,6 +592,11 @@ int emulator_leave_smm(struct x86_emulate_ctxt *ctxt)if ((vcpu->arch.hflags &HF_SMM_INSIDE_NMI_MASK ) ==0 )static_call (kvm_x86_set_nmi_mask)(vcpu, false); +#ifdef CONFIG_X86_64 +if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && +kvm_set_msr (vcpu,MSR_KVM_GUEST_SSP , smram.smram64.ssp)) +return X86EMUL_UNHANDLEABLE ; +#endif kvm_smm_changed (vcpu, false);/* arch/x86/kvm/smm.h +1
-1@@ -116,8 +116,8 @@ struct kvm_smram_state_64 {u32 smbase;u32 reserved4[5 ]; -/* ssp and svm_* fields below are not implemented by KVM */ u64 ssp; +/* svm_* fields below are not implemented by KVM */ u64 svm_guest_pat;u64 svm_host_efer;u64 svm_host_cr4;arch/x86/kvm/x86.c +0
-0@@ -3644,8 +3644,17 @@ static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu,if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ))return false;Quoted 11 lines
arch/x86/kvm/x86.c static bool kvm_cet_is_msr_accessible(struct kvm_vcpu *vcpu, · line 3654
Quoted 9 lines
arch/x86/kvm/x86.c +8
-1-if (msr->index ==MSR_KVM_GUEST_SSP ) +/* +* This MSR is synthesized mainly for userspace access during +* Live Migration, it also can be accessed in SMM mode by VMM. +* Guest is not allowed to access this MSR. +*/ +if (msr->index ==MSR_KVM_GUEST_SSP ) { +if (IS_ENABLED (CONFIG_X86_64 ) &&is_smm (vcpu)) +return true;On second thoughts, this is incorrect. We don't want guest in SMM mode to read/write SSP via the synthesized MSR. Right?
It's not a guest read though, KVM is doing the read while emulating SMI/RSM.
Quoted 3 lines
You can
1. move set/get guest SSP into two helper functions, e.g., kvm_set/get_ssp()
2. call kvm_set/get_ssp() for host-initiated MSR accesses and SMM transitions.We could, but that would largely defeat the purpose of kvm_x86_ops.{g,s}et_msr(), i.e. we already have hooks to get at MSR values that are buried in the VMCS/VMCB, the interface is just a bit kludgy.
Quoted 1 line
3. refuse guest accesses to the synthesized MSR.
--- arch/x86/include/asm/kvm_host.h | 8 +++++++- arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/smm.c | 10 ++++------ arch/x86/kvm/x86.c | 17 +++++++++++++---- 4 files changed, 25 insertions(+), 12 deletions(-)arch/x86/include/asm/kvm_host.h +7
-1@@ -1939,7 +1939,13 @@ void kvm_prepare_emulation_failure_exit(struct kvm_vcpu *vcpu);void kvm_enable_efer_bits (u64 );bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer); -int __kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data,bool host_initiated); + +/* +* kvm_msr_{read,write}() are KVM-internal helpers, i.e. for when KVM needs to +* get/set an MSR value when emulating CPU behavior. +*/ +int kvm_msr_read (struct kvm_vcpu *vcpu,u32 index,u64 *data); +int kvm_msr_write (struct kvm_vcpu *vcpu,u32 index,u64 *data);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,u32 index,u64 data);int kvm_emulate_rdmsr (struct kvm_vcpu *vcpu);arch/x86/kvm/cpuid.c +1
-1@@ -1515,7 +1515,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, *edx = entry->edx;if (function ==7 && index ==0 ) {u64 data; -if (!__kvm_get_msr (vcpu,MSR_IA32_TSX_CTRL , &data, true) && +if (!kvm_msr_read (vcpu,MSR_IA32_TSX_CTRL , &data) && (data &TSX_CTRL_CPUID_CLEAR )) *ebx &= ~(F (RTM ) |F (HLE )); }else if (function ==0x80000007 ) {arch/x86/kvm/smm.c +4
-6@@ -275,6 +275,10 @@ static void enter_smm_save_state_64(struct kvm_vcpu *vcpu,enter_smm_save_seg_64 (vcpu, &smram->gs,VCPU_SREG_GS ); smram->int_shadow =static_call (kvm_x86_get_interrupt_shadow)(vcpu); + + if (guest_can_use(vcpu, X86_FEATURE_SHSTK) +KVM_BUG_ON (kvm_msr_read (vcpu,MSR_KVM_GUEST_SSP , + &smram.smram64.ssp), vcpu->kvm)); }#endif @@ -309,12 +313,6 @@ void enter_smm(struct kvm_vcpu *vcpu)kvm_smm_changed (vcpu, true); -#ifdef CONFIG_X86_64 -if (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && -kvm_get_msr (vcpu,MSR_KVM_GUEST_SSP , &smram.smram64.ssp)) - goto error; -#endif -if (kvm_vcpu_write_guest (vcpu, vcpu->arch.smbase +0xfe00 , &smram,sizeof (smram))) goto error;arch/x86/kvm/x86.c +13
-4@@ -1924,8 +1924,8 @@ static int kvm_set_msr_ignored_check(struct kvm_vcpu *vcpu,* Returns 0 on success, non-0 otherwise. * Assumes vcpu_load() was already called. */ -int __kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data, -bool host_initiated) +static int __kvm_get_msr (struct kvm_vcpu *vcpu,u32 index,u64 *data, +bool host_initiated) {struct msr_data msr;int ret;@@ -1951,6 +1951,16 @@ int __kvm_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data,return ret; } +int kvm_msr_write (struct kvm_vcpu *vcpu,u32 index,u64 *data) +{ +return __kvm_get_msr (vcpu, index, data, true); +} + +int kvm_msr_read (struct kvm_vcpu *vcpu,u32 index,u64 *data) +{ +return __kvm_get_msr (vcpu, index, data, true); +} +static int kvm_get_msr_ignored_check (struct kvm_vcpu *vcpu,u32 index,u64 *data,bool host_initiated) {@@ -4433,8 +4443,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)return 1 ;if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || msr ==MSR_IA32_PL2_SSP ) { - msr_info->data = - vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ]; + msr_info->data = vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ]; }else if (msr ==MSR_IA32_U_CET || msr ==MSR_IA32_PL3_SSP ) {kvm_get_xsave_msr (msr_info); }base-commit:
82e95ab0094bf1b823a6f9c9a07238852b375a22
PATCH v5 13/19 KVM:VMX: Set up interception for CET MSRs
In reply to Yang WeijiangPass through CET MSRs when the associated feature is enabled. Shadow Stack feature requires all the CET MSRs to make it architectural support in guest. IBT feature only depends on MSR_IA32_U_CET and MSR_IA32_S_CET to enable both user and supervisor IBT. Note, This MSR design introduced an architectual limitation of SHSTK and IBT control for guest, i.e., when SHSTK is exposed, IBT is also available to guest from architectual level since IBT relies on subset of SHSTK relevant MSRs.
--- arch/x86/kvm/vmx/vmx.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
arch/x86/kvm/vmx/vmx.c +41 -0
@@ -709,6 +709,10 @@ static bool is_valid_passthrough_msr(u32 msr) case MSR_LBR_CORE_TO ... MSR_LBR_CORE_TO + 8:/* LBR MSRs. These are handled in vmx_update_intercept_for_lbr_msrs() */ return true; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +return true; } r =possible_passthrough_msr_slot (msr) != -ENOENT ;
@@ -7747,6 +7751,41 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) vmx->pt_desc.ctl_bitmask &= ~(0xfULL << (32 + i *4 )); } +static void vmx_update_intercept_for_cet_msr (struct kvm_vcpu *vcpu) +{ +bool incpt; + +if (kvm_cpu_cap_has (X86_FEATURE_SHSTK )) { + incpt = !guest_cpuid_has (vcpu,X86_FEATURE_SHSTK ); + +vmx_set_intercept_for_msr (vcpu,MSR_IA32_U_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_S_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL0_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL1_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL2_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL3_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_INT_SSP_TAB , +MSR_TYPE_RW , incpt); +if (!incpt) +return ; + } + +if (kvm_cpu_cap_has (X86_FEATURE_IBT )) { + incpt = !guest_can_use (vcpu,X86_FEATURE_IBT ); + +vmx_set_intercept_for_msr (vcpu,MSR_IA32_U_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_S_CET , +MSR_TYPE_RW , incpt); + } +} +static void vmx_vcpu_after_set_cpuid (struct kvm_vcpu *vcpu) {struct vcpu_vmx *vmx =to_vmx (vcpu);
@@ -7814,6 +7853,8 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)/* Refresh #PF interception to account for MAXPHYADDR changes. */ vmx_update_exception_bitmap (vcpu); + +vmx_update_intercept_for_cet_msr (vcpu); }static u64 vmx_get_perf_capabilities (void )
Signature · 1 line
2.27.0
Re: [PATCH v5 13/19] KVM:VMX: Set up interception for CET MSRs
Quoted 10 lines · Yang Weijiang
Pass through CET MSRs when the associated feature is enabled. Shadow Stack feature requires all the CET MSRs to make it architectural support in guest. IBT feature only depends on
MSR_IA32_U_CETandMSR_IA32_S_CETto enable both user and supervisor IBT. Note, This MSR design introduced an architectual limitation of SHSTK and IBT control for guest, i.e., when SHSTK is exposed, IBT is also available to guest from architectual level since IBT relies on subset of SHSTK relevant MSRs.Signed-off-by Yang Weijiang <[email protected]>
one nit below
Quoted 29 lines
---
arch/x86/kvm/vmx/vmx.c| 41 +++++++++++++++++++++++++++++++++++++++++1 file changed, 41 insertions(+)arch/x86/kvm/vmx/vmx.c +10
-0@@ -709,6 +709,10 @@ static bool is_valid_passthrough_msr(u32 msr) case MSR_LBR_CORE_TO ... MSR_LBR_CORE_TO + 8:/* LBR MSRs. These are handled in vmx_update_intercept_for_lbr_msrs() */ return true; +case MSR_IA32_U_CET : +case MSR_IA32_S_CET : + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: +return true; } r =possible_passthrough_msr_slot (msr) != -ENOENT ;@@ -7747,6 +7751,41 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) vmx->pt_desc.ctl_bitmask &= ~(0xfULL << (32 + i *4 )); } +static void vmx_update_intercept_for_cet_msr (struct kvm_vcpu *vcpu) +{ +bool incpt; + +if (kvm_cpu_cap_has (X86_FEATURE_SHSTK )) { + incpt = !guest_cpuid_has (vcpu,X86_FEATURE_SHSTK );
...
Quoted 11 lines
arch/x86/kvm/vmx/vmx.c +11
-0+ +vmx_set_intercept_for_msr (vcpu,MSR_IA32_U_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_S_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL0_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL1_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL2_SSP , +MSR_TYPE_RW , incpt);
arch/x86/kvm/vmx/vmx.c static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) · line 7780
Quoted 10 lines
arch/x86/kvm/vmx/vmx.c +10
-0+vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL3_SSP , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_INT_SSP_TAB , +MSR_TYPE_RW , incpt); +if (!incpt) +return ; + } + +if (kvm_cpu_cap_has (X86_FEATURE_IBT )) { + incpt = !guest_can_use (vcpu,X86_FEATURE_IBT );
can you use guest_can_use() or guest_cpuid_has() consistently?
Quoted 23 lines
arch/x86/kvm/vmx/vmx.c +8
-0+ +vmx_set_intercept_for_msr (vcpu,MSR_IA32_U_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_S_CET , +MSR_TYPE_RW , incpt); + } +} +static void
vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu){ struct vcpu_vmx *vmx = to_vmx(vcpu);arch/x86/kvm/vmx/vmx.c +2
-0@@ -7814,6 +7853,8 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)/* Refresh #PF interception to account for MAXPHYADDR changes. */ vmx_update_exception_bitmap (vcpu); + +vmx_update_intercept_for_cet_msr (vcpu); }static u64 vmx_get_perf_capabilities (void )Signature · 1 line
2.27.0
Re: [PATCH v5 13/19] KVM:VMX: Set up interception for CET MSRs
Quoted 10 lines · Chao Gao
Quoted 9 lines · Yang Weijiang
Pass through CET MSRs when the associated feature is enabled. Shadow Stack feature requires all the CET MSRs to make it architectural support in guest. IBT feature only depends on
MSR_IA32_U_CETandMSR_IA32_S_CETto enable both user and supervisor IBT. Note, This MSR design introduced an architectual limitation of SHSTK and IBT control for guest, i.e., when SHSTK is exposed, IBT is also available to guest from architectual level since IBT relies on subset of SHSTK relevant MSRs.
Quoted 4 lines
Quoted 1 line
Signed-off-by Yang Weijiang <[email protected]>Reviewed-by Chao Gao <[email protected]>one nit below
Thanks!
Quoted 5 lines
[...]
arch/x86/kvm/vmx/vmx.c static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) · line 7780
Quoted 3 lines
arch/x86/kvm/vmx/vmx.c +3
-0+ +if (kvm_cpu_cap_has (X86_FEATURE_IBT )) { + incpt = !guest_can_use (vcpu,X86_FEATURE_IBT );can you use
guest_can_use()orguest_cpuid_has()consistently?
Hmm, the inspiration actually came from Sean:
Re: [RFC PATCH v2 3/6] KVM: x86: SVM: Pass through shadow stack MSRs - Sean Christopherson (kernel.org) <https://lore.kernel.org/all/[email protected]/>
it would make the code more reasonable on non-CET platforms.
Quoted 23 lines
Quoted 23 lines
arch/x86/kvm/vmx/vmx.c +8
-0+ +vmx_set_intercept_for_msr (vcpu,MSR_IA32_U_CET , +MSR_TYPE_RW , incpt); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_S_CET , +MSR_TYPE_RW , incpt); + } +} +static void
vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu){ struct vcpu_vmx *vmx = to_vmx(vcpu);arch/x86/kvm/vmx/vmx.c +2
-0@@ -7814,6 +7853,8 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)/* Refresh #PF interception to account for MAXPHYADDR changes. */ vmx_update_exception_bitmap (vcpu); + +vmx_update_intercept_for_cet_msr (vcpu); }static u64 vmx_get_perf_capabilities (void )Signature · 1 line
2.27.0
Re: [PATCH v5 13/19] KVM:VMX: Set up interception for CET MSRs
Quoted 6 lines
Quoted 3 lines
arch/x86/kvm/vmx/vmx.c static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) · line 7780
Quoted 2 lines
arch/x86/kvm/vmx/vmx.c +2
-0+if (kvm_cpu_cap_has (X86_FEATURE_IBT )) { + incpt = !guest_can_use (vcpu,X86_FEATURE_IBT );can you use
guest_can_use()orguest_cpuid_has()consistently?Hmm, the inspiration actually came from Sean:
Re: [RFC PATCH v2 3/6] KVM: x86: SVM: Pass through shadow stack MSRs - Sean Christopherson (kernel.org) <https://lore.kernel.org/all/[email protected]/>
it would make the code more reasonable on non-CET platforms.
then, can you switch to use guest_cpuid_has() for IBT here as you do a few lines above for the SHSTK? that's why I said "consistently".
Re: [PATCH v5 13/19] KVM:VMX: Set up interception for CET MSRs
Quoted 8 lines · Chao Gao
Quoted 6 lines
Quoted 3 lines
arch/x86/kvm/vmx/vmx.c static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) · line 7780
Quoted 2 lines
arch/x86/kvm/vmx/vmx.c +2
-0+if (kvm_cpu_cap_has (X86_FEATURE_IBT )) { + incpt = !guest_can_use (vcpu,X86_FEATURE_IBT );can you use
guest_can_use()orguest_cpuid_has()consistently?Hmm, the inspiration actually came from Sean:
Re: [RFC PATCH v2 3/6] KVM: x86: SVM: Pass through shadow stack MSRs - Sean Christopherson (kernel.org) <https://lore.kernel.org/all/[email protected]/>
it would make the code more reasonable on non-CET platforms.then, can you switch to use
guest_cpuid_has()for IBT here as you do a few lines above for the SHSTK? that's why I said "consistently".
Oh, I should use guest_cpuid_has() instead of guest_can_use() here, thanks!
PATCH v5 14/19 KVM:VMX: Set host constant supervisor states to VMCS fields
In reply to Yang WeijiangSet constant values to HOST_{S_CET,SSP,INTR_SSP_TABLE} VMCS fields explicitly. Kernel IBT is supported and the setting in MSR_IA32_S_CET is static after post-boot(except is BIOS call case but vCPU thread never across it.), i.e. KVM doesn't need to refresh HOST_S_CET field before every VM-Enter/VM-Exit sequence.
Host supervisor shadow stack is not enabled now and SSP is not accessible to kernel mode, thus it's safe to set host IA32_INT_ SSP_TAB/SSP VMCS fields to 0s. When shadow stack is enabled for CPL3, SSP is reloaded from IA32_PL3_SSP before it exits to userspace. Check SDM Vol 2A/B Chapter 3/4 for SYSCALL/SYSRET/SYSENTER SYSEXIT/ RDSSP/CALL etc.
Prevent KVM module loading and if host supervisor shadow stack SHSTK_EN is set in MSR_IA32_S_CET as KVM cannot co-exit with it correctly.
--- arch/x86/kvm/vmx/capabilities.h | 4 ++++ arch/x86/kvm/vmx/vmx.c | 15 +++++++++++++++ arch/x86/kvm/x86.c | 14 ++++++++++++++ arch/x86/kvm/x86.h | 1 + 4 files changed, 34 insertions(+)
arch/x86/kvm/vmx/capabilities.h +4 -0
@@ -106,6 +106,10 @@ static inline bool cpu_has_load_perf_global_ctrl(void)return vmcs_config.vmentry_ctrl &VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ; } +static inline bool cpu_has_load_cet_ctrl (void ) +{ +return (vmcs_config.vmentry_ctrl &VM_ENTRY_LOAD_CET_STATE ); +}static inline bool cpu_has_vmx_mpx (void ) {return vmcs_config.vmentry_ctrl &VM_ENTRY_LOAD_BNDCFGS ;
arch/x86/kvm/vmx/vmx.c +15 -0
@@ -4341,6 +4341,21 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)if (cpu_has_load_ia32_efer ())vmcs_write64 (HOST_IA32_EFER , host_efer); + +/* +* Supervisor shadow stack is not enabled on host side, i.e., +* host IA32_S_CET.SHSTK_EN bit is guaranteed to 0 now, per SDM +* description(RDSSP instruction), SSP is not readable in CPL0, +* so resetting the two registers to 0s at VM-Exit does no harm +* to kernel execution. When execution flow exits to userspace, +* SSP is reloaded from IA32_PL3_SSP. Check SDM Vol.2A/B Chapter +* 3 and 4 for details. +*/ +if (cpu_has_load_cet_ctrl ()) { +vmcs_writel (HOST_S_CET , host_s_cet); +vmcs_writel (HOST_SSP ,0 ); +vmcs_writel (HOST_INTR_SSP_TABLE ,0 ); + } }void set_cr4_guest_host_mask (struct vcpu_vmx *vmx)
arch/x86/kvm/x86.c +14 -0
@@ -113,6 +113,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);#endif static u64 __read_mostly cr4_reserved_bits =CR4_RESERVED_BITS ; +u64 __read_mostly host_s_cet; +EXPORT_SYMBOL_GPL (host_s_cet);#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE)
@@ -9615,6 +9617,18 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)return -EIO ; } +if (boot_cpu_has (X86_FEATURE_SHSTK )) { +rdmsrl (MSR_IA32_S_CET , host_s_cet); +/* +* Linux doesn't yet support supervisor shadow stacks (SSS), so +* KVM doesn't save/restore the associated MSRs, i.e. KVM may +* clobber the host values. Yell and refuse to load if SSS is +* unexpectedly enabled, e.g. to avoid crashing the host. +*/ +if (WARN_ON_ONCE (host_s_cet &CET_SHSTK_EN )) +return -EIO ; + } + x86_emulator_cache =kvm_alloc_emulator_cache ();if (!x86_emulator_cache) {pr_err ("failed to allocate cache for x86 emulator\n" );
arch/x86/kvm/x86.h +1 -0
@@ -323,6 +323,7 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu);extern u64 host_xcr0;extern u64 host_xss; +extern u64 host_s_cet;extern struct kvm_caps kvm_caps;
Signature · 1 line
2.27.0
Re: [PATCH v5 14/19] KVM:VMX: Set host constant supervisor states to VMCS fields
Quoted 14 lines · Yang Weijiang
Set constant values to HOST_{S_CET,SSP,INTR_SSP_TABLE} VMCS fields explicitly. Kernel IBT is supported and the setting in
MSR_IA32_S_CETis static after post-boot(except is BIOS call case but vCPU thread never across it.), i.e. KVM doesn't need to refreshHOST_S_CETfield before every VM-Enter/VM-Exit sequence.Host supervisor shadow stack is not enabled now and SSP is not accessible to kernel mode, thus it's safe to set host
IA32_INT_SSP_TAB/SSP VMCS fields to 0s. When shadow stack is enabled for CPL3, SSP is reloaded fromIA32_PL3_SSPbefore it exits to userspace. Check SDM Vol 2A/B Chapter 3/4 for SYSCALL/SYSRET/SYSENTER SYSEXIT/ RDSSP/CALL etc.
Quoted 7 lines
Prevent KVM module loading and if host supervisor shadow stack
SHSTK_ENis set inMSR_IA32_S_CETas KVM cannot co-exit with it correctly.Suggested-by Sean Christopherson <[email protected]>Suggested-by Chao Gao <[email protected]>Signed-off-by Yang Weijiang <[email protected]>
PATCH v5 15/19 KVM:x86: Optimize CET supervisor SSP save/reload
In reply to Yang WeijiangMake PL{0,1,2}_SSP as write-intercepted to detect whether guest is using these MSRs. Disable intercept to the MSRs if they're written with non-zero values. KVM does save/ reload for the MSRs only if they're used by guest.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx/vmx.c | 31 ++++++++++++++++++++++++++++--- arch/x86/kvm/x86.c | 8 ++++++-- 3 files changed, 35 insertions(+), 5 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -748,6 +748,7 @@ struct kvm_vcpu_arch {bool tpr_access_reporting;bool xsaves_enabled;bool xfd_no_write_intercept; +bool cet_sss_active;u64 ia32_xss;u64 microcode_version;u64 arch_capabilities;
arch/x86/kvm/vmx/vmx.c +28 -3
@@ -2152,6 +2152,18 @@ static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiatedreturn debugctl; } +static void vmx_disable_write_intercept_sss_msr (struct kvm_vcpu *vcpu) +{ +if (guest_can_use (vcpu,X86_FEATURE_SHSTK )) { +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL0_SSP , +MSR_TYPE_RW , false); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL1_SSP , +MSR_TYPE_RW , false); +vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL2_SSP , +MSR_TYPE_RW , false); + } +} +/* * Writes msr value into the appropriate "register". * Returns 0 on success, non-0 otherwise.
@@ -2420,6 +2432,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; + case MSR_IA32_PL0_SSP ... MSR_IA32_PL2_SSP: +if (kvm_set_msr_common (vcpu, msr_info)) +return 1 ; +if (data) { +vmx_disable_write_intercept_sss_msr (vcpu); +wrmsrl (msr_index, data); + } +break ;case MSR_IA32_S_CET :case MSR_KVM_GUEST_SSP :case MSR_IA32_INT_SSP_TAB :
@@ -7777,12 +7797,17 @@ static void vmx_update_intercept_for_cet_msr(struct kvm_vcpu *vcpu) MSR_TYPE_RW, incpt);vmx_set_intercept_for_msr (vcpu,MSR_IA32_S_CET ,MSR_TYPE_RW , incpt); +/* +* Supervisor shadow stack MSRs are intercepted until +* they're written by guest, this is designed to +* optimize the save/restore overhead. +*/ vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL0_SSP , -MSR_TYPE_RW , incpt); +MSR_TYPE_R , incpt);vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL1_SSP , -MSR_TYPE_RW , incpt); +MSR_TYPE_R , incpt);vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL2_SSP , -MSR_TYPE_RW , incpt); +MSR_TYPE_R , incpt);vmx_set_intercept_for_msr (vcpu,MSR_IA32_PL3_SSP ,MSR_TYPE_RW , incpt); vmx_set_intercept_for_msr(vcpu, MSR_IA32_INT_SSP_TAB,
arch/x86/kvm/x86.c +6 -2
@@ -4060,6 +4060,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)if (msr ==MSR_IA32_PL0_SSP || msr ==MSR_IA32_PL1_SSP || msr ==MSR_IA32_PL2_SSP ) { vcpu->arch.cet_s_ssp[msr -MSR_IA32_PL0_SSP ] = data; +if (!vcpu->arch.cet_sss_active && data) + vcpu->arch.cet_sss_active = true; }else if (msr ==MSR_IA32_PL3_SSP ) {kvm_set_xsave_msr (msr_info); }
@@ -11241,7 +11243,8 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)void save_cet_supervisor_ssp (struct kvm_vcpu *vcpu) { -if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) { +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && + vcpu->arch.cet_sss_active)) {rdmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]);rdmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]);rdmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]);
@@ -11256,7 +11259,8 @@ EXPORT_SYMBOL_GPL(save_cet_supervisor_ssp);void reload_cet_supervisor_ssp (struct kvm_vcpu *vcpu) { -if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ))) { +if (unlikely (guest_can_use (vcpu,X86_FEATURE_SHSTK ) && + vcpu->arch.cet_sss_active)) {wrmsrl (MSR_IA32_PL0_SSP , vcpu->arch.cet_s_ssp[0 ]);wrmsrl (MSR_IA32_PL1_SSP , vcpu->arch.cet_s_ssp[1 ]);wrmsrl (MSR_IA32_PL2_SSP , vcpu->arch.cet_s_ssp[2 ]);
Signature · 1 line
2.27.0
Re: [PATCH v5 15/19] KVM:x86: Optimize CET supervisor SSP save/reload
Quoted 4 lines · Yang Weijiang
Make PL{0,1,2}_SSP as write-intercepted to detect whether guest is using these MSRs. Disable intercept to the MSRs if they're written with non-zero values. KVM does save/ reload for the MSRs only if they're used by guest.
What would happen if guest tries to use XRSTORS to load S_CET state from a xsave area without any writes to the PL0-2_SSP (i.e., at that point, writes to the MSRs are still intercepted)?
arch/x86/kvm/vmx/vmx.c static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2440
Quoted 10 lines
arch/x86/kvm/vmx/vmx.c +6
-0@@ -2420,6 +2432,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; + case MSR_IA32_PL0_SSP ... MSR_IA32_PL2_SSP: +if (kvm_set_msr_common (vcpu, msr_info)) +return 1 ; +if (data) { +vmx_disable_write_intercept_sss_msr (vcpu); +wrmsrl (msr_index, data);
Is it necessary to do the wrmsl()?
looks the next kvm_x86_prepare_switch_to_guest() will load PL0-2_SSP from the caching values.
Re: [PATCH v5 15/19] KVM:x86: Optimize CET supervisor SSP save/reload
Quoted 8 lines · Chao Gao
Quoted 4 lines · Yang Weijiang
Make PL{0,1,2}_SSP as write-intercepted to detect whether guest is using these MSRs. Disable intercept to the MSRs if they're written with non-zero values. KVM does save/ reload for the MSRs only if they're used by guest.
What would happen if guest tries to use XRSTORS to load
S_CETstate from a xsave area without any writes to the PL0-2_SSP (i.e., at that point, writes to the MSRs are still intercepted)?
I need to do some experiments to get the details, but now expect some kind of error in guest is seen.
Quoted 5 lines
Quoted 5 lines
arch/x86/kvm/vmx/vmx.c +1
-0@@ -2420,6 +2432,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else vmx->pt_desc.guest.addr_a[index /2 ] = data;break ; + case MSR_IA32_PL0_SSP ... MSR_IA32_PL2_SSP:
Quoted 8 lines
arch/x86/kvm/vmx/vmx.c static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 2440
Quoted 5 lines
arch/x86/kvm/vmx/vmx.c +5
-0+if (kvm_set_msr_common (vcpu, msr_info)) +return 1 ; +if (data) { +vmx_disable_write_intercept_sss_msr (vcpu); +wrmsrl (msr_index, data);Is it necessary to do the
wrmsl()?
looks the nextkvm_x86_prepare_switch_to_guest()will load PL0-2_SSP from the caching values.
Oh, yes, it's not necessary after moving the reload logic to kvm_x86_prepare_switch_to_guest(). Thanks!
PATCH v5 16/19 KVM:x86: Enable CET virtualization for VMX and advertise to userspace
In reply to Yang WeijiangEnable CET related feature bits in KVM capabilities array and make X86_CR4_CET available to guest. Remove the feature bits if host side dependencies cannot be met.
Set the feature bits so that CET features are available in guest CPUID. Add CR4.CET bit support in order to allow guest set CET master control bit(CR4.CET).
Disable KVM CET feature if unrestricted_guest is unsupported/disabled as KVM does not support emulating CET.
Don't expose CET feature if dependent CET bit(U_CET) is cleared in host XSS or if XSAVES isn't supported.
The CET bits in VM_ENTRY/VM_EXIT control fields should be set to make guest CET states isolated from host side. CET is only available on platforms that enumerate VMX_BASIC[bit 56] as 1.
--- arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/include/asm/msr-index.h | 1 + arch/x86/kvm/cpuid.c | 12 ++++++++++-- arch/x86/kvm/vmx/capabilities.h | 6 ++++++ arch/x86/kvm/vmx/vmx.c | 20 ++++++++++++++++++++ arch/x86/kvm/vmx/vmx.h | 6 ++++-- arch/x86/kvm/x86.c | 16 +++++++++++++++- arch/x86/kvm/x86.h | 3 +++ 8 files changed, 61 insertions(+), 6 deletions(-)
arch/x86/include/asm/kvm_host.h +2 -1
@@ -125,7 +125,8 @@ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \ | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \ | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \ - | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP)) + | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP \ + | X86_CR4_CET))#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
arch/x86/include/asm/msr-index.h +1 -0
@@ -1078,6 +1078,7 @@#define VMX_BASIC_MEM_TYPE_MASK 0x003c000000000000LLU#define VMX_BASIC_MEM_TYPE_WB 6LLU#define VMX_BASIC_INOUT 0x0040000000000000LLU +#define VMX_BASIC_NO_HW_ERROR_CODE 0x0100000000000000LLU/* Resctrl MSRs: */ /* - Intel: */
arch/x86/kvm/cpuid.c +10 -2
@@ -624,7 +624,7 @@ void kvm_set_cpu_caps(void)F (AVX512_VPOPCNTDQ ) |F (UMIP ) |F (AVX512_VBMI2 ) |F (GFNI ) |F (VAES ) |F (VPCLMULQDQ ) |F (AVX512_VNNI ) |F (AVX512_BITALG ) |F (CLDEMOTE ) |F (MOVDIRI ) |F (MOVDIR64B ) |0 /*WAITPKG*/ | -F (SGX_LC ) |F (BUS_LOCK_DETECT ) +F (SGX_LC ) |F (BUS_LOCK_DETECT ) |F (SHSTK ) );/* Set LA57 based on hardware capability. */ if (cpuid_ecx (7 ) &F (LA57 ))
@@ -642,7 +642,8 @@ void kvm_set_cpu_caps(void)F (SPEC_CTRL_SSBD ) |F (ARCH_CAPABILITIES ) |F (INTEL_STIBP ) |F (MD_CLEAR ) |F (AVX512_VP2INTERSECT ) |F (FSRM ) |F (SERIALIZE ) |F (TSXLDTRK ) |F (AVX512_FP16 ) | -F (AMX_TILE ) |F (AMX_INT8 ) |F (AMX_BF16 ) |F (FLUSH_L1D ) +F (AMX_TILE ) |F (AMX_INT8 ) |F (AMX_BF16 ) |F (FLUSH_L1D ) | +F (IBT ) );/* TSC_ADJUST and ARCH_CAPABILITIES are emulated in software. */
@@ -655,6 +656,13 @@ void kvm_set_cpu_caps(void)kvm_cpu_cap_set (X86_FEATURE_INTEL_STIBP );if (boot_cpu_has (X86_FEATURE_AMD_SSBD ))kvm_cpu_cap_set (X86_FEATURE_SPEC_CTRL_SSBD ); +/* +* The feature bit in boot_cpu_data.x86_capability could have been +* cleared due to ibt=off cmdline option, then add it back if CPU +* supports IBT. +*/ +if (cpuid_edx (7 ) &F (IBT )) +kvm_cpu_cap_set (X86_FEATURE_IBT ); kvm_cpu_cap_mask(CPUID_7_1_EAX, F(AVX_VNNI) | F(AVX512_BF16) | F(CMPCCXADD) |
arch/x86/kvm/vmx/capabilities.h +6 -0
@@ -79,6 +79,12 @@ static inline bool cpu_has_vmx_basic_inout(void)return (((u64 )vmcs_config.basic_cap <<32 ) &VMX_BASIC_INOUT ); } +static inline bool cpu_has_vmx_basic_no_hw_errcode (void ) +{ +return ((u64 )vmcs_config.basic_cap <<32 ) & +VMX_BASIC_NO_HW_ERROR_CODE ; +} +static inline bool cpu_has_virtual_nmis (void ) { return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS &&
arch/x86/kvm/vmx/vmx.c +20 -0
@@ -2624,6 +2624,7 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf, { VM_ENTRY_LOAD_IA32_EFER, VM_EXIT_LOAD_IA32_EFER }, { VM_ENTRY_LOAD_BNDCFGS, VM_EXIT_CLEAR_BNDCFGS }, { VM_ENTRY_LOAD_IA32_RTIT_CTL, VM_EXIT_CLEAR_IA32_RTIT_CTL }, + { VM_ENTRY_LOAD_CET_STATE, VM_EXIT_LOAD_CET_STATE }, };memset (vmcs_conf,0 ,sizeof (*vmcs_conf));
@@ -6357,6 +6358,12 @@ void dump_vmcs(struct kvm_vcpu *vcpu)if (vmcs_read32 (VM_EXIT_MSR_STORE_COUNT ) >0 )vmx_dump_msrs ("guest autostore" , &vmx->msr_autostore.guest); +if (vmentry_ctl &VM_ENTRY_LOAD_CET_STATE ) { +pr_err ("S_CET = 0x%016lx\n" ,vmcs_readl (GUEST_S_CET )); +pr_err ("SSP = 0x%016lx\n" ,vmcs_readl (GUEST_SSP )); +pr_err ("INTR SSP TABLE = 0x%016lx\n" , +vmcs_readl (GUEST_INTR_SSP_TABLE )); + }pr_err ("*** Host State ***\n" );pr_err ("RIP = 0x%016lx RSP = 0x%016lx\n" ,vmcs_readl (HOST_RIP ),vmcs_readl (HOST_RSP ));
@@ -6434,6 +6441,12 @@ void dump_vmcs(struct kvm_vcpu *vcpu)if (secondary_exec_control &SECONDARY_EXEC_ENABLE_VPID )pr_err ("Virtual processor ID = 0x%04x\n" ,vmcs_read16 (VIRTUAL_PROCESSOR_ID )); +if (vmexit_ctl &VM_EXIT_LOAD_CET_STATE ) { +pr_err ("S_CET = 0x%016lx\n" ,vmcs_readl (HOST_S_CET )); +pr_err ("SSP = 0x%016lx\n" ,vmcs_readl (HOST_SSP )); +pr_err ("INTR SSP TABLE = 0x%016lx\n" , +vmcs_readl (HOST_INTR_SSP_TABLE )); + } }/*
@@ -7970,6 +7983,13 @@ static __init void vmx_set_cpu_caps(void)if (cpu_has_vmx_waitpkg ())kvm_cpu_cap_check_and_set (X86_FEATURE_WAITPKG ); + +if (!cpu_has_load_cet_ctrl () || !enable_unrestricted_guest || + !cpu_has_vmx_basic_no_hw_errcode ()) { +kvm_cpu_cap_clear (X86_FEATURE_SHSTK ); +kvm_cpu_cap_clear (X86_FEATURE_IBT ); + kvm_caps.supported_xss &= ~CET_XSTATE_MASK ; + } }static void vmx_request_immediate_exit (struct kvm_vcpu *vcpu)
arch/x86/kvm/vmx/vmx.h +4 -2
@@ -481,7 +481,8 @@ static inline u8 vmx_get_rvi(void) VM_ENTRY_LOAD_IA32_EFER | \ VM_ENTRY_LOAD_BNDCFGS | \ VM_ENTRY_PT_CONCEAL_PIP | \ - VM_ENTRY_LOAD_IA32_RTIT_CTL) + VM_ENTRY_LOAD_IA32_RTIT_CTL | \ + VM_ENTRY_LOAD_CET_STATE)#define __KVM_REQUIRED_VMX_VM_EXIT_CONTROLS \ (VM_EXIT_SAVE_DEBUG_CONTROLS | \
@@ -503,7 +504,8 @@ static inline u8 vmx_get_rvi(void) VM_EXIT_LOAD_IA32_EFER | \ VM_EXIT_CLEAR_BNDCFGS | \ VM_EXIT_PT_CONCEAL_PIP | \ - VM_EXIT_CLEAR_IA32_RTIT_CTL) + VM_EXIT_CLEAR_IA32_RTIT_CTL | \ + VM_EXIT_LOAD_CET_STATE)#define KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL \ (PIN_BASED_EXT_INTR_MASK | \
arch/x86/kvm/x86.c +15 -1
@@ -230,7 +230,7 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) -#define KVM_SUPPORTED_XSS 0 +#define KVM_SUPPORTED_XSS (XFEATURE_MASK_CET_USER)u64 __read_mostly host_efer;EXPORT_SYMBOL_GPL (host_efer);
@@ -9669,6 +9669,20 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)kvm_ops_update (ops); +if (!kvm_is_cet_supported ()) { +kvm_cpu_cap_clear (X86_FEATURE_SHSTK ); +kvm_cpu_cap_clear (X86_FEATURE_IBT ); + } + +/* +* If SHSTK and IBT are not available in KVM, clear CET user bit in +* kvm_caps.supported_xss so that kvm_is_cet__supported() returns +* false when called. +*/ +if (!kvm_cpu_cap_has (X86_FEATURE_SHSTK ) && + !kvm_cpu_cap_has (X86_FEATURE_IBT )) + kvm_caps.supported_xss &= ~CET_XSTATE_MASK ; +for_each_online_cpu (cpu) {smp_call_function_single (cpu, kvm_x86_check_cpu_compat, &r,1 );if (r <0 )
arch/x86/kvm/x86.h +3 -0
@@ -542,6 +542,9 @@ bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type); __reserved_bits |=X86_CR4_VMXE ; \if (!__cpu_has (__c,X86_FEATURE_PCID )) \ __reserved_bits |=X86_CR4_PCIDE ; \ +if (!__cpu_has (__c,X86_FEATURE_SHSTK ) && \ + !__cpu_has (__c,X86_FEATURE_IBT )) \ + __reserved_bits |=X86_CR4_CET ; \ __reserved_bits; \ })
Signature · 1 line
2.27.0
PATCH v5 17/19 KVM:x86: Enable guest CET supervisor xstate bit support
In reply to Yang WeijiangAdd S_CET bit in kvm_caps.supported_xss so that guest can enumerate the feature in CPUID(0xd,1).ECX.
Guest S_CET xstate bit is specially handled, i.e., it can be exposed without related enabling on host side, because KVM manually saves/reloads guest supervisor SHSTK SSPs and current XSS swap logic for host/guest aslo supports doing so, thus it's safe to enable the bit without host support.
--- arch/x86/kvm/x86.c | 8 +++++++- arch/x86/kvm/x86.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +7 -1
@@ -230,7 +230,8 @@ static struct kvm_user_return_msrs __percpu *user_return_msrs; | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \ | XFEATURE_MASK_PKRU | XFEATURE_MASK_XTILE) -#define KVM_SUPPORTED_XSS (XFEATURE_MASK_CET_USER) +#define KVM_SUPPORTED_XSS (XFEATURE_MASK_CET_USER | \ + XFEATURE_MASK_CET_KERNEL)u64 __read_mostly host_efer;EXPORT_SYMBOL_GPL (host_efer);
@@ -9657,8 +9658,13 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)rdmsrl_safe (MSR_EFER , &host_efer);if (boot_cpu_has (X86_FEATURE_XSAVES )) { +u32 eax, ebx, ecx, edx; + +cpuid_count (0xd ,1 , &eax, &ebx, &ecx, &edx);rdmsrl (MSR_IA32_XSS , host_xss); kvm_caps.supported_xss = host_xss &KVM_SUPPORTED_XSS ; +if (ecx &XFEATURE_MASK_CET_KERNEL ) + kvm_caps.supported_xss |=XFEATURE_MASK_CET_KERNEL ; }kvm_init_pmu_capability (ops->pmu_ops);
arch/x86/kvm/x86.h +1 -1
@@ -363,7 +363,7 @@ static inline bool kvm_mpx_supported(void) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); } -#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER) +#define CET_XSTATE_MASK (XFEATURE_MASK_CET_USER | XFEATURE_MASK_CET_KERNEL)/* * Shadow Stack and Indirect Branch Tracking feature enabling depends on * whether host side CET user xstate bit is supported or not.
Signature · 1 line
2.27.0
Paolo Bonzini
maintainerRe: [PATCH v5 17/19] KVM:x86: Enable guest CET supervisor xstate bit support
arch/x86/kvm/x86.c static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) · line 9668
Quoted 9 lines · Yang Weijiang
if (boot_cpu_has(X86_FEATURE_XSAVES)) {arch/x86/kvm/x86.c +5
-0+u32 eax, ebx, ecx, edx; + +cpuid_count (0xd ,1 , &eax, &ebx, &ecx, &edx);rdmsrl (MSR_IA32_XSS , host_xss); kvm_caps.supported_xss = host_xss &KVM_SUPPORTED_XSS ; +if (ecx &XFEATURE_MASK_CET_KERNEL ) + kvm_caps.supported_xss |=XFEATURE_MASK_CET_KERNEL ; }
This is a bit hackish and makes me lean more towards adding support for XFEATURE_MASK_CET_KERNEL in host MSR_IA32_XSS (and then possibly hide it in the actual calls to XSAVE/XRSTORS for non-guest FPU).
Paolo
Re: [PATCH v5 17/19] KVM:x86: Enable guest CET supervisor xstate bit support
Quoted 11 lines · Paolo Bonzini
Quoted 9 lines · Yang Weijiang
if (
boot_cpu_has(X86_FEATURE_XSAVES)) {
+ u32 eax, ebx, ecx, edx;
+
+cpuid_count(0xd, 1, &eax, &ebx, &ecx, &edx);rdmsrl(MSR_IA32_XSS, host_xss); kvm_caps.supported_xss =host_xss&KVM_SUPPORTED_XSS; + if (ecx &XFEATURE_MASK_CET_KERNEL)
+ kvm_caps.supported_xss |=XFEATURE_MASK_CET_KERNEL; }
Quoted 1 line
This is a bit hackish and makes me lean more towards adding support for
XFEATURE_MASK_CET_KERNELin hostMSR_IA32_XSS(and then possibly hide it in the actual calls to XSAVE/XRSTORS for non-guest FPU).
Yes, if kernel can support CET_U/S bits in XSS, things would be much easier. But if CET_S bit cannot be enabled for somehow, we may have KVM emulation for it.
Quoted 2 lines
Paolo
PATCH v5 18/19 KVM:nVMX: Refine error code injection to nested VM
In reply to Yang WeijiangPer SDM description(Vol.3D, Appendix A.1):
"If bit 56 is read as 1, software can use VM entry to deliver a hardware exception with or without an error code, regardless of vector"
Modify has_error_code check before inject events to nested guest. Only enforce the check when guest is in real mode, the exception is not hard exception and the platform doesn't enumerate bit56 in VMX_BASIC, otherwise ignore it.
--- arch/x86/kvm/vmx/nested.c | 22 ++++++++++++++-------- arch/x86/kvm/vmx/nested.h | 7 +++++++ 2 files changed, 21 insertions(+), 8 deletions(-)
arch/x86/kvm/vmx/nested.c +14 -8
@@ -1205,9 +1205,9 @@ static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data) {const u64 feature_and_reserved =/* feature (except bit 48; see below) */ -BIT_ULL (49 ) |BIT_ULL (54 ) |BIT_ULL (55 ) | +BIT_ULL (49 ) |BIT_ULL (54 ) |BIT_ULL (55 ) |BIT_ULL (56 ) |/* reserved */ -BIT_ULL (31 ) |GENMASK_ULL (47 ,45 ) |GENMASK_ULL (63 ,56 ); +BIT_ULL (31 ) |GENMASK_ULL (47 ,45 ) |GENMASK_ULL (63 ,57 );u64 vmx_basic = vmcs_config.nested.basic;if (!is_bitwise_subset (vmx_basic, data, feature_and_reserved))
@@ -2846,12 +2846,16 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu, CC(intr_type == INTR_TYPE_OTHER_EVENT && vector != 0))return -EINVAL ; -/* VM-entry interruption-info field: deliver error code */ - should_have_error_code = - intr_type ==INTR_TYPE_HARD_EXCEPTION && prot_mode && -x86_exception_has_error_code (vector); -if (CC (has_error_code != should_have_error_code)) -return -EINVAL ; +if (!prot_mode || intr_type !=INTR_TYPE_HARD_EXCEPTION || + !nested_cpu_has_no_hw_errcode (vcpu)) { +/* VM-entry interruption-info field: deliver error code */ + should_have_error_code = + intr_type ==INTR_TYPE_HARD_EXCEPTION && + prot_mode && +x86_exception_has_error_code (vector); +if (CC (has_error_code != should_have_error_code)) +return -EINVAL ; + }/* VM-entry exception error code */ if (CC(has_error_code &&
@@ -6967,6 +6971,8 @@ static void nested_vmx_setup_basic(struct nested_vmx_msrs *msrs)if (cpu_has_vmx_basic_inout ()) msrs->basic |=VMX_BASIC_INOUT ; +if (cpu_has_vmx_basic_no_hw_errcode ()) + msrs->basic |=VMX_BASIC_NO_HW_ERROR_CODE ; }static void nested_vmx_setup_cr_fixed (struct nested_vmx_msrs *msrs)
arch/x86/kvm/vmx/nested.h +7 -0
@@ -284,6 +284,13 @@ static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val)__kvm_is_valid_cr4 (vcpu, val); } +static inline bool nested_cpu_has_no_hw_errcode (struct kvm_vcpu *vcpu) +{ +struct vcpu_vmx *vmx =to_vmx (vcpu); + +return vmx->nested.msrs.basic &VMX_BASIC_NO_HW_ERROR_CODE ; +} +/* No difference in the restrictions on guest and host CR4 in VMX operation. */ #define nested_guest_cr4_valid nested_cr4_valid#define nested_host_cr4_valid nested_cr4_valid
Signature · 1 line
2.27.0
Sean Christopherson
maintainerRe: [PATCH v5 18/19] KVM:nVMX: Refine error code injection to nested VM
This is not "refinement", this is full on supporting a new nVMX feature. Please phrase the shortlog accordingly, e.g. something like this (it's not very good, but it's a start).
KVM: nVMX: Add support for exposing "No PM H/W error code checks" to L1
Regarding shortlog, please update all of them in this series to put a space after the colon, i.e. "KVM: VMX:" and "KVM: x86:", not "KVM:x86:".
Quoted 6 lines
static void
nested_vmx_setup_cr_fixed(struct nested_vmx_msrs *msrs)arch/x86/kvm/vmx/nested.h +0
-0
arch/x86/kvm/vmx/nested.h static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val) · line 291
Quoted 8 lines
arch/x86/kvm/vmx/nested.h +5
-0@@ -284,6 +284,13 @@ static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val)__kvm_is_valid_cr4 (vcpu, val); } +static inline bool nested_cpu_has_no_hw_errcode (struct kvm_vcpu *vcpu) +{ +struct vcpu_vmx *vmx =to_vmx (vcpu); + +return vmx->nested.msrs.basic &VMX_BASIC_NO_HW_ERROR_CODE ;
The "CC" part of my suggestion is critical to this being sane. As is, this reads "nested CPU has no hardware error code", which is not even remotely close to the truth.
static inline bool nested_cpu_has_no_hw_errcode_cc(struct kvm_vcpu *vcpu)
{
return to_vmx(vcpu)->nested.msrs.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC;
}Re: [PATCH v5 18/19] KVM:nVMX: Refine error code injection to nested VM
Quoted 8 lines · Sean Christopherson
This is not "refinement", this is full on supporting a new nVMX feature. Please phrase the shortlog accordingly, e.g. something like this (it's not very good, but it's a start).
KVM: nVMX: Add support for exposing "No PM H/W error code checks" to L1
Regarding shortlog, please update all of them in this series to put a space after the colon, i.e. "KVM: VMX:" and "KVM: x86:", not "KVM:x86:".
OK, will update this part.
Quoted 9 lines
Quoted 9 lines
static void
nested_vmx_setup_cr_fixed(struct nested_vmx_msrs *msrs)arch/x86/kvm/vmx/nested.h +0
-0@@ -284,6 +284,13 @@ static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val)__kvm_is_valid_cr4 (vcpu, val); }
Quoted 8 lines
arch/x86/kvm/vmx/nested.h static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val) · line 291
Quoted 5 lines
arch/x86/kvm/vmx/nested.h +5
-0+static inline bool nested_cpu_has_no_hw_errcode (struct kvm_vcpu *vcpu) +{ +struct vcpu_vmx *vmx =to_vmx (vcpu); + +return vmx->nested.msrs.basic &VMX_BASIC_NO_HW_ERROR_CODE ;The "CC" part of my suggestion is critical to this being sane. As is, this reads "nested CPU has no hardware error code", which is not even remotely close to the truth.
Understood, I was not aware of the essence of "CC".
Quoted 6 lines
static inline bool
nested_cpu_has_no_hw_errcode_cc(struct kvm_vcpu *vcpu){ return to_vmx(vcpu)->nested.msrs.basic & VMX_BASIC_NO_HW_ERROR_CODE_CC; }
PATCH v5 19/19 KVM:nVMX: Enable CET support for nested VM
In reply to Yang WeijiangSet up CET MSRs, related VM_ENTRY/EXIT control bits and fixed setting for CR4 to enable CET for nested VM.
--- arch/x86/kvm/vmx/nested.c | 27 +++++++++++++++++++++++++-- arch/x86/kvm/vmx/vmcs12.c | 6 ++++++ arch/x86/kvm/vmx/vmcs12.h | 14 +++++++++++++- arch/x86/kvm/vmx/vmx.c | 2 ++ 4 files changed, 46 insertions(+), 3 deletions(-)
arch/x86/kvm/vmx/nested.c +25 -2
@@ -660,6 +660,28 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0,MSR_IA32_FLUSH_CMD ,MSR_TYPE_W ); +/* Pass CET MSRs to nested VM if L0 and L1 are set to pass-through. */ +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_U_CET ,MSR_TYPE_RW ); + +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_S_CET ,MSR_TYPE_RW ); + +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_PL0_SSP ,MSR_TYPE_RW ); + +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_PL1_SSP ,MSR_TYPE_RW ); + +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_PL2_SSP ,MSR_TYPE_RW ); + +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_PL3_SSP ,MSR_TYPE_RW ); + +nested_vmx_set_intercept_for_msr (vmx, msr_bitmap_l1, msr_bitmap_l0, +MSR_IA32_INT_SSP_TAB ,MSR_TYPE_RW ); +kvm_vcpu_unmap (vcpu, &vmx->nested.msr_bitmap_map, false); vmx->nested.force_msr_bitmap_recalc = false;
@@ -6793,7 +6815,7 @@ static void nested_vmx_setup_exit_ctls(struct vmcs_config *vmcs_conf,VM_EXIT_HOST_ADDR_SPACE_SIZE | #endifVM_EXIT_LOAD_IA32_PAT |VM_EXIT_SAVE_IA32_PAT | -VM_EXIT_CLEAR_BNDCFGS ; +VM_EXIT_CLEAR_BNDCFGS |VM_EXIT_LOAD_CET_STATE ; msrs->exit_ctls_high |=VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER |
@@ -6815,7 +6837,8 @@ static void nested_vmx_setup_entry_ctls(struct vmcs_config *vmcs_conf,#ifdef CONFIG_X86_64 VM_ENTRY_IA32E_MODE | #endif -VM_ENTRY_LOAD_IA32_PAT |VM_ENTRY_LOAD_BNDCFGS ; +VM_ENTRY_LOAD_IA32_PAT |VM_ENTRY_LOAD_BNDCFGS | +VM_ENTRY_LOAD_CET_STATE ; msrs->entry_ctls_high |= (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR |VM_ENTRY_LOAD_IA32_EFER |VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL );
arch/x86/kvm/vmx/vmcs12.c +6 -0
@@ -139,6 +139,9 @@ const unsigned short vmcs12_field_offsets[] = {FIELD (GUEST_PENDING_DBG_EXCEPTIONS , guest_pending_dbg_exceptions),FIELD (GUEST_SYSENTER_ESP , guest_sysenter_esp),FIELD (GUEST_SYSENTER_EIP , guest_sysenter_eip), +FIELD (GUEST_S_CET , guest_s_cet), +FIELD (GUEST_SSP , guest_ssp), +FIELD (GUEST_INTR_SSP_TABLE , guest_ssp_tbl),FIELD (HOST_CR0 , host_cr0),FIELD (HOST_CR3 , host_cr3), FIELD(HOST_CR4, host_cr4),
@@ -151,5 +154,8 @@ const unsigned short vmcs12_field_offsets[] = {FIELD (HOST_IA32_SYSENTER_EIP , host_ia32_sysenter_eip),FIELD (HOST_RSP , host_rsp),FIELD (HOST_RIP , host_rip), +FIELD (HOST_S_CET , host_s_cet), +FIELD (HOST_SSP , host_ssp), + FIELD(HOST_INTR_SSP_TABLE, host_ssp_tbl), };const unsigned int nr_vmcs12_fields =ARRAY_SIZE (vmcs12_field_offsets);
arch/x86/kvm/vmx/vmcs12.h +13 -1
@@ -117,7 +117,13 @@ struct __packed vmcs12 {natural_width host_ia32_sysenter_eip;natural_width host_rsp;natural_width host_rip; -natural_width paddingl[8 ];/* room for future expansion */ +natural_width host_s_cet; +natural_width host_ssp; +natural_width host_ssp_tbl; +natural_width guest_s_cet; +natural_width guest_ssp; +natural_width guest_ssp_tbl; +natural_width paddingl[2 ];/* room for future expansion */ u32 pin_based_vm_exec_control;u32 cpu_based_vm_exec_control;u32 exception_bitmap;
@@ -292,6 +298,12 @@ static inline void vmx_check_vmcs12_offsets(void)CHECK_OFFSET (host_ia32_sysenter_eip,656 );CHECK_OFFSET (host_rsp,664 );CHECK_OFFSET (host_rip,672 ); +CHECK_OFFSET (host_s_cet,680 ); +CHECK_OFFSET (host_ssp,688 ); +CHECK_OFFSET (host_ssp_tbl,696 ); +CHECK_OFFSET (guest_s_cet,704 ); +CHECK_OFFSET (guest_ssp,712 ); +CHECK_OFFSET (guest_ssp_tbl,720 );CHECK_OFFSET (pin_based_vm_exec_control,744 );CHECK_OFFSET (cpu_based_vm_exec_control,748 );CHECK_OFFSET (exception_bitmap,752 );
arch/x86/kvm/vmx/vmx.c +2 -0
@@ -7726,6 +7726,8 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu)cr4_fixed1_update (X86_CR4_PKE , ecx,feature_bit (PKU ));cr4_fixed1_update (X86_CR4_UMIP , ecx,feature_bit (UMIP ));cr4_fixed1_update (X86_CR4_LA57 , ecx,feature_bit (LA57 )); +cr4_fixed1_update (X86_CR4_CET , ecx,feature_bit (SHSTK )); +cr4_fixed1_update (X86_CR4_CET , edx,feature_bit (IBT ));#undef cr4_fixed1_update }
Signature · 1 line
2.27.0