[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen stable-4.7] x86/shadow: hold references for the duration of emulated writes
commit 5d6ab83a2dc5b52b866a016cb04e7715403a2a75 Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Tue Jun 20 16:15:56 2017 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Tue Jun 20 16:15:56 2017 +0200 x86/shadow: hold references for the duration of emulated writes The (misnamed) emulate_gva_to_mfn() function translates a linear address to an mfn, but releases its page reference before returning the mfn to its caller. sh_emulate_map_dest() uses the results of one or two translations to construct a virtual mapping to the underlying frames, completes an emulated write/cmpxchg, then unmaps the virtual mappings. The page references need holding until the mappings are unmapped, or the frames can change ownership before the writes occurs. This is XSA-219. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> Reviewed-by: Tim Deegan <tim@xxxxxxx> master commit: 26217aff67ae1538d4e1b2226afab6993cdbe772 master date: 2017-06-20 14:36:11 +0200 --- xen/arch/x86/mm/shadow/common.c | 54 +++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index cbd81a0..a0ecc25 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1704,7 +1704,10 @@ static unsigned int shadow_get_allocation(struct domain *d) /**************************************************************************/ /* Handling guest writes to pagetables. */ -/* Translate a VA to an MFN, injecting a page-fault if we fail. */ +/* + * Translate a VA to an MFN, injecting a page-fault if we fail. If the + * mapping succeeds, a reference will be held on the underlying page. + */ #define BAD_GVA_TO_GFN (~0UL) #define BAD_GFN_TO_MFN (~1UL) #define READONLY_GFN (~2UL) @@ -1752,16 +1755,15 @@ static mfn_t emulate_gva_to_mfn(struct vcpu *v, unsigned long vaddr, ASSERT(mfn_valid(mfn)); v->arch.paging.last_write_was_pt = !!sh_mfn_is_a_page_table(mfn); - /* - * Note shadow cannot page out or unshare this mfn, so the map won't - * disappear. Otherwise, caller must hold onto page until done. - */ - put_page(page); return mfn; } -/* Check that the user is allowed to perform this write. */ +/* + * Check that the user is allowed to perform this write. If a mapping is + * returned, page references will be held on sh_ctxt->mfn[0] and + * sh_ctxt->mfn[1] iff !INVALID_MFN. + */ void *sh_emulate_map_dest(struct vcpu *v, unsigned long vaddr, unsigned int bytes, struct sh_emulate_ctxt *sh_ctxt) @@ -1769,13 +1771,6 @@ void *sh_emulate_map_dest(struct vcpu *v, unsigned long vaddr, struct domain *d = v->domain; void *map; - sh_ctxt->mfn[0] = emulate_gva_to_mfn(v, vaddr, sh_ctxt); - if ( !mfn_valid(sh_ctxt->mfn[0]) ) - return ((mfn_x(sh_ctxt->mfn[0]) == BAD_GVA_TO_GFN) ? - MAPPING_EXCEPTION : - (mfn_x(sh_ctxt->mfn[0]) == READONLY_GFN) ? - MAPPING_SILENT_FAIL : MAPPING_UNHANDLEABLE); - #ifndef NDEBUG /* We don't emulate user-mode writes to page tables. */ if ( has_hvm_container_domain(d) @@ -1788,6 +1783,17 @@ void *sh_emulate_map_dest(struct vcpu *v, unsigned long vaddr, } #endif + sh_ctxt->mfn[0] = emulate_gva_to_mfn(v, vaddr, sh_ctxt); + if ( !mfn_valid(sh_ctxt->mfn[0]) ) + { + switch ( mfn_x(sh_ctxt->mfn[0]) ) + { + case BAD_GVA_TO_GFN: return MAPPING_EXCEPTION; + case READONLY_GFN: return MAPPING_SILENT_FAIL; + default: return MAPPING_UNHANDLEABLE; + } + } + /* Unaligned writes mean probably this isn't a pagetable. */ if ( vaddr & (bytes - 1) ) sh_remove_shadows(d, sh_ctxt->mfn[0], 0, 0 /* Slow, can fail. */ ); @@ -1804,6 +1810,7 @@ void *sh_emulate_map_dest(struct vcpu *v, unsigned long vaddr, * Cross-page emulated writes are only supported for HVM guests; * PV guests ought to know better. */ + put_page(mfn_to_page(sh_ctxt->mfn[0])); return MAPPING_UNHANDLEABLE; } else @@ -1811,17 +1818,26 @@ void *sh_emulate_map_dest(struct vcpu *v, unsigned long vaddr, /* This write crosses a page boundary. Translate the second page. */ sh_ctxt->mfn[1] = emulate_gva_to_mfn(v, vaddr + bytes - 1, sh_ctxt); if ( !mfn_valid(sh_ctxt->mfn[1]) ) - return ((mfn_x(sh_ctxt->mfn[1]) == BAD_GVA_TO_GFN) ? - MAPPING_EXCEPTION : - (mfn_x(sh_ctxt->mfn[1]) == READONLY_GFN) ? - MAPPING_SILENT_FAIL : MAPPING_UNHANDLEABLE); + { + put_page(mfn_to_page(sh_ctxt->mfn[0])); + switch ( mfn_x(sh_ctxt->mfn[1]) ) + { + case BAD_GVA_TO_GFN: return MAPPING_EXCEPTION; + case READONLY_GFN: return MAPPING_SILENT_FAIL; + default: return MAPPING_UNHANDLEABLE; + } + } /* Cross-page writes mean probably not a pagetable. */ sh_remove_shadows(d, sh_ctxt->mfn[1], 0, 0 /* Slow, can fail. */ ); map = vmap(sh_ctxt->mfn, 2); if ( !map ) + { + put_page(mfn_to_page(sh_ctxt->mfn[0])); + put_page(mfn_to_page(sh_ctxt->mfn[1])); return MAPPING_UNHANDLEABLE; + } map += (vaddr & ~PAGE_MASK); } @@ -1891,10 +1907,12 @@ void sh_emulate_unmap_dest(struct vcpu *v, void *addr, unsigned int bytes, } paging_mark_dirty(v->domain, mfn_x(sh_ctxt->mfn[0])); + put_page(mfn_to_page(sh_ctxt->mfn[0])); if ( unlikely(mfn_valid(sh_ctxt->mfn[1])) ) { paging_mark_dirty(v->domain, mfn_x(sh_ctxt->mfn[1])); + put_page(mfn_to_page(sh_ctxt->mfn[1])); vunmap((void *)((unsigned long)addr & PAGE_MASK)); } else -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.7 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |