Skip to content

Commit

Permalink
x86, vtd: [CVE-2011-1898] Protect against malicious MSIs from untrust…
Browse files Browse the repository at this point in the history
…ed devices.

In the absence of VT-d interrupt remapping support, a device can send
arbitrary APIC messages to host CPUs. One class of attack that results
is to confuse the hypervisor by delivering asynchronous interrupts to
vectors that are expected to handle only synchronous
traps/exceptions.

We block this class of attack by:
(1) setting APIC.TPR=0x10, to block all interrupts below vector
0x20. This blocks delivery to all architectural exception vectors.
(2) checking APIC.ISR[vec] for vectors 0x80 (fast syscall) and 0x82
(hypercall). In these cases we BUG if we detect we are handling a
hardware interrupt -- turning a potentially more severe infiltration
into a straightforward system crash (i.e, DoS).

Thanks to Invisible Things Lab <http://www.invisiblethingslab.com>
for discovery and detailed investigation of this attack.

Signed-off-by: Keir Fraser <keir@xen.org>
  • Loading branch information
Keir Fraser committed May 12, 2011
1 parent 3229bc7 commit 10fbbbc
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 5 deletions.
13 changes: 8 additions & 5 deletions xen/arch/x86/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,12 +560,9 @@ void __devinit setup_local_APIC(void)
init_apic_ldr();

/*
* Set Task Priority to 'accept all'. We never change this
* later on.
* Set Task Priority to reject any interrupts below FIRST_DYNAMIC_VECTOR.
*/
value = apic_read(APIC_TASKPRI);
value &= ~APIC_TPRI_MASK;
apic_write_around(APIC_TASKPRI, value);
apic_write_around(APIC_TASKPRI, (FIRST_DYNAMIC_VECTOR & 0xF0) - 0x10);

/*
* After a crash, we no longer service the interrupts and a pending
Expand Down Expand Up @@ -1439,3 +1436,9 @@ int __init APIC_init_uniprocessor (void)

return 0;
}

void check_for_unexpected_msi(unsigned int vector)
{
unsigned long v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
BUG_ON(v & (1 << (vector & 0x1f)));
}
10 changes: 10 additions & 0 deletions xen/arch/x86/x86_64/compat/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@
#include <asm/page.h>
#include <asm/desc.h>
#include <public/xen.h>
#include <irq_vectors.h>

ALIGN
ENTRY(compat_hypercall)
pushq $0
movl $TRAP_syscall,4(%rsp)
SAVE_ALL

cmpb $0,untrusted_msi(%rip)
UNLIKELY_START(ne, msi_check)
movl $HYPERCALL_VECTOR,%edi
call check_for_unexpected_msi
RESTORE_ALL
SAVE_ALL
UNLIKELY_END(msi_check)

GET_CURRENT(%rbx)

cmpl $NR_hypercalls,%eax
Expand Down
8 changes: 8 additions & 0 deletions xen/arch/x86/x86_64/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ ENTRY(int80_direct_trap)
pushq $0
SAVE_ALL

cmpb $0,untrusted_msi(%rip)
UNLIKELY_START(ne, msi_check)
movl $0x80,%edi
call check_for_unexpected_msi
RESTORE_ALL
SAVE_ALL
UNLIKELY_END(msi_check)

GET_CURRENT(%rbx)

/* Check that the callback is non-null. */
Expand Down
11 changes: 11 additions & 0 deletions xen/drivers/passthrough/vtd/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
#define nr_ioapics iosapic_get_nr_iosapics()
#endif

/* Possible unfiltered LAPIC/MSI messages from untrusted sources? */
bool_t __read_mostly untrusted_msi;

int nr_iommus;

static void setup_dom0_devices(struct domain *d);
Expand Down Expand Up @@ -1579,6 +1582,14 @@ static int reassign_device_ownership(
if (!pdev)
return -ENODEV;

/*
* Devices assigned to untrusted domains (here assumed to be any domU)
* can attempt to send arbitrary LAPIC/MSI messages. We are unprotected
* by the root complex unless interrupt remapping is enabled.
*/
if ( (target != dom0) && !iommu_intremap )
untrusted_msi = 1;

ret = domain_context_unmap(source, bus, devfn);
if ( ret )
return ret;
Expand Down

0 comments on commit 10fbbbc

Please sign in to comment.