summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schwenke <martin@meltin.net>2016-08-26 16:29:47 +1000
committerStefan Metzmacher <metze@samba.org>2016-09-06 08:22:17 +0200
commit41ca635abb14ee3fd881978d1559c284e2e4737a (patch)
treee0b6454c5e1f1eac02c2328a28d750c42dbe3ff6
parent0ccfa212e431238b6ca1623d4280041872d5126d (diff)
downloadsamba-41ca635abb14ee3fd881978d1559c284e2e4737a.tar.gz
ctdb-daemon: Schedule running of callback if there are no event scripts
The callback should never be called before an immediate return. The callback might reply to a control and the caller of ctdb_event_script_callback_v() may not have assigned/stolen the pointer to control structure into the private data. Therefore, calling the callback can dereference an uninitialised pointer to the control structure when attempting to reply. ctdb_event_script_callback_v() must succeed when there are no event scripts. On success the caller will mark the call as asynchronous and expect the callback to be called. Given that it can't be called before return then it needs to be scheduled. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12180 Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com> (cherry picked from commit 9076c44f35bf309b9e183bae98829f7154b93f33)
-rw-r--r--ctdb/server/eventscript.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/ctdb/server/eventscript.c b/ctdb/server/eventscript.c
index bd5bc0d6b94..a5f26805a09 100644
--- a/ctdb/server/eventscript.c
+++ b/ctdb/server/eventscript.c
@@ -699,6 +699,62 @@ static int remove_callback(struct event_script_callback *callback)
return 0;
}
+struct schedule_callback_state {
+ struct ctdb_context *ctdb;
+ void (*callback)(struct ctdb_context *, int, void *);
+ void *private_data;
+ int status;
+ struct tevent_immediate *im;
+};
+
+static void schedule_callback_handler(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct schedule_callback_state *state =
+ talloc_get_type_abort(private_data,
+ struct schedule_callback_state);
+
+ if (state->callback != NULL) {
+ state->callback(state->ctdb, state->status,
+ state->private_data);
+ }
+ talloc_free(state);
+}
+
+static int
+schedule_callback_immediate(struct ctdb_context *ctdb,
+ void (*callback)(struct ctdb_context *,
+ int, void *),
+ void *private_data,
+ int status)
+{
+ struct schedule_callback_state *state;
+ struct tevent_immediate *im;
+
+ state = talloc_zero(ctdb, struct schedule_callback_state);
+ if (state == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+ return -1;
+ }
+ im = tevent_create_immediate(state);
+ if (im == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+ talloc_free(state);
+ return -1;
+ }
+
+ state->ctdb = ctdb;
+ state->callback = callback;
+ state->private_data = private_data;
+ state->status = status;
+ state->im = im;
+
+ tevent_schedule_immediate(im, ctdb->ev,
+ schedule_callback_handler, state);
+ return 0;
+}
+
/*
run the event script in the background, calling the callback when
finished
@@ -825,8 +881,14 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
/* Nothing to do? */
if (state->scripts->num_scripts == 0) {
- callback(ctdb, 0, private_data);
+ int ret = schedule_callback_immediate(ctdb, callback,
+ private_data, 0);
talloc_free(state);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,
+ ("Unable to schedule callback for 0 scripts\n"));
+ return 1;
+ }
return 0;
}