Jivin Wolf, Josef lays it down ...
> Hello!
>
> I was searching for a detailed overview about what exactly is allowed
> when vfork is used. I could find only some rough overview, but neither
> uclinux.org nor ucdot.org seem to have a detailed description. Even
> google was of no help. So I've decided to create such an overview by
> thinking about the problem and writing down my thoughts.
>
> My first draft will probably contain many errors, but I hope, with the
> help of this list, we will be able to shake out those errors and create
> a faq entry which will help other people to port applications.
>
> Please correct/comment if you find any objections in the description
> below.
Some quick bits.
> So here I go:
>
> The POSIX manpage that comes with my suse-10.1 box says that the
> client is not allowed to:
> - modify any data except a variable to store vfork()'s return value.
> - return from the function in which vfork() was called.
> - call any other function than _exit() or one of the exec family.
>
> This is a very draconic advice, as (taken by word) it means that the
> only valid construct is
>
> if (!(pid=vfork())) {
> execve (...);
> _exit();
> }
>
> Strictly speaking, in contrast to what the man page says, execve() is
> the only member of the exec family that is safe, since everything else
> is (probably) part of libc and is prone to modify some data.
Not sure this is entirely true, but yes, any libc function can
misbehave, you need to check them to be 100% sure.
> Since strictly following the man page leads to such a disappointing
> result, it is tempting to think about what would actually happen in
> the real world.
My experience says the man page is correct :-)
> The showstopper with the widest consequences is errno. About every
> system call can change errno. As first resort, this can easily be
> worked around by saving/restoring errno. But on a second thought,
> not even this is needed. By definition, errno (in parent context) is
> only valid if vfork() fails. But since the child already _is_
> executing, there's no way for vfork() to signal an error. Therefore
> the parent is not allowed to check errno and thus we are safe to modify
> errno.
if you only call execve after a vfork then you will not mess up errno.
execve only returns in the parent context.
> Next interesting question is the "call any other function" part. Why
> is this restriction? A callee should never clobber caller's stack
> frame.
> In the rest of this discussion I assume that it is safe to call other
> functions _if_ they obey the above rules. (Please correct me if I'm
> wrong). If this assumption is wrong, we are back to the construct shown
> above being the only valid construct. Would some guru please clarify
> this question?
Other functions can:
1) return, returning from a function after a vfork is very bad,
you will start using the parents active stack.
2) modify globals with unexpected results.
3) allocate memory we corrupts the parents malloc/heap data structures.
4) Do things to variables on the stack that have side affects when the
parent gets to run.
5) use stdio (bad ;-)
> There are lots of system calls to retrieve/set administrative data of
> the process like getpid/setpid/chdir and lots more. Such functions
> operate on kernel's data structures. The kernel keeps separate memory
> for every process to store this information. Thus there should be no
> problem with such calls _if_ the results of such functions are stored
> in separate variables which are not accessed by the parent.
Yes, there are things you can run, in practice you will find plenty
of examples in the uCLinux-dist where fd's are closed/opened (NOT fopen
mind you). things like
pid = vfork()
if (pid == 0) {
close(0);
close(1);
close(2);
open("/dev/null", ...)
...
execv(...)
}
> Now let's take a look at things like printf() and friends. They look
> very dangerous at first sight. But OTOH, they should keep their data
> structures consistent. Real problems are to be expected by fopen/fclose
> because they invalidate parent's bookkeeping about which files are open.
Yes, you can get away with printf most of the time.
> malloc/free _can_ be safe, too _if_ _exactly_ the malloc'ed areas are
> freed.
I wouldn't agree here, since free doesn't always free, etc.
Use mmap to get memory and avoid the malloc lib.
> A big can of worms seem to be signal handlers. I can imagine only one
> way to get them safe: disable all of them before vfork is called.
If you signal handlers are well behaved you will be fine. Read the man
page for them, it's almost as restrictive as vfork, of course in
practice people break the rules all the time. Just because you get
"away" with it, doesn't mean it's ok ;-)
My advice.
1) If you are writing new code, make it look like:
pid = vfork();
if (pid == 0) {
execv(...)
_exit(1);
}
It can take a little more thought at times but it will be safe and
not cause you any problems.
2) If you are working with existing code that you do not want to hack
too much, then check for all the known bad things (some listed above)
to see if you "might" get by. Try to get it to look like (1) above
if you have any weirdness.
Cheers,
Davidm
--
David McCullough, [EMAIL PROTECTED], Ph:+61 734352815
Secure Computing - SnapGear http://www.uCdot.org http://www.cyberguard.com
_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev