mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
x86, hvm: Fix issue with user-mode writes to read-only memory.
This patch fixes an issue where a guest could get stuck if a write to memory marked p2m_ram_ro happened from user mode. It would get misinterpreted as a user-mode page-table write, and the "dummy write" emulation necessary to skip over the instruction never got done. In looking into this, I also discovered that the user-mode page-table check is done in two places, the second (in emulate_map_dest) of which can never be reached and is just a waste of cycles. Tim Deegan requested that rather than completely removing that code, I'd leave it in for debug-builds with an added warning-print. Signed-off-by: Trolle Selander <trolle.selander@eu.citrix.com>
This commit is contained in:
1 parent
8d375aa174
commit
e8ea651a7a
1 file changed
+17
-6
@@ -3359,7 +3359,7 @@ static int sh_page_fault(struct vcpu *v,
|
||||
gdprintk(XENLOG_DEBUG, "guest attempted write to read-only memory"
|
||||
" page. va page=%#lx, mfn=%#lx\n",
|
||||
va & PAGE_MASK, mfn_x(gmfn));
|
||||
goto emulate; /* skip over the instruction */
|
||||
goto emulate_readonly; /* skip over the instruction */
|
||||
}
|
||||
|
||||
/* In HVM guests, we force CR0.WP always to be set, so that the
|
||||
@@ -3404,6 +3404,11 @@ static int sh_page_fault(struct vcpu *v,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write from userspace to ro-mem needs to jump here to avoid getting
|
||||
* caught by user-mode page-table check above.
|
||||
*/
|
||||
emulate_readonly:
|
||||
/*
|
||||
* We don't need to hold the lock for the whole emulation; we will
|
||||
* take it again when we write to the pagetables.
|
||||
@@ -4644,11 +4649,6 @@ static void *emulate_map_dest(struct vcpu *v,
|
||||
unsigned long offset;
|
||||
void *map = NULL;
|
||||
|
||||
/* We don't emulate user-mode writes to page tables */
|
||||
sreg = hvm_get_seg_reg(x86_seg_ss, sh_ctxt);
|
||||
if ( sreg->attr.fields.dpl == 3 )
|
||||
return MAPPING_UNHANDLEABLE;
|
||||
|
||||
sh_ctxt->mfn1 = emulate_gva_to_mfn(v, vaddr, sh_ctxt);
|
||||
if ( !mfn_valid(sh_ctxt->mfn1) )
|
||||
return ((mfn_x(sh_ctxt->mfn1) == BAD_GVA_TO_GFN) ?
|
||||
@@ -4656,6 +4656,17 @@ static void *emulate_map_dest(struct vcpu *v,
|
||||
(mfn_x(sh_ctxt->mfn1) == READONLY_GFN) ?
|
||||
MAPPING_SILENT_FAIL : MAPPING_UNHANDLEABLE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* We don't emulate user-mode writes to page tables */
|
||||
sreg = hvm_get_seg_reg(x86_seg_ss, sh_ctxt);
|
||||
if ( sreg->attr.fields.dpl == 3 )
|
||||
{
|
||||
gdprintk(XENLOG_DEBUG, "User-mode write to pagetable reached "
|
||||
"emulate_map_dest(). This should never happen!\n");
|
||||
return MAPPING_UNHANDLEABLE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Unaligned writes mean probably this isn't a pagetable */
|
||||
if ( vaddr & (bytes - 1) )
|
||||
sh_remove_shadows(v, sh_ctxt->mfn1, 0, 0 /* Slow, can fail */ );
|
||||
|
||||