summaryrefslogtreecommitdiff
path: root/source4/lib/ldb
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2009-03-09 18:04:38 -0400
committerSimo Sorce <idra@samba.org>2009-03-09 20:12:11 -0400
commitf088353d37b433af7b979a17871233cccddf7aca (patch)
tree35a022bf85b756bb500fda1b195aeb938da29925 /source4/lib/ldb
parent218ce0e80532b0dbc595e72502d9596a35acdffd (diff)
downloadsamba-f088353d37b433af7b979a17871233cccddf7aca.tar.gz
samba-f088353d37b433af7b979a17871233cccddf7aca.tar.bz2
samba-f088353d37b433af7b979a17871233cccddf7aca.zip
Fix potential segfaults using freed memory.
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.
Diffstat (limited to 'source4/lib/ldb')
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_index.c2
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_search.c6
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c49
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.h7
4 files changed, 54 insertions, 10 deletions
diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c
index ad27c9a9a9..c99c2936d8 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_index.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_index.c
@@ -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;
}
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c
index 0f595267fc..d395c28f28 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_search.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_search.c
@@ -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) {
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index 24ec06ea32..d38cb828bb 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -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;
}
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
index 0a06cdb1b0..5a1c8fee2d 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -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;