子进程socket继承问题

昨天实习的时候遇到这样一个问题,抽象起来如下:

有一个进程A,它是一个全局监控进程,监控进程B。
进程B是一个局部监控进程,监控C,C是由B fork出来的子进程。
C向B汇报,B向A汇报。
因为进程A和其他进程在不同机器上,所以所有的操作都是通过json rpc的远程调用执行的。
假设B监听11111端口,A通过这个端口与其通信。
现在我手动kill B,理论上的现象应该11111端口此时无人监听,A发rpc call的时候会报一个异常,rpc连接会断掉。
实际的情况是A会在rpc call上阻塞,观察11111端口的情况没,发现被C监听了。

分析的结果如下:

Linux下socket也是文件描述符的一种,当B fork进程C的时候,C也会继承B的11111端口socket文件描述符,当B挂了的时候,C就会占领监听权。
所以现在的需求就是在fork的时候关闭B已经打开的文件描述符。
系统给出的解决方案是:close_on_exec。当父进程打开文件时,只需要应用程序设置FD_CLOSEXEC标志位,则当fork后exec其他程序的时候,内核自动会将其继承的父进程FD关闭。
因为我用的是python的subprocess模块fork的子进程,他有一个参数close_fds可以设为True或者False:
文档说明:If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. (Unix only). Or, on Windows, if close_fds is true then no handles will be inherited by the child process. Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr.

意义:

close_on_exec另外的一大意义就是安全。比如父进程打开了某些文件,父进程fork了子进程,但是子进程就会默认有这些文件的读取权限,但是很多时候我们并不想让子进程有这么多的权限。
试想一下这样的场景:在Webserver中,首先会使用root权限启动,以此打开root权限才能打开的端口、日志等文件。然后降权到普通用户,fork出一些worker进程,这些进程中再进行解析脚本、写日志、输出结果等进一步操作。
然而这里,就会发现隐含一个安全问题:子进程中既然继承了父进程的FD,那么子进程中运行的脚本只需要继续操作这些FD,就能够使用普通权限“越权”操作root用户才能操作的文件。
系统提供的close_on_exec就可以有效解决这个问题。

Tags : , ,

0 thoughts on “子进程socket继承问题”

发表评论

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

Click the right image To submit your comment: