nmh-workers
[Top] [All Lists]

Re: [nmh-workers] closefds() _before_ fork?

2019-04-23 18:43:10
to that end,  i propose that we  treat any open descriptor  N>2 at the
time  of an  exec() to  be a  bug,  which is  to be  fixed by  setting
O_CLOEXEC at time of creation.

What impact will such a decision have on tools like setlock which open a
filedescriptor, obtain an  exclusive lock, and then exec  a process? For
example, I may  use something like the following in  a script to prevent
multiple processes from incorporating email:

setlock /tmp/mit.lock inc +MyIncTmp ...

Well, my reading of the setlock man page (assuming this is the FreeBSD
one) is that it is not depending on a _descriptor_ to be passed down
(I don't even know how that would work), but in fact it is opening a
particular _file_ and locking it.

But let's pretend that it actually did need to have a descriptor passed
down to nmh programs, and the locking needed to extend to any children
that inc forked (that's the critical case here).  Today, depending on
which code path was executed, that would either a) work fine (because we
don't close any descriptors) or b) fail miserably (because we close all
descriptors above 2, but sometimes maybe 3).

My change makes it so we no longer close all descriptors when creating
a child process (in the majority of cases we didn't).  The particular
change I have started implementing is that any descriptors _created by
nmh_ will be marked as close-on-exec, so they will no longer be available
to child processes (well, technically, child processes that have called
exec(), but you know what I mean).

For example, let's say inc(1) is talking to a POP server.  Before,
the network connection to the POP server was available to programs
that inc(1) happened to fork off.  One possible example would be the
add-hook program if you happened to define one (the hook code never
closed extra file descriptors).  I think most people would agree that
this is probably not desirable.  Now that the network descriptors are
marked as close-on-exec, child processes (like the hooks code) never see
them.  Even if the hooks are not doing anything malicious, it's easy
to imagine possible problems with a network socket ending up in their
address space.  If the hooks code forks off a long-running process, for
example, that could leave a network socket open that nmh had considered
closed and could potentially cause problems if (for example) the POP
server expected you to close the connection before it allowed another
one.

There are tons of examples like this in nmh; plenty of child processes
are created with descriptors open.  Most of these are for files, but
clearly at best that's sloppy and at worst is dangerous.  I can see this
only getting worse if we get IMAP support or additional plugin interfaces.

My eventual goal is to make it so every new descriptor created _by nmh_
has close-on-exec set by default.  This wouldn't affect descriptors
inherited by nmh programs (because they wouldn't know about them) or
descriptors created by library functions (nmh wouldn't know about them
either); hopefully any descriptors created internally by a library
function would be marked properly (a quick check shows that this is
not an unfounded assumption; at least on MacOS X the descriptor created
by getutxent() is marked as close-on-exec).

As a side note, I see that documentation for the hooks interface has
never made it into a man page; anyone willing to rectify that?

--Ken

-- 
nmh-workers
https://lists.nongnu.org/mailman/listinfo/nmh-workers

<Prev in Thread] Current Thread [Next in Thread>