diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 6a47c5915c..a745acd903 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -2546,7 +2546,8 @@ void asmlinkage svm_vmexit_handler(void) regs->rsp = vmcb->rsp; regs->rflags = vmcb->rflags; - hvm_invalidate_regs_fields(regs); + hvm_sanitize_regs_fields( + regs, !(vmcb_get_efer(vmcb) & EFER_LMA) || !(vmcb->cs.l)); if ( paging_mode_hap(v->domain) ) v->arch.hvm.guest_cr[3] = v->arch.hvm.hw_cr[3] = vmcb_get_cr3(vmcb); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 23bdf0d195..319a37b745 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -4033,6 +4033,7 @@ static void undo_nmis_unblocked_by_iret(void) void asmlinkage vmx_vmexit_handler(struct cpu_user_regs *regs) { unsigned long exit_qualification, exit_reason, idtv_info, intr_info = 0; + unsigned long cs_ar_bytes = 0; unsigned int vector = 0; struct vcpu *v = current; struct domain *currd = v->domain; @@ -4041,7 +4042,10 @@ void asmlinkage vmx_vmexit_handler(struct cpu_user_regs *regs) __vmread(GUEST_RSP, ®s->rsp); __vmread(GUEST_RFLAGS, ®s->rflags); - hvm_invalidate_regs_fields(regs); + if ( hvm_long_mode_active(v) ) + __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes); + + hvm_sanitize_regs_fields(regs, !(cs_ar_bytes & X86_SEG_AR_CS_LM_ACTIVE)); if ( paging_mode_hap(v->domain) ) { diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h index 87a6935d97..595253babe 100644 --- a/xen/arch/x86/include/asm/hvm/hvm.h +++ b/xen/arch/x86/include/asm/hvm/hvm.h @@ -569,8 +569,24 @@ static inline unsigned int hvm_get_insn_bytes(struct vcpu *v, uint8_t *buf) ? alternative_call(hvm_funcs.get_insn_bytes, v, buf) : 0); } -static inline void hvm_invalidate_regs_fields(struct cpu_user_regs *regs) +static inline void hvm_sanitize_regs_fields(struct cpu_user_regs *regs, + bool compat) { + if ( compat ) + { + /* Clear GPR upper halves, to counteract guests playing games. */ + regs->rbp = (uint32_t)regs->ebp; + regs->rbx = (uint32_t)regs->ebx; + regs->rax = (uint32_t)regs->eax; + regs->rcx = (uint32_t)regs->ecx; + regs->rdx = (uint32_t)regs->edx; + regs->rsi = (uint32_t)regs->esi; + regs->rdi = (uint32_t)regs->edi; + regs->rip = (uint32_t)regs->eip; + regs->rflags = (uint32_t)regs->eflags; + regs->rsp = (uint32_t)regs->esp; + } + #ifndef NDEBUG regs->error_code = 0xbeef; regs->entry_vector = 0xbeef;