summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2010-12-06 21:01:35 +0100
committerKarolin Seeger <kseeger@samba.org>2011-09-22 21:52:37 +0200
commitda08c8ac7cf9e2833c39e7ef39caafa4ab34424d (patch)
tree8f1305cd5d973032fdb4f92f72204636f7a68319
parentc5bf8ac4ee60fe808a2593a5ece12e8bfad5695b (diff)
downloadsamba-da08c8ac7cf9e2833c39e7ef39caafa4ab34424d.tar.gz
samba-da08c8ac7cf9e2833c39e7ef39caafa4ab34424d.tar.xz
samba-da08c8ac7cf9e2833c39e7ef39caafa4ab34424d.zip
s3: Fix bug 7844: Race in winbind
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.
-rw-r--r--source3/winbindd/winbindd_dual.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index 117d55d2dac..360f1b2dbb2 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -134,7 +134,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;
}
@@ -164,6 +164,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;
}
@@ -502,6 +508,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");
@@ -530,9 +537,6 @@ void winbind_child_died(pid_t pid)
/* This will be re-added in fork_domain_child() */
DLIST_REMOVE(children, child);
-
- close(child->sock);
- child->sock = -1;
child->pid = 0;
}