2019-12-11 20:49:11

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 00/13] KVM: x86: Extend Spectre-v1 mitigation

From: Nick Finco <[email protected]>

This extends the Spectre-v1 mitigation introduced in
commit 75f139aaf896 ("KVM: x86: Add memory barrier on vmcs field lookup")
and commit 085331dfc6bb ("x86/kvm: Update spectre-v1 mitigation") in light
of the Spectre-v1/L1TF combination described here:
https://xenbits.xen.org/xsa/advisory-289.html

As reported in the link, an attacker can use the cache-load part of a
Spectre-v1 gadget to bring memory into the L1 cache, then use L1TF to
leak the loaded memory. Note that this attack is not fully mitigated by
core scheduling; firstly when "kvm-intel.vmentry_l1d_flush" is not set
to "always", an attacker could use L1TF on the same thread that loaded the
memory values in the cache on paths that do not flush the L1 cache on
VMEntry. Otherwise, an attacker could perform this attack using a
collusion of two sibling hyperthreads: one that loads memory values in
the cache during VMExit handling and another that performs L1TF to leak
them.

This patch uses array_index_nospec() to prevent index computations from
causing speculative loads into the L1 cache. These cases involve a
bounds check followed by a memory read using the index; this is more
common than the full Spectre-v1 pattern. In some cases, the index
computation can be eliminated entirely by small amounts of refactoring.

Marios Pomonis (13):
KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks
KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from
Spectre-v1/L1TF attacks
KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks
KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks
KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks
KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks
KVM: x86: Protect MSR-based index computations in
fixed_msr_to_seg_unit()
KVM: x86: Protect MSR-based index computations in pmu.h
KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF
attacks in x86.c
KVM: x86: Protect memory accesses from Spectre-v1/L1TF attacks in
x86.c
KVM: x86: Protect exit_reason from being used in Spectre-v1/L1TF
attacks
KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF
attacks
KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks

arch/x86/kvm/emulate.c | 11 ++++--
arch/x86/kvm/hyperv.c | 10 +++--
arch/x86/kvm/i8259.c | 6 ++-
arch/x86/kvm/ioapic.c | 15 +++++---
arch/x86/kvm/lapic.c | 13 +++++--
arch/x86/kvm/mtrr.c | 8 +++-
arch/x86/kvm/pmu.h | 18 +++++++--
arch/x86/kvm/vmx/pmu_intel.c | 24 ++++++++----
arch/x86/kvm/vmx/vmx.c | 71 +++++++++++++++++++++---------------
arch/x86/kvm/x86.c | 18 +++++++--
10 files changed, 129 insertions(+), 65 deletions(-)

--
2.24.0.393.g34dc348eaf-goog


2019-12-11 20:49:27

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks

This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
and kvm_hv_msr_set_crash_data().
These functions contain index computations that use the
(attacker-controlled) MSR number.

Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/hyperv.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 23ff65504d7e..26408434b9bc 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -809,11 +809,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
u32 index, u64 *pdata)
{
struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
+ size_t size = ARRAY_SIZE(hv->hv_crash_param);

- if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
+ if (WARN_ON_ONCE(index >= size))
return -EINVAL;

- *pdata = hv->hv_crash_param[index];
+ *pdata = hv->hv_crash_param[array_index_nospec(index, size)];
return 0;
}

@@ -852,11 +853,12 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu,
u32 index, u64 data)
{
struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
+ size_t size = ARRAY_SIZE(hv->hv_crash_param);

- if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
+ if (WARN_ON_ONCE(index >= size))
return -EINVAL;

- hv->hv_crash_param[index] = data;
+ hv->hv_crash_param[array_index_nospec(index, size)] = data;
return 0;
}

--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:49:37

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 03/13] KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in picdev_write().
It replaces index computations based on the (attacked-controlled) port
number with constants through a minor refactoring.

Fixes: commit 85f455f7ddbe ("KVM: Add support for in-kernel PIC emulation")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/i8259.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 8b38bb4868a6..629a09ca9860 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -460,10 +460,14 @@ static int picdev_write(struct kvm_pic *s,
switch (addr) {
case 0x20:
case 0x21:
+ pic_lock(s);
+ pic_ioport_write(&s->pics[0], addr, data);
+ pic_unlock(s);
+ break;
case 0xa0:
case 0xa1:
pic_lock(s);
- pic_ioport_write(&s->pics[addr >> 7], addr, data);
+ pic_ioport_write(&s->pics[1], addr, data);
pic_unlock(s);
break;
case 0x4d0:
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:49:40

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 04/13] KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in ioapic_read_indirect().
This function contains index computations based on the
(attacker-controlled) IOREGSEL register.

Fixes: commit a2c118bfab8b ("KVM: Fix bounds checking in ioapic indirect register reads (CVE-2013-1798)")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/ioapic.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 9fd2dd89a1c5..0c672eefaabe 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -36,6 +36,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/nospec.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/current.h>
@@ -68,13 +69,14 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
default:
{
u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
- u64 redir_content;
+ u64 redir_content = ~0ULL;

- if (redir_index < IOAPIC_NUM_PINS)
- redir_content =
- ioapic->redirtbl[redir_index].bits;
- else
- redir_content = ~0ULL;
+ if (redir_index < IOAPIC_NUM_PINS) {
+ u32 index = array_index_nospec(
+ redir_index, IOAPIC_NUM_PINS);
+
+ redir_content = ioapic->redirtbl[index].bits;
+ }

result = (ioapic->ioregsel & 0x1) ?
(redir_content >> 32) & 0xffffffff :
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:09

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 08/13] KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in the get_gp_pmc() and
get_fixed_pmc() functions.
They both contain index computations based on the (attacker-controlled)
MSR number.

Fixes: commit 25462f7f5295 ("KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/pmu.h | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 7ebb62326c14..13332984b6d5 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -2,6 +2,8 @@
#ifndef __KVM_X86_PMU_H
#define __KVM_X86_PMU_H

+#include <linux/nospec.h>
+
#define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu)
#define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu))
#define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
@@ -102,8 +104,12 @@ static inline bool kvm_valid_perf_global_ctrl(struct kvm_pmu *pmu,
static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
u32 base)
{
- if (msr >= base && msr < base + pmu->nr_arch_gp_counters)
- return &pmu->gp_counters[msr - base];
+ if (msr >= base && msr < base + pmu->nr_arch_gp_counters) {
+ u32 index = array_index_nospec(msr - base,
+ pmu->nr_arch_gp_counters);
+
+ return &pmu->gp_counters[index];
+ }

return NULL;
}
@@ -113,8 +119,12 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
{
int base = MSR_CORE_PERF_FIXED_CTR0;

- if (msr >= base && msr < base + pmu->nr_arch_fixed_counters)
- return &pmu->fixed_counters[msr - base];
+ if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
+ u32 index = array_index_nospec(msr - base,
+ pmu->nr_arch_fixed_counters);
+
+ return &pmu->fixed_counters[index];
+ }

return NULL;
}
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:18

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 11/13] KVM: x86: Protect exit_reason from being used in Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in vmx_handle_exit().
While exit_reason is set by the hardware and therefore should not be
attacker-influenced, an unknown exit_reason could potentially be used to
perform such an attack.

Fixes: commit 55d2375e58a6 ("KVM: nVMX: Move nested code to dedicated files")

Signed-off-by: Marios Pomonis <[email protected]>
Signed-off-by: Nick Finco <[email protected]>
Suggested-by: Sean Christopherson <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/vmx/vmx.c | 55 +++++++++++++++++++++++-------------------
1 file changed, 30 insertions(+), 25 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 82b25f1812aa..78f2fef97d93 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -5918,34 +5918,39 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
}
}

- if (exit_reason < kvm_vmx_max_exit_handlers
- && kvm_vmx_exit_handlers[exit_reason]) {
+ if (exit_reason >= kvm_vmx_max_exit_handlers)
+ goto unexpected_vmexit;
#ifdef CONFIG_RETPOLINE
- if (exit_reason == EXIT_REASON_MSR_WRITE)
- return kvm_emulate_wrmsr(vcpu);
- else if (exit_reason == EXIT_REASON_PREEMPTION_TIMER)
- return handle_preemption_timer(vcpu);
- else if (exit_reason == EXIT_REASON_PENDING_INTERRUPT)
- return handle_interrupt_window(vcpu);
- else if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
- return handle_external_interrupt(vcpu);
- else if (exit_reason == EXIT_REASON_HLT)
- return kvm_emulate_halt(vcpu);
- else if (exit_reason == EXIT_REASON_EPT_MISCONFIG)
- return handle_ept_misconfig(vcpu);
+ if (exit_reason == EXIT_REASON_MSR_WRITE)
+ return kvm_emulate_wrmsr(vcpu);
+ else if (exit_reason == EXIT_REASON_PREEMPTION_TIMER)
+ return handle_preemption_timer(vcpu);
+ else if (exit_reason == EXIT_REASON_PENDING_INTERRUPT)
+ return handle_interrupt_window(vcpu);
+ else if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
+ return handle_external_interrupt(vcpu);
+ else if (exit_reason == EXIT_REASON_HLT)
+ return kvm_emulate_halt(vcpu);
+ else if (exit_reason == EXIT_REASON_EPT_MISCONFIG)
+ return handle_ept_misconfig(vcpu);
#endif
- return kvm_vmx_exit_handlers[exit_reason](vcpu);
- } else {
- vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n",
- exit_reason);
- dump_vmcs();
- vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
- vcpu->run->internal.suberror =
+
+ exit_reason = array_index_nospec(exit_reason,
+ kvm_vmx_max_exit_handlers);
+ if (!kvm_vmx_exit_handlers[exit_reason])
+ goto unexpected_vmexit;
+
+ return kvm_vmx_exit_handlers[exit_reason](vcpu);
+
+unexpected_vmexit:
+ vcpu_unimpl(vcpu, "vmx: unexpected exit reason 0x%x\n", exit_reason);
+ dump_vmcs();
+ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON;
- vcpu->run->internal.ndata = 1;
- vcpu->run->internal.data[0] = exit_reason;
- return 0;
- }
+ vcpu->run->internal.ndata = 1;
+ vcpu->run->internal.data[0] = exit_reason;
+ return 0;
}

/*
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:24

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 12/13] KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in __kvm_set_dr() and
kvm_get_dr().
Both kvm_get_dr() and kvm_set_dr() (a wrapper of __kvm_set_dr()) are
exported symbols so KVM should tream them conservatively from a security
perspective.

Fixes: commit 020df0794f57 ("KVM: move DR register access handling into generic code")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/x86.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a9e66f09422e..9a2789652231 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1057,9 +1057,11 @@ static u64 kvm_dr6_fixed(struct kvm_vcpu *vcpu)

static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
{
+ size_t size = ARRAY_SIZE(vcpu->arch.db);
+
switch (dr) {
case 0 ... 3:
- vcpu->arch.db[dr] = val;
+ vcpu->arch.db[array_index_nospec(dr, size)] = val;
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
vcpu->arch.eff_db[dr] = val;
break;
@@ -1096,9 +1098,11 @@ EXPORT_SYMBOL_GPL(kvm_set_dr);

int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
{
+ size_t size = ARRAY_SIZE(vcpu->arch.db);
+
switch (dr) {
case 0 ... 3:
- *val = vcpu->arch.db[dr];
+ *val = vcpu->arch.db[array_index_nospec(dr, size)];
break;
case 4:
/* fall through */
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:34

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 01/13] KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in x86_decode_insn().
kvm_emulate_instruction() (an ancestor of x86_decode_insn()) is an exported
symbol, so KVM should treat it conservatively from a security perspective.

Fixes: commit 045a282ca415 ("KVM: emulator: implement fninit, fnstsw, fnstcw")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/emulate.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 952d1a4f4d7e..fcf7cdb21d60 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -5303,10 +5303,15 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
}
break;
case Escape:
- if (ctxt->modrm > 0xbf)
- opcode = opcode.u.esc->high[ctxt->modrm - 0xc0];
- else
+ if (ctxt->modrm > 0xbf) {
+ size_t size = ARRAY_SIZE(opcode.u.esc->high);
+ u32 index = array_index_nospec(
+ ctxt->modrm - 0xc0, size);
+
+ opcode = opcode.u.esc->high[index];
+ } else {
opcode = opcode.u.esc->op[(ctxt->modrm >> 3) & 7];
+ }
break;
case InstrDual:
if ((ctxt->modrm >> 6) == 3)
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:43

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 09/13] KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF attacks in x86.c

This fixes a Spectre-v1/L1TF vulnerability in set_msr_mce() and
get_msr_mce().
Both functions contain index computations based on the
(attacker-controlled) MSR number.

Fixes: commit 890ca9aefa78 ("KVM: Add MCE support")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/x86.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a256e09f321a..a9e66f09422e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2496,7 +2496,10 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
default:
if (msr >= MSR_IA32_MC0_CTL &&
msr < MSR_IA32_MCx_CTL(bank_num)) {
- u32 offset = msr - MSR_IA32_MC0_CTL;
+ u32 offset = array_index_nospec(
+ msr - MSR_IA32_MC0_CTL,
+ MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);
+
/* only 0 or all 1s can be written to IA32_MCi_CTL
* some Linux kernels though clear bit 10 in bank 4 to
* workaround a BIOS/GART TBL issue on AMD K8s, ignore
@@ -2937,7 +2940,10 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
default:
if (msr >= MSR_IA32_MC0_CTL &&
msr < MSR_IA32_MCx_CTL(bank_num)) {
- u32 offset = msr - MSR_IA32_MC0_CTL;
+ u32 offset = array_index_nospec(
+ msr - MSR_IA32_MC0_CTL,
+ MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);
+
data = vcpu->arch.mce_banks[offset];
break;
}
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:45

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 10/13] KVM: x86: Protect memory accesses from Spectre-v1/L1TF attacks in x86.c

This fixes Spectre-v1/L1TF vulnerabilities in
vmx_read_guest_seg_selector(), vmx_read_guest_seg_base(),
vmx_read_guest_seg_limit() and vmx_read_guest_seg_ar().
These functions contain index computations based on the
(attacker-influenced) segment value.

Fixes: commit 2fb92db1ec08 ("KVM: VMX: Cache vmcs segment fields")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/vmx/vmx.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index d39475e2d44e..82b25f1812aa 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -753,7 +753,9 @@ static bool vmx_segment_cache_test_set(struct vcpu_vmx *vmx, unsigned seg,

static u16 vmx_read_guest_seg_selector(struct vcpu_vmx *vmx, unsigned seg)
{
- u16 *p = &vmx->segment_cache.seg[seg].selector;
+ size_t size = ARRAY_SIZE(vmx->segment_cache.seg);
+ size_t index = array_index_nospec(seg, size);
+ u16 *p = &vmx->segment_cache.seg[index].selector;

if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_SEL))
*p = vmcs_read16(kvm_vmx_segment_fields[seg].selector);
@@ -762,7 +764,9 @@ static u16 vmx_read_guest_seg_selector(struct vcpu_vmx *vmx, unsigned seg)

static ulong vmx_read_guest_seg_base(struct vcpu_vmx *vmx, unsigned seg)
{
- ulong *p = &vmx->segment_cache.seg[seg].base;
+ size_t size = ARRAY_SIZE(vmx->segment_cache.seg);
+ size_t index = array_index_nospec(seg, size);
+ ulong *p = &vmx->segment_cache.seg[index].base;

if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_BASE))
*p = vmcs_readl(kvm_vmx_segment_fields[seg].base);
@@ -771,7 +775,9 @@ static ulong vmx_read_guest_seg_base(struct vcpu_vmx *vmx, unsigned seg)

static u32 vmx_read_guest_seg_limit(struct vcpu_vmx *vmx, unsigned seg)
{
- u32 *p = &vmx->segment_cache.seg[seg].limit;
+ size_t size = ARRAY_SIZE(vmx->segment_cache.seg);
+ size_t index = array_index_nospec(seg, size);
+ u32 *p = &vmx->segment_cache.seg[index].limit;

if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_LIMIT))
*p = vmcs_read32(kvm_vmx_segment_fields[seg].limit);
@@ -780,7 +786,9 @@ static u32 vmx_read_guest_seg_limit(struct vcpu_vmx *vmx, unsigned seg)

static u32 vmx_read_guest_seg_ar(struct vcpu_vmx *vmx, unsigned seg)
{
- u32 *p = &vmx->segment_cache.seg[seg].ar;
+ size_t size = ARRAY_SIZE(vmx->segment_cache.seg);
+ size_t index = array_index_nospec(seg, size);
+ u32 *p = &vmx->segment_cache.seg[index].ar;

if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_AR))
*p = vmcs_read32(kvm_vmx_segment_fields[seg].ar_bytes);
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:50:50

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 05/13] KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in ioapic_write_indirect().
This function contains index computations based on the
(attacker-controlled) IOREGSEL register.

This patch depends on patch
"KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks".

Fixes: commit 70f93dae32ac ("KVM: Use temporary variable to shorten lines.")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/ioapic.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 0c672eefaabe..8aa58727045e 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -294,6 +294,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)

if (index >= IOAPIC_NUM_PINS)
return;
+ index = array_index_nospec(index, IOAPIC_NUM_PINS);
e = &ioapic->redirtbl[index];
mask_before = e->fields.mask;
/* Preserve read-only fields */
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:51:00

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 07/13] KVM: x86: Protect MSR-based index computations in fixed_msr_to_seg_unit() from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in fixed_msr_to_seg_unit().
This function contains index computations based on the
(attacker-controlled) MSR number.

