Subject: bin/30253: Race condition in identd -b (pipe: no child processes)
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <pmcphee@dilbert.givex.com>
List: netbsd-bugs
Date: 05/17/2005 13:31:00
>Number:         30253
>Category:       bin
>Synopsis:       Race condition in identd -b (pipe: no child processes)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue May 17 13:31:00 +0000 2005
>Originator:     Patrick McPhee
>Release:        NetBSD 2.0_RC4
>Organization:
	Givex Canada Corporation
>Environment:
System: NetBSD dilbert 2.0_RC4 NetBSD 2.0_RC4 (GIVEX) #0: Sat Oct 9 04:10:28 EDT 2004 door@dilbert:/usr/src/sys/arch/i386/compile/GIVEX i386
Architecture: i386
Machine: i386
>Description:
When run as a daemon, identd sometimes fails with the error

 "poll: No child processes"

The problem arises when two or more identd requests are handled at roughly
the same time. If poll is interrupted by SIGCLD from one child process,
it returns -1 and sets errno to EINTR. If a second child process returns
between the time poll() sets errno and identd tests errno, the signal
handler sets errno to ECHILD. identd treats this as a fatal error.

>How-To-Repeat:

Flood identd with concurrent requests.

>Fix:

This patch fixes the problem. openbsd has fixed this by moving the call
to waitpid() out of the signal handler.

A work-around is to run identd -b in a wrapper which waits for it to
exit and restarts it.


Index: identd.c
===================================================================
RCS file: /cvsroot/src/libexec/identd/identd.c,v
retrieving revision 1.22.2.1
diff -u -r1.22.2.1 identd.c
--- identd.c	18 Sep 2004 19:14:41 -0000	1.22.2.1
+++ identd.c	7 Apr 2005 13:26:02 -0000
@@ -221,7 +221,7 @@
 		/* Mainloop for daemon */
 		for (;;) {
 			rv = poll(rfds, nfds, INFTIM);
-			if (rv < 0 && errno == EINTR)
+			if (rv < 0 && (errno == EINTR || errno == ECHILD))
 				continue;
 			if (rv < 0)
 				fatal("poll");