Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 Dec 1998 17:38:16 -0800
From:      Don Lewis <Don.Lewis@tsc.tdk.com>
To:        Matthew Dillon <dillon@apollo.backplane.com>, Peter Edwards <peter.edwards@isocor.ie>
Cc:        Archie Cobbs <archie@whistle.com>, freebsd-current@FreeBSD.ORG
Subject:   Re: inetd: realloc/free bug
Message-ID:  <199812130138.RAA22963@salsa.gv.tsc.tdk.com>
In-Reply-To: Matthew Dillon <dillon@apollo.backplane.com> "Re: inetd: realloc/free bug" (Dec 11,  4:31pm)

next in thread | previous in thread | raw e-mail | index | archive | help
On Dec 11,  4:31pm, Matthew Dillon wrote:
} Subject: Re: inetd: realloc/free bug
}     I've commited my fix to inetd.  As I said before, there
}     really isn't much to it.  You simply allow signal operation
}     around the select() code and block signals at all other
}     times and you are done.  No fancy pipes, no fancy global
}     flags, insignificantly delayed signal operation (and 
}     nominally not delayed at all), inherent event serialization,
}     etc etc etc.

It also has the downside of keeping inetd "active", so it can't
be totally swapped out if it's not in use.  This might be a bit
of a concern to some folks, like those who run FreeBSD on their
laptops.  Your implementation is also more syscall intensive than
some of the alternatives.

Your patch also doesn't eliminate all the race conditions.  When
a signal handler is invoked, it blocks reception of the signal that
triggered it, but not the reception of other signals, so it is possible
for one of the signal handlers to be active when another one is invoked.
This is fixable by blocking the other signals from within the handlers,
at the expense of more syscalls.

I hadn't thought of writing the signals to a pipe and in the past I've
always used global flags.  I think the pipe idea is kind of elegant
because it avoids having to fiddle with the signal masks to avoid
race conditions between testing and clearing the flags.

Oh yeah, there is another race condition that I've never seen mentioned.
In the case of TCP services where we do something like
	ctrl = accept(...);
	pid = fork();
	if (pid == 0) {
		fiddle with fds
		exec(...);
	}
	close(ctrl);
there is a problem if the child process runs, writes a bunch of data
to the socket and exits before the parent process executes the close().
If this happens, the close() in the parent can hang for an indefinite
period of time, until the client consumes the buffered data on the socket.
I fixed this in BIND 4.x a few years ago using a pipe to synchronize
the parent and child processes.  This fix would roughly translate as
the following (ignoring error checking):
	int pipefd[2];
	char c;
	ctrl = accept(...);
	pipe(pipefd);
	pid = fork();
	if (pid == 0) {
		close(pipefd[1]);	/* close the write end */
		/* wait for EOF */
		while (read(pipefd[0], &c, 1) == -1 && errno == EINTR)
			; /* nothing */
		close(pipefd[0]);
		fiddle with fds
		exec(...);
	}
	close(pipefd[0]);	/* close the read end */
	close(ctrl);
	close(pipefd[1]);	/* close the write end to release the child */

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199812130138.RAA22963>