制御フロー検証ツール設計ドキュメント¶
目的¶
このドキュメントでは、Clangの_制御フロー整合性_(CFI)スキーム(-fsanitize=cfi
)によって実装された保護メカニズムを検証するための外部ツールの概要を説明します。このツールは、バイナリまたはDSOが与えられると、間接制御フロー操作がCFIによって保護されているかどうかを推測し、これらの結果を人間が読める形式で出力する必要があります。
このツールは、Clangの継続的インテグレーションテストフレームワークの一部としても追加されるべきです。コンパイラへの変更により、CFI保護スキームが最終的なバイナリに依然として存在することが保証されます。
場所¶
このツールはLLVMツールチェーンの一部として存在し、LLVMトランクからの相対パス「/llvm/tools/llvm-cfi-verify」ディレクトリに配置されます。 2つの方法でテストされます。
コードセクションを検証するためのユニットテストは、「/llvm/unittests/tools/llvm-cfi-verify」にあります。
統合テストは、「/llvm/tools/clang/test/LLVMCFIVerify」にあります。 これらの統合テストは、継続的インテグレーションフレームワークの一部としてclangに含まれており、間接制御フロー命令のCFIカバレッジを低下させるコンパイラの更新が識別されることを保証します。
背景¶
このツールは、出力されたマシンコードを分析することにより、CFIディレクティブがすべての間接制御フローの周囲に適切に実装されていることを継続的に検証します。 マシンコードの分析は、リンカまたはコンパイラに存在するバグが、最終的に出荷されるバイナリでCFI保護を無効にしないことを保証するため、重要です。
保護されていない間接制御フロー命令は、手動レビューのためにフラグが付けられます。 これらの予期しない制御フローは、コンパイラのCFI実装で考慮されていないだけかもしれません(たとえば、switch文を容易にするための間接ジャンプは完全に保護されていない可能性があります)。
将来的には、このツールを拡張して、不要なCFIディレクティブ(たとえば、非多相基本型への静的呼び出しに関するCFIディレクティブ)にフラグを付けることができるようになる可能性があります。 このタイプのディレクティブはセキュリティへの影響はありませんが、パフォーマンスへの影響を与える可能性があります。
設計アイデア¶
このツールは、バイナリとDSOをマシンコード形式から逆アセンブルし、逆アセンブルされたマシンコードを分析します。 このツールは、仮想呼び出しと間接関数呼び出しを検査します。 このツールは、インライン関数とジャンプテーブルもCFI保護の対象となるため、間接ジャンプも検査します。 バイトコードによって提供される情報が不足しているため、非仮想呼び出し(-fsanitize=cfi-nvcall
)とキャストチェック(-fsanitize=cfi-*cast*
)は実装されていません。
このツールは、逆アセンブリで間接制御フロー命令を検索することによって動作します。 「ターゲット」制御フロー命令を囲む命令の小さなバッファから、制御フローグラフが生成されます。 ターゲット命令に分岐する場合、分岐のフォールスルーはCFIトラップである必要があります(x86では、これはud2
命令です)。 ターゲット命令が条件付きジャンプのフォールスルー(つまり、直後に続く)である場合、条件付きジャンプターゲットはCFIトラップである必要があります。 間接制御フロー命令がこれらの形式のいずれにも準拠していない場合、ターゲットはCFIで保護されていないと見なされます。
上記の2番目のケース(ターゲット命令が条件付きジャンプのフォールスルーである場合)では、ターゲットが引数を取るvcallを表す場合、これらの引数は分岐後、ターゲット命令の前にスタックにプッシュされる可能性があることに注意してください。 これらの場合、2番目の「スピルグラフ」が構築され、間接ジャンプ/呼び出しで使用されるレジスタ引数が、中間期間にスタックからスピルされないことが保証されます。 ターゲットレジスタに影響を与えるスピルがない場合、ターゲットはCFIで保護されているとマークされます。
その他の設計上の注意¶
実行可能としてマークされているマシンコードセクションのみがこの分析の対象となります。 実行不可能なセクションでは、これらのセクションに存在するすべての実行がすでに制御フローの整合性に違反しているため、分析は必要ありません。
DSO境界を越えた間接制御フロー操作の分析を含めるために、適切な拡張機能が後日行われる可能性があります。 現在、これらのCFI機能は不安定なABIでのみ実験的に使用できるため、分析には適していません。
このツールは現在、x86、x86_64、およびAArch64アーキテクチャのみをサポートしています。