The vfork() man page says that after a vfork(), the child needs to just call exec(), and nothing else. Don't write to stack variables (with the sole exception of your pid_t). Don't call any other functions. Don't even return from the current function. Just call exec(), and if that fails you can call _exit(). For convenience, here is the relevant hunk of the vfork() man page: == DESCRIPTION Standard Description (From POSIX.1) The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before success- fully calling _exit(2) or one of the exec(3) family of functions. Linux Description vfork(), just like fork(2), creates a child process of the calling process. For details and return value and errors, see fork(2). vfork() is a special case of clone(2). It is used to create new pro- cesses without copying the page tables of the parent process. It may be useful in performance-sensitive applications where a child is cre- ated which then immediately issues an execve(2). vfork() differs from fork(2) in that the parent is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Until that point, the child shares all memory with its parent, includ- ing the stack. The child must not return from the current function or call exit(3), but may call _exit(2). Signal handlers are inherited, but not shared. Signals to the parent arrive after the child releases the parent's memory (i.e., after the child terminates or calls execve(2)). == In busybox's init.c, run() violates most of those requirements. I am currently investigating a bug on ASUS routers (which make heavy use of busybox) in which certain processes unexpectedly are blocking a wide variety of signals, presumably because they are inheriting bad masks from their parents across fork()/exec() calls. This may have something to do with the races in busybox's init.c:run(), though I have not yet proven this. For example, after running 'tail -F', I can't type control-C to kill it, because it has inherited a blocking mask that includes SIGINT: == admin@(none):/proc/2741# ps w | grep tail 6778 admin 1552 S tail -F /tmp/syslog.log admin@(none):/proc/2741# cat /proc/6778/status | grep Sig SigQ: 10/2047 SigPnd: 00000000000000000000000000000000 SigBlk: 0000000000000000000000008001e007 SigIgn: 00000000000000000000000040000006 SigCgt: 00000000000000000000000000000000 admin@(none):/proc/2741# kill 6778 admin@(none):/proc/2741# ps w | grep tail 6778 admin 1552 S tail -F /tmp/syslog.log admin@(none):/proc/2741# == The SigBlk value of 8001e007 corresponds to SIGHUP, SIGINT, SIGQUIT, SIGALRM, SIGTERM, SIGUSR1, and SIGUSR2. As you can imagine, this kind of thing makes life pretty miserable on the OS in general -- all those rc.d scripts that rely on TERM to shut things down, all those programs that rely on the delivery of SIGALRM for timer events, or on SIGHUP to re-read their configs, etc etc. Again, I am not 100% certain that the unclean handling of vfork() is to blame. I will follow up if I am able to prove that it is.
(In reply to comment #0) > The vfork() man page says that after a vfork(), the child needs to just call > exec(), and nothing else. Don't write to stack variables (with the sole > exception of your pid_t). Don't call any other functions. Don't even return > from the current function. Just call exec(), and if that fails you can call > _exit(). POSIX rules for vfork are very restrictive because various other Unixes have restrictive vfork implementations and/or compilers which do not understand that vfork + needs special treatment. What init.c is doing after vfork is valid for Linux vfork implementation. > Don't even return from the current function. We do obey this, because doing that is almost guaranteed to smash the stack of the parent. > Don't call any other functions. Not even a strlen()? Why? Please point out which operation in init.c after vfork you consider questionable.