fork() vs vfork()

摘自: http://tldp.org/HOWTO/Secure-Programs-HOWTO/avoid-vfork.html

The portable way to create new processes in Unix-like systems is to use the fork(2) call. BSD introduced a variant called vfork(2) as an optimization technique. In vfork(2), unlike fork(2), the child borrows the parent’s memory and thread of control until a call to execve(2V) or an exit occurs; the parent process is suspended while the child is using its resources. The rationale is that in old BSD systems, fork(2) would actually cause memory to be copied while vfork(2) would not. Linux never had this problem; because Linux used copy-on-write semantics internally, Linux only copies pages when they changed (actually, there are still some tables that have to be copied; in most circumstances their overhead is not significant). Nevertheless, since some programs depend on vfork(2), recently Linux implemented the BSD vfork(2) semantics (previously vfork(2) had been an alias for fork(2)).

翻译:

在类Unix系统中, 可移植的创建一个新进程的方式是调用fork(2)。BSD中作为一种优化技术引入了一个叫做vfork(2) 的变体。vfork(2) 和fork(2) 不同,它在退出或者调用execve(2V)之前是作为父进程的一个线程存在的,和父进程共用内存空间;而在子进程使用这些资源时,父进程是被挂起的。之所以会有vfork(2),是因为在老的BSD系统中,fork(2)将导致一次真实的内存拷贝,而vfork(2)则不会。Linux中从来没有过这个问题;因为,Linux内部使用的是写时复制(copy-on-write)的机制,Linux仅仅在页被修改时才复制(事实上,仍然会有一些表被复制;在大多数情况下,这没有太大影响)。然而,因为一些程序依赖了vfork(2),最近Linux也实现了BSD的vfork(2)机制(以前的vfork(2)是fork(2)的别名)。

There are a number of problems with vfork(2). From a portability point-of-view, the problem with vfork(2) is that it’s actually fairly tricky for a process to not interfere with its parent, especially in high-level languages. The not interfering” requirement applies to the actual machine code generated, and many compilers generate hidden temporaries and other code structures that cause unintended interference. The result: programs using vfork(2) can easily fail when the code changes or even when compiler versions change.

For secure programs it gets worse on Linux systems, because Linux (at least 2.2 versions through 2.2.17) is vulnerable to a race condition in vfork()’s implementation. If a privileged process uses a vfork(2)/execve(2) pair in Linux to execute user commands, there’s a race condition while the child process is already running as the user’s UID, but hasnt entered execve(2) yet. The user may be able to send signals, including SIGSTOP, to this process. Due to the semantics of vfork(2), the privileged parent process would then be blocked as well. As a result, an unprivileged process could cause the privileged process to halt, resulting in a denial-of-service of the privileged process' service. FreeBSD and OpenBSD, at least, have code to specifically deal with this case, so to my knowledge they are not vulnerable to this problem. My thanks to Solar Designer, who noted and documented this problem in Linux on the `security-audit” mailing list on October 7, 2000.

The bottom line with vfork(2) is simple: don’t use vfork(2) in your programs. This shouldn’t be difficult; the primary use of vfork(2) is to support old programs that needed vfork’s semantics.

 

其它参考: http://linux.about.com/library/cmd/blcmdl2_vfork.htm

 

重点:

1. fork不会挂起父进程, vfork会挂起父进程,直到调用execve或_exit

2. 一般来讲,vfork都是会和execve成对出现的

3. vfork中不应该调用exit

4. 当一个特权进程使用vfork来派生一个非特权进程时,在vfork设置为非特权进程之后,调用execve之前,非特权用户给该进程发送一个STOP信号,将可能会挂起特权进程,所以,尽量不要使用vfork

 

留下评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据