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

问题描述 投票:0回答:2

Windows句柄可以设置为可继承或不可继承,以控制子进程是否接收它们(当

bInheritHandles
中的
CreateProcess
为TRUE时)。但是,使用
SetHandleInformation
标记 SOCKET 不可继承并不总是有效。特别是,当安装了某些分层服务提供程序 (LSP) 时,子进程无论如何都会继承句柄。这特别有可能导致侦听套接字出现错误。 (但是,因为另一个问题,如果孩子要尝试使用插座,它就不能!真正的 catch-22!)

重现步骤

  1. 创建一个监听套接字。使用
    SetHandleInformation
    .
  2. 将其标记为不可继承
  3. 生一个孩子,
    bInheritHandles
    为真。
  4. 关闭父套接字,并尝试重新绑定到端口。

安装(非 IFS)LSP 时,例如。 PCTools Internet Security,监听套接字将在孩子中打开(在

netstat
中可见),尽管在创建孩子之前在套接字上调用
SetHandleInformation
以禁用继承。

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

有哪些解决方法?

winapi winsock
2个回答
10
投票

简答

一般情况下不可能将 SOCKET 句柄设置为不可继承。也就是说,当安装了某些(非 IFS)LSP 时,即使您将进程中的句柄标记为不可继承,也无法使用

bInheritHandles=TRUE
停止子进程接收它们。

说明

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

accept
bind
)传递给底层句柄。

因此,问题是在您创建的套接字上调用

SetHandleInformation
是不够的:您永远看不到的底层句柄(由 LSP 在内部使用)仍然由子进程继承。

解决方法

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

0
投票

您可以明确选择将由子进程继承的句柄。请参阅https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873

© www.soinside.com 2019 - 2024. All rights reserved.