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

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


  • To: Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
  • Date: Wed, 31 Mar 2021 14:31:25 +0100
  • Authentication-results: esa5.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Jan Beulich <JBeulich@xxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Wei Liu <wl@xxxxxxx>
  • Delivery-date: Wed, 31 Mar 2021 13:31:44 +0000
  • Ironport-hdrordr: A9a23:Q9VhAakruDqz3bIrFSI6+vsCKALpDfLI3DAbvn1ZSRFFG/Gwve rGppom/DXzjyscX2xlpMuJP7OOTWiZ2Zl+54QQOrnKZniAhEKDKoZ+4Yz+hwDxAiGWzJ846Y 5Me7VzYeeRMXFUlsD/iTPVL/8F4P2qtJ+lnv3fyXAFd3AOV4hF4x1iAgiWVm1aLTM2ZqYRL5 aX6spZqzfIQx1+Ba7XOlA/U/XevNqOrZr6YHc9dngawTOThjCl4qOSKXml9yoZOgkh/Z4StU zMkwn0/cyYwpOG9iM=
  • Ironport-sdr: J4ijsB0nSleINzq/D3PSRBUORAKA4YgMG8kNvkGZoU7lW66Qk7HuuXtDccpSpufh87+EL4wuem 72qqt7rN9wZKVDJ8CtgvCjvt5fijUEoJ5+GSRXiC1X/FcVGkHHeE1vNuBY0qbWjf/I09rU0PlQ WdSy4fMAfnVjONnbqQNK1VsdXtfIwmCkvWG3rKJkWTEXbZBZNirjPO8NtYTsaVu0RV2wae/1Zp rRsRMhYqyLh1vE+vVPk0K+JhD4LJhX6zBcc5uhLA5Sj+hi5fYkKGj9XjIxVzv4cSyz05C/OR7P 3Ik=
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

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




 


Rackspace

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