# 機能設計書 93-llvm-cfi-verify

## 概要

本ドキュメントは、LLVMプロジェクトにおけるllvm-cfi-verify（Control Flow Integrity検証ツール）の機能設計書である。llvm-cfi-verifyは、バイナリファイルを静的解析し、CFI（Control Flow Integrity）による保護が正しく適用されているかを検証するツールである。

### 本機能の処理概要

llvm-cfi-verifyは、コンパイル済みバイナリ（ELF形式等）を逆アセンブルし、間接的な制御フロー命令（indirect call/jump）がCFIによって適切に保護されているかを静的に検証するツールである。

**業務上の目的・背景**：CFI（Control Flow Integrity）は、ROP（Return-Oriented Programming）やJOP（Jump-Oriented Programming）などの攻撃から保護するためのセキュリティ機構である。しかし、CFIが正しく適用されているかを確認するには、バイナリレベルでの検証が必要である。llvm-cfi-verifyは、CFI保護の網羅性を自動的に検証する。

**機能の利用シーン**：
- セキュリティ監査でのCFI保護状況の確認
- ビルドパイプラインでのCFI適用検証
- CFI関連のコンパイラバグ調査
- セキュリティ研究での保護範囲分析

**主要な処理内容**：
1. バイナリファイルの読み込みと逆アセンブル
2. 間接制御フロー命令の特定
3. CFI保護状態の判定（制御フローグラフ構築）
4. DWARF情報によるシンボル化
5. 保護状況の統計レポート生成

**関連システム・外部連携**：LLVMのMCディスアセンブラ、DWARFデバッグ情報パーサ、シンボライザと連携する。

**権限による制御**：特になし（スタンドアロンツール）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | コマンドライン | 主画面 | コマンドライン引数による操作 |

## 機能種別

バイナリ解析 / セキュリティ検証

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input file | string | Yes | 解析対象バイナリファイル | 存在するファイルであること |
| ignorelist file | string | No | 無視リストファイル（デフォルト: "-"） | - |
| --print-graphs | bool | No | DOT形式でグラフ出力 | - |
| --blame-context | unsigned | No | BAD命令のソースコンテキスト行数 | 0以上 |
| --blame-context-all | unsigned | No | 全命令のソースコンテキスト行数 | 0以上 |
| --summarize | bool | No | サマリーのみ出力 | - |
| --ignore-dwarf | bool | No | DWARF情報を無視 | - |

### 入力データソース

- ELFバイナリファイル（x86/x86_64/AArch64）
- オプション: 無視リストファイル（SpecialCaseList形式）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 命令情報 | text | 各間接CF命令のアドレスと保護状態 |
| シンボル情報 | text | ソースファイル名:行番号:関数名 |
| DOTグラフ | text | 制御フローグラフ（--print-graphs時） |
| 統計情報 | text | 保護/非保護命令の数と割合 |

### 出力先

標準出力（stdout）、エラーは標準エラー（stderr）

## 処理フロー

### 処理シーケンス

