Fix potential segfaults using freed memory.
authorSimo Sorce <idra@samba.org>
Mon, 9 Mar 2009 22:04:38 +0000 (18:04 -0400)
committerSimo Sorce <idra@samba.org>
Tue, 10 Mar 2009 00:12:11 +0000 (20:12 -0400)
In some code paths ltdb_context was still referenced even after we were returned
an error by one of the callbacks. Because the interface assumes that once an
error is returned the ldb_request may be freed, and because the ltdb_context was
allocated as a child of the request, this might cause access to freed memory.
Allocate the ltdb_context on ldb, and keep track of what's going on with the
request by adding a spy children on it. This way even if the request is freed
before the ltdb_callback is called, we will safely free the ctx and just quietly
return.

source4/lib/ldb/ldb_tdb/ldb_index.c
source4/lib/ldb/ldb_tdb/ldb_search.c
source4/lib/ldb/ldb_tdb/ldb_tdb.c
source4/lib/ldb/ldb_tdb/ldb_tdb.h

index ad27c9a9a9a9d77f7b8a9b397f30451731852ca5..c99c2936d850236720c070fcfe0435b26f0581e7 100644 (file)
@@ -1055,7 +1055,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
 
                ret = ldb_module_send_entry(ac->req, msg, NULL);
                if (ret != LDB_SUCCESS) {
-                       ac->callback_failed = true;
+                       ac->request_terminated = true;
                        return ret;
                }
        }
index 0f595267fcbcfbf7fd07aeb7f548490da2677a8c..d395c28f287a922e45bd1b85c88032445ed8777d 100644 (file)
@@ -424,10 +424,10 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
 
        ret = ldb_module_send_entry(ac->req, msg, NULL);
        if (ret != LDB_SUCCESS) {
-               ac->callback_failed = true;
+               ac->request_terminated = true;
                /* the callback failed, abort the operation */
                return -1;
-       }       
+       }
 
        return 0;
 }
@@ -544,7 +544,7 @@ int ltdb_search(struct ltdb_context *ctx)
                /* Check if we got just a normal error.
                 * In that case proceed to a full search unless we got a
                 * callback error */
-               if ( ! ctx->callback_failed && ret != LDB_SUCCESS) {
+               if ( ! ctx->request_terminated && ret != LDB_SUCCESS) {
                        /* Not indexed, so we need to do a full scan */
                        ret = ltdb_search_full(ctx);
                        if (ret != LDB_SUCCESS) {
index 24ec06ea32056cfe1d9ef2a9b5cbc34097bff326..d38cb828bbe61e69c677251af7ab795634abf0a6 100644 (file)
@@ -1019,7 +1019,15 @@ static void ltdb_timeout(struct tevent_context *ev,
        struct ltdb_context *ctx;
        ctx = talloc_get_type(private_data, struct ltdb_context);
 
-       ltdb_request_done(ctx, LDB_ERR_TIME_LIMIT_EXCEEDED);
+       if (!ctx->request_terminated) {
+               /* neutralize the spy */
+               ctx->spy->ctx = NULL;
+
+               /* request is done now */
+               ltdb_request_done(ctx, LDB_ERR_TIME_LIMIT_EXCEEDED);
+       }
+
+       talloc_free(ctx);
 }
 
 static void ltdb_request_extended_done(struct ltdb_context *ctx,
@@ -1078,6 +1086,11 @@ static void ltdb_callback(struct tevent_context *ev,
 
        ctx = talloc_get_type(private_data, struct ltdb_context);
 
+       if (!ctx->request_terminated) {
+               /* neutralize the spy */
+               ctx->spy->ctx = NULL;
+       } else goto done;
+
        switch (ctx->req->operation) {
        case LDB_SEARCH:
                ret = ltdb_search(ctx);
@@ -1102,11 +1115,24 @@ static void ltdb_callback(struct tevent_context *ev,
                ret = LDB_ERR_UNWILLING_TO_PERFORM;
        }
 
-       if (!ctx->callback_failed) {
-               /* Once we are done, we do not need timeout events */
-               talloc_free(ctx->timeout_event);
+       if (!ctx->request_terminated) {
+               /* request is done now */
                ltdb_request_done(ctx, ret);
        }
+
+done:
+       talloc_free(ctx);
+}
+
+static int ltdb_request_destructor(void *ptr)
+{
+       struct ltdb_req_spy *spy = talloc_get_type(ptr, struct ltdb_req_spy);
+
+       if (spy->ctx != NULL) {
+               spy->ctx->request_terminated = true;
+       }
+
+       return 0;
 }
 
 static int ltdb_handle_request(struct ldb_module *module,
@@ -1131,7 +1157,7 @@ static int ltdb_handle_request(struct ldb_module *module,
 
        ev = ldb_get_event_context(ldb);
 
-       ac = talloc_zero(req, struct ltdb_context);
+       ac = talloc_zero(ldb, struct ltdb_context);
        if (ac == NULL) {
                ldb_set_errstring(ldb, "Out of Memory");
                return LDB_ERR_OPERATIONS_ERROR;
@@ -1144,15 +1170,28 @@ static int ltdb_handle_request(struct ldb_module *module,
        tv.tv_usec = 0;
        te = tevent_add_timer(ev, ac, tv, ltdb_callback, ac);
        if (NULL == te) {
+               talloc_free(ac);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
        tv.tv_sec = req->starttime + req->timeout;
        ac->timeout_event = tevent_add_timer(ev, ac, tv, ltdb_timeout, ac);
        if (NULL == ac->timeout_event) {
+               talloc_free(ac);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
+       /* set a spy so that we do not try to use the request context
+        * if it is freed before ltdb_callback fires */
+       ac->spy = talloc(req, struct ltdb_req_spy);
+       if (NULL == ac->spy) {
+               talloc_free(ac);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       ac->spy->ctx = ac;
+
+       talloc_set_destructor((TALLOC_CTX *)ac->spy, ltdb_request_destructor);
+
        return LDB_SUCCESS;
 }
 
index 0a06cdb1b0816583b5bf74f3266227948bdc7146..5a1c8fee2d7482948754bcc5e264c914e8da2d79 100644 (file)
@@ -36,11 +36,16 @@ struct ltdb_private {
   the async local context
   holds also internal search state during a full db search
 */
+struct ltdb_req_spy {
+       struct ltdb_context *ctx;
+};
+
 struct ltdb_context {
        struct ldb_module *module;
        struct ldb_request *req;
 
-       bool callback_failed;
+       bool request_terminated;
+       struct ltdb_req_spy *spy;
 
        /* search stuff */
        const struct ldb_parse_tree *tree;