Linuxカーネルのファジングツールsyzkaller / Linux kernel fuzzing tool syzkaller

Dd7fa413be25d8672c03a487db6a8fe6?s=47 fujiihda
December 13, 2019

Linuxカーネルのファジングツールsyzkaller / Linux kernel fuzzing tool syzkaller

syzkaller/syzbot は、2 年で 1500 件以上の Linux カーネルの不具合修正に貢献しています。自らが生成した複数の仮想マシンに対して問題の起きそうな入力を送り続けることで未発見の不具合を発見します。最小限の入力で不具合を再現させるための再試行を繰り返し、最終的には不具合を再現するための C 言語のプログラム生成を試みます。

syzkaller の概要
syzkaller のドキュメント調査結果
syzkaller のソースコード調査結果
syzkaller の動作確認結果 (未発見の不具合の発見)

Dd7fa413be25d8672c03a487db6a8fe6?s=128

fujiihda

December 13, 2019
Tweet

Transcript

  1. © 2019 NTT DATA Corporation 2019年12月13日 株式会社NTTデータ 藤井 秀行 Linux

    カーネルのファジングツール syzkaller
  2. © 2019 NTT DATA Corporation 2 Whois セキュリティ専門家でもなく、カーネル分野で突出してもいないけれど、いろいろできる 名前 •

    藤井 秀行 (ふじい ひでゆき) 業務経歴 • 入社以来 OSS に関わる業務を担当 • 最近はパブリッククラウド (GCP等) で コンテナしつつ、技術系コミュニティの オーガナイザ 直近 1 年くらいの主なアウトプット • RHEL 8 の新機能と検証結果の紹介 • Linux 特権機能使用制御技術 ~コンテナセキュリティ~ • コンテナ管理ツール機能調査 ~Podman~ • Container-native Virtualization ~コンテナの中で無理やり仮想マシンを動かす~ 年度 案件名 技術 2013- 2015 Hinemos Hinemos と Hinemos が含む OSS 全般、 各社ハイパーバイザとクラウド、Linux 全般 2016- 2017 某OSSセンタ ユーザサポート ほぼすべての OSS ミドルウェア全般を広く 浅く、Linux 全般 2018- 2019.9 某OSSセンタ OS 担当 Linux カーネル、コンテナ技術、NFS 2019.10- new クラウド技術 センタ パブリッククラウド全般、コンテナ技術、 マイグレーション技術、 SRE ???
  3. © 2019 NTT DATA Corporation 3 掲載内容は個人の見解であり、 所属する企業やコミュニティの立場、 戦略、意見を代表するものではありません はじめに

  4. © 2019 NTT DATA Corporation 4 • 社内ネットワークではやらないでください • 社内のマシンではやらないでください

    • プライベート環境などの完全に隔離された 環境で自己責任でやってください 警告
  5. © 2019 NTT DATA Corporation 5 本日の流れ 1. 背景 2.

    テーマ選定 3. 実施内容 4. ドキュメント調査 5. ソースコード調査 6. syzkaller の動作確認 7. まとめ 8. 個人的な振り返り 9. 今後 時間の都合上ここに注力
  6. © 2019 NTT DATA Corporation 6 背景 (ファジングと Linux のセキュリティ品質向上)

    • ファジングは未知の不具合や脆弱性の検出に適したテスト手法 – 検査対象にランダムな入力データを送ることで意図的に例外を発生させる • ファジングがセキュリティ品質に与える影響が話題に – Open Source Summit Japan 2019 では、カーネルのリードメンテナなどの複数講演者がファジングの貢献に言及 • 2017 年前後を境としてファジングをはじめとする自動化された高度なテスト技術が普及 • リリース前にセキュリティ脆弱性が修正されるようになり CVE の件数は減少傾向 0 100 200 300 400 500 600 700 800 900 1000 0 2000 4000 6000 8000 10000 12000 14000 16000 18000 20000 2012 2013 2014 2015 2016 2017 2018 2019 全体 Linux (件) (件) (年) (予測) 図:ソフトウェア全体および Linux の CVE 件数の推移
  7. © 2019 NTT DATA Corporation 7 テーマ選定 • 選定理由 –

    カーネルの世界に大きな影響を与えたわりに情報がない (特に日本語は皆無) • 最新技術が投入されているはずの仕組み、設計、実装に興味がある • 使われている技術や考え方が他分野に転用可能かもしれない – syzkaller を通じてカーネルのエンジニアとしてレベルアップしたい • syzkaller で発見したカーネルの不具合修正には逆アセンブルが有効なことも
  8. © 2019 NTT DATA Corporation 8 • ドキュメント調査 (英語) –

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

  10. © 2019 NTT DATA Corporation 10 ドキュメント調査 - ファジング技術の肝 •

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

    • Google の Dmitry Vyukov さんによって開発された カーネルのファジングツール • 2 年間でカバレッジを 7 %カバーした時点で 、 1500 件以上のカーネルの不具合修正に貢献 • 特徴 – ハイブリッドな仕組みにより効率良くシステムコールの シーケンスを生成 • 攻撃対象プロトコル (システムコール) のテンプ レートが実装されている • ソースコードのコンパイル時にコンパイラが出力 するカバレッジを利用して入力を変える – 不具合発見の一連の流れがほぼすべて自動化 • 自らが生成した複数の試験対象の仮想マシンに 対して問題の起きそうな入力を送り続けて、 デバッグ支援機構を活用してその挙動を観測 • 発見した不具合を最小限の入力で再現させる ための再試行を自ら繰り返し、不具合を再現する ための C 言語のプログラム生成を試みる 図: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 各構成要素の詳細は 次ページから解説
  12. © 2019 NTT DATA Corporation 12 (参考) ドキュメント調査 - Sanitizer

    とは • カーネルに存在する複数のデバッグ支援機構 – 動的テストツール – コンパイラの機能 (gcc および C 言語で利用可能) – メモリを破壊したことや違反したことなどをはっきり示すもの – 不具合を示してくれるのでファジングを補助してくれる – エラーが起きたら、エラーの深刻度に関わらず、 カーネルパニックを発生させる設定を使用する*1 (コンソールにパニックメッセージを出力) • syzkaller で使用している主な Sanitizer – KASAN (Kernel Address Sanitizer) • メモリアクセスエラーを検出 – KMSAN (Kernel Memory Sanitizer) • 初期化されていない読み取りを検出 – KTSAN (Kernel Thread Sanitizer) • 異なるスレッド間のデータの競合状態を検出 – UBSAN (Undefined Behavior Sanitizer) • 未定義の動作を引き起こす機能の使用を検出 ユーザ空間 カーネル 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 操作 図:syzkaller の構成図 *1 厳密には warning などの文字列を syzkaller が検出し、カーネルパニック前に止めることもある
  13. © 2019 NTT DATA Corporation 13 (参考) ドキュメント調査 - KCOV

    (Kernel Code Coverage) とは • コンパイラ (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 操作 図:syzkaller の構成図 __fuzz_coverage(); if (...) { __fuzz_coverage(); ... } __fuzz_coverage(); if (...) { ... } 図:KCOV 無効時と KCOV 有効時のイメージ
  14. © 2019 NTT DATA Corporation 14 ドキュメント調査 - syzkaller の全体像

    • syz-manager – 仮想化ホスト上に存在するプロセス – 試験対象としての VMs の管理 (起動、監視、再起動) • この VMs はカーネルパニックのたびに再起動 – 試験対象としての VMs 内で syz-fuzzer プロセスを起動 – syz-fuzzer プロセスに指示を送る – workdir 上のコーパスとクラッシュ (次ページで説明) を更新 ユーザ空間 カーネル 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 操作 図:syzkaller の構成図
  15. © 2019 NTT DATA Corporation 15 ドキュメント調査 - 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/* – コーパスは個別ファイルとして格納されているファズターゲット の入力セット – 理想的なコーパスは最大限のコードカバレッジを提供する 最小限の入力セット ユーザ空間 カーネル 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 操作 図:syzkaller の構成図
  16. © 2019 NTT DATA Corporation 16 ドキュメント調査 - syzkaller の全体像

    • syz-fuzzer – 先述の不安定な試験対象 VMs 内に存在するプロセス – テストケース (入力) を生成、突然変異、最小化 – 任意の数の syz-executor プロセスを起動 – コーパスで入力を変える??? → ドキュメント調査だけでは、なにをいっているのか いまいちわからなかった・・・ ソースコードを調査した結果: コーパスの有無で条件分岐して Generate 関数 もしくは Mutate 関数のいずれかを呼び出すことで システムコールのシーケンスを決める (詳細はソースコードを追いかけるときに説明) ユーザ空間 カーネル 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 操作 図:syzkaller の構成図
  17. © 2019 NTT DATA Corporation 17 ドキュメント調査 - syzkaller の全体像

    • syz-executor – 先述の不安定な試験対象 VMs 内に任意の個数存在するプロセス – syz-fuzzer から syscalls のシーケンスを受け取る – syscalls のシーケンスを実行する – syscalls の実行結果を syz-fuzzer に送り返す – 単一の executor プロセスのことを Proc とも呼ぶ • Proc がカーネルに送るデータは ProgData とも呼ぶ ユーザ空間 カーネル 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 操作 図:syzkaller の構成図
  18. © 2019 NTT DATA Corporation 18 ソースコード調査

  19. © 2019 NTT DATA Corporation 19 ソースコード調査 - どの処理を深く調べるか •

    一連の流れのなかで面白そうな処理 (核となる 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 ユーザ空間 カーネル 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 の構成図 1 2
  20. © 2019 NTT DATA Corporation 20 ソースコード調査 - fuzzer (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() } ユーザ空間 カーネル 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 操作 引数として与えた FlagProcs の数だけ Proc (executor の プロセス) を生成 ゴルーチン (Go 言語で 言語仕様として提供され る並列処理の機能) で syz-fuzzer/proc.go の loop 関数を呼び出す https://github.com/google/syzkaller/blob/master/syz-fuzzer/fuzzer.go # ./bin/syz-manager -config my.cfg 図:syzkaller の構成図 1
  21. © 2019 NTT DATA Corporation 21 ソースコード調査 - executor (syz-fuzzer/proc.go)

    ユーザ空間 カーネル 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 操作 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) } } } https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go コーパス (ファズターゲット の入力セット) の有無で条 件分岐して、次のいずれか の関数を呼び出す Generate 関数 を呼び、引数 StatGenerate で execute 関 数を呼ぶ Mutate 関数を 呼び、引数 StatFuzz で execute 関数 を呼ぶ 図:syzkaller の構成図 2
  22. © 2019 NTT DATA Corporation 22 ソースコード調査 - executor (syz-fuzzer/proc.go)

    ユーザ空間 カーネル 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 操作 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 } https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go executeRaw 関数を呼び 出す 図:syzkaller の構成図 2
  23. © 2019 NTT DATA Corporation 23 ソースコード調査 - executor (syz-fuzzer/proc.go)

    ユーザ空間 カーネル 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 操作 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 } } https://github.com/google/syzkaller/blob/master/syz-fuzzer/proc.go env.Exec 関数 を呼び出す 図:syzkaller の構成図 2
  24. © 2019 NTT DATA Corporation 24 ソースコード調査 - executor (pkg/ipc/ipc.go)

    ユーザ空間 カーネル 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 操作 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) (以下省略) https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go makeCommand 関数を呼び出す 図:syzkaller の構成図 2
  25. © 2019 NTT DATA Corporation 25 ソースコード調査 - executor (pkg/ipc/ipc.go)

    ユーザ空間 カーネル 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 操作 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 (以下省略) https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go osutil.Command で executor 実行 executor の標準 入力を os のパイ プにつなぐ 入出力リダイレクト 図:syzkaller の構成図 2
  26. © 2019 NTT DATA Corporation 26 ソースコード調査 - executor (pkg/ipc/ipc.go)

    ユーザ空間 カーネル 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 操作 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 } } https://github.com/google/syzkaller/tree/master/pkg/ipc/ipc.go progData を 継続して送る 図:syzkaller の構成図 2
  27. © 2019 NTT DATA Corporation 27 syzkaller の動作確認

  28. © 2019 NTT DATA Corporation 28 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 分程で不具合 らしいものを発見 クラッシュ時に 事象を取り逃す こともある 同上 再現を試みる
  29. © 2019 NTT DATA Corporation 29 # cat bd744ffeabd8fcd8ae152d0c44dde8112311663f/repro.cprog //

    autogenerated by syzkaller (https://github.com/google/syzkaller) #define _GNU_SOURCE #include <endian.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> 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; } syzkaller の動作確認 - 前ページの事象を再現する C 言語のプログラム autogenerated by syzkaller
  30. © 2019 NTT DATA Corporation 30 まとめ、振り返り、今後

  31. © 2019 NTT DATA Corporation 31 まとめ • ドキュメント調査 (英語)

    – 公式ドキュメントの調査 – 開発者による講演資料 / 講演映像の調査 – 学術論文の調査 – セキュリティカンファレンスの講演資料 / 講演映像の調査 – コミュニティの調査 (開発者の SNS 等を含む) • ソースコード調査 (ほぼ Go 言語) – Go 言語の言語仕様の差異の把握 – Go 言語の開発環境構築および手順の確立 – 全体構成把握および関数名とコメント文の斜め読み – 処理の順にソースコードの関数を追いかける • syzkaller の動作確認 (未発見の不具合の発見) – 環境構築および構築手順の確立 – ファジング実行と挙動の確認 – カーネルの I/O スケジューラに関連する use-after-free の 新規不具合の発見 – 再現用の C 言語のプログラム生成 全体像、各種構成要素、 大まかな処理の流れ の解明 ソースコードにしかない 動作の仕組みや細かい 処理の流れを解明 動かして理解しつつ 未発見の不具合を探す 完 完 完
  32. © 2019 NTT DATA Corporation 32 個人的な振り返り (自分向け教訓) • 知識ゼロから知らない言語の処理を追うときこそ急がば回れ

    – いきなりソースコード斜め読みは精神的に辛い (熟練者向けなので個人的にはおすすめしない) – たとえ遠回りに見えても、以下からはじめるとよい • 開発環境構築 • 言語仕様把握 • 各コンポーネントの役割や処理の流れを把握 • 実機による簡単な動作確認 • 不具合は常に最新版で探し、見つけたら放置せずに即直せ – カーネルの不具合は、(素晴らしいことだが) 見つけたらすぐに直さないと、誰かが修正する (c3e2219216c92919a6bd1711f340f5faa98695e6) – 長期間放置されている不具合は、発生条件が不明確なものや修正が困難なものばかり (https://syzkaller.appspot.com/upstream)
  33. © 2019 NTT DATA Corporation 33 今後 • これから調べたい –

    テストケース (入力) を生成する仕組みのさらなる深掘り • テストケース (入力) の最小化 • テストケース (入力) の突然変異 – ファジング対象をシステムコール単位で絞り込む (できること確認済) • クラウドで提供されるマネージドなコンテナサービスは、 システムコールが限定されていることがあり、 その制限で有効なシステムコールのみに絞り込んで ファジングする – ファジング対象を機能単位で絞り込む (できること確認済) • ファイルシステムやネットワークなどの一部の機能 に限定してファジングする • 今日のファジングネタの続き – 4月 にやります!(昨日急遽決定) – テーマ: Nested Virtualization のできる某クラウドベンダの マシンリソースでお金をかけずにごりごりファジングする話 (仮)
  34. © 2019 NTT DATA Corporation 34 • 社内ネットワークではやらないでください • 社内のマシンではやらないでください

    • プライベート環境などの完全に隔離された 環境で自己責任でやってください 警告 (再)
  35. © 2019 NTT DATA Corporation

  36. © 2019 NTT DATA Corporation 36 (参考) my.cfg # cat

    my.cfg { "target": "linux/amd64", "http": "127.0.0.1:56741", "workdir": "/root/gopath/src/github.com/google/syzkaller/workdir", "kernel_obj": "/root/kernel", "image": "/root/wheezy.img", "sshkey": "/root/wheezy.img.key", "syzkaller": "/root/gopath/src/github.com/google/syzkaller", "procs": 8, "type": "qemu", "vm": { "count": 4, "kernel": "/root/kernel/arch/x86/boot/bzImage", "cpu": 4, "mem": 4096 } }
  37. © 2019 NTT DATA Corporation 37 (参考) バージョン • syzkaller:bfb4a51e30c8c04658a2675333b9b89a9d327c4a

    など (その時の最新版) • gcc:gcc-9.0.0-20181231.tar.gz • Go 言語:go1.8.1.linux-amd64.tar.gz • kernel:788a024921c48985939f8241c1ff862a7374d8f9 など (その時の最新版)
  38. © 2019 NTT DATA Corporation 38 (参考) 検出した不具合と不具合らしきもの