From 0e9563e10a023092b6086a673a266323e9b1d603 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Fri, 30 Aug 2013 10:56:04 +0200 Subject: SIGCHLD handler: do not call callback when pvt data was freed https://fedorahosted.org/sssd/ticket/1992 --- src/providers/ipa/ipa_dyndns.c | 10 +++++++++- src/providers/krb5/krb5_child_handler.c | 2 +- src/providers/ldap/sdap_child_helpers.c | 2 +- src/util/child_common.c | 24 +++++++++++++++++++++++- src/util/child_common.h | 8 +++++++- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c index 22a16a11a..a3d358ec2 100644 --- a/src/providers/ipa/ipa_dyndns.c +++ b/src/providers/ipa/ipa_dyndns.c @@ -860,6 +860,7 @@ failed: struct nsupdate_send_ctx { struct ipa_nsupdate_ctx *nsupdate_ctx; + struct sss_child_ctx_old *child_ctx; int child_status; }; @@ -1105,7 +1106,8 @@ fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx) /* Set up SIGCHLD handler */ ret = child_handler_setup(ctx->dyndns_ctx->ipa_ctx->id_ctx->sdap_id_ctx->be->ev, - pid, ipa_dyndns_child_handler, req); + pid, ipa_dyndns_child_handler, req, + &state->child_ctx); if (ret != EOK) { return NULL; } @@ -1135,9 +1137,15 @@ static void ipa_dyndns_timeout(struct tevent_context *ev, { struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); + struct nsupdate_send_ctx *state = + tevent_req_data(req, struct nsupdate_send_ctx); DEBUG(1, ("Timeout reached for dynamic DNS update\n")); + child_handler_destroy(state->child_ctx); + state->child_ctx = NULL; + state->child_status = ETIMEDOUT; + tevent_req_error(req, ETIMEDOUT); } diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index e792db3f7..89ed0487e 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -275,7 +275,7 @@ static errno_t fork_child(struct tevent_req *req) fd_nonblocking(state->io->read_from_child_fd); fd_nonblocking(state->io->write_to_child_fd); - ret = child_handler_setup(state->ev, pid, NULL, NULL); + ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL); if (ret != EOK) { DEBUG(1, ("Could not set up child signal handler\n")); return ret; diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c index f2412f9e5..6db0dbf23 100644 --- a/src/providers/ldap/sdap_child_helpers.c +++ b/src/providers/ldap/sdap_child_helpers.c @@ -119,7 +119,7 @@ static errno_t sdap_fork_child(struct tevent_context *ev, fd_nonblocking(child->read_from_child_fd); fd_nonblocking(child->write_to_child_fd); - ret = child_handler_setup(ev, pid, NULL, NULL); + ret = child_handler_setup(ev, pid, NULL, NULL, NULL); if (ret != EOK) { return ret; } diff --git a/src/util/child_common.c b/src/util/child_common.c index 5f0b26595..fe4684fb0 100644 --- a/src/util/child_common.c +++ b/src/util/child_common.c @@ -260,7 +260,8 @@ struct sss_child_ctx_old { }; int child_handler_setup(struct tevent_context *ev, int pid, - sss_child_callback_t cb, void *pvt) + sss_child_callback_t cb, void *pvt, + struct sss_child_ctx_old **_child_ctx) { struct sss_child_ctx_old *child_ctx; @@ -284,9 +285,30 @@ int child_handler_setup(struct tevent_context *ev, int pid, child_ctx->pvt = pvt; DEBUG(8, ("Signal handler set up for pid [%d]\n", pid)); + + if (_child_ctx != NULL) { + *_child_ctx = child_ctx; + } + return EOK; } +void child_handler_destroy(struct sss_child_ctx_old *ctx) +{ + errno_t ret; + + /* We still want to wait for the child to finish, but the caller is not + * interested in the result anymore (e.g. timeout was reached). */ + ctx->cb = NULL; + ctx->pvt = NULL; + + ret = kill(ctx->pid, SIGKILL); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, ("kill failed [%d][%s].\n", ret, strerror(ret))); + } +} + /* Async communication with the child process via a pipe */ struct write_pipe_state { diff --git a/src/util/child_common.h b/src/util/child_common.h index 237969f2f..95865bb52 100644 --- a/src/util/child_common.h +++ b/src/util/child_common.h @@ -78,9 +78,15 @@ typedef void (*sss_child_callback_t)(int child_status, struct tevent_signal *sige, void *pvt); +struct sss_child_ctx_old; + /* Set up child termination signal handler */ int child_handler_setup(struct tevent_context *ev, int pid, - sss_child_callback_t cb, void *pvt); + sss_child_callback_t cb, void *pvt, + struct sss_child_ctx_old **_child_ctx); + +/* Destroy child termination signal handler */ +void child_handler_destroy(struct sss_child_ctx_old *ctx); /* Async communication with the child process via a pipe */ struct tevent_req *write_pipe_send(TALLOC_CTX *mem_ctx, -- cgit