From: Matthias Gerstner <matthias.gerstner@suse.de>
Date: Fri, 14 Jul 2017 16:17:09 +0200
Subject: fixed a number of memory leaks with (de)registering of dbus handlers
Git-commit: 7a78eda52d973d3edc06fea84ad874678d6055f0
References: bsc#1049490

A number of dynamic memory leaks that could be triggered by any user
with access to DBus have been fixed:

- deregistering a previously registered dbus handler failed to free the
dynamically allocated handler data
- trying to register a dbus handler that doesn't exist failed to free
the dynamically allocated handler data
- trying to register a dbus handler with an invalid name (e.g. starting
with a number like "0memory" caused the g_bus_watch_name() call to fail,
the callback never came in, no response was ever sent to the requestor
o

Example:

dbus-send --system --print-reply --dest=org.kernel.TCMUService1 /org/kernel/TCMUService1/HandlerManager1 org.kernel.TCMUService1.HandlerManager1.RegisterHandler string:0memory string:stuff

These bugs can all lead to a kind of local DoS, wasting memory in the
tcmu-runner daemon, which can be triggered by any local user with access
to the system bus.

Acked-by: Lee Duncan <lduncan@suse.com>
---
 main.c |   27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

--- a/main.c
+++ b/main.c
@@ -102,6 +102,14 @@ bool tcmur_unregister_handler(struct tcm
 	return false;
 }
 
+static void free_dbus_handler(struct tcmur_handler *handler)
+{
+	g_free((char*)handler->opaque);
+	g_free((char*)handler->subtype);
+	g_free((char*)handler->cfg_desc);
+	g_free(handler);
+}
+
 static bool tcmur_unregister_dbus_handler(struct tcmur_handler *handler)
 {
 	bool ret = false;
@@ -109,6 +117,10 @@ static bool tcmur_unregister_dbus_handle
 
 	ret = tcmur_unregister_handler(handler);
 
+	if (ret == true) {
+		free_dbus_handler(handler);
+	}
+
 	return ret;
 }
 
@@ -562,8 +574,8 @@ on_handler_vanished(GDBusConnection *con
 			    g_variant_new("(bs)", FALSE, reason));
 		g_free(reason);
 	}
-	tcmur_unregister_dbus_handler(handler);
 	dbus_unexport_handler(handler);
+	tcmur_unregister_dbus_handler(handler);
 }
 
 static gboolean
@@ -598,8 +610,15 @@ on_register_handler(TCMUService1HandlerM
 					    on_handler_vanished,
 					    handler,
 					    NULL);
+	if (info->watcher_id == 0) {
+		// probably an invalid name, roll back and report an error
+		free_dbus_handler(handler);
+
+		g_dbus_method_invocation_return_value(invocation,
+			g_variant_new("(bs)", FALSE,
+				      "failed to watch for DBus handler name"));
+	}
 	g_free(bus_name);
-	handler->opaque = info;
 	return TRUE;
 }
 
@@ -626,11 +645,9 @@ on_unregister_handler(TCMUService1Handle
 	}
 
 	dbus_unexport_handler(handler);
+	g_bus_unwatch_name(info->watcher_id);
 	tcmur_unregister_dbus_handler(handler);
 
-	g_bus_unwatch_name(info->watcher_id);
-	g_free(info);
-	g_free(handler);
 	g_dbus_method_invocation_return_value(invocation,
 		g_variant_new("(bs)", TRUE, "succeeded"));
 	return TRUE;
