我正在阅读此article
它说fork创建了自己的副本,fork
man也这样说
。父级的整个虚拟地址空间将复制到子级
中
这是否意味着子进程可以读取我的所有进程内存状态?
子进程可以转储整个父内存状态,并且可以对其进行分析以提取父变量及其值。吗
但该文章还说,两个进程无法准备好彼此的数据。 所以我很困惑?答案 0 :(得分:4)
是的,子进程可以在fork(2)之后读取所有父进程状态的原始副本(但在写入时,只影响其自己的地址空间)。但是,大多数情况下,孩子最终会使用execve(2)来启动一个新程序,这将“清除”并替换原始父母的地址空间的副本(通过新的地址空间)。请注意,execve
和mmap(2)(另请参阅shared memory中的shm_overview(7) ...)是更改address space中virtual memory的常用方法一些process(以及内核如何处理page faults)。
内核使用(并设置MMU)lazy copy on write机制来使子地址空间成为父项的地址空间的副本,因此fork
在实践中非常有效。
另请阅读proc(5),然后输入以下命令:
cat /proc/self/maps
cat /proc/$$/maps
sudo cat /proc/1/maps
并了解正在发生的事情
另请阅读fork上的wikipage和Advanced Linux Programming本书。
没有不安全因素,因为如果孩子正在更改某些数据(例如变量,堆或堆栈位置......),它不会影响父进程。
如果执行fork的程序在某个虚拟内存位置保留了一些密码,则子进程只要执行相同的程序就能读取该位置。一旦孩子成功execve
(这是常见情况,以及任何shell正在做的事情),之前的地址空间就会消失并被新的地址空间取代,在ELF可执行文件中描述{ {1}} - ed program。
Unix模型中没有“谎言”或“不安全”。但与其他几个操作系统相反,Unix& POSIX有两个单独的system calls用于创建新进程(exec
)和执行新程序(fork
)。其他系统可能会混合两种能力进行单spawn次操作。 posix_spawn通常由execve
& fork
(以及system(3)和popen(3)也是如此,同时使用waitpid(2)& execve
....)。
这种Unix方法(已经分开/bin/sh
& fork
)的优点是在execve
之后和孩子fork
之前你可以做很多事情有用的东西(例如关闭无用的文件描述符,......)。不分离这两个特征的操作系统可能需要具有相当复杂的产生原语。
在极少数情况下execve
不后跟一些fork
。一些MPI实现可能会这样做,您也可以这样做。但是你知道你能够通过你自己的副本阅读所有父母的地址空间 - 所以你觉得不安全感正在变成一个有用的功能。在过去,你有过时的vfork阻止了父母。今天不需要使用它;实际上,execve
通常是通过clone(2)实现的,您不应该直接在实践中使用(请参阅futex(7) ...),但只能通过POSIX pthreads。但是将fork
视为过程的神奇克隆者可能有所帮助。
编码时(即使在C中)不要忘记测试fork
和fork
的失败。见perror(3)
PS。 execve
系统调用与multiverse想法一样难以理解。两者都在“分叉”时间!
答案 1 :(得分:2)
当您致电fork()
时,新流程将可以访问父进程内存的副本(即变量,文件描述符等)。
这与线程相反,其中所有线程共享相同的内存空间,即在一个线程中修改的变量将在所有其他线程中获得新值。
因此,如果,分叉后,父进程修改内存,子进程将不会看到该更改 - 因为内存已被复制,子进程的内存不会被更改。