Blame SOURCES/0113-SBUS-defer-deallocation-of-sbus_watch_ctx.patch

f35488
From f845355e32127c5e8f2bf700cdaa5b8721804232 Mon Sep 17 00:00:00 2001
f35488
From: Alexey Tikhonov <atikhono@redhat.com>
f35488
Date: Fri, 8 Nov 2019 20:01:50 +0100
f35488
Subject: [PATCH] SBUS: defer deallocation of sbus_watch_ctx
f35488
MIME-Version: 1.0
f35488
Content-Type: text/plain; charset=UTF-8
f35488
Content-Transfer-Encoding: 8bit
f35488
f35488
The following flow was causing use-after-free error:
f35488
  tevent_common_invoke_fd_handler(RW) -> sbus_watch_handler(RW) ->
f35488
  dbus_watch_handle(R) -> ...libdbus detects connection is closed... ->
f35488
  sbus_remove_watch() -> talloc_free(watch) ->
f35488
  ... get back to libdbus and back to sbus_watch_handler() ->
f35488
  "if (watch->dbus_write_watch) dbus_watch_handle(W)" => use-after-free
f35488
f35488
To resolve an issue schedule deallocation of watch as immediate event.
f35488
f35488
Resolves: https://pagure.io/SSSD/sssd/issue/2660
f35488
f35488
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
f35488
---
f35488
 src/sbus/sssd_dbus_common.c  | 24 +++++++++++++++++++++++-
f35488
 src/sbus/sssd_dbus_private.h |  1 +
f35488
 2 files changed, 24 insertions(+), 1 deletion(-)
f35488
f35488
diff --git a/src/sbus/sssd_dbus_common.c b/src/sbus/sssd_dbus_common.c
f35488
index 50100320a..dbdcae9ec 100644
f35488
--- a/src/sbus/sssd_dbus_common.c
f35488
+++ b/src/sbus/sssd_dbus_common.c
f35488
@@ -133,6 +133,12 @@ dbus_bool_t sbus_add_watch(DBusWatch *dbus_watch, void *data)
f35488
             DEBUG(SSSDBG_FATAL_FAILURE, "Out of Memory!\n");
f35488
             return FALSE;
f35488
         }
f35488
+        watch->im_event = tevent_create_immediate(watch);
f35488
+        if (watch->im_event == NULL) {
f35488
+            DEBUG(SSSDBG_CRIT_FAILURE, "Out of Memory!\n");
f35488
+            talloc_free(watch);
f35488
+            return FALSE;
f35488
+        }
f35488
         watch->conn = conn;
f35488
         watch->fd = fd;
f35488
     }
f35488
@@ -243,6 +249,13 @@ void sbus_toggle_watch(DBusWatch *dbus_watch, void *data)
f35488
            enabled?"enabled":"disabled");
f35488
 }
f35488
 
f35488
+static void free_sbus_watch(struct tevent_context *ev,
f35488
+                            struct tevent_immediate *im,
f35488
+                            void *data)
f35488
+{
f35488
+    struct sbus_watch_ctx *w = talloc_get_type(data, struct sbus_watch_ctx);
f35488
+    talloc_free(w); /* this will free attached 'im' as well */
f35488
+}
f35488
 /*
f35488
  * sbus_remove_watch
f35488
  * Hook for D-BUS to remove file descriptor-based events
f35488
@@ -274,7 +287,16 @@ void sbus_remove_watch(DBusWatch *dbus_watch, void *data)
f35488
         watch->dbus_write_watch = NULL;
f35488
     }
f35488
     if (!watch->dbus_read_watch && !watch->dbus_write_watch) {
f35488
-        talloc_free(watch);
f35488
+        /* libdus doesn't need this watch{fd} anymore, so associated
f35488
+         * tevent_fd should be removed from monitoring at the spot.
f35488
+         */
f35488
+        talloc_zfree(watch->fde);
f35488
+        /* watch itself can't be freed yet as it still may be referenced
f35488
+         * in the current context (for example in sbus_watch_handler())
f35488
+         * so instead schedule immediate event to delete it.
f35488
+         */
f35488
+        tevent_schedule_immediate(watch->im_event, watch->conn->ev,
f35488
+                                  free_sbus_watch, watch);
f35488
     }
f35488
 }
f35488
 
f35488
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
f35488
index a3d4bae16..92649f113 100644
f35488
--- a/src/sbus/sssd_dbus_private.h
f35488
+++ b/src/sbus/sssd_dbus_private.h
f35488
@@ -88,6 +88,7 @@ struct sbus_watch_ctx {
f35488
 
f35488
     struct tevent_fd *fde;
f35488
     int fd;
f35488
+    struct tevent_immediate *im_event;
f35488
 
f35488
     DBusWatch *dbus_read_watch;
f35488
     DBusWatch *dbus_write_watch;
f35488
-- 
f35488
2.21.1
f35488