From ff477d073f2e71a1fa59f86cb44bd9d48674a71b Mon Sep 17 00:00:00 2001
From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Date: Fri, 4 Sep 2015 16:53:31 +0100
Subject: [PATCH] greybus: loopback: make sure to list_del on connection_exit

gb_loopback_connection_exit does a kfree on a data structure associated
with a loopback connection but fails to do a corresponding list_del(). On
subsequent enumerations this can lead to a NULL pointer dereference. Each
list_add in gb_loopback_connection_init() must have a corresponding
list_del in gb_loopback_connection_exit(), this patch adds the relevant
list_del() and ensures that an appropriate mutex protecting gb_dev.list is
held while doing so.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Reported-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
---
 drivers/staging/greybus/loopback.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c
index 8dd648cc0796..231d1d4c1104 100644
--- a/drivers/staging/greybus/loopback.c
+++ b/drivers/staging/greybus/loopback.c
@@ -944,18 +944,23 @@ static void gb_loopback_connection_exit(struct gb_connection *connection)
 	struct gb_loopback *gb = connection->private;
 	struct kobject *kobj = &connection->bundle->intf->module->dev.kobj;
 
-	gb_dev.count--;
-	connection->private = NULL;
 	if (!IS_ERR_OR_NULL(gb->task))
 		kthread_stop(gb->task);
 
+	mutex_lock(&gb_dev.mutex);
+
+	connection->private = NULL;
 	kfifo_free(&gb->kfifo_lat);
 	kfifo_free(&gb->kfifo_ts);
 	if (!gb_dev.count)
 		sysfs_remove_groups(kobj, loopback_dev_groups);
 	sysfs_remove_groups(&connection->dev.kobj, loopback_con_groups);
 	debugfs_remove(gb->file);
+	list_del(&gb->entry);
 	kfree(gb);
+	gb_dev.count--;
+
+	mutex_unlock(&gb_dev.mutex);
 }
 
 static struct gb_protocol loopback_protocol = {