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

Re: [Xen-devel] [PATCH v4] x86/mm: Add mem access rights to NPT



[Resending]
On Wed, Sep 26, 2018 at 5:02 PM George Dunlap
<George.Dunlap@xxxxxxxxxxxxx> wrote:
>
> On Mon, Jul 23, 2018 at 2:48 PM Alexandru Isaila
> <aisaila@xxxxxxxxxxxxxxx> wrote:
> >
> > From: Isaila Alexandru <aisaila@xxxxxxxxxxxxxxx>
> >
> > This patch adds access control for NPT mode.
> >
> > There aren’t enough extra bits to store the access rights in the NPT p2m
> > table, so we add a radix tree to store the rights.  For efficiency,
> > remove entries which match the default permissions rather than
> > continuing to store them.
> >
> > Modify p2m-pt.c:p2m_type_to_flags() to mirror the ept version: taking an
> > access, and removing / adding RW or NX flags as appropriate.
> >
> > Note: It was tested with xen-access write
> >
> > Signed-off-by: Alexandru Isaila <aisaila@xxxxxxxxxxxxxxx>
> >
> > ---
> > Changes since V3:
> >         - Add p2m_pt_check_access() to filter n, w, wx, n2rwx from
> >           supported page rights
> >         - Add rights check for the default_access change in the
> >           IVALID_GFN case
> >         - Add blank lines
> >         - Remove cpu_has_svm if from p2m_mem_access_check()
> >         - Add xfree(msr_bitmap) in case of error on
> >           xalloc(raxid_tree_root).
> > ---
> >  xen/arch/x86/mm/mem_access.c     |  17 +++---
> >  xen/arch/x86/mm/p2m-ept.c        |   7 +++
> >  xen/arch/x86/mm/p2m-pt.c         | 124 
> > ++++++++++++++++++++++++++++++++++-----
> >  xen/arch/x86/mm/p2m.c            |   6 ++
> >  xen/arch/x86/monitor.c           |  15 +++++
> >  xen/include/asm-x86/mem_access.h |   2 +-
> >  xen/include/asm-x86/p2m.h        |   7 +++
> >  7 files changed, 156 insertions(+), 22 deletions(-)
> >
> > diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
> > index c0cd017..cab72bc 100644
> > --- a/xen/arch/x86/mm/mem_access.c
> > +++ b/xen/arch/x86/mm/mem_access.c
> > @@ -221,12 +221,12 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long 
> > gla,
> >          {
> >              req->u.mem_access.flags |= MEM_ACCESS_GLA_VALID;
> >              req->u.mem_access.gla = gla;
> > -
> > -            if ( npfec.kind == npfec_kind_with_gla )
> > -                req->u.mem_access.flags |= MEM_ACCESS_FAULT_WITH_GLA;
> > -            else if ( npfec.kind == npfec_kind_in_gpt )
> > -                req->u.mem_access.flags |= MEM_ACCESS_FAULT_IN_GPT;
> >          }
> > +
> > +        if ( npfec.kind == npfec_kind_with_gla )
> > +            req->u.mem_access.flags |= MEM_ACCESS_FAULT_WITH_GLA;
> > +        else if ( npfec.kind == npfec_kind_in_gpt )
> > +            req->u.mem_access.flags |= MEM_ACCESS_FAULT_IN_GPT;
> >          req->u.mem_access.flags |= npfec.read_access    ? MEM_ACCESS_R : 0;
> >          req->u.mem_access.flags |= npfec.write_access   ? MEM_ACCESS_W : 0;
> >          req->u.mem_access.flags |= npfec.insn_fetch     ? MEM_ACCESS_X : 0;
> > @@ -366,8 +366,11 @@ long p2m_set_mem_access(struct domain *d, gfn_t gfn, 
> > uint32_t nr,
> >      /* If request to set default access. */
> >      if ( gfn_eq(gfn, INVALID_GFN) )
> >      {
> > -        p2m->default_access = a;
> > -        return 0;
> > +        if ( (rc = p2m->check_access(a)) == 0 )
> > +        {
> > +            p2m->default_access = a;
> > +            return 0;
> > +        }
> >      }
>
> BTW this introduces a bug -- if the check fails, this will fall
> through into the gfn loop below, rather than returning the error.
>
> > @@ -87,23 +88,27 @@ static unsigned long p2m_type_to_flags(const struct 
> > p2m_domain *p2m,
> >      case p2m_ram_paged:
> >      case p2m_ram_paging_in:
> >      default:
> > -        return flags | _PAGE_NX_BIT;
> > +        flags |= P2M_BASE_FLAGS | _PAGE_NX_BIT;
> > +        break;
>
> Why did  you add in P2M_BASE_FLAGS here?
>
> >      case p2m_grant_map_ro:
> >          return flags | P2M_BASE_FLAGS | _PAGE_NX_BIT;
>
> And is this `return` left here on purpose, or was it missed?
>
> >  /* Returns: 0 for success, -errno for failure */
> >  static int
> >  p2m_next_level(struct p2m_domain *p2m, void **table,
> > @@ -201,6 +268,7 @@ p2m_next_level(struct p2m_domain *p2m, void **table,
> >          new_entry = l1e_from_mfn(mfn, P2M_BASE_FLAGS | _PAGE_RW);
> >
> >          p2m_add_iommu_flags(&new_entry, level, 
> > IOMMUF_readable|IOMMUF_writable);
> > +        p2m_set_access(p2m, gfn, p2m->default_access);
>
> This is clearly wrong -- this isn't a leaf node, it's an intermediate
> p2m table; and p2m_next_level() is just acting "under the covers",
> filling in missing bits of the p2m table or breaking down superpages.
> Since the access information is in a completely separate structure, it
> shouldn't need to be modified here at all (indeed, it would be a bug
> to do so).
>
> But that does bring up an important issue -- it would appear that this
> code is incorrect when setting superpages -- if we set a 2MiB page but
> then read a non-2MiB-aligned entry within that page, we'll get the
> default access rather than the one we set; same thing with splintering
> a superpage into smaller pages.
>
> There's a draft patch addressing this on the way.
>
>  -George

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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