Blame SOURCES/dleyna-core-Don-t-remove-a-queue-more-than-once.patch

f8f92e
From 1b5282d8303177cebf8496656da1dada29517e9d Mon Sep 17 00:00:00 2001
f8f92e
From: Debarshi Ray <debarshir@freedesktop.org>
f8f92e
Date: Fri, 4 Dec 2020 02:17:48 +0100
f8f92e
Subject: [PATCH] Don't remove a queue more than once
f8f92e
f8f92e
Currently, the dleyna_task_processor_remove_queues_for_sink and
f8f92e
dleyna_task_processor_remove_queues_for_source APIs can corrupt the
f8f92e
memory of the hash table of queues in the processor.
f8f92e
f8f92e
These APIs iterate through the queues in the hash table using
f8f92e
g_hash_table_foreach_remove, and let the callbacks return TRUE when a
f8f92e
queue is to be removed. Unfortunately, the callbacks use prv_cancel,
f8f92e
which might have already removed the queue using g_hash_table_remove.
f8f92e
It happens specifically for queues that have no current_task and have
f8f92e
the DLEYNA_TASK_QUEUE_FLAG_AUTO_REMOVE flag set.
f8f92e
f8f92e
dleyna-renderer-service has such a queue, whose task_delete_cb handler
f8f92e
is set to dleyna_gasync_task_delete_cb. When dleyna-renderer-service
f8f92e
loses it's last D-Bus client, it first invokes
f8f92e
dleyna_task_processor_remove_queues_for_source, followed by
f8f92e
dleyna_task_processor_set_quitting. The former corrupts the hash
f8f92e
table. The latter invokes prv_cancel_all_queues, which again goes
f8f92e
through the hash table and tries to remove them. This leads to crashes
f8f92e
with backtraces containing dleyna_gasync_task_delete_cb, GPtrArray,
f8f92e
prv_task_cancel_and_free_cb, or similar code paths originating from
f8f92e
prv_cancel_only.
f8f92e
f8f92e
Here's an example:
f8f92e
f8f92e
%0  prv_task_cancel_and_free_cb (data=0x56246f2425f0,
f8f92e
                                 user_data=<optimized out>)
f8f92e
    at libdleyna/core/task-processor.c:180
f8f92e
%1  g_ptr_array_foreach (array=0x56246f68b5a0,
f8f92e
                         func=0x7f41d2335850 <prv_task_cancel_and_free_cb>,
f8f92e
                         user_data=0x56246f4ea1a0)
f8f92e
    at ../glib/garray.c:2091
f8f92e
%2  prv_cancel_only (queue_id=<optimized out>,
f8f92e
                     task_queue=0x56246f4ea1a0)
f8f92e
    at libdleyna/core/task-processor.c:193
f8f92e
%3  prv_cancel_cb (key=<optimized out>,
f8f92e
                   value=0x56246f4ea1a0,
f8f92e
                   user_data=<optimized out>)
f8f92e
    at libdleyna/core/task-processor.c:229
f8f92e
%4  g_hash_table_foreach_remove_or_steal (hash_table=0x56246f1e82a0,
f8f92e
                                          func=func@entry=0x7f41d2335c10 <prv_cancel_cb>,
f8f92e
                                          user_data=user_data@entry=0x0,
f8f92e
                                          notify=notify@entry=1)
f8f92e
    at ../glib/ghash.c:1947
f8f92e
%5  g_hash_table_foreach_remove (hash_table=<optimized out>,
f8f92e
                                 func=func@entry=0x7f41d2335c10 <prv_cancel_cb>,
f8f92e
                                 user_data=user_data@entry=0x0)
f8f92e
    at ../glib/ghash.c:1993
f8f92e
%6  prv_cancel_all_queues (processor=0x56246f1f3510)
f8f92e
    at libdleyna/core/task-processor.c:244
f8f92e
%7  dleyna_task_processor_set_quitting (processor=0x56246f1f3510)
f8f92e
    at libdleyna/core/task-processor.c:259
f8f92e
%8  prv_lost_client (connection=<optimized out>,
f8f92e
                     name=0x56246f24e5d0 ":1.47515",
f8f92e
                     user_data=<optimized out>)
f8f92e
    at src/connector-dbus.c:283
f8f92e
%9  actually_do_call (call_type=CALL_TYPE_NAME_VANISHED,
f8f92e
                      name_owner=<optimized out>,
f8f92e
                      connection=<optimized out>,
f8f92e
                      client=0x56246f24efb0)
f8f92e
    at ../gio/gdbusnamewatching.c:171
f8f92e
%10 actually_do_call (call_type=CALL_TYPE_NAME_VANISHED,
f8f92e
                      name_owner=<optimized out>,
f8f92e
                      connection=<optimized out>,
f8f92e
                      client=0x56246f24efb0)
f8f92e
    at ../gio/gdbusnamewatching.c:149
f8f92e
%11 do_call (client=0x56246f24efb0, call_type=CALL_TYPE_NAME_VANISHED)
f8f92e
    at ../gio/gdbusnamewatching.c:224
f8f92e
%12 call_vanished_handler (client=0x56246f24efb0)
f8f92e
    at ../gio/gdbusnamewatching.c:249
f8f92e
%13 call_vanished_handler (client=0x56246f24efb0)
f8f92e
    at ../gio/gdbusnamewatching.c:242
f8f92e
%14 on_name_owner_changed (connection=<optimized out>,
f8f92e
                           sender_name=0x56246f24a260 "org.freedesktop.DBus",
f8f92e
                           object_path=0x56246f7ad950 "/org/freedesktop/DBus",
f8f92e
                           interface_name=0x56246f27a2a0 "org.freedesktop.DBus",
f8f92e
                           signal_name=<optimized out>,
f8f92e
                           parameters=0x56246f21ee90, user_data=0x1)
f8f92e
    at ../gio/gdbusnamewatching.c:352
f8f92e
%15 emit_signal_instance_in_idle_cb (data=data@entry=0x56246f236950)
f8f92e
    at ../gio/gdbusconnection.c:3777
f8f92e
%16 g_idle_dispatch (source=source@entry=0x56246f7080a0,
f8f92e
                     callback=0x7f41d1e1e640 <emit_signal_instance_in_idle_cb>,
f8f92e
                     user_data=0x56246f236950)
f8f92e
    at ../glib/gmain.c:5836
f8f92e
%17 g_main_dispatch (context=0x56246f1f2920) at ../glib/gmain.c:3325
f8f92e
%18 g_main_context_dispatch (context=0x56246f1f2920)
f8f92e
    at ../glib/gmain.c:4043
f8f92e
%19 g_main_context_iterate.constprop.0 (context=0x56246f1f2920,
f8f92e
                                        block=block@entry=1,
f8f92e
                                        dispatch=dispatch@entry=1,
f8f92e
                                        self=<optimized out>)
f8f92e
    at ../glib/gmain.c:4119
f8f92e
%20 g_main_loop_run (loop=0x56246f2337a0) at ../glib/gmain.c:4317
f8f92e
%21 dleyna_main_loop_start (server=<optimized out>,
f8f92e
                            control_point=<optimized out>,
f8f92e
                            user_data=<optimized out>)
f8f92e
    at libdleyna/core/main-loop.c:154
f8f92e
%22 __libc_start_main (main=0x56246d8b40d0 <main>,
f8f92e
                       argc=1,
f8f92e
                       argv=0x7ffd4b757768,
f8f92e
                       init=<optimized out>,
f8f92e
                       fini=<optimized out>,
f8f92e
                       rtld_fini=<optimized out>,
f8f92e
                       stack_end=0x7ffd4b757758)
f8f92e
    at ../csu/libc-start.c:314
f8f92e
%23 _start ()
f8f92e
f8f92e
Looking at the innards of the task_queue, it's seen that all the
f8f92e
function pointers have the same value, which doesn't match with the
f8f92e
reality of the code and is indicative of a memory error:
f8f92e
f8f92e
(gdb) print *task_queue
f8f92e
$2 = {tasks = 0x56210d62385a,
f8f92e
  task_process_cb = 0x9595959595959595,
f8f92e
  task_cancel_cb = 0x9595959595959595,
f8f92e
  task_delete_cb = 0x9595959595959595,
f8f92e
  task_queue_finally_cb = 0x9595959595959595,
f8f92e
  current_task = 0x9595959595959595,
f8f92e
  idle_id = 2509608341,
f8f92e
  defer_remove = -1785358955,
f8f92e
  flags = 2509608341,
f8f92e
  user_data = 0x9595959595959595,
f8f92e
  cancelled = -1785358955}
f8f92e
f8f92e
Based on initial work done by Robert Tiemann.
f8f92e
f8f92e
https://bugzilla.redhat.com/show_bug.cgi?id=1903139
f8f92e
https://github.com/phako/dleyna-core/pull/1
f8f92e
---
f8f92e
 libdleyna/core/task-processor.c | 4 ++--
f8f92e
 1 file changed, 2 insertions(+), 2 deletions(-)
f8f92e
f8f92e
diff --git a/libdleyna/core/task-processor.c b/libdleyna/core/task-processor.c
f8f92e
index 39529a3dc967..f50dd569ed61 100644
f8f92e
--- a/libdleyna/core/task-processor.c
f8f92e
+++ b/libdleyna/core/task-processor.c
f8f92e
@@ -285,7 +285,7 @@ static gboolean prv_free_queue_for_source(gpointer key, gpointer value,
f8f92e
 
f8f92e
 	if (!strcmp(source, queue_key->source) && !queue->defer_remove) {
f8f92e
 		queue->defer_remove = (queue->current_task != NULL);
f8f92e
-		prv_cancel(queue_key, queue);
f8f92e
+		prv_cancel_only(queue_key, queue);
f8f92e
 
f8f92e
 		if (!queue->defer_remove) {
f8f92e
 			DLEYNA_LOG_DEBUG("Removing queue <%s,%s>",
f8f92e
@@ -320,7 +320,7 @@ static gboolean prv_free_queue_for_sink(gpointer key, gpointer value,
f8f92e
 
f8f92e
 	if (!strcmp(sink, queue_key->sink) && !queue->defer_remove) {
f8f92e
 		queue->defer_remove = (queue->current_task != NULL);
f8f92e
-		prv_cancel(queue_key, queue);
f8f92e
+		prv_cancel_only(queue_key, queue);
f8f92e
 
f8f92e
 		if (!queue->defer_remove) {
f8f92e
 			DLEYNA_LOG_DEBUG("Removing queue <%s,%s>",
f8f92e
-- 
f8f92e
2.28.0
f8f92e