On Thu, Mar 12, 2015 at 1:08 PM, Ian Campbell <ian.campb...@citrix.com> wrote:
> On Fri, 2015-03-06 at 22:24 +0100, Tamas K Lengyel wrote: > > The guestcopy helpers use the MMU to verify that the given guest has > read/write > > access to a given page during hypercalls. As we may have custom > mem_access > > permissions set on these pages, we do a software-based type checking in > case > > the MMU based approach failed, but only if mem_access_enabled is set. > > > > These memory accesses are not forwarded to the mem_event listener. > Accesses > > performed by the hypervisor are currently not part of the mem_access > scheme. > > This is consistent behaviour with the x86 side as well. > > > > Signed-off-by: Tamas K Lengyel <tkleng...@sec.in.tum.de> > > --- > > v12: - Check for mfn_valid as well. > > --- > > xen/arch/arm/guestcopy.c | 124 > +++++++++++++++++++++++++++++++++++++++++++++-- > > 1 file changed, 121 insertions(+), 3 deletions(-) > > > > diff --git a/xen/arch/arm/guestcopy.c b/xen/arch/arm/guestcopy.c > > index 7dbaeca..d42a469 100644 > > --- a/xen/arch/arm/guestcopy.c > > +++ b/xen/arch/arm/guestcopy.c > > @@ -6,6 +6,115 @@ > > > > #include <asm/mm.h> > > #include <asm/guest_access.h> > > +#include <asm/p2m.h> > > + > > +/* > > + * If mem_access is in use it might have been the reason why > get_page_from_gva > > + * failed to fetch the page, as it uses the MMU for the permission > checking. > > + * Only in these cases we do a software-based type check and fetch the > page if > > + * we indeed found a conflicting mem_access setting. > > + */ > > +static int check_type_get_page(vaddr_t gva, unsigned long flag, > > + struct page_info** page) > > +{ > > + long rc; > > + paddr_t ipa; > > + unsigned long maddr; > > + unsigned long mfn; > > + xenmem_access_t xma; > > + p2m_type_t t; > > + > > + rc = gva_to_ipa(gva, &ipa); > > + if ( rc < 0 ) > > + return rc; > > + > > + /* > > + * We do this first as this is faster in the default case when no > > + * permission is set on the page. > > + */ > > + rc = p2m_get_mem_access(current->domain, paddr_to_pfn(ipa), &xma); > > + if ( rc < 0 ) > > + return rc; > > + > > + /* Let's check if mem_access limited the access. */ > > + switch ( xma ) > > + { > > + default: > > + case XENMEM_access_rwx: > > + case XENMEM_access_rw: > > If I've understood correctly then this is deliberately backwards > looking. > > i.e. if we have gotten here then we have failed an earlier > get_page_from_gva check, so if xma is XENMEM_access_rwx that means that > the result of that first get_page_from_gva is valid because memaccess > hasn't been messing with the permissions. > > Since this interface only does reads or writes and not executableness > rwx and rw are effectively the same. > > Is my understanding correct? > Yes, correct. If mem_access had no r/w restriction on this page, the result of get_page_from_gva is valid. > > > + return -EFAULT; > > + case XENMEM_access_n2rwx: > > + case XENMEM_access_n: > > + case XENMEM_access_x: > > + break; > > If xenaccess contains no rw perms at all then we need to check what the > original p2m type was in order to decide what to do. > Correct. > > > + case XENMEM_access_wx: > > + case XENMEM_access_w: > > + if ( flag == GV2M_READ ) > > + break; > > + else return -EFAULT; > > If thing was a read then it might be because of xenaccess, so we must > check, but if it was a write then the origianl get_page_from_gva fault > was correct. > Correct, mem_access here had a write restriction but get_page_from_gva faulted with read, so that fault was correct. > > > > + case XENMEM_access_rx2rw: > > + case XENMEM_access_rx: > > + case XENMEM_access_r: > > + if ( flag == GV2M_WRITE ) > > + break; > > + else return -EFAULT; > > and vice versa. > > (sorry to be so tedious, I wanted to work through them all to ensure I'd > understood correctly and that they were right). > Yes, this is a bit complex but your understanding is correct. I will add a comment describing it in human readable way as Julien also had the same question couple months ago. > > > @@ -68,7 +180,10 @@ unsigned long raw_clear_guest(void *to, unsigned len) > > > > page = get_page_from_gva(current->domain, (vaddr_t) to, > GV2M_WRITE); > > if ( page == NULL ) > > - return len; > > + { > > + if ( check_mem_access((vaddr_t) to, GV2M_WRITE, &page) < 0 ) > > + return len; > > + } > > I think this would be better done by a making check_mem_access include > the initial call to get_page_from_gva and calling that helper here > instead instead of repeating this code. > > I'd even consider putting the memaccess check as a call at the tail end > of get_page_from_gva, I don't think there are any callers who don't want > this behaviour. > Sure, that sounds reasonable. Thanks, Tamas
_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel