aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2015-02-04 12:06:37 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2015-02-04 12:32:14 -0500
commitf798217dfd038af981a18bbe4bc57027a08bb182 (patch)
tree196c26efeb980fa684dd732cdab6c73ac314a7eb
parentc4c6f2cad9e1d4cc076bc183c3689cc9e7019c75 (diff)
KVM: MIPS: Don't leak FPU/DSP to guest
The FPU and DSP are enabled via the CP0 Status CU1 and MX bits by kvm_mips_set_c0_status() on a guest exit, presumably in case there is active state that needs saving if pre-emption occurs. However neither of these bits are cleared again when returning to the guest. This effectively gives the guest access to the FPU/DSP hardware after the first guest exit even though it is not aware of its presence, allowing FP instructions in guest user code to intermittently actually execute instead of trapping into the guest OS for emulation. It will then read & manipulate the hardware FP registers which technically belong to the user process (e.g. QEMU), or are stale from another user process. It can also crash the guest OS by causing an FP exception, for which a guest exception handler won't have been registered. First lets save and disable the FPU (and MSA) state with lose_fpu(1) before entering the guest. This simplifies the problem, especially for when guest FPU/MSA support is added in the future, and prevents FR=1 FPU state being live when the FR bit gets cleared for the guest, which according to the architecture causes the contents of the FPU and vector registers to become UNPREDICTABLE. We can then safely remove the enabling of the FPU in kvm_mips_set_c0_status(), since there should never be any active FPU or MSA state to save at pre-emption, which should plug the FPU leak. DSP state is always live rather than being lazily restored, so for that it is simpler to just clear the MX bit again when re-entering the guest. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Sanjay Lal <sanjayl@kymasys.com> Cc: Gleb Natapov <gleb@kernel.org> Cc: kvm@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: <stable@vger.kernel.org> # v3.10+: 044f0f03eca0: MIPS: KVM: Deliver guest interrupts Cc: <stable@vger.kernel.org> # v3.10+ Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/mips/kvm/locore.S2
-rw-r--r--arch/mips/kvm/mips.c6
2 files changed, 4 insertions, 4 deletions
diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S
index d7279c03c517..4a68b176d6e4 100644
--- a/arch/mips/kvm/locore.S
+++ b/arch/mips/kvm/locore.S
@@ -434,7 +434,7 @@ __kvm_mips_return_to_guest:
434 /* Setup status register for running guest in UM */ 434 /* Setup status register for running guest in UM */
435 .set at 435 .set at
436 or v1, v1, (ST0_EXL | KSU_USER | ST0_IE) 436 or v1, v1, (ST0_EXL | KSU_USER | ST0_IE)
437 and v1, v1, ~ST0_CU0 437 and v1, v1, ~(ST0_CU0 | ST0_MX)
438 .set noat 438 .set noat
439 mtc0 v1, CP0_STATUS 439 mtc0 v1, CP0_STATUS
440 ehb 440 ehb
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index 9a28ea4f54f3..e97b90784031 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -15,6 +15,7 @@
15#include <linux/vmalloc.h> 15#include <linux/vmalloc.h>
16#include <linux/fs.h> 16#include <linux/fs.h>
17#include <linux/bootmem.h> 17#include <linux/bootmem.h>
18#include <asm/fpu.h>
18#include <asm/page.h> 19#include <asm/page.h>
19#include <asm/cacheflush.h> 20#include <asm/cacheflush.h>
20#include <asm/mmu_context.h> 21#include <asm/mmu_context.h>
@@ -379,6 +380,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
379 vcpu->mmio_needed = 0; 380 vcpu->mmio_needed = 0;
380 } 381 }
381 382
383 lose_fpu(1);
384
382 local_irq_disable(); 385 local_irq_disable();
383 /* Check if we have any exceptions/interrupts pending */ 386 /* Check if we have any exceptions/interrupts pending */
384 kvm_mips_deliver_interrupts(vcpu, 387 kvm_mips_deliver_interrupts(vcpu,
@@ -986,9 +989,6 @@ static void kvm_mips_set_c0_status(void)
986{ 989{
987 uint32_t status = read_c0_status(); 990 uint32_t status = read_c0_status();
988 991
989 if (cpu_has_fpu)
990 status |= (ST0_CU1);
991
992 if (cpu_has_dsp) 992 if (cpu_has_dsp)
993 status |= (ST0_MX); 993 status |= (ST0_MX);
994 994