git: b5d236785dc3 - stable/12 - vmci: fix panic due to freeing unallocated resources

From: Mark Peek <mp_at_FreeBSD.org>
Date: Sun, 17 Oct 2021 15:32:24 UTC
The branch stable/12 has been updated by mp:

URL: https://cgit.FreeBSD.org/src/commit/?id=b5d236785dc352a65bc29d97c8a89b40387eb7a0

commit b5d236785dc352a65bc29d97c8a89b40387eb7a0
Author:     Mark Peek <mp@FreeBSD.org>
AuthorDate: 2021-10-09 21:21:16 +0000
Commit:     Mark Peek <mp@FreeBSD.org>
CommitDate: 2021-10-17 15:31:53 +0000

    vmci: fix panic due to freeing unallocated resources
    
    Summary:
    An error mapping PCI resources results in a panic due to unallocated
    resources being freed up. This change puts the appropriate checks in
    place to prevent the panic.
    
    PR:             252445
    Reported by:    Marek Zarychta <zarychtam@plan-b.pwste.edu.pl>
    Tested by:      marcus
    MFC after:      1 week
    Sponsored by:   VMware
    
    Test Plan:
    Along with user testing, also simulated error by inserting a ENXIO
    return in vmci_map_bars().
    
    Reviewed by:    marcus
    Subscribers:    imp
    Differential Revision: https://reviews.freebsd.org/D32016
    
    (cherry picked from commit 0f14bcbe384091c729464cb770372aeb79061070)
---
 sys/dev/vmware/vmci/vmci.c            |  9 ++++---
 sys/dev/vmware/vmci/vmci_event.c      |  3 +++
 sys/dev/vmware/vmci/vmci_kernel_if.c  | 48 ++++++++++++++++++++++++++++++++++-
 sys/dev/vmware/vmci/vmci_kernel_if.h  |  2 ++
 sys/dev/vmware/vmci/vmci_queue_pair.c |  3 +++
 5 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/sys/dev/vmware/vmci/vmci.c b/sys/dev/vmware/vmci/vmci.c
index 3f195231d8e2..9d0cbbdef67c 100644
--- a/sys/dev/vmware/vmci/vmci.c
+++ b/sys/dev/vmware/vmci/vmci.c
@@ -242,8 +242,10 @@ vmci_detach(device_t dev)
 
 	vmci_components_cleanup();
 
