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

Re: [PATCH] x86/hvm: Fix double free from vlapic_init() early error path


  • To: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
  • From: Roger Pau Monné <roger.pau@xxxxxxxxxx>
  • Date: Wed, 31 Mar 2021 15:49:46 +0200
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=FZNS2mJd/FbJHrnS83x1Zr1zbQob3rCmLpZKA1B+rEw=; b=OYzqh5l9sRs9XoIHnw+vFpJJqHXuGhl70Fd13uSx9CUuKr803Ks8ucvGqtrvEX9KkZxcf9F77qo63lJuOGB2mX9a/zOz5DwM3SM6sBcmE0neXXdVMNGVceVTChLIk1n4MxzP+gHrxp6Fyp8eqU1VO+En3wawuO+n5PrfOSAIBZjpTE0c9/tMs+C7t6x2UtFb4vYHIFLciT1csIvQkHctdVvoqis6Ms0T2d12cxC/8KJ1FkMa7J1xHkdmvqrO1F/kmqcB8nftRRkMDTxpyvMKLqHj1WO+SiN3dcC/HpuLJ8mCEbjMZphyLhDVhkO0tmtb+AtIdAX5JOVQR5jLQnhFig==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=b7UVQxYi4YlDsDZB+JsLdUBY4byFQZiqavQdqf8UTpBy446TP6FtjROUmHP0z19nWEYhqQ9MpnMVxG6NRK3/Y7pYd+2whTVjk75hTDsBvwXsmKlGXcR7ln3AgLuooy0J7u35r3UYpHFuZABeMyMRTh7BXnXZ/mlNz3eci+2F1jl7DHvuL5UnTtPTDtqWRTsUoN6a6fuhehcBfxdLkaclpkh2yVAMvRlZ9CJCYQVziZ7+z5/oWAJbJoie1lsZPXdnSPwItrEwUn8zO7f3VY01KP++1rF6fhVQwD0RKsaXZOWsT7samHR/53yyoCib6WKMFT33jhFxBxGePrXMnhEVpw==
  • Authentication-results: esa1.hc3370-68.iphmx.com; dkim=pass (signature verified) header.i=@citrix.onmicrosoft.com
  • Cc: Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Jan Beulich <JBeulich@xxxxxxxx>, Wei Liu <wl@xxxxxxx>
  • Delivery-date: Wed, 31 Mar 2021 13:50:21 +0000
  • Ironport-hdrordr: A9a23:nMx2A6rV4+VADvpk0XoSEWQaV5vYL9V00zAX/kB9WHVpW+SFis Gjm+ka3xfoiDAXHEotg8yEJbPoex7h3LR+iLNwAZ6JWg76tGy0aLxz9IeK+UyHJwTS1M54kZ 1hfa93FcHqATFB5/rSzQGkH78br+Wv37uvgY7loUtFbQYvUK146hc8NwDzKDwVeCBjJb4UUK WR/dBGoT3IQwVxUu2eCmMeV+bO4/3n/aiWAiIuPBIs5AmQgT7A0teTfySw5RsQXyhCxr0v6w H+4mnEz56uru2hzVvk33LThq48pPLa1tBBCMaQ4/JlTgnEtwDAXuVccozHhh8ZiqWF6FEmkN 7Dyi1QQPhb2jfqUUye5Tfo0wnk+j4y53Hl0k/wuwqcneXJAAgUJuAEqYVFcgbIy0dIhqAM7I t7m1i3mrASLRTckD/z79LFPisa5nackD4ZvsM4y1l8OLFuEYN5nMgk025+VKokJmbc7rsqFe F/Zfusmcp+QBehQF3y+lV0zMfEZAVKIj62BnIsl+ayyDZskHVw3yIjtbAit0ZFzp47RpVejt 60SZhApfVLRs8SW6p3GP0Md8uxEnDMWhLBKgupUC7aKJ0=
  • Ironport-sdr: HV0IjXBGr/d1OLwwNRvmVtYVAonN8FeR14k85zfUCxCzq21TNtMQI99ucU7jlaR9n8Y7xPv4lL BMOL0f8cKKytzYTwY0SVkRZds18X0G4xDrsWVAgyGZSGj0h8vdXlU/E8mhBNXqMu9HlPql1VZl pdRP35C/POtgZOTyx/hmZ+F8ayCh+ZybfKzsYsg9p+QSUex8Jtt4G3Q13H6rtpYBAtM5/pONia 66YHnSj8IyDZsCLb8EmcH46JlleGU3mPNw7RuJyc3d/v5W9FzlJLYBwcTUpkn4wqiD/y/ZAvf8 +i4=
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On Wed, Mar 31, 2021 at 02:31:25PM +0100, Andrew Cooper wrote:
> vlapic_init()'s caller calls vlapic_destroy() on error.  Therefore, the error
> path from __map_domain_page_global() failing would doubly free
> vlapic->regs_page.
> 
> Rework vlapic_destroy() to be properly idempotent, introducing the necessary
> UNMAP_DOMAIN_PAGE_GLOBAL() and FREE_DOMHEAP_PAGE() wrappers.
> 
> Rearrange vlapic_init() to group all trivial initialisation, and leave all
> cleanup to the caller, in line with our longer term plans.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---
> CC: Jan Beulich <JBeulich@xxxxxxxx>
> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
> CC: Wei Liu <wl@xxxxxxx>
> ---
>  xen/arch/x86/hvm/vlapic.c     | 11 ++++-------
>  xen/include/xen/domain_page.h |  5 +++++
>  xen/include/xen/mm.h          |  6 ++++++
>  3 files changed, 15 insertions(+), 7 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
> index 5e21fb4937..da030f41b5 100644
> --- a/xen/arch/x86/hvm/vlapic.c
> +++ b/xen/arch/x86/hvm/vlapic.c
> @@ -1608,7 +1608,9 @@ int vlapic_init(struct vcpu *v)
>          return 0;
>      }
>  
> +    /* Trivial init. */
>      vlapic->pt.source = PTSRC_lapic;
> +    spin_lock_init(&vlapic->esr_lock);
>  
>      vlapic->regs_page = alloc_domheap_page(v->domain, MEMF_no_owner);
>      if ( !vlapic->regs_page )
> @@ -1616,17 +1618,12 @@ int vlapic_init(struct vcpu *v)
>  
>      vlapic->regs = __map_domain_page_global(vlapic->regs_page);
>      if ( vlapic->regs == NULL )
> -    {
> -        free_domheap_page(vlapic->regs_page);
>          return -ENOMEM;
> -    }
>  
>      clear_page(vlapic->regs);
>  
>      vlapic_reset(vlapic);
>  
> -    spin_lock_init(&vlapic->esr_lock);
> -
>      tasklet_init(&vlapic->init_sipi.tasklet, vlapic_init_sipi_action, v);
>  
>      if ( v->vcpu_id == 0 )
> @@ -1645,8 +1642,8 @@ void vlapic_destroy(struct vcpu *v)
>      tasklet_kill(&vlapic->init_sipi.tasklet);
>      TRACE_0D(TRC_HVM_EMUL_LAPIC_STOP_TIMER);
>      destroy_periodic_time(&vlapic->pt);
> -    unmap_domain_page_global(vlapic->regs);
> -    free_domheap_page(vlapic->regs_page);
> +    UNMAP_DOMAIN_PAGE_GLOBAL(vlapic->regs);

