[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH V13 3/7] xen/arm: Allow hypervisor access to mem_access protected pages





On Thu, Mar 12, 2015 at 1:08 PM, Ian Campbell <ian.campbell@xxxxxxxxxx> 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 <tklengyel@xxxxxxxxxxxxx>
> ---
> 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@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.