Fixes: commit de9aef5e1ad6 ("KVM: MTRR: introduce fixed_mtrr_segment table")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/mtrr.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
index 25ce3edd1872..7f0059aa30e1 100644
--- a/arch/x86/kvm/mtrr.c
+++ b/arch/x86/kvm/mtrr.c
@@ -192,11 +192,15 @@ static bool fixed_msr_to_seg_unit(u32 msr, int *seg, int *unit)
break;
case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000:
*seg = 1;
- *unit = msr - MSR_MTRRfix16K_80000;
+ *unit = array_index_nospec(
+ msr - MSR_MTRRfix16K_80000,
+ MSR_MTRRfix16K_A0000 - MSR_MTRRfix16K_80000 + 1);
break;
case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000:
*seg = 2;
- *unit = msr - MSR_MTRRfix4K_C0000;
+ *unit = array_index_nospec(
+ msr - MSR_MTRRfix4K_C0000,
+ MSR_MTRRfix4K_F8000 - MSR_MTRRfix4K_C0000 + 1);
break;
default:
return false;
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:51:11

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 06/13] KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks

This fixes a Spectre-v1/L1TF vulnerability in kvm_lapic_reg_write().
This function contains index computations based on the
(attacker-controlled) MSR number.

Fixes: commit 0105d1a52640 ("KVM: x2apic interface to lapic")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/lapic.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index cf9177b4a07f..3323115f52d5 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1963,15 +1963,20 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
case APIC_LVTTHMR:
case APIC_LVTPC:
case APIC_LVT1:
- case APIC_LVTERR:
+ case APIC_LVTERR: {
/* TODO: Check vector */
+ size_t size;
+ u32 index;
+
if (!kvm_apic_sw_enabled(apic))
val |= APIC_LVT_MASKED;
-
- val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
+ size = ARRAY_SIZE(apic_lvt_mask);
+ index = array_index_nospec(
+ (reg - APIC_LVTT) >> 4, size);
+ val &= apic_lvt_mask[index];
kvm_lapic_set_reg(apic, reg, val);
-
break;
+ }

case APIC_LVTT:
if (!kvm_apic_sw_enabled(apic))
--
2.24.0.525.g8f36a354ae-goog

2019-12-11 20:51:41

by Marios Pomonis

[permalink] [raw]
Subject: [PATCH v2 13/13] KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks

This fixes Spectre-v1/L1TF vulnerabilities in intel_find_fixed_event()
and intel_rdpmc_ecx_to_pmc().
kvm_rdpmc() (ancestor of intel_find_fixed_event()) and
reprogram_fixed_counter() (ancestor of intel_rdpmc_ecx_to_pmc()) are
exported symbols so KVM should treat them conservatively from a security
perspective.

Fixes: commit 25462f7f5295 ("KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch")

