]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3:winbindd: make sure we remove pending io requests before closing client sockets
authorStefan Metzmacher <metze@samba.org>
Mon, 18 May 2015 11:17:40 +0000 (13:17 +0200)
committerKarolin Seeger <kseeger@samba.org>
Thu, 21 May 2015 13:35:23 +0000 (15:35 +0200)
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)

source3/winbindd/winbindd.c
source3/winbindd/winbindd.h

index 27c43dc29d76dcf1629b3ef6bec53bf0f43a07e1..2c94f49cf19d106c8b4eedf60c76a4a8a958e6db 100644 (file)
@@ -792,6 +792,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)
@@ -801,6 +802,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) {
@@ -827,6 +830,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)
@@ -897,6 +901,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 */
 
@@ -910,6 +915,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) {
@@ -941,6 +948,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));
index 72eb3ec3dc04222072c284fcef4813d366162a8d..986a41d6ba846f9005179b0e434eae864a1c5008 100644 (file)
@@ -66,6 +66,8 @@ 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_* */
+
        bool getpwent_initialized;                /* Has getpwent_state been
                                                   * initialized? */
        bool getgrent_initialized;                /* Has getgrent_state been