Skip to content

Commit c0883f6

Browse files
Maxim Levitskygregkh
authored andcommitted
KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl (CVE-2021-3653)
commit 0f923e0 upstream. * Invert the mask of bits that we pick from L2 in nested_vmcb02_prepare_control * Invert and explicitly use VIRQ related bits bitmask in svm_clear_vintr This fixes a security issue that allowed a malicious L1 to run L2 with AVIC enabled, which allowed the L2 to exploit the uninitialized and enabled AVIC to read/write the host physical memory at some offsets. Fixes: 3d6368e ("KVM: SVM: Add VMRUN handler") Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent b5f05bd commit c0883f6

3 files changed

Lines changed: 13 additions & 8 deletions

File tree

arch/x86/include/asm/svm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
166166
#define V_IGN_TPR_SHIFT 20
167167
#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
168168

169+
#define V_IRQ_INJECTION_BITS_MASK (V_IRQ_MASK | V_INTR_PRIO_MASK | V_IGN_TPR_MASK)
170+
169171
#define V_INTR_MASKING_SHIFT 24
170172
#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
171173

arch/x86/kvm/svm/nested.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,17 +429,20 @@ static void nested_prepare_vmcb_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
429429

430430
static void nested_prepare_vmcb_control(struct vcpu_svm *svm)
431431
{
432-
const u32 mask = V_INTR_MASKING_MASK | V_GIF_ENABLE_MASK | V_GIF_MASK;
432+
const u32 int_ctl_vmcb01_bits =
433+
V_INTR_MASKING_MASK | V_GIF_MASK | V_GIF_ENABLE_MASK;
434+
435+
const u32 int_ctl_vmcb12_bits = V_TPR_MASK | V_IRQ_INJECTION_BITS_MASK;
433436

434437
if (nested_npt_enabled(svm))
435438
nested_svm_init_mmu_context(&svm->vcpu);
436439

437440
svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset =
438441
svm->vcpu.arch.l1_tsc_offset + svm->nested.ctl.tsc_offset;
439442

440-
svm->vmcb->control.int_ctl =
441-
(svm->nested.ctl.int_ctl & ~mask) |
442-
(svm->nested.hsave->control.int_ctl & mask);
443+
svm->vmcb->control.int_ctl =
444+
(svm->nested.ctl.int_ctl & int_ctl_vmcb12_bits) |
445+
(svm->nested.hsave->control.int_ctl & int_ctl_vmcb01_bits);
443446

444447
svm->vmcb->control.virt_ext = svm->nested.ctl.virt_ext;
445448
svm->vmcb->control.int_vector = svm->nested.ctl.int_vector;

arch/x86/kvm/svm/svm.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,17 +1486,17 @@ static void svm_set_vintr(struct vcpu_svm *svm)
14861486

14871487
static void svm_clear_vintr(struct vcpu_svm *svm)
14881488
{
1489-
const u32 mask = V_TPR_MASK | V_GIF_ENABLE_MASK | V_GIF_MASK | V_INTR_MASKING_MASK;
14901489
svm_clr_intercept(svm, INTERCEPT_VINTR);
14911490

14921491
/* Drop int_ctl fields related to VINTR injection. */
1493-
svm->vmcb->control.int_ctl &= mask;
1492+
svm->vmcb->control.int_ctl &= ~V_IRQ_INJECTION_BITS_MASK;
14941493
if (is_guest_mode(&svm->vcpu)) {
1495-
svm->nested.hsave->control.int_ctl &= mask;
1494+
svm->nested.hsave->control.int_ctl &= ~V_IRQ_INJECTION_BITS_MASK;
14961495

14971496
WARN_ON((svm->vmcb->control.int_ctl & V_TPR_MASK) !=
14981497
(svm->nested.ctl.int_ctl & V_TPR_MASK));
1499-
svm->vmcb->control.int_ctl |= svm->nested.ctl.int_ctl & ~mask;
1498+
svm->vmcb->control.int_ctl |= svm->nested.ctl.int_ctl &
1499+
V_IRQ_INJECTION_BITS_MASK;
15001500
}
15011501

15021502
vmcb_mark_dirty(svm->vmcb, VMCB_INTR);

0 commit comments

Comments
 (0)