Skip to content

Commit 9d6812d

Browse files
yang-weijiangsean-jc
authored andcommitted
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/[email protected] Suggested-by: Sean Christopherson <[email protected]> Signed-off-by: Yang Weijiang <[email protected]> Tested-by: Mathias Krause <[email protected]> Tested-by: John Allen <[email protected]> Tested-by: Rick Edgecombe <[email protected]> Signed-off-by: Chao Gao <[email protected]> Reviewed-by: Binbin Wu <[email protected]> Reviewed-by: Xiaoyao Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Co-developed-by: Sean Christopherson <[email protected]> Signed-off-by: Sean Christopherson <[email protected]>
1 parent d6c387f commit 9d6812d

4 files changed

Lines changed: 54 additions & 4 deletions

File tree

Documentation/virt/kvm/api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,6 +2911,14 @@ such as set vcpu counter or reset vcpu, and they have the following id bit patte
29112911
x86 MSR registers have the following id bit patterns::
29122912
0x2030 0002 <msr number:32>
29132913

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+
29142922
4.69 KVM_GET_ONE_REG
29152923
--------------------
29162924

arch/x86/include/uapi/asm/kvm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,9 @@ struct kvm_xcrs {
437437
#define KVM_X86_REG_KVM(index) \
438438
KVM_X86_REG_ID(KVM_X86_REG_TYPE_KVM, index)
439439

440+
/* KVM-defined registers starting from 0 */
441+
#define KVM_REG_GUEST_SSP 0
442+
440443
#define KVM_SYNC_X86_REGS (1UL << 0)
441444
#define KVM_SYNC_X86_SREGS (1UL << 1)
442445
#define KVM_SYNC_X86_EVENTS (1UL << 2)

arch/x86/kvm/x86.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6016,9 +6016,27 @@ struct kvm_x86_reg_id {
60166016
__u8 x86;
60176017
};
60186018

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)
60206021
{
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;
60226040
}
60236041

60246042
static int kvm_get_one_msr(struct kvm_vcpu *vcpu, u32 msr, u64 __user *user_val)
@@ -6067,7 +6085,7 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl,
60676085
return -EINVAL;
60686086

60696087
if (reg->type == KVM_X86_REG_TYPE_KVM) {
6070-
r = kvm_translate_kvm_reg(reg);
6088+
r = kvm_translate_kvm_reg(vcpu, reg);
60716089
if (r)
60726090
return r;
60736091
}
@@ -6098,11 +6116,22 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl,
60986116
static int kvm_get_reg_list(struct kvm_vcpu *vcpu,
60996117
struct kvm_reg_list __user *user_list)
61006118
{
6101-
u64 nr_regs = 0;
6119+
u64 nr_regs = guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) ? 1 : 0;
6120+
u64 user_nr_regs;
6121+
6122+
if (get_user(user_nr_regs, &user_list->n))
6123+
return -EFAULT;
61026124

61036125
if (put_user(nr_regs, &user_list->n))
61046126
return -EFAULT;
61056127

6128+
if (user_nr_regs < nr_regs)
6129+
return -E2BIG;
6130+
6131+
if (nr_regs &&
6132+
put_user(KVM_X86_REG_KVM(KVM_REG_GUEST_SSP), &user_list->reg[0]))
6133+
return -EFAULT;
6134+
61066135
return 0;
61076136
}
61086137

arch/x86/kvm/x86.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ do { \
101101
#define KVM_SVM_DEFAULT_PLE_WINDOW_MAX USHRT_MAX
102102
#define KVM_SVM_DEFAULT_PLE_WINDOW 3000
103103

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+
104114
static inline unsigned int __grow_ple_window(unsigned int val,
105115
unsigned int base, unsigned int modifier, unsigned int max)
106116
{

0 commit comments

Comments
 (0)