On 4/12/19 8:47 PM, Tamas K Lengyel wrote:
> Patch 0502e0adae2 "x86: correct instances of PGC_allocated clearing" 
> introduced
> grabbing extra references for pages that drop references tied to 
> PGC_allocated.
> However, the way these extra references were grabbed were incorrect, resulting
> in both share_pages and unshare_pages failing.

Why?  Is cd not the owner of the page?

> There actually is no need to
> grab extra references, only a reordering was needed for when the existing
> references are being released. This is in accordance to the XSA-242
> recommendation of not calling _put_page_type while also holding the page_lock
> for that page.
> 
> Signed-off-by: Tamas K Lengyel <ta...@tklengyel.com>
> Cc: Jan Beulich <jbeul...@suse.com>
> Cc: Andrew Cooper <andrew.coop...@citrix.com>
> Cc: George Dunlap <george.dun...@eu.citrix.com>
> Cc: Wei Liu <wei.l...@citrix.com>
> Cc: Roger Pau Monne <roger....@citrix.com>
> ---
> v2: Add assert that put_count is at least 1
> ---
>  xen/arch/x86/mm/mem_sharing.c | 32 +++++++++-----------------------
>  1 file changed, 9 insertions(+), 23 deletions(-)
> 
> diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
> index 5ac9d8f54c..708037d91e 100644
> --- a/xen/arch/x86/mm/mem_sharing.c
> +++ b/xen/arch/x86/mm/mem_sharing.c
> @@ -900,6 +900,7 @@ static int share_pages(struct domain *sd, gfn_t sgfn, 
> shr_handle_t sh,
>      p2m_type_t smfn_type, cmfn_type;
>      struct two_gfns tg;
>      struct rmap_iterator ri;
> +    unsigned long put_count = 0;
>  
>      get_two_gfns(sd, sgfn, &smfn_type, NULL, &smfn,
>                   cd, cgfn, &cmfn_type, NULL, &cmfn, 0, &tg);
> @@ -964,15 +965,6 @@ static int share_pages(struct domain *sd, gfn_t sgfn, 
> shr_handle_t sh,
>          goto err_out;
>      }
>  
> -    /* Acquire an extra reference, for the freeing below to be safe. */
> -    if ( !get_page(cpage, cd) )
> -    {
> -        ret = -EOVERFLOW;
> -        mem_sharing_page_unlock(secondpg);
> -        mem_sharing_page_unlock(firstpg);
> -        goto err_out;
> -    }

Why does this fail?  Is cd not the owner of the page?

> -
>      /* Merge the lists together */
>      rmap_seed_iterator(cpage, &ri);
>      while ( (gfn = rmap_iterate(cpage, &ri)) != NULL)
> @@ -984,7 +976,7 @@ static int share_pages(struct domain *sd, gfn_t sgfn, 
> shr_handle_t sh,
>           * Don't change the type of rmap for the client page. */
>          rmap_del(gfn, cpage, 0);
>          rmap_add(gfn, spage);
> -        put_page_and_type(cpage);
> +        put_count++;
>          d = get_domain_by_id(gfn->domain);
>          BUG_ON(!d);
>          BUG_ON(set_shared_p2m_entry(d, gfn->gfn, smfn));
> @@ -1002,7 +994,10 @@ static int share_pages(struct domain *sd, gfn_t sgfn, 
> shr_handle_t sh,
>      /* Free the client page */
>      if(test_and_clear_bit(_PGC_allocated, &cpage->count_info))
>          put_page(cpage);
> -    put_page(cpage);
> +
> +    ASSERT(put_count);
> +    while ( put_count-- )
> +        put_page_and_type(cpage);

I don't think this is in the spirit of the fix in 0502e0adae2; the idea
there seems to have been to make sure that cpage belongs to the right
domain, and that the ownership doesn't change.  If such a race / mistake
were possible before that change, such a race / mistake would be
possible after this change, wouldn't it?

 -George

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

Reply via email to