Permalink
Browse files

x86: vtd: Ignore lower two bits when evaluating VTD_REQ_INV_WAIT

If the guest sets the wait request status address to the top of the
page, we crossed the border to the next page and either wrote some bytes
into a guest page that was previously mapped at page 2 in the temporary
mapping range, or we crashed the hypervisor on a fault if nothing was
mapped before.

Fix this by masking out the two lowest bits of the status address which
are actually reserved according to the Intel manual.

Along that, replace the hard-coded shift value with the right symbolic
constant.

Fixes: 20b09b8 ("x86: Emulate interrupt remapping support to enable x2APIC usage")
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
  • Loading branch information...
jan-kiszka committed Jan 27, 2019
1 parent 3a4f417 commit ae8b272f997bc720efc7f18476e5a407e2580ead
Showing with 6 additions and 5 deletions.
  1. +6 −5 hypervisor/arch/x86/vtd.c
@@ -411,7 +411,7 @@ static int vtd_emulate_qi_request(unsigned int unit_no,
struct vtd_entry inv_desc)
{
unsigned int start, count, n;
void *status_page;
void *status_addr;
int result;

switch (inv_desc.lo_word & VTD_REQ_INV_MASK) {
@@ -437,13 +437,14 @@ static int vtd_emulate_qi_request(unsigned int unit_no,
!(inv_desc.lo_word & VTD_INV_WAIT_SW))
return -EINVAL;

status_page = paging_get_guest_pages(NULL, inv_desc.hi_word, 1,
status_addr = paging_get_guest_pages(NULL, inv_desc.hi_word, 1,
PAGE_DEFAULT_FLAGS);
if (!status_page)
if (!status_addr)
return -EINVAL;

*(u32 *)(status_page + (inv_desc.hi_word & ~PAGE_MASK)) =
inv_desc.lo_word >> 32;
status_addr += inv_desc.hi_word & PAGE_OFFS_MASK & ~3;
*(u32 *)status_addr =
inv_desc.lo_word >> VTD_INV_WAIT_SDATA_SHIFT;

return 0;
}

0 comments on commit ae8b272

Please sign in to comment.