From cad3d40f8b3da4ce1754da56e06a588e8d864502 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 May 2015 13:17:40 +0200 Subject: [PATCH] s3:winbindd: make sure we remove pending io requests before closing client sockets This avoids a crash inside the tevent epoll backend. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11141 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed May 20 22:16:54 CEST 2015 on sn-devel-104 (cherry picked from commit 435ddd8223eaa6fafb62cead0399bdd042d998e8) --- source3/winbindd/winbindd.c | 26 ++++++++++++++++++++++++++ source3/winbindd/winbindd.h | 1 + 2 files changed, 27 insertions(+) diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index caa9ed1..09ca278 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -824,6 +824,7 @@ static void request_finished(struct winbindd_cli_state *state) return; } tevent_req_set_callback(req, winbind_client_response_written, state); + state->io_req = req; } static void winbind_client_response_written(struct tevent_req *req) @@ -833,6 +834,8 @@ static void winbind_client_response_written(struct tevent_req *req) ssize_t ret; int err; + state->io_req = NULL; + ret = wb_resp_write_recv(req, &err); TALLOC_FREE(req); if (ret == -1) { @@ -859,6 +862,7 @@ static void winbind_client_response_written(struct tevent_req *req) return; } tevent_req_set_callback(req, winbind_client_request_read, state); + state->io_req = req; } void request_error(struct winbindd_cli_state *state) @@ -929,6 +933,7 @@ static void new_connection(int listen_sock, bool privileged) return; } tevent_req_set_callback(req, winbind_client_request_read, state); + state->io_req = req; /* Add to connection list */ @@ -942,6 +947,8 @@ static void winbind_client_request_read(struct tevent_req *req) ssize_t ret; int err; + state->io_req = NULL; + ret = wb_req_read_recv(req, state, &state->request, &err); TALLOC_FREE(req); if (ret == -1) { @@ -973,6 +980,25 @@ static void remove_client(struct winbindd_cli_state *state) return; } + /* + * We need to remove a pending wb_req_read_* + * or wb_resp_write_* request before closing the + * socket. + * + * This is important as they might have used tevent_add_fd() and we + * use the epoll * backend on linux. So we must remove the tevent_fd + * before closing the fd. + * + * Otherwise we might hit a race with close_conns_after_fork() (via + * winbindd_reinit_after_fork()) where a file description + * is still open in a child, which means it's still active in + * the parents epoll queue, but the related tevent_fd is already + * already gone in the parent. + * + * See bug #11141. + */ + TALLOC_FREE(state->io_req); + if (state->sock != -1) { /* tell client, we are closing ... */ nwritten = write(state->sock, &c, sizeof(c)); diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index db5dac8..d9adb96 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -67,6 +67,7 @@ struct winbindd_cli_state { struct winbindd_request *request; /* Request from client */ struct tevent_queue *out_queue; struct winbindd_response *response; /* Respose to client */ + struct tevent_req *io_req; /* wb_req_read_* or wb_resp_write_* */ struct getpwent_state *pwent_state; /* State for getpwent() */ struct getgrent_state *grent_state; /* State for getgrent() */ -- 1.9.1