提案手法の概要

目的:データの保護

  • Buffer Overflowの検知
  • Use After Freeの検知
  • Use After Returnの検知
  • etc..

保護手法:データの正しい定義・使用を保証

  • アイデア: 以下の条件が成り立つとき,データは安全である
    • データが正しく書き込まれる
    • データが正しく読み込まれる
  • 方針: プログラムにチェック関数を挿入し,データが正しく読み書きされるかどうかを監視
  • 既存研究との差別化点
    • 構造体の要素を正確に保護できる
    • Re-allocateされたオブジェクトのuse-after-freeを検知できる

保護の流れ

ステップ:
  1. Use-Def解析 (静的解析)
    • 正しいデータ読み書きの関係を求める
  2. チェック関数の挿入 (静的計装)
  3. 実行時チェック (動的解析)
    • データの読み書きが正しく行われるかをチェック

Motivating Example

1
2
3
4
5
6
7
8
9
10
11
12
struct Student {
  char name[32];
  int id;
};

struct Student s;
s.id = 100;

InputName(s.name);    // Cause buffer overflow!!


return s.id;

L.9 InputNameにバッファオーバーフローの脆弱性あり!!
→ s.idが不正に上書きされてしまう,,,

Step1: Use-Def解析 (静的解析)
  • 目的:データの使用と,そこで使用されうる定義元を求める (Use-definition Chain)
  • 手法:静的解析
    • ref) ISA, Dragon Book Ch.9
1
2
3
4
5
6
7
8
9
10
11
12
struct Student {
  char name[32];
  int id;
};

struct Student s;
s.id = 100;

InputName(s.name);


return s.id;
Use-Def解析の結果
Use Def
s.id L.12 L.7
s.name - L.9
Step2: チェック関数の挿入 (静的計装)
  • 目的:実行時チェックのための関数呼び出しを挿入
    • __set(): 変数への書き込み情報を取得
    • __check(): 変数の読み込み時,定義元が正しいかどうかをチェック
  • 手法:静的計装
    • ref) PBA(動的計装)
1
2
3
4
5
6
7
8
9
10
11
12
struct Student {
  char name[32];
  int id;
};

struct Student s;
s.id = 100;
__set(&s.id, L.7);
InputName(s.name);
__set(s.name, input_count, L.9);
__check(&s.id, L.7);
return s.id;
Use-Def解析の結果
Use Def
s.id L.12 L.7
s.name - L.9
Step3: 実行時チェック (動的解析)
  • 目的:データの使用時,そのデータが正しい定義元であるかを確認
    • L.12 return s.id;で使用されるs.idの正しい定義元は L.7
  • 手法:動的解析
    • ref) PBA
1
2
3
4
5
6
7
8
9
10
11
12
struct Student {
  char name[32];
  int id;
};

struct Student s;
s.id = 100;
__set(&s.id, L.7);
InputName(s.name);
__set(s.name, input_count, L.9);
__check(&s.id, L.7);
return s.id;
Use-Def解析の結果
Use Def
s.id L.12 L.7
s.name - L.9
L.8 __set(&s.id, L.7)
L.10 __set(s.name, input_count, L.9)

L.11 __check(&s.id, L.7)にて,s.idはL.7で定義された値が使用されることをチェック
→ L.9であるため,攻撃として検知!!

まとめ

  • アイデア:データが正しく読み書きされているかをチェック
  • 保護の流れ
    1. Use-Def解析
      • 正しいデータの読み書き(データの使用場所 + 使われうる定義元)を近似的に求める
      • 🗝 解析の精度がデータ保護の精度に直結
        • 解析精度を高める → データ保護の精度が高まる
    2. チェック関数の挿入
    3. 実行時チェック
      • 実行中のデータの読み書きが正しいかどうかをStep.1の結果と比較し,チェックする

既存研究との比較

  • 構造体の要素を正確に保護できる
    • 理由:構造体の要素を区別したUse-Def解析 (Field-sensitiveな解析)
    • 保護できない関連研究:AddressSanitizer[Usenix ATC'12], Data-Flow Integrity[OSDI'06]
  • Re-allocateされたオブジェクトのuse-after-freeを検知できる
    • 理由:データの定義元を確認する
    • 保護できない関連研究:EffectiveSan[PLDI'18]

今後の展望

  • 検知できるバグの種類を増やす
    • Data Race
    • Atomicity Violation
    • Interrupt Error
  • カーネル空間も保護できるように拡張