From: Tu Dinh <ngoc-tu.dinh@vates.tech>

xen-netback: Fix XenBus connection failure cleanup

xenvif_get_stats and xenvif_get_ethtool_stats capture vif->num_queues
under rcu_read_lock. We need to unpublish vif->num_queues before
synchronize_net to ensure that readers that come afterwards will not
read a non-zero vif->num_queues and attempt to access invalid queues.

This is the same cleanup algorithm as used in backend_disconnect and
added in commit b17075d5c198 ("xen-netback: fix race condition on XenBus
disconnect").

This is XSA-531

Fixes: 5fb756f1bbec ("xen-netback: Fix UAF when reading statistics data")
Signed-off-by: Tu Dinh <ngoc-tu.dinh@vates.tech>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 drivers/net/xen-netback/xenbus.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index a826fa24258b..74c2745086bb 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -731,6 +731,7 @@ static void connect(struct backend_info *be)
 	unsigned int queue_index;
 	unsigned int requested_num_queues;
 	struct xenvif_queue *queue;
+	unsigned int num_queues;
 
 	/* Check whether the frontend requested multiple queues
 	 * and read the number requested.
@@ -837,14 +838,15 @@ static void connect(struct backend_info *be)
 	return;
 
 err:
-	if (be->vif->num_queues > 0)
+	num_queues = be->vif->num_queues;
+	if (num_queues > 0)
 		xenvif_disconnect_data(be->vif); /* Clean up existing queues */
+	be->vif->num_queues = 0;
 	synchronize_net();
-	for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index)
+	for (queue_index = 0; queue_index < num_queues; ++queue_index)
 		xenvif_deinit_queue(&be->vif->queues[queue_index]);
 	vfree(be->vif->queues);
 	be->vif->queues = NULL;
-	be->vif->num_queues = 0;
 	xenvif_disconnect_ctrl(be->vif);
 	return;
 }
-- 
2.56.0
