From: Ersek, Laszlo on
On Sun, 18 Apr 2010, Joshua Maurice wrote:

> how to make sure I don't get resources leaking across fork + exec calls

No resource can "leak" through fork()/exec() calls that don't exist.

Main program connects to inetd. Inetd forks and executes single-shot
wrapper daemon. Daemon has (at least) two phases, init phase and servicing
phase. In the init phase, before initializing the wrapped library, it sets
FD_CLOEXEC on fd's 0 and 1, redirects fd 2 to a log file and sets
FD_CLOEXEC on it. As the final step, it initializes the library. Then it
starts taking requests on stdin and writing answers to stdout. There is no
ancestry between your main process and the wrapper process.

If the library has constructor functions, then don't link it into the
wrapper daemon at build time; open it with dlopen() after setting
FD_CLOEXEC on [012].

lacos
From: Joshua Maurice on
On Apr 18, 7:25 pm, "Ersek, Laszlo" <la...(a)caesar.elte.hu> wrote:
> On Sun, 18 Apr 2010, Joshua Maurice wrote:
> > how to make sure I don't get resources leaking across fork + exec calls
>
> No resource can "leak" through fork()/exec() calls that don't exist.
>
> Main program connects to inetd. Inetd forks and executes single-shot
> wrapper daemon. Daemon has (at least) two phases, init phase and servicing
> phase. In the init phase, before initializing the wrapped library, it sets
> FD_CLOEXEC on fd's 0 and 1, redirects fd 2 to a log file and sets
> FD_CLOEXEC on it. As the final step, it initializes the library. Then it
> starts taking requests on stdin and writing answers to stdout. There is no
> ancestry between your main process and the wrapper process.
>
> If the library has constructor functions, then don't link it into the
> wrapper daemon at build time; open it with dlopen() after setting
> FD_CLOEXEC on [012].

And again, for the rest of the world which may not have complete
control over the process, what do those people do? My team in my
company writes a library which is used by other teams, and we also use
libraries written by other companies. It's kind of difficult to do
what you suggest in the real world for general purpose libraries, both
users and writers. Then some of us use C++ and not C, so dlopen
because a bit less practical as well when using or writing a C++
library.

Many developers don't actually control the entire code base, nor all
of the entry and exit points, and instead have to work with other
pieces of code, some quite old, and possibly not the most correct.
There should be simple code to achieve the desired semantics: to
create a new process from an executable image and without leaking any
resources into that new process.

I suppose that as a practical matter, it will only come up if you do
unbounded forking, but it still rubs me the wrong way.
From: David Given on
On 20/04/10 01:15, Ersek, Laszlo wrote:
> On Mon, 19 Apr 2010, David Given wrote:
[...]
>> So, basically, you're saying, don't use fopen()? In any multithreaded
>> apps? And in any *library* which might be used by a multithreaded app?
>
> s/fopen/fork, I guess.

I did mean fopen(): if I have a multithreaded application where one
thread, *any* thread, creates a file descriptor, and another thread,
*any* thread, calls exec(), then there's a potential problem.

[...]
> Reimplement open(), forward request to actual (or rather, next, as in
> RTLD_NEXT) open(), but add O_CLOEXEC. If you're lucky, fopen() /
> freopen() / whatever will go through open().
[...]
> $ LD_PRELOAD=./cloexec.so strace touch testfile 2>&1 | grep O_WRONLY
> open("testfile", O_WRONLY|O_CREAT|O_NCTTY|O_NONBLOCK|O_CLOEXEC, 0666) = 3

Hmm. I'd forgotten you can do that. It's not entirely reliable --- if
the program calls the syscall directly rather than going through libc,
then the hack won't work. It's a promising approach, though, and is
likely to work in most cases.

[...]
> Now do something similar with socket():
[...]
> Call pipe2() instead of pipe():

Ah, but it's not me that's calling socket() or pipe() --- it's a
third-party library that's not under my control. And setting the CLOEXEC
flag for socket() as described still has a (rare, but potential) race
condition between socket() returning and the call to fcntl() immediately
afterward.

Again, this will probably work in most cases, but there's still that
rare situation where something horrible will happen that makes me
uneasy. If only there were a nice portable way of telling the kernel
that all file descriptors for my process should be CLOEXEC until further
notice...

--
┌─── dg@cowlark.com ───── http://www.cowlark.com ─────

│ "In the beginning was the word.
│ And the word was: Content-type: text/plain" --- Unknown sage
From: Casper H.S. Dik on
William Ahern <william(a)wilbur.25thandClement.com> writes:

>The Solaris closefrom() man page suggests it may be using /proc, which would
>not be cool for chroot'd applications. Is this the case? OpenBSD's
>closefrom() is a system call, which seems more reasonable given the most
>common use for this is as a step immediately before or upon a fork or exec.

Correct. It doesn't use a specific system call.

Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
From: Jonathan de Boyne Pollard on
>
>>
>> [... usual trolling by Rainer Weikusat ...]
>>
> Hmm. I reviewed the win32 documentation. It appears that I was
> mistaken, and that it has the exact same problem. You inherit all
> (file) handles or no (file) handles, nothing inbetween as any sane use
> of fork + exec or CreateProcess would want.
>
Go and read the message that I just posted. It mentions the relevant
Win32 API and C library functions, and even hyperlinks to the MSDN
documentation for one of them.

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10
Prev: Kill process tree, again
Next: ANN: Seed7 Release 2010-04-18