簡潔な答え
通常、SOCKET ハンドルを継承不可に設定することはできません。つまり、特定の (非 IFS) LSP がインストールされている場合、プロセス内のハンドルを特に継承不可としてマークしても、子プロセスがハンドルをbInheritHandles=TRUE
受け取るのを停止することはできません。
説明
LSP は一般に、すべての TCP 接続をフィルタリングするために、ファイアウォールまたは A/V 製品で使用されます。LSP は、WinSock によってプロセスにロードされる DLL であり、すべての TCP 操作を処理します。通常は、何らかのフィルタリングを実行してから、基になる WinSock 実装に直接呼び出しを渡します。LSP は、WinSock 実装を生成した実際の SOCKET ハンドルごとにダミー ハンドルを作成することによって機能します。WSASocket を呼び出すと、ダミー ハンドルが得られます。ダミー ハンドルを使用すると、コールはそれを作成した LSP に送信されます。次に、LSP はダミーを実際のハンドルにマップし直し、操作 (accept
または などbind
) を基になるハンドルに渡します。
したがって、問題は、SetHandleInformation
作成したソケットを呼び出すだけでは十分ではないということです。(LSP によって内部的に使用される) 表示されることのない基になるハンドルは、子プロセスによって引き続き継承されます。
回避策
CreateProcess
ソケットを使用するアプリケーションからの継承を許可する呼び出しは絶対に行わないでください。これが最も信頼できるソリューションです。代わりに、子との通信を設定するには、適切な権限を持つ名前付きパイプを作成し、コマンドラインでその名前を子に渡し、子に接続し直します。次に、子に継承させたいハンドルを手動で渡します。コマンドラインは他のユーザーが読み取ることができますが、パイプが正しく設定されていれば、子の実際のユーザー トークンのみがパイプに接続できるため、これは安全です。
子での引数の解析を制御する必要があるため、子の stdio をリダイレクトするなどの単純なことだけを行いたい場合、これは非常に洗練されていません。これを回避するには、コマンドラインから名前付きパイプ名を読み取って接続し、ハンドルを継承可能に設定し、stdio をリダイレクトして残りの引数を再度呼び出すラッパー バイナリを作成します。プロセスにはソケットがないため、ラッパーからハンドルを継承しても安全です。
- または、Vista ( KB2398202 )、Windows 7 (SP1) 以降では、
WSA_FLAG_NO_HANDLE_INHERIT
フラグが に追加されましたWSASocket
。(これは、Microsoft から入手できる問題のドキュメントと同じです。修正プログラムを作成することは、ベース サービス プロバイダー ハンドルの継承を防止するためには、それなしでは不可能であることをほぼ認めています。しかし、それは十分に宣伝されていません!)
- 最後に、Vista では、ベース サービス プロバイダが使用するハンドルを照会できるようにする ioctl もあります。これらは継承不可とマークすることができます。これは面倒ですが、XP の問題はまだ修正されていません。