Re: [PATCH v15 13/41] KVM: x86: Enable guest SSP read/write interface with new uAPIs

Xiaoyao Li
2025-09-15T06:55:10Z

On 9/13/2025 7:22 AM, Sean Christopherson wrote:
> From: Yang Weijiang <weijiang.yang@intel.com>
>
> Enable guest shadow stack pointer(SSP) access interface with new uAPIs.
> CET guest SSP is HW register which has corresponding VMCS field to save
> and restore guest values when VM-{Exit,Entry} happens. KVM handles SSP
> as a fake/synthetic MSR for userspace access.
>
> Use a translation helper to set up mapping for SSP synthetic index and
> KVM-internal MSR index so that userspace doesn't need to take care of
> KVM's management for synthetic MSRs and avoid conflicts.
>
> 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>
> Co-developed-by: Sean Christopherson <seanjc@google.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
> Documentation/virt/kvm/api.rst | 8 ++++++++
> arch/x86/include/uapi/asm/kvm.h | 3 +++
> arch/x86/kvm/x86.c | 23 +++++++++++++++++++++--
> arch/x86/kvm/x86.h | 10 ++++++++++
> 4 files changed, 42 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index abd02675a24d..6ae24c5ca559 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -2911,6 +2911,14 @@ such as set vcpu counter or reset vcpu, and they have the following id bit patte
> x86 MSR registers have the following id bit patterns::
> 0x2030 0002 <msr number:32>
>
> +Following are the KVM-defined registers for x86:
> +
> +======================= ========= =============================================
> + Encoding Register Description
> +======================= ========= =============================================
> + 0x2030 0003 0000 0000 SSP Shadow Stack Pointer
> +======================= ========= =============================================
> +
> 4.69 KVM_GET_ONE_REG
> --------------------
>
> diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
> index 508b713ca52e..8cc79eca34b2 100644
> --- a/arch/x86/include/uapi/asm/kvm.h
> +++ b/arch/x86/include/uapi/asm/kvm.h
> @@ -437,6 +437,9 @@ struct kvm_xcrs {
> #define KVM_X86_REG_KVM(index) \
> KVM_X86_REG_ENCODE(KVM_X86_REG_TYPE_KVM, index)
>
> +/* KVM-defined registers starting from 0 */
> +#define KVM_REG_GUEST_SSP 0
> +
> #define KVM_SYNC_X86_REGS (1UL << 0)
> #define KVM_SYNC_X86_SREGS (1UL << 1)
> #define KVM_SYNC_X86_EVENTS (1UL << 2)
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 2c9908bc8b32..460ceae11495 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -6017,7 +6017,15 @@ struct kvm_x86_reg_id {
>
> static int kvm_translate_kvm_reg(struct kvm_x86_reg_id *reg)
> {
> - return -EINVAL;
> + switch (reg->index) {
> + case KVM_REG_GUEST_SSP:
> + reg->type = KVM_X86_REG_TYPE_MSR;
> + reg->index = MSR_KVM_INTERNAL_GUEST_SSP;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return 0;
> }
>
> static int kvm_get_one_msr(struct kvm_vcpu *vcpu, u32 msr, u64 __user *user_val)
> @@ -6097,11 +6105,22 @@ static int kvm_get_set_one_reg(struct kvm_vcpu *vcpu, unsigned int ioctl,
> static int kvm_get_reg_list(struct kvm_vcpu *vcpu,
> struct kvm_reg_list __user *user_list)
> {
> - u64 nr_regs = 0;
> + u64 nr_regs = guest_cpu_cap_has(vcpu, X86_FEATURE_SHSTK) ? 1 : 0;

I wonder what's the semantic of KVM returning KVM_REG_GUEST_SSP on
KVM_GET_REG_LIST. Does it ensure KVM_{G,S}ET_ONE_REG returns -EINVAL on
KVM_REG_GUEST_SSP when it's not enumerated by KVM_GET_REG_LIST?

If so, but KVM_{G,S}ET_ONE_REG can succeed on GUEST_SSP even if
!guest_cpu_cap_has() when @ignore_msrs is true.

> + u64 user_nr_regs;
> +
> + if (get_user(user_nr_regs, &user_list->n))
> + return -EFAULT;
>
> if (put_user(nr_regs, &user_list->n))
> return -EFAULT;
>
> + if (user_nr_regs < nr_regs)
> + return -E2BIG;
> +
> + if (nr_regs &&
> + put_user(KVM_X86_REG_KVM(KVM_REG_GUEST_SSP), &user_list->reg[0]))
> + return -EFAULT;
> +
> return 0;
> }
>
> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
> index 786e36fcd0fb..a7c9c72fca93 100644
> --- a/arch/x86/kvm/x86.h
> +++ b/arch/x86/kvm/x86.h
> @@ -101,6 +101,16 @@ do { \
> #define KVM_SVM_DEFAULT_PLE_WINDOW_MAX USHRT_MAX
> #define KVM_SVM_DEFAULT_PLE_WINDOW 3000
>
> +/*
> + * KVM's internal, non-ABI indices for synthetic MSRs. The values themselves
> + * are arbitrary and have no meaning, the only requirement is that they don't
> + * conflict with "real" MSRs that KVM supports. Use values at the upper end
> + * of KVM's reserved paravirtual MSR range to minimize churn, i.e. these values
> + * will be usable until KVM exhausts its supply of paravirtual MSR indices.
> + */
> +
> +#define MSR_KVM_INTERNAL_GUEST_SSP 0x4b564dff
> +
> static inline unsigned int __grow_ple_window(unsigned int val,
> unsigned int base, unsigned int modifier, unsigned int max)
> {