From 41c2411286f76919546b677f98f1166f1e40c706 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 26 Aug 2011 16:54:18 +0200 Subject: [PATCH] s3: Fix a winbind race leading to 100% CPU This fixes a race condition that leads to the winbindd_children list becoming corrupted. It happens when on a busy winbind SIGCHLD is a bit late. Imagine a winbind with multiple requests in the queue for a single child. Child dies, and before the SIGCHLD handler is called we find the socket to be dead. wb_child_request_done is called, receiving an error from wb_simple_trans_recv. It closes the socket. Then immediately the wb_child_request_trigger will do another fork_domain_child before the signal handler is called. This means that we do another fork_domain_child, we have child->sock==-1 at this point. fork_domain_child will do a DLIST_ADD(winbindd_children, child) a second time where the child is already part of that list. This corrupts the list. Then the signal handler kicks in, spinning in for (child = winbindd_children; child != NULL; child = child->next) { forever. Not good. This patch makes sure that both conditions (sock==-1 and not part of the list) for a winbindd_child struct match up. Autobuild-User: Volker Lendecke Autobuild-Date: Fri Aug 26 18:51:24 CEST 2011 on sn-devel-104 Fix bug #9000 - winbindd hangs when disconnect domain connection. --- source3/winbindd/winbindd_dual.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 360f1b2dbb2..2c0633c3eaa 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -37,6 +37,8 @@ extern bool override_logfile; extern struct winbindd_methods cache_methods; +static struct winbindd_child *children = NULL; + /* Read some data from a client connection */ static NTSTATUS child_read_request(struct winbindd_cli_state *state) @@ -170,6 +172,7 @@ static void wb_child_request_done(struct tevent_req *subreq) */ close(state->child->sock); state->child->sock = -1; + DLIST_REMOVE(children, state->child); tevent_req_error(req, err); return; } @@ -517,8 +520,6 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, SMB_ASSERT(child->rpccli != NULL); } -struct winbindd_child *children = NULL; - void winbind_child_died(pid_t pid) { struct winbindd_child *child; -- 2.34.1