]>
Commit | Line | Data |
---|---|---|
0a915aee WB |
1 | commit 54a20552e1eae07aa240fa370a0293e006b5faed |
2 | Author: Eric Northup <digitaleric@google.com> | |
3 | Date: Tue Nov 3 18:03:53 2015 +0100 | |
4 | ||
5 | KVM: x86: work around infinite loop in microcode when #AC is delivered | |
6 | ||
7 | It was found that a guest can DoS a host by triggering an infinite | |
8 | stream of "alignment check" (#AC) exceptions. This causes the | |
9 | microcode to enter an infinite loop where the core never receives | |
10 | another interrupt. The host kernel panics pretty quickly due to the | |
11 | effects (CVE-2015-5307). | |
12 | ||
13 | Signed-off-by: Eric Northup <digitaleric@google.com> | |
14 | Cc: stable@vger.kernel.org | |
15 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
16 | ||
9c7ad3bc WB |
17 | diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h |
18 | --- a/arch/x86/include/asm/kvm.h | |
19 | +++ b/arch/x86/include/asm/kvm.h | |
20 | @@ -23,6 +23,7 @@ | |
21 | #define GP_VECTOR 13 | |
22 | #define PF_VECTOR 14 | |
23 | #define MF_VECTOR 16 | |
24 | +#define AC_VECTOR 17 | |
25 | #define MC_VECTOR 18 | |
26 | ||
27 | /* Select x86 specific features in <linux/kvm.h> */ | |
0a915aee WB |
28 | diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h |
29 | index b5d7640..8a4add8 100644 | |
30 | --- a/arch/x86/include/asm/svm.h | |
31 | +++ b/arch/x86/include/asm/svm.h | |
32 | @@ -100,6 +100,7 @@ | |
33 | { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ | |
34 | { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ | |
35 | { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ | |
36 | + { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \ | |
37 | { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ | |
38 | { SVM_EXIT_INTR, "interrupt" }, \ | |
39 | { SVM_EXIT_NMI, "nmi" }, \ | |
40 | diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c | |
41 | index f2ba919..1839264 100644 | |
42 | --- a/arch/x86/kvm/svm.c | |
43 | +++ b/arch/x86/kvm/svm.c | |
44 | @@ -1019,7 +1019,8 @@ static void init_vmcb(struct vcpu_svm *svm) | |
45 | ||
46 | control->intercept_exceptions = (1 << PF_VECTOR) | | |
47 | (1 << UD_VECTOR) | | |
48 | - (1 << MC_VECTOR); | |
49 | + (1 << MC_VECTOR) | | |
50 | + (1 << AC_VECTOR); | |
51 | ||
52 | control->intercept = (1ULL << INTERCEPT_INTR) | | |
53 | (1ULL << INTERCEPT_NMI) | | |
54 | @@ -1707,6 +1708,12 @@ static int ud_interception(struct vcpu_svm *svm) | |
55 | return 1; | |
56 | } | |
57 | ||
58 | +static int ac_interception(struct vcpu_svm *svm) | |
59 | +{ | |
60 | + kvm_queue_exception_e(&svm->vcpu, AC_VECTOR, 0); | |
61 | + return 1; | |
62 | +} | |
63 | + | |
64 | static int nm_interception(struct vcpu_svm *svm) | |
65 | { | |
66 | svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); | |
67 | @@ -3270,6 +3277,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { | |
68 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, | |
69 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, | |
70 | [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, | |
71 | + [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception, | |
72 | [SVM_EXIT_INTR] = intr_interception, | |
73 | [SVM_EXIT_NMI] = nmi_interception, | |
74 | [SVM_EXIT_SMI] = nop_on_interception, | |
75 | diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c | |
76 | index b765b03..89aaedd 100644 | |
77 | --- a/arch/x86/kvm/vmx.c | |
78 | +++ b/arch/x86/kvm/vmx.c | |
79 | @@ -1639,7 +1639,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) | |
80 | u32 eb; | |
81 | ||
82 | eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) | |
83 | - | (1u << NM_VECTOR); | |
84 | + | (1u << NM_VECTOR) | (1u << AC_VECTOR); | |
85 | /* | |
86 | * Unconditionally intercept #DB so we can maintain dr6 without | |
87 | * reading it every exit. | |
88 | @@ -5261,6 +5261,9 @@ static int handle_exception(struct kvm_vcpu *vcpu) | |
89 | return handle_rmode_exception(vcpu, ex_no, error_code); | |
90 | ||
91 | switch (ex_no) { | |
92 | + case AC_VECTOR: | |
93 | + kvm_queue_exception_e(vcpu, AC_VECTOR, error_code); | |
94 | + return 1; | |
95 | case DB_VECTOR: | |
96 | dr6 = vmcs_readl(EXIT_QUALIFICATION); | |
97 | if (!(vcpu->guest_debug & |