diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2015-11-18 20:48:51 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2015-12-07 16:13:35 +0100 |
commit | a92f68763a57b211a1bf6b80b6dd80c4a1aa2738 (patch) | |
tree | be7bc80881885c004115c17a5c4fc5f2486c9851 /src/providers | |
parent | 9f69dff2af5ee0e922ca75efa9749913fd2d944f (diff) | |
download | sssd-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.c | 15 |
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 { |