[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH RFC v2 1/4] x86/mm: Shadow and p2m changes for PV mem_access
>> +/* Get the page permission of the mfn from page_info->shadow_flags */ >> +static mfn_t >> +p2m_mem_access_get_entry(struct p2m_domain *p2m, unsigned long >gfn, >> + p2m_type_t *t, p2m_access_t *a, p2m_query_t q, >> + unsigned int *page_order) >> +{ >> + struct domain *d = p2m->domain; >> + /* For PV guests mfn == gfn */ > >Valid, but why is this not being checked in any way in the earlier >"set" counterpart? I will add that check. >> + mfn_t mfn = _mfn(gfn); >> + struct page_info *page = mfn_to_page(mfn); >> + >> + ASSERT(shadow_mode_enabled(d)); >> + >> + *t = p2m_ram_rw; >> + >> + if ( page_get_owner(page) != d ) > >I think there's a mfn_valid() check missing prior to this re-ref of page. I will add that too. >> @@ -1356,7 +1357,7 @@ void shadow_prealloc(struct domain *d, u32 type, >> unsigned int count) >> >> /* Deliberately free all the memory we can: this will tear down all of >> * this domain's shadows */ >> -static void shadow_blow_tables(struct domain *d) >> +void shadow_blow_tables(struct domain *d) > >This doesn't belong here - the patch doesn't add any new/external >caller of this function. I was trying to bunch shadow changes in to one patch. I will add this to the mem_access patch where the external caller is being added. >> @@ -2435,15 +2436,20 @@ int sh_remove_all_mappings(struct vcpu *v, >mfn_t gmfn) >> /* If that didn't catch the mapping, something is very wrong */ >> if ( !sh_check_page_has_no_refs(page) ) >> { >> - /* Don't complain if we're in HVM and there are some extra mappings: >> + /* >> + * Don't complain if we're in HVM and there are some extra mappings: >> * The qemu helper process has an untyped mapping of this dom's RAM >> >> * and the HVM restore program takes another. >> * Also allow one typed refcount for xenheap pages, to match >> - * share_xen_page_with_guest(). */ >> + * share_xen_page_with_guest(). >> + * PV domains that have a mem_access listener, runs in shadow mode >> + * without refcounts. >> + */ >> if ( !(shadow_mode_external(v->domain) >> && (page->count_info & PGC_count_mask) <= 3 >> && ((page->u.inuse.type_info & PGT_count_mask) >> - == !!is_xen_heap_page(page))) ) >> + == !!is_xen_heap_page(page))) && >> + !mem_event_check_ring(&v->domain->mem_event->access) ) > >To me this doesn't look to be in sync with the comment, as the new >check is being carried out regardless of domain type. Furthermore >this continues to have the problem of also hiding issues unrelated >to mem-access handling. I will add a check for PV domain. This check is wrt to refcouting. From what Tim told me PV domains cannot run in that mode, so I don't think any issues will be hidden if I add the check for PV domain. >> @@ -3009,7 +3020,84 @@ static int sh_page_fault(struct vcpu *v, >> >> /* What mfn is the guest trying to access? */ >> gfn = guest_l1e_get_gfn(gw.l1e); >> - gmfn = get_gfn(d, gfn, &p2mt); >> + if ( likely(!mem_event_check_ring(&d->mem_event->access)) ) >> + gmfn = get_gfn(d, gfn, &p2mt); >> + /* >> + * A mem_access listener is present, so we will first check if a >> violation >> + * has occurred. >> + */ >> + else >> + { >> + struct p2m_domain *p2m = p2m_get_hostp2m(v->domain); >> + p2m_access_t p2ma; >> + >> + gmfn = get_gfn_type_access(p2m, gfn_x(gfn), &p2mt, &p2ma, 0, >NULL); >> + if ( mfn_valid(gmfn) && !sh_mfn_is_a_page_table(gmfn) >> + && regs->error_code & PFEC_page_present >> + && !(regs->error_code & PFEC_reserved_bit) ) >> + { >> + int violation = 0; >> + bool_t access_w = !!(regs->error_code & PFEC_write_access); >> + bool_t access_x = !!(regs->error_code & PFEC_insn_fetch); >> + bool_t access_r = access_x ? 0 : !access_w; > >"violation" looks to be a boolean just like the other three, so wants >to also be bool_t. Done. >> + >> + /* If the access is against the permissions, then send to >> mem_event >*/ >> + switch ( p2ma ) >> + { >> + case p2m_access_r: >> + violation = access_w || access_x; >> + break; >> + case p2m_access_rx: >> + case p2m_access_rx2rw: >> + violation = access_w; >> + break; >> + case p2m_access_rw: >> + violation = access_x; >> + break; >> + case p2m_access_rwx: >> + default: >> + break; >> + } >> + >> + /* >> + * Do not police writes to guest memory from the Xen hypervisor. >> + * This keeps PV mem_access on par with HVM. Turn off CR0.WP >here to >> + * allow the write to go through if the guest has marked the >> page as >> + * writable. Turn it back on in the guest access functions >> + * __copy_to_user / __put_user_size() after the write is >> completed. >> + */ >> + if ( violation && access_w && >> + regs->eip >= XEN_VIRT_START && regs->eip <= XEN_VIRT_END ) > >Definitely < instead of <= on the right side. But - is this safe, the more >that this again doesn't appear to be sitting in a guest kind specific block? >I'd at least expect this to be qualified by a regs->cs and/or >guest_mode() check. I will add the guest kind check. Should I do it for the whole block i.e add is_pv_domain() in addition to mem_event_check_ring()? That will also address next comment below. I will add the guest_mode() in addition to the above check for policing Xen writes to guest memory. >> + { >> + unsigned long cr0 = read_cr0(); >> + >> + violation = 0; >> + if ( cr0 & X86_CR0_WP && >> + guest_l1e_get_flags(gw.l1e) & _PAGE_RW ) >> + { >> + cr0 &= ~X86_CR0_WP; >> + write_cr0(cr0); >> + v->arch.pv_vcpu.need_cr0_wp_set = 1; > >PV field access within a non-PV-only code block? > >> + } > >I wonder how well the window where you're running with CR0.WP clear >is bounded: The flag serves as a kind of security measure, and hence >shouldn't be left off for extended periods of time. I agree. Is there a way I can bound this? >> + } >> + >> + if ( violation ) >> + { >> + paddr_t gpa = (mfn_x(gmfn) << PAGE_SHIFT) + >> + (va & ((1 << PAGE_SHIFT) - 1)); >> + if ( !p2m_mem_access_check(gpa, 1, va, access_r, access_w, >> + access_x, &req_ptr) ) >> + { >> + SHADOW_PRINTK("Page access %c%c%c for gmfn=%"PRI_mfn" >p2ma: %d\n", >> + (access_r ? 'r' : '-'), >> + (access_w ? 'w' : '-'), >> + (access_x ? 'x' : '-'), mfn_x(gmfn), >> p2ma); >> + /* Rights not promoted, vcpu paused, work here is done >> */ >> + goto out_put_gfn; > >Rather than re-using just two lines from the normal exit path and >introducing to it a mem-access specific code block, put the exit >processing here, at once allowing req_ptr to be limited in scope? Good idea. I will do that. >> --- a/xen/common/page_alloc.c >> +++ b/xen/common/page_alloc.c >> @@ -43,6 +43,7 @@ >> #include <asm/page.h> >> #include <asm/numa.h> >> #include <asm/flushtlb.h> >> +#include <asm/shadow.h> > >Breaking ARM? >> #ifdef CONFIG_X86 >> #include <asm/p2m.h> >> #include <asm/setup.h> /* for highmem_start only */ >> @@ -1660,6 +1661,8 @@ int assign_pages( >> page_set_owner(&pg[i], d); >> smp_wmb(); /* Domain pointer must be visible before updating refcnt. >*/ >> pg[i].count_info = PGC_allocated | 1; >> + if ( is_pv_domain(d) ) >> + shadow_set_access(&pg[i], p2m_get_hostp2m(d)->default_access); > >I don't think you should call shadow code from here. Should I add a p2m wrapper for this, so that it is valid only for x86 and a no-op for ARM? >> --- a/xen/include/asm-x86/domain.h >> +++ b/xen/include/asm-x86/domain.h >> @@ -380,6 +380,12 @@ struct pv_vcpu >> /* Deferred VA-based update state. */ >> bool_t need_update_runstate_area; >> struct vcpu_time_info pending_system_time; >> + >> + /* >> + * Flag that tracks if CR0.WP needs to be set after a Xen write to guest >> + * memory when a PV domain has a mem_access listener attached to it. >> + */ >> + bool_t need_cr0_wp_set; >> }; > >The new field would better go above need_update_runstate_area >for better space usage. Done. >> --- a/xen/include/asm-x86/x86_64/uaccess.h >> +++ b/xen/include/asm-x86/x86_64/uaccess.h >> @@ -1,6 +1,8 @@ >> #ifndef __X86_64_UACCESS_H >> #define __X86_64_UACCESS_H >> >> +#include <xen/sched.h> > >This is pretty ugly. You only reference the needed fields in a macro, >so you don't strictly need to include this here as long as all (or at least >most - the rest could be patched up) use sites include it. OK, I will give that a shot. >> @@ -65,6 +67,11 @@ do { > \ >> case 8: __put_user_asm(x,ptr,retval,"q","","ir",errret);break; \ >> default: __put_user_bad(); \ >> } \ >> + if ( unlikely(current->arch.pv_vcpu.need_cr0_wp_set) ) \ >> + { \ >> + write_cr0(read_cr0() | X86_CR0_WP); \ >> + current->arch.pv_vcpu.need_cr0_wp_set = 0; \ >> + } \ >> } while (0) > >Please obey to the original indentation method. I thought tab characters were not allowed for indentation. But I guess you do not want tabs and spaces for indentation purposes to be mixed within a macro? Thanks, Aravindh _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |