daemon: Protect against double free of callback state while shutting down
authorAmitay Isaacs <amitay@gmail.com>
Mon, 29 Oct 2012 03:56:10 +0000 (14:56 +1100)
committerAmitay Isaacs <amitay@gmail.com>
Wed, 9 Jan 2013 03:39:23 +0000 (14:39 +1100)
When CTDB is shut down and monitoring has been stopped, monitor_context
gets freed and all the callback states hanging off it.  This includes
callback state for current_monitor, if the current monitor event has
not yet finished.  As a result, when the shutdown event is called,
current_monitor->callback state is not NULL, but it's actually freed
and it's a dangling reference.

So before executing callback function and freeing callback state check
if ctdb->monitor->monitor_context is not NULL.

Signed-off-by: Amitay Isaacs <amitay@gmail.com>
include/ctdb_private.h
server/ctdb_monitor.c
server/eventscript.c

index fb541958f4aba7cc7598e51e7b8ac459405bf38f..5b519fbc6822fd9e6c474f29705c73d392641de1 100644 (file)
@@ -1343,6 +1343,7 @@ int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv);
 void ctdb_block_signal(int signum);
 void ctdb_unblock_signal(int signum);
 int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb);
+bool ctdb_stopped_monitoring(struct ctdb_context *ctdb);
 int ctdb_set_child_logging(struct ctdb_context *ctdb);
 void ctdb_lockdown_memory(struct ctdb_context *ctdb);
 
index bc21e5bb1da1f5ae402d67935c0a68cf9b990d84..984f947a3b4b1c7d7479ed0055ef38e248147abf 100644 (file)
@@ -506,3 +506,10 @@ int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb)
        return ctdb->monitor->monitoring_mode;
 }
 
+/*
+ * Check if monitoring has been stopped
+ */
+bool ctdb_stopped_monitoring(struct ctdb_context *ctdb)
+{
+       return (ctdb->monitor->monitor_context == NULL ? true : false);
+}
index 6a75877bff8a2e306531d46be0e6ff744dbfe79d..762f9506fa99c9eabae73dcc7493ca794cffae80 100644 (file)
@@ -781,8 +781,9 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
        if (ctdb->current_monitor) {
                struct ctdb_event_script_state *ms = talloc_get_type(ctdb->current_monitor, struct ctdb_event_script_state);
 
-               /* cancel it */
-               if (ms->callback != NULL) {
+               /* Cancel current monitor callback state only if monitoring
+                * context ctdb->monitor->monitor_context has not been freed */
+               if (ms->callback != NULL && !ctdb_stopped_monitoring(ctdb)) {
                        ms->callback->fn(ctdb, -ECANCELED, ms->callback->private_data);
                        talloc_free(ms->callback);
                }