Signed-off-by: Nick Finco <[email protected]>
Signed-off-by: Marios Pomonis <[email protected]>
Reviewed-by: Andrew Honig <[email protected]>
Cc: [email protected]
---
arch/x86/kvm/vmx/pmu_intel.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 7023138b1cb0..34a3a17bb6d7 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -86,10 +86,14 @@ static unsigned intel_find_arch_event(struct kvm_pmu *pmu,

static unsigned intel_find_fixed_event(int idx)
{
- if (idx >= ARRAY_SIZE(fixed_pmc_events))
+ u32 event;
+ size_t size = ARRAY_SIZE(fixed_pmc_events);
+
+ if (idx >= size)
return PERF_COUNT_HW_MAX;

- return intel_arch_events[fixed_pmc_events[idx]].event_type;
+ event = fixed_pmc_events[array_index_nospec(idx, size)];
+ return intel_arch_events[event].event_type;
}

/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
@@ -130,16 +134,20 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
bool fixed = idx & (1u << 30);
struct kvm_pmc *counters;
+ unsigned int num_counters;

idx &= ~(3u << 30);
- if (!fixed && idx >= pmu->nr_arch_gp_counters)
- return NULL;
- if (fixed && idx >= pmu->nr_arch_fixed_counters)
+ if (fixed) {
+ counters = pmu->fixed_counters;
+ num_counters = pmu->nr_arch_fixed_counters;
+ } else {
+ counters = pmu->gp_counters;
+ num_counters = pmu->nr_arch_gp_counters;
+ }
+ if (idx >= num_counters)
return NULL;
- counters = fixed ? pmu->fixed_counters : pmu->gp_counters;
*mask &= pmu->counter_bitmask[fixed ? KVM_PMC_FIXED : KVM_PMC_GP];
-
- return &counters[idx];
+ return &counters[array_index_nospec(idx, num_counters)];
}

static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
--
2.24.0.525.g8f36a354ae-goog

2019-12-12 09:45:48

by Vitaly Kuznetsov

[permalink] [raw]
Subject: Re: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks

Marios Pomonis <[email protected]> writes:

> This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
> and kvm_hv_msr_set_crash_data().
> These functions contain index computations that use the
> (attacker-controlled) MSR number.

Just to educate myself,

in both cases 'index' is equal to 'msr - HV_X64_MSR_CRASH_P0' where
'msr' is constrained:
case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
....

and moreover, kvm_hv_{get,set}_msr_common() is only being called for a
narrow set of MSRs. How can an atacker overcome these limitations?

>
> Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]
> ---
> arch/x86/kvm/hyperv.c | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> index 23ff65504d7e..26408434b9bc 100644
> --- a/arch/x86/kvm/hyperv.c
> +++ b/arch/x86/kvm/hyperv.c
> @@ -809,11 +809,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
> u32 index, u64 *pdata)
> {
> struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
> + size_t size = ARRAY_SIZE(hv->hv_crash_param);
>
> - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
> + if (WARN_ON_ONCE(index >= size))
> return -EINVAL;
>
> - *pdata = hv->hv_crash_param[index];
> + *pdata = hv->hv_crash_param[array_index_nospec(index, size)];
> return 0;
> }
>
> @@ -852,11 +853,12 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu,
> u32 index, u64 data)
> {
> struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
> + size_t size = ARRAY_SIZE(hv->hv_crash_param);
>
> - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
> + if (WARN_ON_ONCE(index >= size))
> return -EINVAL;
>
> - hv->hv_crash_param[index] = data;
> + hv->hv_crash_param[array_index_nospec(index, size)] = data;
> return 0;
> }

--
Vitaly

2019-12-12 17:12:22

by Marios Pomonis

[permalink] [raw]
Subject: Re: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks

On Thu, Dec 12, 2019 at 1:43 AM Vitaly Kuznetsov <[email protected]> wrote:
>
> Marios Pomonis <[email protected]> writes:
>
> > This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
> > and kvm_hv_msr_set_crash_data().
> > These functions contain index computations that use the
> > (attacker-controlled) MSR number.
>
> Just to educate myself,
>
> in both cases 'index' is equal to 'msr - HV_X64_MSR_CRASH_P0' where
> 'msr' is constrained:
> case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
> ....
>
> and moreover, kvm_hv_{get,set}_msr_common() is only being called for a
> narrow set of MSRs. How can an atacker overcome these limitations?
>
This attack scenario relies on speculative execution. Practically, one
could train the branch predictors involved to speculatively execute
this path even if the adversary-supplied MSR number does not fall into
the legitimate range. The adversary-supplied MSR number however is
going to be used when -speculatively- computing the index of the array
thus allowing an attacker to load normally illegitimate memory values
in the L1 cache.
> >
> > Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")
> >
> > Signed-off-by: Nick Finco <[email protected]>
> > Signed-off-by: Marios Pomonis <[email protected]>
> > Reviewed-by: Andrew Honig <[email protected]>
> > Cc: [email protected]
> > ---
> > arch/x86/kvm/hyperv.c | 10 ++++++----
> > 1 file changed, 6 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> > index 23ff65504d7e..26408434b9bc 100644
> > --- a/arch/x86/kvm/hyperv.c
> > +++ b/arch/x86/kvm/hyperv.c
> > @@ -809,11 +809,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
> > u32 index, u64 *pdata)
> > {
> > struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
> > + size_t size = ARRAY_SIZE(hv->hv_crash_param);
> >
> > - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
> > + if (WARN_ON_ONCE(index >= size))
> > return -EINVAL;
> >
> > - *pdata = hv->hv_crash_param[index];
> > + *pdata = hv->hv_crash_param[array_index_nospec(index, size)];
> > return 0;
> > }
> >
> > @@ -852,11 +853,12 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu,
> > u32 index, u64 data)
> > {
> > struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
> > + size_t size = ARRAY_SIZE(hv->hv_crash_param);
> >
> > - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
> > + if (WARN_ON_ONCE(index >= size))
> > return -EINVAL;
> >
> > - hv->hv_crash_param[index] = data;
> > + hv->hv_crash_param[array_index_nospec(index, size)] = data;
> > return 0;
> > }
>
> --
> Vitaly
>


