Windows句柄可以设置为可继承或不可继承,以控制子进程是否接收它们(当
bInheritHandles
中的CreateProcess
为TRUE时)。但是,使用 SetHandleInformation
标记 SOCKET 不可继承并不总是有效。特别是,当安装了某些分层服务提供程序 (LSP) 时,子进程无论如何都会继承句柄。这特别有可能导致侦听套接字出现错误。 (但是,因为另一个问题,如果孩子要尝试使用插座,它就不能!真正的 catch-22!)
SetHandleInformation
.bInheritHandles
为真。安装(非 IFS)LSP 时,例如。 PCTools Internet Security,监听套接字将在孩子中打开(在
netstat
中可见),尽管在创建孩子之前在套接字上调用SetHandleInformation
以禁用继承。
对于替代方案,请参阅 KB2398202 中的(简要)步骤。
一般情况下不可能将 SOCKET 句柄设置为不可继承。也就是说,当安装了某些(非 IFS)LSP 时,即使您将进程中的句柄标记为不可继承,也无法使用
bInheritHandles=TRUE
停止子进程接收它们。
LSP 通常被防火墙或 A/V 产品用来过滤所有 TCP 连接。 LSP 是一个由 WinSock 加载到您的进程中的 DLL,它处理所有 TCP 操作,通常通过执行一些过滤然后将调用直接向下传递到底层 WinSock 实现。 LSP 通过为 WinSock 实现产生的每个实际 SOCKET 句柄创建一个虚拟句柄来工作:您对 WSASocket 的调用将为您提供虚拟句柄;当您使用虚拟句柄时,调用将发送到创建它的 LSP; LSP 然后将虚拟对象映射回实际句柄,并将操作(例如
accept
或bind
)传递给底层句柄。
因此,问题是在您创建的套接字上调用
SetHandleInformation
是不够的:您永远看不到的底层句柄(由 LSP 在内部使用)仍然由子进程继承。
CreateProcess
允许从使用套接字的应用程序继承。这是最可靠的解决方案。相反,要与孩子建立通信,创建一个具有适当权限的命名管道,在命令行上将其名称传递给孩子,然后连接回孩子。然后手动传递您希望孩子继承的任何句柄。这是安全的,因为尽管其他用户可以读取命令行,但如果设置正确,只有孩子的实际用户令牌才能连接到管道。WSA_FLAG_NO_HANDLE_INHERIT
标志被添加到 WSASocket
。 (这是我可以从 Microsoft 找到的尽可能多的问题文档。创建修补程序几乎是承认没有它就不可能阻止基本服务提供商句柄被继承。虽然它没有很好地宣传!)您可以明确选择将由子进程继承的句柄。请参阅https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873