summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2015-05-18 13:17:40 +0200
committerKarolin Seeger <kseeger@samba.org>2015-05-21 17:44:34 +0200
commitfa55c75bf4e4cdee327f80f203a9b2cd3e6ca339 (patch)
tree3c4a0e5ccfd9a68d88d882a3c0fca036fe01b98f
parent60f1f761aa28e9ce891797afa40bd3e1af442a4d (diff)
downloadsamba-fa55c75bf4e4cdee327f80f203a9b2cd3e6ca339.tar.gz
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 <metze@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Autobuild-User(master): Stefan Metzmacher <metze@samba.org> Autobuild-Date(master): Wed May 20 22:16:54 CEST 2015 on sn-devel-104 (cherry picked from commit 435ddd8223eaa6fafb62cead0399bdd042d998e8)
-rw-r--r--source3/winbindd/winbindd.c26
-rw-r--r--source3/winbindd/winbindd.h1
2 files changed, 27 insertions, 0 deletions
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index caa9ed127dd..09ca27880c5 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 db5dac8e3d9..d9adb96eefc 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() */