Subject: `close()' loop in `inetd'
To: None <current-users@NetBSD.ORG>
From: Alan Peakall <email@example.com>
Date: 06/28/1996 13:03:01
`[inetd]/inetd.c' contains the following code fragment:
for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
if (sep->se_socktype != SOCK_STREAM)
recv(0, buf, sizeof (buf), 0);
syslog(LOG_ERR, "execv %s: %m", sep->se_server);
The intention is to close, for the successor process, all descriptors
except the standard ones, even if they do not have the close on exec
flag set. If they do have the close on exec flag set, then the `close()'
call is redundant. The particular problem here arises with the `syslog(3)'
call. Syslog maintains a private variable referencing its own socket
for which the close on exec flag is set. If you close that socket
behind syslog's back (rather than using `closelog()') then there is the
possibility of the log message after a failed `exec()' getting lost.
This is a bug is in `inetd' (and possibly in any other code that uses
a similar idiom).
I can see three remedies:
+ Add a call to `closelog' ahead of the loop over file
descriptors. This is not very general, as in other situations
a different descriptor, managed by a different module, may be
required after a failed exec. (eg if the log message were to
include information found through `getpwuid(), an `endpwent()'
call could be required).
+ Change the code controlled by the loop over file descriptors to
only close file descriptors that do not have the close on exec
flag set, on the assumption that a correctly written package,
that maintains a static variable holding a private descriptor >2,
will always set the the close on exec flag on it. A routine
which did this would be a candidate for incorporation in `libutil'.
+ Add specific backstop code in `syslog()' to do an `fcntl()' on its
private socket before attempting to send through it to guard against
callers that close arbitrary file descriptors. This would still
be fooled if the private descriptor were reused between the
erroneous `close()' call and the next call to `syslog()'.
Alan Peakall, applications engineer Parsys Ltd
Email: firstname.lastname@example.org London W7 2QE, United Kingdom
Tel: +44 181 5798683 Fax: +44 181 5798365