TCP SOCKET句柄可以设置为不可继承吗?

时间:2012-08-21 16:07:53

标签: winapi winsock

可以将Windows句柄设置为可继承或不可继承,以控制子进程是否会接收它们(bInheritHandles中的CreateProcess为TRUE时)。但是,使用SetHandleInformation标记SOCKET不可继承并不总是有效。特别是,当安装某些分层服务提供程序(LSP)时,子进程无论如何都会继承句柄。这特别容易导致监听套接字的错误。 (但是,由于another issue,如果孩子尝试使用套接字,它将无法使用!真正的捕获22!)

重现的步骤

  1. 创建一个侦听套接字。使用SetHandleInformation将其标记为不可继承。
  2. 生成一个孩子,bInheritHandles为真。
  3. 关闭父级中的套接字,并尝试重新绑定到该端口。
  4. 安装(非IFS)LSP时,例如。 PCTools Internet Security,监听套接字将在子进程中打开(在netstat中可见),尽管在创建子进程之前在套接字上调用SetHandleInformation来禁用继承。

    有关替代方案,请参阅KB2398202中的(简要)步骤。

    有哪些可用的解决方法?

1 个答案:

答案 0 :(得分:10)

简短回答

通常不可能将SOCKET句柄设置为不可继承。也就是说,当安装了某些(非IFS)LSP时,即使您将流程中的句柄标记为具有不可继承性,也无法阻止bInheritHandles=TRUE的子流程接收它们。

说明

防火墙或A / V产品通常使用LSP来过滤所有TCP连接。 LSP是由WinSock加载到您的进程中的DLL,它通常通过执行一些过滤然后将调用直接传递给底层的WinSock实现来处理所有TCP操作。 LSP通过为生成WinSock实现的每个实际SOCKET句柄创建一个虚拟句柄来工作:您对WSASocket的调用将为您提供虚拟句柄;当你使用虚拟句柄时,调用被发送到创建它的LSP; LSP然后将虚拟映射回实际句柄,并将操作(例如acceptbind)传递给底层句柄。

因此,问题是在您创建的套接字上调用SetHandleInformation是不够的:您从未看到的底层句柄(由LSP内部使用)仍然由子进程继承。

变通方法

  1. 不要调用CreateProcess允许来自使用套接字的应用程序的任何继承。这是最可靠的解决方案。相反,要设置与子进程的通信,请创建具有适当权限的命名管道,将其在命令行上的名称传递给子进程,然后在子进程中重新连接。然后手动传递您希望孩子继承的任何句柄。这是安全的,因为虽然命令行可能是其他用户可读的,但只有正确设置的孩子的实际用户令牌才能连接到管道。
    如果您想要做的只是重定向子项的stdio这样简单,那么这是非常不优雅的,因为您必须控制在子项中解析的参数。要解决此问题,请创建一个包装器二进制文件,它从命令行读取命名管道名称并连接,设置句柄可继承,并重新引导其余参数,并重定向stdio。从包装器继承句柄是安全的,因为进程中没有套接字。
  2. 或者,在Vista(带KB2398202),Windows 7(带SP1)以及更高版本的WSA_FLAG_NO_HANDLE_INHERIT标记中添加WSASocket标记。 (这是我从Microsoft可以找到的问题的文档。尽管如此,创建此修补程序几乎可以肯定,如果没有它可以阻止基本服务提供程序句柄被继承。虽然它没有得到很好的宣传!)
  3. 最后,在Vista上,还有ioctl允许查询基本服务提供商使用的句柄。然后可以将这些标记为不可继承的。这虽然很痛苦,但仍然没有解决XP的问题。