```
1. ターゲット初期化
   └─ InitializeAllTargetInfos/MCs/AsmParsers/Disassemblers
2. バイナリ読み込み
   └─ FileAnalysis::Create()でファイル解析
3. 無視リスト読み込み（オプション）
   └─ SpecialCaseList::create()
4. 間接CF命令の検出と検証
   └─ getIndirectInstructions()で命令取得
   └─ GraphBuilder::buildFlowGraph()でグラフ構築
   └─ validateCFIProtection()で保護判定
5. 結果出力
   └─ 統計情報とエラー詳細の表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ターゲット初期化]
    B --> C[FileAnalysis::Create]
    C --> D{成功?}
    D -->|No| E[エラー終了]
    D -->|Yes| F[無視リスト読込]
    F --> G[間接CF命令取得]
    G --> H{命令あり?}
    H -->|No| I[命令なし表示]
    H -->|Yes| J[各命令を処理]
    J --> K[GraphBuilder::buildFlowGraph]
    K --> L[validateCFIProtection]
    L --> M{保護状態判定}
    M -->|PROTECTED| N[Expected Protected++]
    M -->|FAIL_*| O[Unexpected Unprotected++]
    N --> P{次の命令?}
    O --> P
    P -->|Yes| J
    P -->|No| Q[統計出力]
    I --> R[終了]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-93-01 | 保護判定 | 条件分岐後にトラップ命令があれば保護済み | CFI検証時 |
| BR-93-02 | レジスタクロバー | 間接CFで使用するレジスタが上書きされていないこと | CFI検証時 |
| BR-93-03 | 孤立ノード | 制御フローで到達不能なノードがあれば失敗 | グラフ検証時 |
| BR-93-04 | DWARF必須 | --ignore-dwarf以外はDWARF情報が必要 | デフォルト動作 |

### 計算ロジック

- 保護率 = ExpectedProtected / (ExpectedProtected + UnexpectedUnprotected)
- 各カテゴリの割合を%で表示

## データベース操作仕様

### 操作別データベース影響一覧

本ツールはデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EXIT_FAILURE | ファイルエラー | バイナリ読込失敗 | ファイルパス確認 |
| EXIT_FAILURE | 無視リストエラー | 無視リスト読込失敗 | フォーマット確認 |
| EXIT_FAILURE | シンボル化エラー | DWARF情報なし | -gオプションで再コンパイル |
| UnsupportedDisassembly | アーキテクチャエラー | 未対応アーキテクチャ | x86/x86_64/AArch64を使用 |

### リトライ仕様

リトライは実装されていない。

## トランザクション仕様

該当なし（読み取り専用ツール）

## パフォーマンス要件

- 大規模バイナリでも全命令をスキャンするため、ファイルサイズに比例した時間を要する
- SearchLengthForConditionalBranchでグラフ探索深度を制限（デフォルト20）

## セキュリティ考慮事項

- 入力バイナリの検証は基本的なファイル形式チェックのみ
- 悪意あるバイナリによる攻撃リスクは低い（読み取り専用解析）

## 備考

CFIProtectionStatusの値：PROTECTED, FAIL_NOT_INDIRECT_CF, FAIL_ORPHANS, FAIL_BAD_CONDITIONAL_BRANCH, FAIL_REGISTER_CLOBBERED, FAIL_INVALID_INSTRUCTION

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FileAnalysis.h | `llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h` | Instr構造体、CFIProtectionStatus列挙型 |
| 1-2 | GraphBuilder.h | `llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h` | GraphResult、ConditionalBranchNode構造体 |

**読解のコツ**: Instr構造体がバイナリ命令のメタデータを保持し、GraphResultが制御フローグラフを表現する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | llvm-cfi-verify.cpp | `llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp` | main関数とコマンドライン処理 |

**主要処理フロー**:
1. **256-268行目**: ターゲット初期化（InitializeAll*）
2. **273-282行目**: 無視リストの読み込み
3. **284行目**: FileAnalysis::Create()でファイル解析
4. **285行目**: printIndirectCFInstructions()で検証実行

#### Step 3: ファイル解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FileAnalysis.cpp | `llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp` | バイナリ解析の実装 |

**主要処理フロー**:
- **73-116行目**: FileAnalysis::Create()でバイナリ読み込みと初期化
- **374-432行目**: initialiseDisassemblyMembers()でディスアセンブラ設定
- **434-478行目**: parseCodeSections()で実行可能セクション解析
- **480-542行目**: parseSectionContents()で命令パース
- **284-309行目**: validateCFIProtection()で保護判定

#### Step 4: グラフ構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | GraphBuilder.cpp | `llvm/tools/llvm-cfi-verify/lib/GraphBuilder.cpp` | 制御フローグラフ構築 |

**主要処理フロー**:
- **95-110行目**: buildFlowGraph()でグラフ構築開始
- **197-337行目**: buildFlowGraphImpl()で再帰的にグラフ構築
- **112-195行目**: buildFlowsToUndefined()でトラップへのパス確認

### プログラム呼び出し階層図

```
main() [llvm-cfi-verify.cpp:256]
    │
    ├─ InitializeAllTargetInfos() 等
    │
    ├─ SpecialCaseList::create() [オプション]
    │
    ├─ FileAnalysis::Create() [FileAnalysis.cpp:73]
    │      │
    │      ├─ object::createBinary()
    │      ├─ initialiseDisassemblyMembers()
    │      │      └─ TargetRegistry::lookupTarget()
    │      │      └─ createMCDisassembler()
    │      ├─ parseCodeSections()
    │      │      └─ parseSectionContents()
    │      └─ parseSymbolTable()
    │
    └─ printIndirectCFInstructions() [llvm-cfi-verify.cpp:130]
           │
           ├─ getIndirectInstructions()
           │
           └─ [各命令について]
                  │
                  ├─ GraphBuilder::buildFlowGraph() [GraphBuilder.cpp:95]
                  │      └─ buildFlowGraphImpl() [再帰]
                  │             └─ buildFlowsToUndefined()
                  │
                  └─ validateCFIProtection() [FileAnalysis.cpp:284]
```

### データフロー図

```
[入力]                      [処理]                        [出力]

バイナリファイル ───▶ MCDisassembler ───▶ Instr[]
                            │
                            ▼
                    間接CF命令フィルタ ───▶ IndirectInstructions
                            │
                            ▼
                    GraphBuilder ───────▶ GraphResult
                            │
                            ▼
                    validateCFIProtection ───▶ CFIProtectionStatus
                            │
                            ▼
DWARF情報 ─────────▶ LLVMSymbolizer ────▶ シンボル化された結果
                            │
                            ▼
                    統計計算 ──────────▶ 標準出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-cfi-verify.cpp | `llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp` | ソース | エントリーポイント |
| FileAnalysis.h | `llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h` | ヘッダ | 解析データ構造定義 |
| FileAnalysis.cpp | `llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp` | ソース | バイナリ解析実装 |
| GraphBuilder.h | `llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h` | ヘッダ | グラフ構造定義 |
| GraphBuilder.cpp | `llvm/tools/llvm-cfi-verify/lib/GraphBuilder.cpp` | ソース | グラフ構築実装 |
