From bbe22093322ad3d622eb9d3ea864cdfe252bfc8a Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 13 Dec 2017 16:12:09 +1100 Subject: [PATCH] ctdb-recovery-helper: Deregister message handler in error paths BUG: https://bugzilla.samba.org/show_bug.cgi?id=13188 If PULL_DB control times out but the remote node is still sending the data, then the tevent_req for pull_database_send will be freed without removing the message handler. So when the data is received, srvid handler will be called and it will try to access tevent_req which will result in use-after-free and abort. Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- ctdb/server/ctdb_recovery_helper.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ctdb/server/ctdb_recovery_helper.c b/ctdb/server/ctdb_recovery_helper.c index 474b900c71b..2c7bb4bb25a 100644 --- a/ctdb/server/ctdb_recovery_helper.c +++ b/ctdb/server/ctdb_recovery_helper.c @@ -428,6 +428,7 @@ struct pull_database_state { uint32_t pnn; uint64_t srvid; int num_records; + int result; }; static void pull_database_handler(uint64_t srvid, TDB_DATA data, @@ -625,8 +626,8 @@ static void pull_database_new_done(struct tevent_req *subreq) if (! status) { LOG("control DB_PULL failed for %s on node %u, ret=%d\n", recdb_name(state->recdb), state->pnn, ret); - tevent_req_error(req, ret); - return; + state->result = ret; + goto unregister; } ret = ctdb_reply_control_db_pull(reply, &num_records); @@ -634,13 +635,15 @@ static void pull_database_new_done(struct tevent_req *subreq) if (num_records != state->num_records) { LOG("mismatch (%u != %u) in DB_PULL records for %s\n", num_records, state->num_records, recdb_name(state->recdb)); - tevent_req_error(req, EIO); - return; + state->result = EIO; + goto unregister; } LOG("Pulled %d records for db %s from node %d\n", state->num_records, recdb_name(state->recdb), state->pnn); +unregister: + subreq = ctdb_client_remove_message_handler_send( state, state->ev, state->client, state->srvid, req); @@ -668,6 +671,11 @@ static void pull_database_unregister_done(struct tevent_req *subreq) return; } + if (state->result != 0) { + tevent_req_error(req, state->result); + return; + } + tevent_req_done(req); } -- 2.14.3