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

Nic*_*son 9 winapi winsock

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

重现步骤

  1. 创建例如监听套接字.使用标记为不可继承SetHandleInformation.
  2. 产生一个孩子,bInheritHandles真实.
  3. 关闭父级中的套接字,并尝试重新绑定到该端口.

当安装(非IFS)LSP时,例如.PCTools Internet Security,监听套接字将在子进程中打开(可见netstat),尽管SetHandleInformation在创建子进程之前在套接字上调用以禁用继承.

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

有哪些变通方法?

Nic*_*son 10

简短的回答

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

说明

防火墙或A/V产品通常使用LSP来过滤所有TCP连接.LSP是由WinSock加载到您的进程中的DLL,它通常通过执行一些过滤然后将调用直接传递给底层的WinSock实现来处理所有TCP操作.LSP的工作原理是为每个实际的SOCKET句柄创建一个虚拟句柄,生成WinSock实现:您对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的问题.