[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] x86/hvm: Fix double free from vlapic_init() early error path
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); + 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); \ + (p) = NULL; \ +} while ( false ) +#define FREE_DOMHEAP_PAGE(p) FREE_DOMHEAP_PAGES(p, 0) + /* Map machine page range in Xen virtual address space. */ int map_pages_to_xen( unsigned long virt, -- 2.11.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |