Upgrade to Pro — share decks privately, control downloads, hide ads and more …

1893件以上のカーネルの不具合修正に貢献した再現用プログラムを自動生成するsyzkallerのテスト自動化技術 / syzkaller Kernel VM Kansai 10th

fujiihda
February 08, 2020

1893件以上のカーネルの不具合修正に貢献した再現用プログラムを自動生成するsyzkallerのテスト自動化技術 / syzkaller Kernel VM Kansai 10th

syzkaller は、Google の Dmitry Vyukov さんが開発し OSS として公開したカーネルのファジングツールで、2 年で 1500 件以上の Linux カーネルの不具合修正に貢献した実績を持ちます。自らが生成した複数の仮想マシンに対して問題の起きそうな入力を送り続けることで未発見の不具合を発見します。最小限の入力で不具合を再現させるための再試行を繰り返し、最終的には不具合を再現するための C 言語のプログラム生成を試みます。本資料は 2020/2/8 の「カーネル/VM探検隊@関西 10回目」の発表資料です。

fujiihda

February 08, 2020
Tweet

More Decks by fujiihda

Other Decks in Technology

Transcript

  1. fujiihda
    2020/2/8
    カーネル/VM探検隊@関⻄ 10回⽬
    1893件以上のカーネルの不具合修正に貢献した再現用
    プログラムを自動生成するsyzkallerのテスト自動化技術

    View Slide

  2. 2
    2
    @fujiihda
    Whois
    fujiihda
    • 役割︓Infrastructure Engineer /
    技術系コミュニティ運営等
    • 仕事︓技術調査、SRE、製品開発
    • 経歴︓監視、OS (Linux)、コンテナ
    • 趣味︓セキュリティ技術

    View Slide

  3. 3
    3
    @fujiihda
    はじめに
    掲載内容は個⼈の⾒解であり、
    所属する企業やコミュニティの⽴場、
    戦略、意⾒を代表するものではありません

    View Slide

  4. 4
    4
    @fujiihda
    警告
    • 社内ネットワークではやらないでください
    • 社内のマシンではやらないでください
    • プライベート環境などの完全に隔離された
    環境で⾃⼰責任でやってください

    View Slide

  5. 5
    5
    @fujiihda
    今⽇話すこと
    カーネルのテスト⾃動化技術として Google の
    Dmitry Vyukov さんが開発し OSS として
    公開した syzkaller (読み⽅︓シスコーラー)
    というファジングツールについて話します

    View Slide

  6. 6
    @fujiihda
    1. 背景
    2. 実施内容
    3. ドキュメント調査
    4. ソースコード調査
    5. syzkaller の動作確認
    6. まとめ
    7. 個⼈的な振り返り
    8. 今後
    本⽇の流れ
    時間の都合上
    ここに注⼒

    View Slide

  7. 7
    7
    @fujiihda
    背景 (ファジングと Linux のセキュリティ品質向上)
    • ファジング は未知の不具合や脆弱性の検出に適したテスト⼿法
    – 検査対象にランダムな⼊⼒データを送ることで意図的に例外を発⽣させる
    • セキュリティ品質 にファジングが与える影響が話題
    – Open Source Summit Japan 2019 で複数講演者がファジングの貢献に⾔及
    • 2017 年前後からファジングをはじめとする⾃動化された⾼度なテスト技術が普及
    • リリース前にセキュリティ脆弱性が修正されるようになり CVE の件数は減少傾向
    図︓ソフトウェア全体および Linux の CVE 件数の推移

    View Slide

  8. 8
    8
    @fujiihda
    実施内容
    • ドキュメント調査 (英語)
    – 公式ドキュメントの調査
    – 開発者による講演資料 / 講演映像の調査
    – 学術論⽂の調査
    – セキュリティカンファレンスの講演資料 / 講演映像の調査
    – コミュニティの調査 (開発者の SNS 等を含む)
    • ソースコード調査 (ほぼ Go ⾔語)
    – Go ⾔語の⾔語仕様の差異の把握
    – Go ⾔語の開発環境構築および⼿順の確⽴
    – 全体構成把握および関数名とコメント⽂の斜め読み
    – 処理の順にソースコードの関数を追いかける
    • syzkaller の動作確認 (未発⾒の不具合の発⾒)
    – 環境構築および構築⼿順の確⽴
    – ファジング実⾏と挙動の確認
    – カーネルの I/O スケジューラに関連する use-after-free の
    新規不具合の発⾒
    – 再現⽤の C ⾔語のプログラム⽣成
    全体像、各種構成要素、
    ⼤まかな処理の流れ
    の解明
    ソースコードにしかない
    動作の仕組みや細かい
    処理の流れを解明
    動かして理解しつつ
    未発⾒の不具合を探す

    View Slide

  9. 9
    @fujiihda
    ドキュメント調査
    (論⽂等のサーベイ)

    View Slide

  10. 10
    10
    @fujiihda
    ドキュメント調査 - ⾼度なファジングの肝
    • ⾼度なファジングの肝となる技術のひとつは検査対象で問題が起きそ
    うな⼊⼒データを⽣成する仕組み
    – この仕組みの⾼度化が発⾒困難な不具合の発⾒を可能にする
    – ファジングの⼊⼒データを⽣成する仕組みを分類した結果は次のとおりで、syzkaller はレベル 4
    – ファジングのターゲットはネットワーク越し限定からそうでないものまで多岐に渡る
    表︓ファジングの⼊⼒データを⽣成する仕組みの分類
    レベル 仕組み 効率 網羅 備考
    1 プロトコル等を考慮しない完全な
    ランダム
    × ○ 実際の入力とは程遠い入力パターンが生成
    される
    2 キャプチャしたパケットをテンプ
    レートとしてその一部を改変
    △ × キャプチャした範囲内の入力パターンしか生
    成されない
    3
    プロトコル仕様や問題の起きそう
    な入力パターンを人間が実装し
    ておき活用
    ○ ○ 主要な商用ツールで採用されている手法
    4 レベル 3 に加えてソースコードの
    カバレッジを活用
    ◎ ○
    syzkaller が採用している手法で、入力を変
    異させるときの分岐条件にソースコードを活
    用する

    View Slide

  11. 11
    11
    @fujiihda
    (補⾜) ここでの⼊⼒データとは具体的に何か
    • カーネルの⼊⼒インターフェイスはシステムコール
    • カーネルへの⼊⼒データは、例えばファイルをオープンする⽬的で使⽤される open() など、
    300 種類ほどのシステムコールとその引数の組合せで構成される
    • つまり、カーネルのファジングでは、どのシステムコールを選択し、どのような引数で、
    さらにはどのような組合せで送るかがポイントとなる
    参照元︓https://www.kimullaa.com/entry/2020/01/05/191221

    View Slide

  12. 12
    12
    @fujiihda
    ドキュメント調査 - syzkaller とは
    • Google の Dmitry Vyukov さんによって開発された
    カーネルのファジングツール
    • 2 年間でカバレッジを 7 %カバーした時点で、
    1500 件以上のカーネルの不具合修正に貢献
    • 本⽇時点では、1893 件の不具合修正に貢献

    View Slide

  13. 13
    13
    @fujiihda
    ドキュメント調査 - syzkaller とは
    • 特徴
    – ハイブリッドな仕組みにより効率良く
    システムコールのシーケンスを⽣成
    • 試験対象プロトコル (システムコール) のテンプ
    レートが実装されている
    • ソースコードのコンパイル時にコンパイラが出⼒
    するカバレッジを利⽤して⼊⼒を変える
    – 不具合発⾒の⼀連の流れがほぼすべて⾃動化
    • ⾃らが⽣成した複数の試験対象の仮想マシンに
    対して問題の起きそうな⼊⼒を送り続けて、
    デバッグ⽀援機構を活⽤してその挙動を観測
    • 発⾒した不具合を最⼩限の⼊⼒で再現させる
    ための再試⾏を⾃ら繰り返し、不具合を再現する
    ための C ⾔語のプログラム⽣成を試みる
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    各構成要素の詳細は
    次ページから解説
    図︓syzkaller の構成図

    View Slide

  14. 14
    14
    @fujiihda
    (参考) Sanitizer とは
    • カーネルに存在する複数のデバッグ⽀援機構
    – 動的テストツール
    – コンパイラの機能 (gcc および C ⾔語で利⽤可能)
    – メモリを破壊したことや違反したことなどをはっきり⽰すもの
    – 不具合を⽰してくれるのでファジングを補助してくれる
    – エラーが起きたら、エラーの深刻度に関わらず、
    カーネルパニックを発⽣させる設定を使⽤する*1
    (コンソールにパニックメッセージを出⼒)
    • syzkaller で使⽤している主な Sanitizer
    – KASAN (Kernel Address Sanitizer)
    • メモリアクセスエラーを検出
    – KMSAN (Kernel Memory Sanitizer)
    • 初期化されていない読み取りを検出
    – KTSAN (Kernel Thread Sanitizer)
    • 異なるスレッド間のデータの競合状態を検出
    – UBSAN (Undefined Behavior Sanitizer)
    • 未定義の動作を引き起こす機能の使⽤を検出
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg

    View Slide

  15. 15
    15
    @fujiihda
    • コンパイラ (gcc) によって提供される機能
    • カバレッジガイドファジングに適した形式でカーネル
    コードカバレッジ情報を⽣成
    • 使い⽅︓CONFIG_KCOV = y
    • 条件︓gcc 6.1.0 以降 (バージョン 231296 以降)
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    __fuzz_coverage();
    if (...)
    {
    __fuzz_coverage();
    ...
    }
    __fuzz_coverage();
    if (...)
    {
    ...
    }
    図︓KCOV 無効時と KCOV 有効時のイメージ 図︓syzkaller の構成図
    (参考) KCOV (Kernel Code Coverage) とは

    View Slide

  16. 16
    16
    @fujiihda
    ドキュメント調査 - syzkaller の全体像
    • syz-manager
    – 仮想化ホスト上に存在するプロセス
    – 試験対象としての VMs の管理 (起動、監視、再起動)
    • この VMs はカーネルパニックのたびに再起動
    – 試験対象としての VMs 内で syz-fuzzer プロセスを起動
    – syz-fuzzer プロセスに指⽰を送る
    – workdir 上のコーパスとクラッシュ (次ページで説明) を更新
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg

    View Slide

  17. 17
    17
    @fujiihda
    ドキュメント調査 - syzkaller の全体像
    • workdir/crashes/*
    – クラッシュに関わるアウトプット
    – アスタリスクにはハッシュ値が名前のフォルダが⽣成される
    – フォルダ内に次の情報を含む
    • description 事象を特定する件名
    • logN (N=0〜99) syzkaller のログ
    • reportN (N=0〜99) カーネルクラッシュレポート
    • repro.cprog 再現⽤の C ⾔語のプログラム
    • repro.log
    • repro.prog
    • repro.report
    • repro.stats
    • reproM (M=0〜9)
    • workdir/corpus/*
    – コーパスは個別ファイルとして格納されているファズターゲット
    の⼊⼒セット
    – 理想的なコーパスは最⼤限のコードカバレッジを提供する
    最⼩限の⼊⼒セット
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg

    View Slide

  18. 18
    18
    @fujiihda
    ドキュメント調査 - syzkaller の全体像
    • syz-fuzzer
    – 先述の不安定な試験対象 VMs 内に存在するプロセス
    – テストケース (⼊⼒) を⽣成、突然変異、最⼩化
    – 任意の数の syz-executor プロセスを起動
    – コーパスで⼊⼒を変える︖︖︖
    → ドキュメント調査だけでは、なにをいっているのか
    いまいちわからなかった・・・
    ソースコードを調査した結果︓
    コーパスの有無で条件分岐して Generate 関数
    もしくは Mutate 関数のいずれかを呼び出すことで
    システムコールのシーケンスを決める
    (詳細はソースコードを追いかけるときに説明)
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg

    View Slide

  19. 19
    19
    @fujiihda
    ドキュメント調査 - syzkaller の全体像
    • syz-executor
    – 先述の不安定な試験対象 VMs 内に任意の個数存在するプロセス
    – syz-fuzzer から syscalls のシーケンスを受け取る
    – syscalls のシーケンスを実⾏する
    – syscalls の実⾏結果を syz-fuzzer に送り返す
    – 単⼀の executor プロセスのことを Proc とも呼ぶ
    • Proc がカーネルに送るデータは ProgData とも呼ぶ
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg

    View Slide

  20. 20
    @fujiihda
    ソースコード調査

    View Slide

  21. 21
    21
    @fujiihda
    ソースコード調査 - どの処理を調べるか
    • ⼀連の流れのなかで⾯⽩そうな処理 (executor) に
    関連するソースコードを処理順に追う
    1. ssh で fuzzer が呼ばれたあとに executor を呼ぶまでの処理 (主に fuzzer)
    https://github.com/google/syzkaller/blob/master/syz-fuzzer/fuzzer.go
    2. executor が呼ばれたあとに syscalls ⽣成までの処理 (主に executor)
    https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go
    https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    1
    2

    View Slide

  22. 22
    22
    @fujiihda
    ソースコード調査 - fuzzer
    https://github.com/google/syzkaller/blob/master/syz-fuzzer/fuzzer.go
    func main() {
    (中略)
    for pid := 0; pid < *flagProcs; pid++ {
    proc, err := newProc(fuzzer, pid)
    if err != nil {
    log.Fatalf("failed to create proc: %v", err)
    }
    fuzzer.procs = append(fuzzer.procs, proc)
    go proc.loop()
    }
    fuzzer.pollLoop()
    }
    引数として与えた
    FlagProcs の数だけ
    Proc (executor の
    プロセス) を⽣成
    ゴルーチン (Go ⾔語で
    ⾔語仕様として提供され
    る並列処理の機能) で
    syz-fuzzer/proc.go の
    loop 関数を呼び出す
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    1

    View Slide

  23. 23
    23
    @fujiihda
    ソースコード調査 - executor
    https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go
    func (proc *Proc) loop() {
    generatePeriod := 100
    if proc.fuzzer.config.Flags&ipc.FlagSignal == 0 {
    // If we don't have real coverage signal, generate programs more frequently
    // because fallback signal is weak.
    generatePeriod = 2
    }
    for i := 0; ; i++ {
    item := proc.fuzzer.workQueue.dequeue()
    if item != nil {
    (中略)
    }
    ct := proc.fuzzer.choiceTable
    corpus := proc.fuzzer.corpusSnapshot()
    if len(corpus) == 0 || i%generatePeriod == 0 {
    // Generate a new prog.
    p := proc.fuzzer.target.Generate(proc.rnd, programLength, ct)
    log.Logf(1, "#%v: generated", proc.pid)
    proc.execute(proc.execOpts, p, ProgNormal, StatGenerate)
    } else {
    // Mutate an existing prog.
    p := corpus[proc.rnd.Intn(len(corpus))].Clone()
    p.Mutate(proc.rnd, programLength, ct, corpus)
    log.Logf(1, "#%v: mutated", proc.pid)
    proc.execute(proc.execOpts, p, ProgNormal, StatFuzz)
    }
    }
    }
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    2
    コーパス (ファズターゲッ
    トの⼊⼒セット) の有無で
    条件分岐して、次のいず
    れかの関数を呼び出す
    Generate 関数
    を呼び、引数
    StatGenerate
    で execute 関
    数を呼ぶ
    Mutate 関数を
    呼び、引数
    StatFuzz で
    execute 関数を
    呼ぶ

    View Slide

  24. 24
    24
    @fujiihda
    ソースコード調査 - executor
    https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go
    func (proc *Proc) execute(execOpts *ipc.ExecOpts, p *prog.Prog, flags ProgTypes,
    stat Stat) *ipc.ProgInfo {
    info := proc.executeRaw(execOpts, p, stat)
    calls, extra := proc.fuzzer.checkNewSignal(p, info)
    for _, callIndex := range calls {
    proc.enqueueCallTriage(p, flags, callIndex, info.Calls[callIndex])
    }
    if extra {
    proc.enqueueCallTriage(p, flags, -1, info.Extra)
    }
    return info
    }
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    2
    executeRaw
    関数を呼び
    出す

    View Slide

  25. 25
    25
    @fujiihda
    ソースコード調査 - executor
    https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go
    func (proc *Proc) executeRaw(opts *ipc.ExecOpts, p *prog.Prog, stat Stat)
    *ipc.ProgInfo {
    if opts.Flags&ipc.FlagDedupCover == 0 {
    log.Fatalf("dedup cover is not enabled")
    }
    // Limit concurrency window and do leak checking once in a while.
    ticket := proc.fuzzer.gate.Enter()
    defer proc.fuzzer.gate.Leave(ticket)
    proc.logProgram(opts, p)
    for try := 0; ; try++ {
    atomic.AddUint64(&proc.fuzzer.stats[stat], 1)
    output, info, hanged, err := proc.env.Exec(opts, p)
    if err != nil {
    if try > 10 {
    log.Fatalf("executor %v failed %v times:¥n%v", proc.pid, try, err)
    }
    log.Logf(4, "fuzzer detected executor failure='%v', retrying #%d", err,
    try+1)
    debug.FreeOSMemory()
    time.Sleep(time.Second)
    continue
    }
    log.Logf(2, "result hanged=%v: %s", hanged, output)
    return info
    }
    }
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    2
    env.Exec 関数
    を呼び出す

    View Slide

  26. 26
    26
    @fujiihda
    ソースコード調査 - executor
    https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go
    func (env *Env) Exec(opts *ExecOpts, p *prog.Prog) (output []byte, info *ProgInfo, hanged
    bool, err0 error) {
    // Copy-in serialized program.
    progSize, err := p.SerializeForExec(env.in)
    if err != nil {
    err0 = fmt.Errorf("failed to serialize: %v", err)
    return
    }
    var progData []byte
    if env.config.Flags&FlagUseShmem == 0 {
    progData = env.in[:progSize]
    }
    // Zero out the first two words (ncmd and nsig), so that we don't have garbage there
    // if executor crashes before writing non-garbage there.
    for i := 0; i < 4; i++ {
    env.out[i] = 0
    }
    atomic.AddUint64(&env.StatExecs, 1)
    if env.cmd == nil {
    if p.Target.OS == "akaros" {
    // On akaros executor is actually ssh,
    // starting them too frequently leads to timeouts.
    <-rateLimit.C
    }
    tmpDirPath := "./"
    if p.Target.OS == "fuchsia" {
    tmpDirPath = "/data/"
    }
    atomic.AddUint64(&env.StatRestarts, 1)
    env.cmd, err0 = makeCommand(env.pid, env.bin, env.config, env.inFile, env.outFile,
    env.out, tmpDirPath)
    (以下省略)
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    2
    makeCommand
    関数を呼び出す

    View Slide

  27. 27
    27
    @fujiihda
    ソースコード調査 - executor
    https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go
    func makeCommand(pid int, bin []string, config *Config, inFile, outFile *os.File, outmem
    []byte,
    tmpDirPath string) (*command, error) {
    (中略)
    // executor->ipc command pipe.
    inrp, inwp, err := os.Pipe()
    if err != nil {
    return nil, fmt.Errorf("failed to create pipe: %v", err)
    }
    defer inwp.Close()
    c.inrp = inrp
    // ipc->executor command pipe.
    outrp, outwp, err := os.Pipe()
    if err != nil {
    return nil, fmt.Errorf("failed to create pipe: %v", err)
    }
    defer outrp.Close()
    c.outwp = outwp
    c.readDone = make(chan []byte, 1)
    c.exited = make(chan struct{})
    cmd := osutil.Command(bin[0], bin[1:]...)
    if inFile != nil && outFile != nil {
    cmd.ExtraFiles = []*os.File{inFile, outFile}
    }
    cmd.Env = []string{}
    cmd.Dir = dir
    cmd.Stdin = outrp
    cmd.Stdout = inwp
    (以下省略)
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    2
    osutil.Command
    で executor 実⾏
    executor の標準
    ⼊⼒を os のパイ
    プにつなぐ
    ⼊出⼒リダイレクト

    View Slide

  28. 28
    28
    @fujiihda
    ソースコード調査 - executor
    https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go
    func (c *command) exec(opts *ExecOpts, progData []byte) (output []byte, hanged bool, err0
    error) {
    req := &executeReq{
    magic: inMagic,
    envFlags: uint64(c.config.Flags),
    execFlags: uint64(opts.Flags),
    pid: uint64(c.pid),
    faultCall: uint64(opts.FaultCall),
    faultNth: uint64(opts.FaultNth),
    progSize: uint64(len(progData)),
    }
    reqData := (*[unsafe.Sizeof(*req)]byte)(unsafe.Pointer(req))[:]
    if _, err := c.outwp.Write(reqData); err != nil {
    output = <-c.readDone
    err0 = fmt.Errorf("executor %v: failed to write control pipe: %v", c.pid, err)
    return
    }
    if progData != nil {
    if _, err := c.outwp.Write(progData); err != nil {
    output = <-c.readDone
    err0 = fmt.Errorf("executor %v: failed to write control pipe: %v", c.pid, err)
    return
    }
    }
    図︓syzkaller の構成図
    ユーザ空間
    カーネル
    VMs (試験対象)
    syzkaller サーバ (仮想化ホスト)
    sshd
    syz-
    fuzzer
    syz-
    manager
    workdir/crashes/*
    workdir/corpus/*
    VMs 管理
    rpc
    ssh, scp
    invoke
    syscalls
    カバレッジ
    syz-
    executor
    syz-
    executor
    syz-
    executor
    syz-
    executor
    カバレッジ
    テストケース
    ファジング対象のカーネル (KCOV 有効)
    UI
    操作
    # ./bin/syz-manager -config my.cfg
    2
    progData を
    継続して送る

    View Slide

  29. 29
    @fujiihda
    syzkaller の動作確認

    View Slide

  30. 30
    30
    @fujiihda
    syzkaller の動作確認 - ファジング実⾏時の画⾯の⼀部
    # ./bin/syz-manager -config=my.cfg
    2019/06/05 03:53:20 loading corpus...
    2019/06/05 03:53:20 serving http on http://127.0.0.1:56741
    2019/06/05 03:53:20 serving rpc on tcp://[::]:37545
    2019/06/05 03:53:20 booting test machines...
    2019/06/05 03:53:20 wait for the connection from test machine...
    2019/06/05 03:54:08 machine check:
    2019/06/05 03:54:08 syscalls : 1380/2699
    2019/06/05 03:54:08 code coverage : enabled
    2019/06/05 03:54:08 comparison tracing : CONFIG_KCOV_ENABLE_COMPARISONS is not enabled
    2019/06/05 03:54:08 extra coverage : extra coverage is not supported by the kernel
    2019/06/05 03:54:08 setuid sandbox : enabled
    2019/06/05 03:54:08 namespace sandbox : /proc/self/ns/user does not exist
    2019/06/05 03:54:08 Android sandbox : /sys/fs/selinux/policy does not exist
    2019/06/05 03:54:08 fault injection : CONFIG_FAULT_INJECTION is not enabled
    2019/06/05 03:54:08 leak checking : CONFIG_DEBUG_KMEMLEAK is not enabled
    2019/06/05 03:54:08 net packet injection : /dev/net/tun does not exist
    2019/06/05 03:54:08 net device setup : enabled
    2019/06/05 03:54:08 corpus : 3844 (0 deleted)
    2019/06/05 03:54:10 VMs 4, executed 0, cover 0, crashes 0, repro 0
    2019/06/05 03:54:20 VMs 4, executed 36, cover 3836, crashes 0, repro 0
    2019/06/05 03:54:30 VMs 4, executed 776, cover 20662, crashes 0, repro 0
    (中略)
    2019/06/05 04:10:00 VMs 4, executed 70734, cover 62967, crashes 0, repro 0
    2019/06/05 04:10:05 vm-3: crash: no output from test machine
    2019/06/05 04:10:10 VMs 3, executed 70918, cover 62967, crashes 1, repro 0
    (中略)
    2019/06/05 04:14:02 VMs 4, executed 87377, cover 63959, crashes 1, repro 0
    2019/06/05 04:14:05 vm-2: crash: no output from test machine
    2019/06/05 04:14:12 VMs 3, executed 87614, cover 63960, crashes 2, repro 0
    (中略)
    2019/06/05 04:14:32 VMs 4, executed 87978, cover 63995, crashes 2, repro 0
    2019/06/05 04:14:40 vm-3: crash: KASAN: use-after-free Read in blk_mq_free_rqs
    2019/06/05 04:14:41 vm-1: running for 20m42.241115632s, restarting
    2019/06/05 04:14:41 vm-0: running for 20m33.97704277s, restarting
    2019/06/05 04:14:41 vm-2: running for 9.643775512s, restarting
    2019/06/05 04:14:42 reproducing crash 'KASAN: use-after-free Read in blk_mq_free_rqs': 1158 programs, 4 VMs, timeouts [15s 1m0s 6m0s]
    2019/06/05 04:14:42 VMs 0, executed 87978, cover 63995, crashes 3, repro 1
    (繰り返す)
    起動からわずか
    20 分程で不具合
    らしいものを発⾒
    クラッシュ時に
    事象を取り逃す
    こともある
    同上
    再現を試みる

    View Slide

  31. 31
    31
    @fujiihda
    syzkaller の動作確認 - 前ページの事象を再現するプログラム
    # cat bd744ffeabd8fcd8ae152d0c44dde8112311663f/repro.cprog
    // autogenerated by syzkaller (https://github.com/google/syzkaller)
    #define _GNU_SOURCE
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    uint64_t r[1] = {0xffffffffffffffff};
    int main(void)
    {
    syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
    intptr_t res = 0;
    memcpy((void *)0x20000040, "/dev/loop-control¥000", 18);
    res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000040, 0x181000, 0);
    if (res != -1)
    r[0] = res;
    syscall(__NR_ioctl, r[0], 0x4c81, 0);
    return 0;
    }
    autogenerated
    by syzkaller

    View Slide

  32. 32
    @fujiihda
    まとめ、振り返り、今後

    View Slide

  33. 33
    33
    @fujiihda
    まとめ
    • ドキュメント調査 (英語)
    – 公式ドキュメントの調査
    – 開発者による講演資料 / 講演映像の調査
    – 学術論⽂の調査
    – セキュリティカンファレンスの講演資料 / 講演映像の調査
    – コミュニティの調査 (開発者の SNS 等を含む)
    • ソースコード調査 (ほぼ Go ⾔語)
    – Go ⾔語の⾔語仕様の差異の把握
    – Go ⾔語の開発環境構築および⼿順の確⽴
    – 全体構成把握および関数名とコメント⽂の斜め読み
    – 処理の順にソースコードの関数を追いかける
    • syzkaller の動作確認 (未発⾒の不具合の発⾒)
    – 環境構築および構築⼿順の確⽴
    – ファジング実⾏と挙動の確認
    – カーネルの I/O スケジューラに関連する use-after-free の
    新規不具合の発⾒
    – 再現⽤の C ⾔語のプログラム⽣成
    全体像、各種構成要素、
    ⼤まかな処理の流れ
    の解明
    ソースコードにしかない
    動作の仕組みや細かい
    処理の流れを解明
    動かして理解しつつ
    未発⾒の不具合を探す



    View Slide

  34. 34
    34
    @fujiihda
    個⼈的な振り返り (⾃分向け教訓)
    • 知識ゼロから知らない⾔語の処理を追うときこそ急がば回れ
    – いきなりソースコード斜め読みは精神的に⾟い (熟練者向けなので個⼈的には⾮推奨)
    – たとえ遠回りに⾒えても、以下からはじめるとよい
    • 開発環境構築
    • ⾔語仕様把握
    • 各コンポーネントの役割や処理の流れを把握
    • 実機による簡単な動作確認
    • 不具合は常に最新版で探し、⾒つけたら放置せずに即直せ
    – カーネルの不具合は (素晴らしいことだが) ⾒つけたらすぐに直さないと誰かが修正する
    (c3e2219216c92919a6bd1711f340f5faa98695e6)
    – ⻑期間放置されている不具合は発⽣条件が不明確なものや修正が困難なものばかり
    (https://syzkaller.appspot.com/upstream)

    View Slide

  35. 35
    35
    @fujiihda
    今後
    • これから調べたい
    – テストケース (⼊⼒) を⽣成する仕組みのさらなる深掘り
    • テストケース (⼊⼒) の最⼩化
    • テストケース (⼊⼒) の突然変異
    – ファジング対象をシステムコール単位で絞り込む (できること確認済)
    • クラウドで提供されるマネージドなコンテナサービスは、
    システムコールが限定されていることがあり、
    その制限で有効なシステムコールのみに絞り込んで
    ファジングする
    – ファジング対象を機能単位で絞り込む (できること確認済)
    • ファイルシステムやネットワークなどの⼀部の機能
    に限定してファジングする
    • ファジング関連の活動の続き
    – 4⽉末 新ネタ 投⼊ (予定)

    View Slide

  36. 36
    36
    @fujiihda
    最後に
    製品リリース前のテスト段階で
    ⾒つかる不具合数が増加し、
    リリースされる製品の品質が
    向上したらいいですね ︕︕

    View Slide

  37. ありがとうございました

    View Slide