2015-11-10 12:23:10

by Paolo Bonzini

[permalink] [raw]
Subject: [PATCH 0/3] Infinite loops in microcode while running guests

Yes, these can happen. The issue is that benign exceptions are
delivered serially, but two of them (#DB and #AC) can also happen
during exception delivery itself. The subsequent infinite stream
of exceptions causes the processor to never exit guest mode.

Paolo

Eric Northup (1):
KVM: x86: work around infinite loop in microcode when #AC is delivered

Paolo Bonzini (2):
KVM: svm: unconditionally intercept #DB
KVM: x86: rename update_db_bp_intercept to update_bp_intercept

arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/include/uapi/asm/svm.h | 1 +
arch/x86/kvm/svm.c | 22 +++++++++++-----------
arch/x86/kvm/vmx.c | 7 +++++--
arch/x86/kvm/x86.c | 2 +-
5 files changed, 19 insertions(+), 15 deletions(-)

--
1.8.3.1


2015-11-10 12:23:09

by Paolo Bonzini

[permalink] [raw]
Subject: [PATCH 1/3] KVM: x86: work around infinite loop in microcode when #AC is delivered

From: Eric Northup <[email protected]>

It was found that a guest can DoS a host by triggering an infinite
stream of "alignment check" (#AC) exceptions. This causes the
microcode to enter an infinite loop where the core never receives
another interrupt. The host kernel panics pretty quickly due to the
effects (CVE-2015-5307).

Signed-off-by: Eric Northup <[email protected]>
Cc: [email protected]
Signed-off-by: Paolo Bonzini <[email protected]>
---
arch/x86/include/uapi/asm/svm.h | 1 +
arch/x86/kvm/svm.c | 8 ++++++++
arch/x86/kvm/vmx.c | 5 ++++-
3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index b5d7640abc5d..8a4add8e4639 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -100,6 +100,7 @@
{ SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \
{ SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \
{ SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \
+ { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \
{ SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \
{ SVM_EXIT_INTR, "interrupt" }, \
{ SVM_EXIT_NMI, "nmi" }, \
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index f2ba91990b4e..183926483c3a 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1019,6 +1019,7 @@ static void init_vmcb(struct vcpu_svm *svm)
set_exception_intercept(svm, PF_VECTOR);
set_exception_intercept(svm, UD_VECTOR);
set_exception_intercept(svm, MC_VECTOR);
+ set_exception_intercept(svm, AC_VECTOR);

set_intercept(svm, INTERCEPT_INTR);
set_intercept(svm, INTERCEPT_NMI);
@@ -1707,6 +1708,12 @@ static int ud_interception(struct vcpu_svm *svm)
return 1;
}

+static int ac_interception(struct vcpu_svm *svm)
+{
+ kvm_queue_exception_e(&svm->vcpu, AC_VECTOR, 0);
+ return 1;
+}
+
static void svm_fpu_activate(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3270,6 +3277,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
[SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception,
[SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception,
+ [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception,
[SVM_EXIT_INTR] = intr_interception,
[SVM_EXIT_NMI] = nmi_interception,
[SVM_EXIT_SMI] = nop_on_interception,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b765b036a048..89aaedd2a91d 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1639,7 +1639,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
u32 eb;

eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) |
- (1u << NM_VECTOR) | (1u << DB_VECTOR);
+ (1u << NM_VECTOR) | (1u << DB_VECTOR) | (1u << AC_VECTOR);
if ((vcpu->guest_debug &
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) ==
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP))
@@ -5261,6 +5261,9 @@ static int handle_exception(struct kvm_vcpu *vcpu)
return handle_rmode_exception(vcpu, ex_no, error_code);

switch (ex_no) {
+ case AC_VECTOR:
+ kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
+ return 1;
case DB_VECTOR:
dr6 = vmcs_readl(EXIT_QUALIFICATION);
if (!(vcpu->guest_debug &
--
1.8.3.1

2015-11-10 12:24:27

by Paolo Bonzini

[permalink] [raw]
Subject: [PATCH 2/3] KVM: svm: unconditionally intercept #DB

This is needed to avoid the possibility that the guest triggers
an infinite stream of #DB exceptions (CVE-2015-8104).

VMX is not affected: because it does not save DR6 in the VMCS,
it already intercepts #DB unconditionally.

Reported-by: Jan Beulich <[email protected]>
Cc: [email protected]
Signed-off-by: Paolo Bonzini <[email protected]>
---
arch/x86/kvm/svm.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 183926483c3a..1cc1ffca0d8c 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1020,6 +1020,7 @@ static void init_vmcb(struct vcpu_svm *svm)
set_exception_intercept(svm, UD_VECTOR);
set_exception_intercept(svm, MC_VECTOR);
set_exception_intercept(svm, AC_VECTOR);
+ set_exception_intercept(svm, DB_VECTOR);

set_intercept(svm, INTERCEPT_INTR);
set_intercept(svm, INTERCEPT_NMI);
@@ -1554,20 +1555,13 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
mark_dirty(svm->vmcb, VMCB_SEG);
}

-static void update_db_bp_intercept(struct kvm_vcpu *vcpu)
+static void update_bp_intercept(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);

- clr_exception_intercept(svm, DB_VECTOR);
clr_exception_intercept(svm, BP_VECTOR);

- if (svm->nmi_singlestep)
- set_exception_intercept(svm, DB_VECTOR);
-
if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
- if (vcpu->guest_debug &
- (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
- set_exception_intercept(svm, DB_VECTOR);
if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
set_exception_intercept(svm, BP_VECTOR);
} else
@@ -1673,7 +1667,6 @@ static int db_interception(struct vcpu_svm *svm)
if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP))
svm->vmcb->save.rflags &=
~(X86_EFLAGS_TF | X86_EFLAGS_RF);
- update_db_bp_intercept(&svm->vcpu);
}

if (svm->vcpu.guest_debug &
@@ -3661,7 +3654,6 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
*/
svm->nmi_singlestep = true;
svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
- update_db_bp_intercept(vcpu);
}

static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -4287,7 +4279,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,

- .update_db_bp_intercept = update_db_bp_intercept,
+ .update_db_bp_intercept = update_bp_intercept,
.get_msr = svm_get_msr,
.set_msr = svm_set_msr,
.get_segment_base = svm_get_segment_base,
--
1.8.3.1

2015-11-10 12:23:42

by Paolo Bonzini

[permalink] [raw]
Subject: [PATCH 3/3] KVM: x86: rename update_db_bp_intercept to update_bp_intercept

Because #DB is now intercepted unconditionally, this callback
only operates on #BP for both VMX and SVM.

Signed-off-by: Paolo Bonzini <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/svm.c | 2 +-
arch/x86/kvm/vmx.c | 2 +-
arch/x86/kvm/x86.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 456a3869a57e..30cfd64295a0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -778,7 +778,7 @@ struct kvm_x86_ops {
void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);

- void (*update_db_bp_intercept)(struct kvm_vcpu *vcpu);
+ void (*update_bp_intercept)(struct kvm_vcpu *vcpu);
int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1cc1ffca0d8c..83a1c643f9a5 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4279,7 +4279,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,

- .update_db_bp_intercept = update_bp_intercept,
+ .update_bp_intercept = update_bp_intercept,
.get_msr = svm_get_msr,
.set_msr = svm_set_msr,
.get_segment_base = svm_get_segment_base,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 89aaedd2a91d..87acc5221740 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -10759,7 +10759,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.vcpu_load = vmx_vcpu_load,
.vcpu_put = vmx_vcpu_put,

- .update_db_bp_intercept = update_exception_bitmap,
+ .update_bp_intercept = update_exception_bitmap,
.get_msr = vmx_get_msr,
.set_msr = vmx_set_msr,
.get_segment_base = vmx_get_segment_base,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2cb074f5aaed..aba7f95d7a64 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7115,7 +7115,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
*/
kvm_set_rflags(vcpu, rflags);

- kvm_x86_ops->update_db_bp_intercept(vcpu);
+ kvm_x86_ops->update_bp_intercept(vcpu);

r = 0;

--
1.8.3.1

2015-11-10 15:38:27

by Jan Kiszka

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests

On 2015-11-10 13:22, Paolo Bonzini wrote:
> Yes, these can happen. The issue is that benign exceptions are
> delivered serially, but two of them (#DB and #AC) can also happen
> during exception delivery itself. The subsequent infinite stream
> of exceptions causes the processor to never exit guest mode.
>
> Paolo
>
> Eric Northup (1):
> KVM: x86: work around infinite loop in microcode when #AC is delivered
>
> Paolo Bonzini (2):
> KVM: svm: unconditionally intercept #DB
> KVM: x86: rename update_db_bp_intercept to update_bp_intercept
>
> arch/x86/include/asm/kvm_host.h | 2 +-
> arch/x86/include/uapi/asm/svm.h | 1 +
> arch/x86/kvm/svm.c | 22 +++++++++++-----------
> arch/x86/kvm/vmx.c | 7 +++++--
> arch/x86/kvm/x86.c | 2 +-
> 5 files changed, 19 insertions(+), 15 deletions(-)
>

So this affects both Intel and AMD CPUs equally? Nice cross-vendor
"compatibility".

And it can only be triggered via #AC and #DB, or also other exceptions
(that KVM already happens to intercept)? You may guess why I'm asking...

Is any of the issues already documented in a vendor errata?

Thanks,
Jan

--
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux

2015-11-10 16:09:59

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests



On 10/11/2015 16:38, Jan Kiszka wrote:
> On 2015-11-10 13:22, Paolo Bonzini wrote:
>> Yes, these can happen. The issue is that benign exceptions are
>> delivered serially, but two of them (#DB and #AC) can also happen
>> during exception delivery itself. The subsequent infinite stream
>> of exceptions causes the processor to never exit guest mode.
>>
>> Paolo
>>
>> Eric Northup (1):
>> KVM: x86: work around infinite loop in microcode when #AC is delivered
>>
>> Paolo Bonzini (2):
>> KVM: svm: unconditionally intercept #DB
>> KVM: x86: rename update_db_bp_intercept to update_bp_intercept
>>
>> arch/x86/include/asm/kvm_host.h | 2 +-
>> arch/x86/include/uapi/asm/svm.h | 1 +
>> arch/x86/kvm/svm.c | 22 +++++++++++-----------
>> arch/x86/kvm/vmx.c | 7 +++++--
>> arch/x86/kvm/x86.c | 2 +-
>> 5 files changed, 19 insertions(+), 15 deletions(-)
>>
>
> So this affects both Intel and AMD CPUs equally? Nice cross-vendor
> "compatibility".

Yes, it's for both.

> And it can only be triggered via #AC and #DB, or also other exceptions
> (that KVM already happens to intercept)?

Yes, these are the sole benign exceptions that can occur during
exception delivery. All other benign exceptions only occur as the
result of executing instructions.

> You may guess why I'm asking...
> Is any of the issues already documented in a vendor errata?

No idea. As far as I understood, processor engineers consider this to
be intended behavior (!) though they admit that the outcome for
virtualization is bad.

I don't have a reproducer for this yet (I have only tested the patches
by ensuring that they do not regress on the legal cases), but from what
I heard at least on Intel the #AC injection actually causes a failed
VM-entry... Yet, nothing in the manual suggests _why_.

Paolo

2015-11-11 00:39:44

by Venkatesh Srinivas

[permalink] [raw]
Subject: Re: [PATCH 1/3] KVM: x86: work around infinite loop in microcode when #AC is delivered

On Tue, Nov 10, 2015 at 01:22:52PM +0100, Paolo Bonzini wrote:
> From: Eric Northup <[email protected]>
>
> It was found that a guest can DoS a host by triggering an infinite
> stream of "alignment check" (#AC) exceptions. This causes the
> microcode to enter an infinite loop where the core never receives
> another interrupt. The host kernel panics pretty quickly due to the
> effects (CVE-2015-5307).
>
> Signed-off-by: Eric Northup <[email protected]>
> Cc: [email protected]
> Signed-off-by: Paolo Bonzini <[email protected]>

Tested-by: Venkatesh Srinivas <[email protected]>

-- vs;

2015-11-11 12:48:15

by Austin S Hemmelgarn

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests

On 2015-11-10 07:22, Paolo Bonzini wrote:
> Yes, these can happen. The issue is that benign exceptions are
> delivered serially, but two of them (#DB and #AC) can also happen
> during exception delivery itself. The subsequent infinite stream
> of exceptions causes the processor to never exit guest mode.
>
> Paolo
>
> Eric Northup (1):
> KVM: x86: work around infinite loop in microcode when #AC is delivered
>
> Paolo Bonzini (2):
> KVM: svm: unconditionally intercept #DB
> KVM: x86: rename update_db_bp_intercept to update_bp_intercept
>
> arch/x86/include/asm/kvm_host.h | 2 +-
> arch/x86/include/uapi/asm/svm.h | 1 +
> arch/x86/kvm/svm.c | 22 +++++++++++-----------
> arch/x86/kvm/vmx.c | 7 +++++--
> arch/x86/kvm/x86.c | 2 +-
> 5 files changed, 19 insertions(+), 15 deletions(-)
>
I just finished running a couple of tests in a KVM instance running
nested on a Xen HVM instance, and found no issues, so for the set as a
whole:

Tested-by: Austin S. Hemmelgarn <[email protected]>

Now to hope the equivalent fix for Xen gets into the Gentoo repositories
soon, as the issue propagates down through nested virtualization and
ties up the CPU regardless (and in turn triggers the watchdog).


Attachments:
smime.p7s (2.95 kB)
S/MIME Cryptographic Signature

2015-11-11 13:07:43

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests



On 11/11/2015 13:47, Austin S Hemmelgarn wrote:
>>
> I just finished running a couple of tests in a KVM instance running
> nested on a Xen HVM instance, and found no issues, so for the set as a
> whole:
>
> Tested-by: Austin S. Hemmelgarn <[email protected]>
>
> Now to hope the equivalent fix for Xen gets into the Gentoo repositories
> soon, as the issue propagates down through nested virtualization and
> ties up the CPU regardless (and in turn triggers the watchdog).

Note that nested guests should _not_ lock up the outer (L0) hypervisor
if the outer hypervisor has the fix. At least this is the case for KVM:
a fixed outer KVM can protect any vulnerable nested (L1) hypervisor from
malicious nested guests. A vulnerable outer KVM is also protected if
the nested hypervisor has the workaround.

Paolo

2015-11-11 13:12:47

by Austin S Hemmelgarn

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests

On 2015-11-11 08:07, Paolo Bonzini wrote:
>
>
> On 11/11/2015 13:47, Austin S Hemmelgarn wrote:
>>>
>> I just finished running a couple of tests in a KVM instance running
>> nested on a Xen HVM instance, and found no issues, so for the set as a
>> whole:
>>
>> Tested-by: Austin S. Hemmelgarn <[email protected]>
>>
>> Now to hope the equivalent fix for Xen gets into the Gentoo repositories
>> soon, as the issue propagates down through nested virtualization and
>> ties up the CPU regardless (and in turn triggers the watchdog).
>
> Note that nested guests should _not_ lock up the outer (L0) hypervisor
> if the outer hypervisor has the fix. At least this is the case for KVM:
> a fixed outer KVM can protect any vulnerable nested (L1) hypervisor from
> malicious nested guests. A vulnerable outer KVM is also protected if
> the nested hypervisor has the workaround.
>
I already knew this, I just hadn't remembered that I hadn't updated Xen
since before the XSA and patch for this had been posted (and it took me
a while to remember this when I accidentally panicked Xen :))



Attachments:
smime.p7s (2.95 kB)
S/MIME Cryptographic Signature

2015-11-12 14:08:27

by Jan Kiszka

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests

On 2015-11-11 14:12, Austin S Hemmelgarn wrote:
> On 2015-11-11 08:07, Paolo Bonzini wrote:
>>
>>
>> On 11/11/2015 13:47, Austin S Hemmelgarn wrote:
>>>>
>>> I just finished running a couple of tests in a KVM instance running
>>> nested on a Xen HVM instance, and found no issues, so for the set as a
>>> whole:
>>>
>>> Tested-by: Austin S. Hemmelgarn <[email protected]>
>>>
>>> Now to hope the equivalent fix for Xen gets into the Gentoo repositories
>>> soon, as the issue propagates down through nested virtualization and
>>> ties up the CPU regardless (and in turn triggers the watchdog).
>>
>> Note that nested guests should _not_ lock up the outer (L0) hypervisor
>> if the outer hypervisor has the fix. At least this is the case for KVM:
>> a fixed outer KVM can protect any vulnerable nested (L1) hypervisor from
>> malicious nested guests. A vulnerable outer KVM is also protected if
>> the nested hypervisor has the workaround.
>>
> I already knew this, I just hadn't remembered that I hadn't updated Xen
> since before the XSA and patch for this had been posted (and it took me
> a while to remember this when I accidentally panicked Xen :))
>

As I'm lazy, both to search and to write something myself: is there
already a test case for the issue(s) circling around?

Thanks,
Jan

--
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux

2015-11-12 14:37:32

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 0/3] Infinite loops in microcode while running guests



On 12/11/2015 15:08, Jan Kiszka wrote:
> On 2015-11-11 14:12, Austin S Hemmelgarn wrote:
>> On 2015-11-11 08:07, Paolo Bonzini wrote:
>>>
>>>
>>> On 11/11/2015 13:47, Austin S Hemmelgarn wrote:
>>>>>
>>>> I just finished running a couple of tests in a KVM instance running
>>>> nested on a Xen HVM instance, and found no issues, so for the set as a
>>>> whole:
>>>>
>>>> Tested-by: Austin S. Hemmelgarn <[email protected]>
>>>>
>>>> Now to hope the equivalent fix for Xen gets into the Gentoo repositories
>>>> soon, as the issue propagates down through nested virtualization and
>>>> ties up the CPU regardless (and in turn triggers the watchdog).
>>>
>>> Note that nested guests should _not_ lock up the outer (L0) hypervisor
>>> if the outer hypervisor has the fix. At least this is the case for KVM:
>>> a fixed outer KVM can protect any vulnerable nested (L1) hypervisor from
>>> malicious nested guests. A vulnerable outer KVM is also protected if
>>> the nested hypervisor has the workaround.
>>>
>> I already knew this, I just hadn't remembered that I hadn't updated Xen
>> since before the XSA and patch for this had been posted (and it took me
>> a while to remember this when I accidentally panicked Xen :))
>
> As I'm lazy, both to search and to write something myself: is there
> already a test case for the issue(s) circling around?

To everybody: keep reproducers offlist, please.

Paolo