ctdb-recovery-helper: Deregister message handler in error paths
authorAmitay Isaacs <amitay@gmail.com>
Wed, 13 Dec 2017 05:12:09 +0000 (16:12 +1100)
committerMartin Schwenke <martins@samba.org>
Wed, 13 Dec 2017 07:48:18 +0000 (08:48 +0100)
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 <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/server/ctdb_recovery_helper.c

index ab9ab4152b099f331c62e32b73af3143e38a0962..2a10b07b508e75cf572a6d4123e5b1ad2238be2c 100644 (file)
@@ -397,6 +397,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,
@@ -595,8 +596,8 @@ static void pull_database_new_done(struct tevent_req *subreq)
        if (! status) {
                D_ERR("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);
@@ -605,13 +606,15 @@ static void pull_database_new_done(struct tevent_req *subreq)
                D_ERR("mismatch (%u != %u) in DB_PULL records for db %s\n",
                      num_records, state->num_records,
                      recdb_name(state->recdb));
-               tevent_req_error(req, EIO);
-               return;
+               state->result = EIO;
+               goto unregister;
        }
 
        D_INFO("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);
@@ -639,6 +642,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);
 }