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

KVM: x86: Enable guest SSP read/write interface with new uAPIs

Add a KVM-defined ONE_REG register, KVM_REG_GUEST_SSP, to let userspace
save and restore the guest's Shadow Stack Pointer (SSP). On both Intel
and AMD, SSP is a hardware register that can only be accessed by software
via dedicated ISA (e.g. RDSSP) or via VMCS/VMCB fields (used by hardware
to context switch SSP at entry/exit). As a result, SSP doesn't fit in
any of KVM's existing interfaces for saving/restoring state.

Internally, treat SSP as a fake/synthetic MSR, as the semantics of writes
to SSP follow that of several other Shadow Stack MSRs, e.g. the PLx_SSP
MSRs. Use a translation layer to hide the KVM-internal MSR index so that
the arbitrary index doesn't become ABI, e.g. so that KVM can rework its
implementation as needed, so long as the ONE_REG ABI is maintained.

Explicitly reject accesses to SSP if the vCPU doesn't have Shadow Stack
support to avoid running afoul of ignore_msrs, which unfortunately applies
to host-initiated accesses (which is a discussion for another day). I.e.
ensure consistent behavior for KVM-defined registers irrespective of
ignore_msrs.

Link: https://lore.kernel.org/all/aca9d389-f11e-4811-90cf-d98e345a5cc2@intel.com
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
Tested-by: Mathias Krause <minipli@grsecurity.net>
Tested-by: John Allen <john.allen@amd.com>
Tested-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Link: https://lore.kernel.org/r/20250919223258.1604852-14-seanjc@google.com
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>

authored by

Yang Weijiang and committed by
Sean Christopherson
9d6812d4 d6c387fc

+54 -4
+8
Documentation/virt/kvm/api.rst
··· 2911 2911 x86 MSR registers have the following id bit patterns:: 2912 2912 0x2030 0002 <msr number:32> 2913 2913 2914 + Following are the KVM-defined registers for x86: 2915 + 2916 + ======================= ========= ============================================= 2917 + Encoding Register Description 2918 + ======================= ========= ============================================= 2919 + 0x2030 0003 0000 0000 SSP Shadow Stack Pointer 2920 + ======================= ========= ============================================= 2921 + 2914 2922 4.69 KVM_GET_ONE_REG 2915 2923 -------------------- 2916 2924
+3
arch/x86/include/uapi/asm/kvm.h
··· 437 437 #define KVM_X86_REG_KVM(index) \ 438 438 KVM_X86_REG_ID(KVM_X86_REG_TYPE_KVM, index) 439 439 440 + /* KVM-defined registers starting from 0 */ 441 + #define KVM_REG_GUEST_SSP 0 442 + 440 443 #define KVM_SYNC_X86_REGS (1UL << 0) 441 444 #define KVM_SYNC_X86_SREGS (1UL << 1) 442 445 #define KVM_SYNC_X86_EVENTS (1UL << 2)
+33 -4
arch/x86/kvm/x86.c
··· 6016 6016 __u8 x86; 6017 6017 }; 6018 6018 6019 - static int kvm_translate_kvm_reg(struct kvm_x86_reg_id *reg) 6019 + static int kvm_translate_kvm_reg(struct kvm_vcpu *vcpu, 6020 + struct kvm_x86_reg_id *reg) 6020 6021 { 6021 - return -EINVAL; 6022 + switch (reg->index) { 6023 + case KVM_REG_GUEST_SSP: 6024 + /* 6025 + * FIXME: If host-initiated accesses are ever exempted from 6026 + * ignore_msrs (in kvm_do_msr_access()), drop this manual check 6027 + * and rely on KVM's standard checks to reject accesses to regs 6028 + * that don't exist. 6029 + */ 6030 + if (!guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK)) 6031 + return -EINVAL; 6032 + 6033 + reg->type = KVM_X86_REG_TYPE_MSR; 6034 + reg->index = MSR_KVM_INTERNAL_GUEST_SSP; 6035 + break; 6036 + default: 6037 + return -EINVAL; 6038 + } 6039 + return 0; 6022 6040 } 6023 6041 6024 6042 static int kvm_get_one_msr(struct kvm_vcpu *vcpu, u32 msr, u64 __user *user_val) ··· 6085 6067 return -EINVAL; 6086 6068 6087 6069 if (reg->type == KVM_X86_REG_TYPE_KVM) { 6088 - r = kvm_translate_kvm_reg(reg); 6070 + r = kvm_translate_kvm_reg(vcpu, reg); 6089 6071 if (r) 6090 6072 return r; 6091 6073 } ··· 6116 6098 static int kvm_get_reg_list(struct kvm_vcpu *vcpu, 6117 6099 struct kvm_reg_list __user *user_list) 6118 6100 { 6119 - u64 nr_regs = 0; 6101 + u64 nr_regs = guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) ? 1 : 0; 6102 + u64 user_nr_regs; 6103 + 6104 + if (get_user(user_nr_regs, &user_list->n)) 6105 + return -EFAULT; 6120 6106 6121 6107 if (put_user(nr_regs, &user_list->n)) 6108 + return -EFAULT; 6109 + 6110 + if (user_nr_regs < nr_regs) 6111 + return -E2BIG; 6112 + 6113 + if (nr_regs && 6114 + put_user(KVM_X86_REG_KVM(KVM_REG_GUEST_SSP), &user_list->reg[0])) 6122 6115 return -EFAULT; 6123 6116 6124 6117 return 0;
+10
arch/x86/kvm/x86.h
··· 101 101 #define KVM_SVM_DEFAULT_PLE_WINDOW_MAX USHRT_MAX 102 102 #define KVM_SVM_DEFAULT_PLE_WINDOW 3000 103 103 104 + /* 105 + * KVM's internal, non-ABI indices for synthetic MSRs. The values themselves 106 + * are arbitrary and have no meaning, the only requirement is that they don't 107 + * conflict with "real" MSRs that KVM supports. Use values at the upper end 108 + * of KVM's reserved paravirtual MSR range to minimize churn, i.e. these values 109 + * will be usable until KVM exhausts its supply of paravirtual MSR indices. 110 + */ 111 + 112 + #define MSR_KVM_INTERNAL_GUEST_SSP 0x4b564dff 113 + 104 114 static inline unsigned int __grow_ple_window(unsigned int val, 105 115 unsigned int base, unsigned int modifier, unsigned int max) 106 116 {