mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
x86/shadow: Don't create self-linear shadow mappings for 4-level translated guests
When initially creating a monitor table for 4-level translated guests, don't install a shadow-linear mapping. This mapping is actually self-linear, and trips up the writeable heuristic logic into following Xen's mappings, not the guests' shadows it was expecting to follow. A consequence of this is that sh_guess_wrmap() needs to cope with there being no shadow-linear mapping present, which in practice occurs once each time a vcpu switches to 4-level paging from a different paging mode. An appropriate shadow-linear slot will be inserted into the monitor table either while constructing lower level monitor tables, or by sh_update_cr3(). While fixing this, clarify the safety of the other mappings. Despite appearing unsafe, it is correct to create a guest-linear mapping for translated domains; this is self-linear and doesn't point into the translated domain. Drop a dead clause for translate != external guests. This is XSA-243. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Acked-by: Tim Deegan <tim@xen.org>
This commit is contained in:
1 parent
6410733a8a
commit
bf2b4eadcf
1 file changed
+30
-13
@@ -1485,26 +1485,38 @@ void sh_install_xen_entries_in_l4(struct domain *d, mfn_t gl4mfn, mfn_t sl4mfn)
|
||||
sl4e[shadow_l4_table_offset(RO_MPT_VIRT_START)] = shadow_l4e_empty();
|
||||
}
|
||||
|
||||
/* Shadow linear mapping for 4-level shadows. N.B. for 3-level
|
||||
* shadows on 64-bit xen, this linear mapping is later replaced by the
|
||||
* monitor pagetable structure, which is built in make_monitor_table
|
||||
* and maintained by sh_update_linear_entries. */
|
||||
sl4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] =
|
||||
shadow_l4e_from_mfn(sl4mfn, __PAGE_HYPERVISOR_RW);
|
||||
|
||||
/* Self linear mapping. */
|
||||
if ( shadow_mode_translate(d) && !shadow_mode_external(d) )
|
||||
/*
|
||||
* Linear mapping slots:
|
||||
*
|
||||
* Calling this function with gl4mfn == sl4mfn is used to construct a
|
||||
* monitor table for translated domains. In this case, gl4mfn forms the
|
||||
* self-linear mapping (i.e. not pointing into the translated domain), and
|
||||
* the shadow-linear slot is skipped. The shadow-linear slot is either
|
||||
* filled when constructing lower level monitor tables, or via
|
||||
* sh_update_cr3() for 4-level guests.
|
||||
*
|
||||
* Calling this function with gl4mfn != sl4mfn is used for non-translated
|
||||
* guests, where the shadow-linear slot is actually self-linear, and the
|
||||
* guest-linear slot points into the guests view of its pagetables.
|
||||
*/
|
||||
if ( shadow_mode_translate(d) )
|
||||
{
|
||||
// linear tables may not be used with translated PV guests
|
||||
sl4e[shadow_l4_table_offset(LINEAR_PT_VIRT_START)] =
|
||||
ASSERT(mfn_eq(gl4mfn, sl4mfn));
|
||||
|
||||
sl4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] =
|
||||
shadow_l4e_empty();
|
||||
}
|
||||
else
|
||||
{
|
||||
sl4e[shadow_l4_table_offset(LINEAR_PT_VIRT_START)] =
|
||||
shadow_l4e_from_mfn(gl4mfn, __PAGE_HYPERVISOR_RW);
|
||||
ASSERT(!mfn_eq(gl4mfn, sl4mfn));
|
||||
|
||||
sl4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] =
|
||||
shadow_l4e_from_mfn(sl4mfn, __PAGE_HYPERVISOR_RW);
|
||||
}
|
||||
|
||||
sl4e[shadow_l4_table_offset(LINEAR_PT_VIRT_START)] =
|
||||
shadow_l4e_from_mfn(gl4mfn, __PAGE_HYPERVISOR_RW);
|
||||
|
||||
unmap_domain_page(sl4e);
|
||||
}
|
||||
#endif
|
||||
@@ -4406,6 +4418,11 @@ static int sh_guess_wrmap(struct vcpu *v, unsigned long vaddr, mfn_t gmfn)
|
||||
|
||||
/* Carefully look in the shadow linear map for the l1e we expect */
|
||||
#if SHADOW_PAGING_LEVELS >= 4
|
||||
/* Is a shadow linear map is installed in the first place? */
|
||||
sl4p = v->arch.paging.shadow.guest_vtable;
|
||||
sl4p += shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START);
|
||||
if ( !(shadow_l4e_get_flags(*sl4p) & _PAGE_PRESENT) )
|
||||
return 0;
|
||||
sl4p = sh_linear_l4_table(v) + shadow_l4_linear_offset(vaddr);
|
||||
if ( !(shadow_l4e_get_flags(*sl4p) & _PAGE_PRESENT) )
|
||||
return 0;
|
||||
|
||||