-	taskqueue_drain(taskqueue_thread, &sc->vmci_delayed_work_task);
-	mtx_destroy(&sc->vmci_delayed_work_lock);
+	if mtx_initialized(&sc->vmci_spinlock) {
+		taskqueue_drain(taskqueue_thread, &sc->vmci_delayed_work_task);
+		mtx_destroy(&sc->vmci_delayed_work_lock);
+	}
 
 	if (sc->vmci_res0 != NULL)
 		bus_space_write_4(sc->vmci_iot0, sc->vmci_ioh0,
@@ -254,7 +256,8 @@ vmci_detach(device_t dev)
 
 	vmci_unmap_bars(sc);
 
-	mtx_destroy(&sc->vmci_spinlock);
+	if mtx_initialized(&sc->vmci_spinlock)
+		mtx_destroy(&sc->vmci_spinlock);
 
 	pci_disable_busmaster(dev);
 
diff --git a/sys/dev/vmware/vmci/vmci_event.c b/sys/dev/vmware/vmci/vmci_event.c
index 9a932340a7b6..c34ff113978b 100644
--- a/sys/dev/vmware/vmci/vmci_event.c
+++ b/sys/dev/vmware/vmci/vmci_event.c
@@ -594,6 +594,9 @@ vmci_event_unregister_subscription(vmci_id sub_id)
 {
 	struct vmci_subscription *s;
 
+	if (!vmci_initialized_lock(&subscriber_lock))
+		return NULL;
+
 	vmci_grab_lock_bh(&subscriber_lock);
 	s = vmci_event_find(sub_id);
 	if (s != NULL) {
diff --git a/sys/dev/vmware/vmci/vmci_kernel_if.c b/sys/dev/vmware/vmci/vmci_kernel_if.c
index 851c4c9df214..a550277500aa 100644
--- a/sys/dev/vmware/vmci/vmci_kernel_if.c
+++ b/sys/dev/vmware/vmci/vmci_kernel_if.c
@@ -70,7 +70,8 @@ void
 vmci_cleanup_lock(vmci_lock *lock)
 {
 
-	mtx_destroy(lock);
+	if mtx_initialized(lock)
+		mtx_destroy(lock);
 }
 
 /*
@@ -165,6 +166,29 @@ vmci_release_lock_bh(vmci_lock *lock)
 	mtx_unlock(lock);
 }
 
+/*
+ *------------------------------------------------------------------------------
+ *
+ * vmci_initialized_lock
+ *
+ *     Returns whether a lock has been initialized.
+ *
+ * Results:
+ *     Return 1 if initialized or 0 if unininitialized.
+ *
+ * Side effects:
+ *     None
+ *
+ *------------------------------------------------------------------------------
+ */
+
+int
+vmci_initialized_lock(vmci_lock *lock)
+{
+
+	return mtx_initialized(lock);
+}
+
 /*
  *------------------------------------------------------------------------------
  *
@@ -446,6 +470,28 @@ vmci_mutex_release(vmci_mutex *mutex)
 	mtx_unlock(mutex);
 }
 
+/*
+ *------------------------------------------------------------------------------
+ *
+ * vmci_mutex_initialized
+ *
+ *     Returns whether a mutex has been initialized.
+ *
+ * Results:
+ *     Return 1 if initialized or 0 if unininitialized.
+ *
+ * Side effects:
+ *     None
+ *
+ *------------------------------------------------------------------------------
+ */
+
+int
+vmci_mutex_initialized(vmci_mutex *mutex)
+{
+
+	return mtx_initialized(mutex);
+}
 /*
  *------------------------------------------------------------------------------
  *
diff --git a/sys/dev/vmware/vmci/vmci_kernel_if.h b/sys/dev/vmware/vmci/vmci_kernel_if.h
index fc23eefe98e0..048e480b0698 100644
--- a/sys/dev/vmware/vmci/vmci_kernel_if.h
+++ b/sys/dev/vmware/vmci/vmci_kernel_if.h
@@ -48,6 +48,7 @@ void	vmci_grab_lock(vmci_lock *lock);
 void	vmci_release_lock(vmci_lock *lock);
 void	vmci_grab_lock_bh(vmci_lock *lock);
 void	vmci_release_lock_bh(vmci_lock *lock);
+int	vmci_initialized_lock(vmci_lock *lock);
 
 void	*vmci_alloc_kernel_mem(size_t size, int flags);
 void	vmci_free_kernel_mem(void *ptr, size_t size);
@@ -72,6 +73,7 @@ int	vmci_mutex_init(vmci_mutex *mutex, char *name);
 void	vmci_mutex_destroy(vmci_mutex *mutex);
 void	vmci_mutex_acquire(vmci_mutex *mutex);
 void	vmci_mutex_release(vmci_mutex *mutex);
+int	vmci_mutex_initialized(vmci_mutex *mutex);
 
 void	*vmci_alloc_queue(uint64_t size, uint32_t flags);
 void	vmci_free_queue(void *q, uint64_t size);
diff --git a/sys/dev/vmware/vmci/vmci_queue_pair.c b/sys/dev/vmware/vmci/vmci_queue_pair.c
index 65ae00c8d167..ebf2824f8d04 100644
--- a/sys/dev/vmware/vmci/vmci_queue_pair.c
+++ b/sys/dev/vmware/vmci/vmci_queue_pair.c
@@ -338,6 +338,9 @@ vmci_qp_guest_endpoints_exit(void)
 {
 	struct qp_guest_endpoint *entry;
 
+	if (!vmci_mutex_initialized(&qp_guest_endpoints.mutex))
+		return;
+
 	vmci_mutex_acquire(&qp_guest_endpoints.mutex);
 
 	while ((entry =