--
Marios Pomonis
Software Engineer, Security
GCP Platform Security
US-KIR-6THC

2019-12-12 17:33:09

by Christian Borntraeger

[permalink] [raw]
Subject: Re: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks



On 11.12.19 21:47, Marios Pomonis wrote:
> This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
> and kvm_hv_msr_set_crash_data().
> These functions contain index computations that use the
> (attacker-controlled) MSR number.
>
> Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]
> ---
> arch/x86/kvm/hyperv.c | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> index 23ff65504d7e..26408434b9bc 100644
> --- a/arch/x86/kvm/hyperv.c
> +++ b/arch/x86/kvm/hyperv.c
> @@ -809,11 +809,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
> u32 index, u64 *pdata)
> {
> struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
> + size_t size = ARRAY_SIZE(hv->hv_crash_param);
>
> - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
> + if (WARN_ON_ONCE(index >= size))
> return -EINVAL;

The fact that we do a WARN_ON_ONCE here, should actually tell that index is not
user controllable. Otherwise this would indicate the possibility to trigger a
kernel warning from a malicious user space. So
a: we do not need this change
or
b: we must also fix the WARN_ON_ONCE


2019-12-12 17:46:13

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks

On Thu, Dec 12, 2019 at 9:31 AM Christian Borntraeger
<[email protected]> wrote:
>
>
>
> On 11.12.19 21:47, Marios Pomonis wrote:
> > This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
> > and kvm_hv_msr_set_crash_data().
> > These functions contain index computations that use the
> > (attacker-controlled) MSR number.
> >
> > Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")
> >
> > Signed-off-by: Nick Finco <[email protected]>
> > Signed-off-by: Marios Pomonis <[email protected]>
> > Reviewed-by: Andrew Honig <[email protected]>
> > Cc: [email protected]
> > ---
> > arch/x86/kvm/hyperv.c | 10 ++++++----
> > 1 file changed, 6 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> > index 23ff65504d7e..26408434b9bc 100644
> > --- a/arch/x86/kvm/hyperv.c
> > +++ b/arch/x86/kvm/hyperv.c
> > @@ -809,11 +809,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
> > u32 index, u64 *pdata)
> > {
> > struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
> > + size_t size = ARRAY_SIZE(hv->hv_crash_param);
> >
> > - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
> > + if (WARN_ON_ONCE(index >= size))
> > return -EINVAL;
>
> The fact that we do a WARN_ON_ONCE here, should actually tell that index is not
> user controllable. Otherwise this would indicate the possibility to trigger a
> kernel warning from a malicious user space. So
> a: we do not need this change
> or
> b: we must also fix the WARN_ON_ONCE

That isn't quite true. The issue is *speculative* execution down this path.

The call site does constrain the *actual* value of index:

case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
return kvm_hv_msr_get_crash_data(...);

However, it is possible to train the branch predictor to go down this
path using valid indices and subsequently pass what would be an
invalid index. The CPU will speculatively follow this path and may
pull interesting data into the cache before it realizes its mistake
and corrects.

2019-12-12 17:49:57

by Christian Borntraeger

[permalink] [raw]
Subject: Re: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks



On 12.12.19 18:44, Jim Mattson wrote:
> On Thu, Dec 12, 2019 at 9:31 AM Christian Borntraeger
> <[email protected]> wrote:
>>
>>
>>
>> On 11.12.19 21:47, Marios Pomonis wrote:
>>> This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
>>> and kvm_hv_msr_set_crash_data().
>>> These functions contain index computations that use the
>>> (attacker-controlled) MSR number.
>>>
>>> Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")
>>>
>>> Signed-off-by: Nick Finco <[email protected]>
>>> Signed-off-by: Marios Pomonis <[email protected]>
>>> Reviewed-by: Andrew Honig <[email protected]>
>>> Cc: [email protected]
>>> ---
>>> arch/x86/kvm/hyperv.c | 10 ++++++----
>>> 1 file changed, 6 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
>>> index 23ff65504d7e..26408434b9bc 100644
>>> --- a/arch/x86/kvm/hyperv.c
>>> +++ b/arch/x86/kvm/hyperv.c
>>> @@ -809,11 +809,12 @@ static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu,
>>> u32 index, u64 *pdata)
>>> {
>>> struct kvm_hv *hv = &vcpu->kvm->arch.hyperv;
>>> + size_t size = ARRAY_SIZE(hv->hv_crash_param);
>>>
>>> - if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param)))
>>> + if (WARN_ON_ONCE(index >= size))
>>> return -EINVAL;
>>
>> The fact that we do a WARN_ON_ONCE here, should actually tell that index is not
>> user controllable. Otherwise this would indicate the possibility to trigger a
>> kernel warning from a malicious user space. So
>> a: we do not need this change
>> or
>> b: we must also fix the WARN_ON_ONCE
>
> That isn't quite true. The issue is *speculative* execution down this path.
>
> The call site does constrain the *actual* value of index:
>
> case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
> return kvm_hv_msr_get_crash_data(...);
>
> However, it is possible to train the branch predictor to go down this
> path using valid indices and subsequently pass what would be an
> invalid index. The CPU will speculatively follow this path and may
> pull interesting data into the cache before it realizes its mistake
> and corrects.

Yes, you are right.

2020-01-06 20:17:59

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 02/13] KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks

On Thu, Dec 12, 2019 at 9:47 AM Christian Borntraeger
<[email protected]> wrote:
>
>
>
> On 12.12.19 18:44, Jim Mattson wrote:
> > On Thu, Dec 12, 2019 at 9:31 AM Christian Borntraeger
> > <[email protected]> wrote:
> >>
> >>
> >>
> >> On 11.12.19 21:47, Marios Pomonis wrote:
> >>> This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data()
> >>> and kvm_hv_msr_set_crash_data().
> >>> These functions contain index computations that use the
> >>> (attacker-controlled) MSR number.
> >>>
> >>> Fixes: commit e7d9513b60e8 ("kvm/x86: added hyper-v crash msrs into kvm hyperv context")
> >>>
> >>> Signed-off-by: Nick Finco <[email protected]>
> >>> Signed-off-by: Marios Pomonis <[email protected]>
> >>> Reviewed-by: Andrew Honig <[email protected]>
> >>> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:18:11

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 01/13] KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:48 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in x86_decode_insn().
> kvm_emulate_instruction() (an ancestor of x86_decode_insn()) is an exported
> symbol, so KVM should treat it conservatively from a security perspective.
>
> Fixes: commit 045a282ca415 ("KVM: emulator: implement fninit, fnstsw, fnstcw")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:19:17

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 03/13] KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:48 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in picdev_write().
> It replaces index computations based on the (attacked-controlled) port
> number with constants through a minor refactoring.
>
> Fixes: commit 85f455f7ddbe ("KVM: Add support for in-kernel PIC emulation")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:19:44

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 04/13] KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:48 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in ioapic_read_indirect().
> This function contains index computations based on the
> (attacker-controlled) IOREGSEL register.
>
> Fixes: commit a2c118bfab8b ("KVM: Fix bounds checking in ioapic indirect register reads (CVE-2013-1798)")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:19:52

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 08/13] KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:49 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in the get_gp_pmc() and
> get_fixed_pmc() functions.
> They both contain index computations based on the (attacker-controlled)
> MSR number.
>
> Fixes: commit 25462f7f5295 ("KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:19:53

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 05/13] KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:48 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in ioapic_write_indirect().
> This function contains index computations based on the
> (attacker-controlled) IOREGSEL register.
>
> This patch depends on patch
> "KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks".
>
> Fixes: commit 70f93dae32ac ("KVM: Use temporary variable to shorten lines.")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:20:12

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 06/13] KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:48 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in kvm_lapic_reg_write().
> This function contains index computations based on the
> (attacker-controlled) MSR number.
>
> Fixes: commit 0105d1a52640 ("KVM: x2apic interface to lapic")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:20:17

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 09/13] KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF attacks in x86.c

On Wed, Dec 11, 2019 at 12:49 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in set_msr_mce() and
> get_msr_mce().
> Both functions contain index computations based on the
> (attacker-controlled) MSR number.
>
> Fixes: commit 890ca9aefa78 ("KVM: Add MCE support")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:20:21

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 10/13] KVM: x86: Protect memory accesses from Spectre-v1/L1TF attacks in x86.c

On Wed, Dec 11, 2019 at 12:49 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes Spectre-v1/L1TF vulnerabilities in
> vmx_read_guest_seg_selector(), vmx_read_guest_seg_base(),
> vmx_read_guest_seg_limit() and vmx_read_guest_seg_ar().
> These functions contain index computations based on the
> (attacker-influenced) segment value.
>
> Fixes: commit 2fb92db1ec08 ("KVM: VMX: Cache vmcs segment fields")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:20:22

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 07/13] KVM: x86: Protect MSR-based index computations in fixed_msr_to_seg_unit() from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:48 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in fixed_msr_to_seg_unit().
> This function contains index computations based on the
> (attacker-controlled) MSR number.
>
> Fixes: commit de9aef5e1ad6 ("KVM: MTRR: introduce fixed_mtrr_segment table")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:21:03

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 13/13] KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:49 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes Spectre-v1/L1TF vulnerabilities in intel_find_fixed_event()
> and intel_rdpmc_ecx_to_pmc().
> kvm_rdpmc() (ancestor of intel_find_fixed_event()) and
> reprogram_fixed_counter() (ancestor of intel_rdpmc_ecx_to_pmc()) are
> exported symbols so KVM should treat them conservatively from a security
> perspective.
>
> Fixes: commit 25462f7f5295 ("KVM: x86/vPMU: Define kvm_pmu_ops to support vPMU function dispatch")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-06 20:21:40

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 12/13] KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF attacks

On Wed, Dec 11, 2019 at 12:49 PM Marios Pomonis <[email protected]> wrote:
>
> This fixes a Spectre-v1/L1TF vulnerability in __kvm_set_dr() and
> kvm_get_dr().
> Both kvm_get_dr() and kvm_set_dr() (a wrapper of __kvm_set_dr()) are
> exported symbols so KVM should tream them conservatively from a security
> perspective.
>
> Fixes: commit 020df0794f57 ("KVM: move DR register access handling into generic code")
>
> Signed-off-by: Nick Finco <[email protected]>
> Signed-off-by: Marios Pomonis <[email protected]>
> Reviewed-by: Andrew Honig <[email protected]>
> Cc: [email protected]

