关于vfork()后链接器解析execve()及PLT存根解析内存安全性的技术问询
关于vfork()后链接器解析execve()及PLT存根解析内存安全性的技术问询
这个问题问到点子上了——毕竟vfork的核心就是子进程和父进程共享整个地址空间,稍有不慎就会搞乱父进程的状态。咱们一步步拆解:
- 首先得明确
execve@plt延迟绑定的机制:当第一次调用这个存根时,它会触发动态链接器的地址解析流程,最终会修改进程的GOT(全局偏移表),把execve的真实地址写入对应的GOT表项里——这样后续调用就可以直接跳转到真实地址,不用再走解析流程。 - 而vfork创建的子进程,是完全共享父进程的地址空间的,包括GOT所在的数据段。所以如果子进程触发了execve的PLT解析,链接器在子进程中修改GOT的操作,会直接反映到父进程的内存里——这就意味着父进程的GOT被修改了,严格来说已经违反了“不修改父进程内存”的要求。
- 当然有个例外情况:如果程序在vfork之前已经调用过execve(或者通过其他方式触发了execve的PLT解析),那GOT里已经存了execve的真实地址,子进程调用
execve@plt时就不会再触发解析流程,自然也就不会修改内存。但这不符合问题里“execve@plt包含调用链接器的存根”的前提——这个前提指的是存根还没被解析过,需要触发链接器的场景。 - 另外从vfork的设计初衷来说,它就是为了让子进程马上调用exec系列函数的。规范里甚至明确要求,vfork的子进程不能做任何会修改内存的操作,包括调用非async-signal-safe的函数,而动态链接的地址解析流程显然不属于async-signal-safe的范畴(因为它会修改全局数据结构)。所以从正确用法的角度,你根本不应该让vfork的子进程触发这种解析流程——正确的做法是在vfork之前就确保execve的地址已经被解析,或者直接使用execve的真实地址。
总结一下:没有任何机制保证这个解析过程不会修改父进程的内存。只要子进程触发了PLT的延迟绑定,链接器修改共享内存里的GOT,就会直接影响父进程。
备注:内容来源于stack exchange,提问作者patraulea
相关产品推荐
相关产品推荐

