diff options
Diffstat (limited to 'system/xen/xsa/xsa243.patch')
-rw-r--r-- | system/xen/xsa/xsa243.patch | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa243.patch b/system/xen/xsa/xsa243.patch new file mode 100644 index 0000000000..aaff277514 --- /dev/null +++ b/system/xen/xsa/xsa243.patch @@ -0,0 +1,93 @@ +From: Andrew Cooper <andrew.cooper3@citrix.com> +Subject: 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> + +diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c +index 8d4f244..a18d286 100644 +--- a/xen/arch/x86/mm/shadow/multi.c ++++ b/xen/arch/x86/mm/shadow/multi.c +@@ -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 +@@ -4405,6 +4417,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; |