Reviewed-by: Jim Mattson <[email protected]>

2020-01-18 20:15:15

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH v2 10/13] KVM: x86: Protect memory accesses from Spectre-v1/L1TF attacks in x86.c

On 11/12/19 21:47, Marios Pomonis wrote:
> This fixes Spectre-v1/L1TF vulnerabilities in
> vmx_read_guest_seg_selector(), vmx_read_guest_seg_base(),
> vmx_read_guest_seg_limit() and vmx_read_guest_seg_ar().
> These functions contain index computations based on the
> (attacker-influenced) segment value.
>
> Fixes: commit 2fb92db1ec08 ("KVM: VMX: Cache vmcs segment fields")

I think we could instead do

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 2d4faefe8dd4..20c0cbdff1be 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -5195,16 +5195,28 @@ int x86_decode_insn(struct x86_emulate_ctxt
*ctxt, void *insn, int insn_len)
ctxt->ad_bytes = def_ad_bytes ^ 6;
break;
case 0x26: /* ES override */
+ has_seg_override = true;
+ ctxt->seg_override = VCPU_SREG_ES;
+ break;
case 0x2e: /* CS override */
+ has_seg_override = true;
+ ctxt->seg_override = VCPU_SREG_CS;
+ break;
case 0x36: /* SS override */
+ has_seg_override = true;
+ ctxt->seg_override = VCPU_SREG_SS;
+ break;
case 0x3e: /* DS override */
has_seg_override = true;
- ctxt->seg_override = (ctxt->b >> 3) & 3;
+ ctxt->seg_override = VCPU_SREG_DS;
break;
case 0x64: /* FS override */
+ has_seg_override = true;
+ ctxt->seg_override = VCPU_SREG_FS;
+ break;
case 0x65: /* GS override */
has_seg_override = true;
- ctxt->seg_override = ctxt->b & 7;
+ ctxt->seg_override = VCPU_SREG_GS;
break;
case 0x40 ... 0x4f: /* REX */
if (mode != X86EMUL_MODE_PROT64)

so that the segment is never calculated.

Paolo

2020-01-18 20:20:11

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH v2 00/13] KVM: x86: Extend Spectre-v1 mitigation

On 11/12/19 21:47, Marios Pomonis wrote:
> From: Nick Finco <[email protected]>
>
> This extends the Spectre-v1 mitigation introduced in
> commit 75f139aaf896 ("KVM: x86: Add memory barrier on vmcs field lookup")
> and commit 085331dfc6bb ("x86/kvm: Update spectre-v1 mitigation") in light
> of the Spectre-v1/L1TF combination described here:
> https://xenbits.xen.org/xsa/advisory-289.html
>
> As reported in the link, an attacker can use the cache-load part of a
> Spectre-v1 gadget to bring memory into the L1 cache, then use L1TF to
> leak the loaded memory. Note that this attack is not fully mitigated by
> core scheduling; firstly when "kvm-intel.vmentry_l1d_flush" is not set
> to "always", an attacker could use L1TF on the same thread that loaded the
> memory values in the cache on paths that do not flush the L1 cache on
> VMEntry. Otherwise, an attacker could perform this attack using a
> collusion of two sibling hyperthreads: one that loads memory values in
> the cache during VMExit handling and another that performs L1TF to leak
> them.
>
> This patch uses array_index_nospec() to prevent index computations from
> causing speculative loads into the L1 cache. These cases involve a
> bounds check followed by a memory read using the index; this is more
> common than the full Spectre-v1 pattern. In some cases, the index
> computation can be eliminated entirely by small amounts of refactoring.
>
> Marios Pomonis (13):
> KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks
> KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from
> Spectre-v1/L1TF attacks
> KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks
> KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks
> KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks
> KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks
> KVM: x86: Protect MSR-based index computations in
> fixed_msr_to_seg_unit()
> KVM: x86: Protect MSR-based index computations in pmu.h
> KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF
> attacks in x86.c
> KVM: x86: Protect memory accesses from Spectre-v1/L1TF attacks in
> x86.c
> KVM: x86: Protect exit_reason from being used in Spectre-v1/L1TF
> attacks
> KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF
> attacks
> KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks
>
> arch/x86/kvm/emulate.c | 11 ++++--
> arch/x86/kvm/hyperv.c | 10 +++--
> arch/x86/kvm/i8259.c | 6 ++-
> arch/x86/kvm/ioapic.c | 15 +++++---
> arch/x86/kvm/lapic.c | 13 +++++--
> arch/x86/kvm/mtrr.c | 8 +++-
> arch/x86/kvm/pmu.h | 18 +++++++--
> arch/x86/kvm/vmx/pmu_intel.c | 24 ++++++++----
> arch/x86/kvm/vmx/vmx.c | 71 +++++++++++++++++++++---------------
> arch/x86/kvm/x86.c | 18 +++++++--
> 10 files changed, 129 insertions(+), 65 deletions(-)
>

Queued all except patch 10, thanks.

Paolo