From fad6f73dc4367adb852ce6953f93f12cbb97b894 Mon Sep 17 00:00:00 2001
From: Camelia Groza <camelia.groza@nxp.com>
Date: Fri, 18 May 2018 10:33:37 +0300
Subject: [PATCH] sdk_dpaa: ceetm: avoid use-after-free scenarios

Once the pfiofo qdiscs are grafted to the netdev queues, they are destroyed
by the kernel when required. Remove references to the pfifo qdiscs after
grafting, in order to avoid double free scenarios.

Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
---
 .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c   | 23 +++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c
@@ -477,7 +477,9 @@ static void ceetm_destroy(struct Qdisc *
 		if (!priv->root.qdiscs)
 			break;
 
-		/* Remove the pfifo qdiscs */
+		/* Destroy the pfifo qdiscs in case they haven't been attached
+		 * to the netdev queues yet.
+		 */
 		for (ntx = 0; ntx < dev->num_tx_queues; ntx++)
 			if (priv->root.qdiscs[ntx])
 				qdisc_destroy(priv->root.qdiscs[ntx]);
@@ -608,7 +610,16 @@ static int ceetm_init_root(struct Qdisc
 		goto err_init_root;
 	}
 
-	/* pre-allocate underlying pfifo qdiscs */
+	/* Pre-allocate underlying pfifo qdiscs.
+	 *
+	 * We want to offload shaping and scheduling decisions to the hardware.
+	 * The pfifo qdiscs will be attached to the netdev queues and will
+	 * guide the traffic from the IP stack down to the driver with minimum
+	 * interference.
+	 *
+	 * The CEETM qdiscs and classes will be crossed when the traffic
+	 * reaches the driver.
+	 */
 	priv->root.qdiscs = kcalloc(dev->num_tx_queues,
 				    sizeof(priv->root.qdiscs[0]),
 				    GFP_KERNEL);
@@ -1280,7 +1291,10 @@ static int ceetm_change(struct Qdisc *sc
 	return ret;
 }
 
-/* Attach the underlying pfifo qdiscs */
+/* Graft the underlying pfifo qdiscs to the netdev queues.
+ * It's safe to remove our references at this point, since the kernel will
+ * destroy the qdiscs on its own and no cleanup from our part is required.
+ */
 static void ceetm_attach(struct Qdisc *sch)
 {
 	struct net_device *dev = qdisc_dev(sch);
@@ -1296,6 +1310,9 @@ static void ceetm_attach(struct Qdisc *s
 		if (old_qdisc)
 			qdisc_destroy(old_qdisc);
 	}
+
+	kfree(priv->root.qdiscs);
+	priv->root.qdiscs = NULL;
 }
 
 static unsigned long ceetm_cls_search(struct Qdisc *sch, u32 handle)
