Slide 1

Slide 1 text

© 2019 NTT DATA Corporation 2019年12月13日 株式会社NTTデータ 藤井 秀行 Linux カーネルのファジングツール syzkaller

Slide 2

Slide 2 text

© 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 ???

Slide 3

Slide 3 text

© 2019 NTT DATA Corporation 3 掲載内容は個人の見解であり、 所属する企業やコミュニティの立場、 戦略、意見を代表するものではありません はじめに

Slide 4

Slide 4 text

© 2019 NTT DATA Corporation 4 • 社内ネットワークではやらないでください • 社内のマシンではやらないでください • プライベート環境などの完全に隔離された 環境で自己責任でやってください 警告

Slide 5

Slide 5 text

© 2019 NTT DATA Corporation 5 本日の流れ 1. 背景 2. テーマ選定 3. 実施内容 4. ドキュメント調査 5. ソースコード調査 6. syzkaller の動作確認 7. まとめ 8. 個人的な振り返り 9. 今後 時間の都合上ここに注力

Slide 6

Slide 6 text

© 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 件数の推移

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

© 2019 NTT DATA Corporation 9 ドキュメント調査 (論文等のサーベイ)

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

© 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 各構成要素の詳細は 次ページから解説

Slide 12

Slide 12 text

© 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 が検出し、カーネルパニック前に止めることもある

Slide 13

Slide 13 text

© 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 有効時のイメージ

Slide 14

Slide 14 text

© 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 の構成図

Slide 15

Slide 15 text

© 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 の構成図

Slide 16

Slide 16 text

© 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 の構成図

Slide 17

Slide 17 text

© 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 の構成図

Slide 18

Slide 18 text

© 2019 NTT DATA Corporation 18 ソースコード調査

Slide 19

Slide 19 text

© 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

Slide 20

Slide 20 text

© 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

Slide 21

Slide 21 text

© 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

Slide 22

Slide 22 text

© 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

Slide 23

Slide 23 text

© 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

Slide 24

Slide 24 text

© 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

Slide 25

Slide 25 text

© 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

Slide 26

Slide 26 text

© 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

Slide 27

Slide 27 text

© 2019 NTT DATA Corporation 27 syzkaller の動作確認

Slide 28

Slide 28 text

© 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 分程で不具合 らしいものを発見 クラッシュ時に 事象を取り逃す こともある 同上 再現を試みる

Slide 29

Slide 29 text

© 2019 NTT DATA Corporation 29 # 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; } syzkaller の動作確認 - 前ページの事象を再現する C 言語のプログラム autogenerated by syzkaller

Slide 30

Slide 30 text

© 2019 NTT DATA Corporation 30 まとめ、振り返り、今後

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

© 2019 NTT DATA Corporation 34 • 社内ネットワークではやらないでください • 社内のマシンではやらないでください • プライベート環境などの完全に隔離された 環境で自己責任でやってください 警告 (再)

Slide 35

Slide 35 text

© 2019 NTT DATA Corporation

Slide 36

Slide 36 text

© 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 } }

Slide 37

Slide 37 text

© 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 など (その時の最新版)

Slide 38

Slide 38 text

© 2019 NTT DATA Corporation 38 (参考) 検出した不具合と不具合らしきもの