]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
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)
committerKarolin Seeger <kseeger@samba.org>
Tue, 2 Jan 2018 09:01:10 +0000 (10:01 +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 474b900c71b4e224efb932af6f31c86240e70944..2c7bb4bb25a72b3100da45aaeec5c2764d2a7f3e 100644 (file)
@@ -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);
 }