I think you need to check whether vlapic->regs_page is NULL here...

> +    FREE_DOMHEAP_PAGE(vlapic->regs_page);
>  }
>  
>  /*
> diff --git a/xen/include/xen/domain_page.h b/xen/include/xen/domain_page.h
> index a182d33b67..0cb7f2aad3 100644
> --- a/xen/include/xen/domain_page.h
> +++ b/xen/include/xen/domain_page.h
> @@ -77,4 +77,9 @@ static inline void unmap_domain_page_global(const void *va) 
> {};
>      (p) = NULL;                     \
>  } while ( false )
>  
> +#define UNMAP_DOMAIN_PAGE_GLOBAL(p) do {   \
> +    unmap_domain_page_global(p);           \
> +    (p) = NULL;                            \
> +} while ( false )
> +
>  #endif /* __XEN_DOMAIN_PAGE_H__ */
> diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
> index 667f9dac83..c274e2eac4 100644
> --- a/xen/include/xen/mm.h
> +++ b/xen/include/xen/mm.h
> @@ -85,6 +85,12 @@ bool scrub_free_pages(void);
>  } while ( false )
>  #define FREE_XENHEAP_PAGE(p) FREE_XENHEAP_PAGES(p, 0)
>  
> +#define FREE_DOMHEAP_PAGES(p, o) do { \
> +    free_domheap_pages(p, o);         \

...as both unmap_domain_page_global and free_domheap_pages don't
support being passed a NULL pointer.

Passing such NULL pointer will result in unmap_domain_page_global
hitting an assert AFAICT, and free_domheap_pages will try to use
page_get_owner(NULL).

Thanks, Roger.



 


Rackspace

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