s3: Fix bug 7844: Race in winbind
authorVolker Lendecke <vl@samba.org>
Mon, 6 Dec 2010 20:45:21 +0000 (12:45 -0800)
committerJeremy Allison <jra@samba.org>
Mon, 6 Dec 2010 22:21:02 +0000 (23:21 +0100)
If a child dies, the parent process right away closes the socket.
This is wrong, with tevent we still have events pending. This works
fine for epoll but does not for at least the FreeBSD select variant.
Tevent sticks a closed socket into the select masks. This then
returns an error EBADF. When this happens, the parent winbind dies
instead of forking a new child.

This moves the socket close from the SIGCHLD cleanup function to
the socket receiver. I could not reproduce the parent death anymore
and it did not create an obvious fd leak.

Autobuild-User: Jeremy Allison <jra@samba.org>
Autobuild-Date: Mon Dec  6 23:21:02 CET 2010 on sn-devel-104

source3/winbindd/winbindd_dual.c

index cc9d6de21dd423cf4c9640820e7bbcd7af9cf318..cdf53d0ac282f18336ab073f4715e28eb8b91fd1 100644 (file)
@@ -138,7 +138,7 @@ static void wb_child_request_trigger(struct tevent_req *req,
                req, struct wb_child_request_state);
        struct tevent_req *subreq;
 
-       if ((state->child->pid == 0) && (!fork_domain_child(state->child))) {
+       if ((state->child->sock == -1) && (!fork_domain_child(state->child))) {
                tevent_req_error(req, errno);
                return;
        }
@@ -168,6 +168,12 @@ static void wb_child_request_done(struct tevent_req *subreq)
        ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
        TALLOC_FREE(subreq);
        if (ret == -1) {
+               /*
+                * The basic parent/child communication broke, close
+                * our socket
+                */
+               close(state->child->sock);
+               state->child->sock = -1;
                tevent_req_error(req, err);
                return;
        }
@@ -437,6 +443,7 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
                          "logname == NULL");
        }
 
+       child->sock = -1;
        child->domain = domain;
        child->table = table;
        child->queue = tevent_queue_create(NULL, "winbind_child");
@@ -465,9 +472,6 @@ void winbind_child_died(pid_t pid)
        /* This will be re-added in fork_domain_child() */
 
        DLIST_REMOVE(winbindd_children, child);
-
-       close(child->sock);
-       child->sock = -1;
        child->pid = 0;
 }