Subject: `close()' loop in `inetd'
To: None <current-users@NetBSD.ORG>
From: Alan Peakall <alan@parsys.co.uk>
List: current-users
Date: 06/28/1996 13:03:01
`[inetd]/inetd.c' contains the following code fragment:

    for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
        (void)close(tmpint);
    execv(sep->se_server, sep->se_argv);
    if (sep->se_socktype != SOCK_STREAM)
        recv(0, buf, sizeof (buf), 0);
    syslog(LOG_ERR, "execv %s: %m", sep->se_server);
    _exit(1);

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

------------------------------------------------------------------------
Alan Peakall, applications engineer                           Parsys Ltd
Email: alan@parsys.co.uk                   London W7 2QE, United Kingdom
Tel: +44 181 5798683                                Fax: +44 181 5798365