summaryrefslogtreecommitdiffstats
path: root/src/providers
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2015-11-18 20:48:51 +0100
committerJakub Hrozek <jhrozek@redhat.com>2015-12-07 16:13:35 +0100
commita92f68763a57b211a1bf6b80b6dd80c4a1aa2738 (patch)
treebe7bc80881885c004115c17a5c4fc5f2486c9851 /src/providers
parent9f69dff2af5ee0e922ca75efa9749913fd2d944f (diff)
downloadsssd-a92f68763a57b211a1bf6b80b6dd80c4a1aa2738.tar.gz
sssd-a92f68763a57b211a1bf6b80b6dd80c4a1aa2738.tar.xz
sssd-a92f68763a57b211a1bf6b80b6dd80c4a1aa2738.zip
FO: Use tevent_req_defer_callback() when notifying callers
If a fo_resolve_service callback would modify the server->common member in any way, for example by dereferencing the server and lowering the refcount to 0, which would free the common structure, then the next iteration of fo_resolve_service_done would access memory that was already gone. Please see https://tevent.samba.org/group__tevent__request.html#ga09373077d0b39e321a196a86bfebf280 for more details. Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/fail_over.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
index c60310d8f..0b99098ad 100644
--- a/src/providers/fail_over.c
+++ b/src/providers/fail_over.c
@@ -131,6 +131,7 @@ struct resolve_service_request {
struct server_common *server_common;
struct tevent_req *req;
+ struct tevent_context *ev;
};
struct status {
@@ -940,7 +941,9 @@ resolve_service_request_destructor(struct resolve_service_request *request)
}
static int
-set_lookup_hook(struct fo_server *server, struct tevent_req *req)
+set_lookup_hook(struct tevent_context *ev,
+ struct fo_server *server,
+ struct tevent_req *req)
{
struct resolve_service_request *request;
@@ -956,6 +959,7 @@ set_lookup_hook(struct fo_server *server, struct tevent_req *req)
talloc_free(request);
return ENOMEM;
}
+ request->ev = ev;
request->req = req;
DLIST_ADD(server->common->request_list, request);
talloc_set_destructor(request, resolve_service_request_destructor);
@@ -1142,7 +1146,7 @@ fo_resolve_service_server(struct tevent_req *req)
case SERVER_RESOLVING_NAME:
/* Name resolution is already under way. Just add ourselves into the
* waiting queue so we get notified after the operation is finished. */
- ret = set_lookup_hook(state->server, req);
+ ret = set_lookup_hook(state->ev, state->server, req);
if (ret != EOK) {
tevent_req_error(req, ret);
return true;
@@ -1194,6 +1198,13 @@ fo_resolve_service_done(struct tevent_req *subreq)
/* Take care of all requests for this server. */
while ((request = common->request_list) != NULL) {
DLIST_REMOVE(common->request_list, request);
+
+ /* If the request callback decresed refcount on the returned
+ * server, we would have crashed as common would not be valid
+ * anymore. Rather schedule the notify for next tev iteration
+ */
+ tevent_req_defer_callback(request->req, request->ev);
+
if (ret) {
tevent_req_error(request->req, ret);
} else {