diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2019-03-26 19:32:48 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2019-03-26 19:32:48 +0000 |
commit | 12f76fe2ff33b12d8f83ba43c7c25117e684f785 (patch) | |
tree | f4dbd192249fffa52ddfc8a04a2d8889e3327c56 | |
parent | 21964eaa67c19c3867d66d69ddc6b05d8e3b1b57 (diff) |
vmm(4): On VMX, use sgdt/sidt to reset the GDT/IDT limits after exiting
the guest VM. By default, VMX sets the limits to 0xFFFF on exit, which is
larger than what we want and can lead to security issues.
While here, reset the LDT as well. We don't use this in OpenBSD, and
VMX loads a null LDT selector on exit anyway, but resetting it here
prevents any future surprises.
Pointed out by Maxime Villard from NetBSD - thanks!
ok deraadt@
-rw-r--r-- | sys/arch/amd64/amd64/vmm.c | 13 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpufunc.h | 26 |
2 files changed, 36 insertions, 3 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c index 794bb941ae9..b6aec5ad752 100644 --- a/sys/arch/amd64/amd64/vmm.c +++ b/sys/arch/amd64/amd64/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.232 2019/03/10 08:27:28 mlarkin Exp $ */ +/* $OpenBSD: vmm.c,v 1.233 2019/03/26 19:32:47 mlarkin Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -3968,8 +3968,9 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp) struct schedstate_percpu *spc; struct vmx_invvpid_descriptor vid; uint64_t eii, procbased, int_st; - uint16_t irq; + uint16_t irq, ldt_sel; u_long s; + struct region_descriptor gdtr, idtr; resume = 0; irq = vrp->vrp_irq; @@ -4170,11 +4171,19 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp) break; } + sgdt(&gdtr); + sidt(&idtr); + sldt(&ldt_sel); + KERNEL_UNLOCK(); ret = vmx_enter_guest(&vcpu->vc_control_pa, &vcpu->vc_gueststate, resume, curcpu()->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr); + bare_lgdt(&gdtr); + lidt(&idtr); + lldt(ldt_sel); + /* * On exit, interrupts are disabled, and we are running with * the guest FPU state still possibly on the CPU. Save the FPU diff --git a/sys/arch/amd64/include/cpufunc.h b/sys/arch/amd64/include/cpufunc.h index edca45c5c2d..c72437e84dd 100644 --- a/sys/arch/amd64/include/cpufunc.h +++ b/sys/arch/amd64/include/cpufunc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc.h,v 1.32 2019/01/20 00:53:08 mlarkin Exp $ */ +/* $OpenBSD: cpufunc.h,v 1.33 2019/03/26 19:32:46 mlarkin Exp $ */ /* $NetBSD: cpufunc.h,v 1.3 2003/05/08 10:27:43 fvdl Exp $ */ /*- @@ -52,12 +52,36 @@ invlpg(u_int64_t addr) } static __inline void +sidt(void *p) +{ + __asm volatile("sidt (%0)" : : "r" (p) : "memory"); +} + +static __inline void lidt(void *p) { __asm volatile("lidt (%0)" : : "r" (p) : "memory"); } static __inline void +sgdt(void *p) +{ + __asm volatile("sgdt (%0)" : : "r" (p) : "memory"); +} + +static __inline void +bare_lgdt(struct region_descriptor *p) +{ + __asm volatile("lgdt (%0)" : : "r" (p) : "memory"); +} + +static __inline void +sldt(u_short *sel) +{ + __asm volatile("sldt (%0)" : : "r" (sel) : "memory"); +} + +static __inline void lldt(u_short sel) { __asm volatile("lldt %0" : : "r" (sel)); |