RustでAmerican Fuzzy Lop(afl)

# はじめに
Rustでafl ([rust-fuzz/afl.rs](https://github.com/rust-fuzz/afl.rs))を使ったファジングを試してみます。
テスト対象は[woothee-rust](https://github.com/hhatto/woothee-rust)を使って説明します。

以下はテスト実行時の画面
![スクリーンショット 2017-03-11 23.30.16.png](https://qiita-image-store.s3.amazonaws.com/0/1775/c682be9c-6c3f-a4fb-40ac-6c475d29ec9f.png)

# 前提条件

| 項目 | 説明 |
|------|------------------|
| 検証日 | 2017.03.10 |
| OS   | Arch Linux (on Vagrant) |
| Rust | rustc 1.11.0-nightly (01411937f 2016-07-01) |
| afl | 0.1.5 |

rustcのバージョンはDockerに内包されているバージョンです。

# 事前準備

まずは`docker pull`でビルド&テスト環境を準備します。

```shell-session
$ docker pull corey/afl.rs
```

テスト対象のwoothee-rustをクローンしてきます。

```shell-session
$ git clone https://github.com/hhatto/woothee-rust.git
$ cd woothee-rust
```

テスト用の初期インプットデータを用意します。aflはこのデータを元に自動生成した入力値を使ってテストを行います。
テスト結果を格納するディレクトリも合わせて準備しておきます。

```shell-session
$ mkdir in
$ echo "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)" > in/basic
$ mkdir out
```

aflを使えるように`src/lib.rs`にプラグイン設定を追加します。

```diff
$ git diff src/lib.rs
diff --git a/src/lib.rs b/src/lib.rs
index fcf80c3..01967a4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,5 @@
+#![feature(plugin)]
+#![plugin(afl_plugin)]
 #![cfg_attr(feature="clippy", feature(plugin))]
 #![cfg_attr(feature="clippy", plugin(clippy))]
```

以下のようなテスト本体の`src/main.rs`を準備します。

```rust
#![feature(plugin)]
#![plugin(afl_plugin)]

extern crate afl;
extern crate woothee;

use woothee::parser::Parser;

fn main() {
    afl::handle_string(|s| {
        let p = Parser::new();
        let _ = p.parse(s.as_str());
    })
}
```

# Docker起動とビルド

以降、`#`はDockerのセッションです。

```shell-session
$ docker run -v $(pwd):/source -it corey/afl.rs sh
# afl-fuzz --version
afl-fuzz 2.34b by <lcamtuf@google.com>
     :
# ls
Cargo.lock  Cargo.toml	LICENSE  README.md  benches  build.rs  in  out	rustfmt.toml  src  target  templates  tests
# rustc --version
rustc 1.11.0-nightly (01411937f 2016-07-01)
# cargo build
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading regex v0.2.1
 Downloading lazy_static v0.2.4
 Downloading afl-plugin v0.1.5
 Downloading afl v0.1.5
 Downloading utf8-ranges v1.0.0
 Downloading regex-syntax v0.4.0
 Downloading memchr v1.0.1
 Downloading aho-corasick v0.6.2
 Downloading thread_local v0.3.3
 Downloading libc v0.2.21
 Downloading unreachable v0.1.1
 Downloading void v1.0.2
 Downloading gcc v0.3.43
 Downloading quale v1.0.0
 Downloading afl-sys v0.1.5
 Downloading thread-id v3.0.0
   Compiling woothee v0.6.0 (file:///source)
afl-llvm-pass by <lszekeres@google.com>
Instrumented 5527 locations (non-hardened mode, ratio 100%).
afl-llvm-pass by <lszekeres@google.com>
Instrumented 429 locations (non-hardened mode, ratio 100%).
# file target/release/woothee
target/release/woothee: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=7823c4b40102920f31d08a2636cab6400e000d62, not stripped
# 
```

# テスト実行

`afl-fuzz`を使ってテストを実行してみます。


# 実行イメージ

```shell-session
afl-fuzz 2.34b by <lcamtuf@google.com>
[+] You have 4 CPU cores and 3 runnable tasks (utilization: 75%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'in'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:basic'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
    len = 64, map size = 2078, exec speed = 6858 us
[!] WARNING: Instrumentation output varies across runs.
[+] All test cases processed.

[+] Here are some useful stats:

    Test case count : 1 favored, 1 variable, 1 total
       Bitmap range : 2078 to 2078 bits (average: 2078.00 bits)
        Exec timing : 6858 to 6858 us (average: 6858 us)

[*] No -t option specified, so I'll use exec timeout of 40 ms.
[+] All set and ready to roll!
```

上記のような出力のあとに、冒頭のような画面になればテスト実行ができたことになります。

# はまったところなど

## `afl-fuzz`が実行できない
```shell-session
# afl-fuzz -i in -o out target/release/woothee
afl-fuzz 2.39b by <lcamtuf@google.com>
[+] You have 2 CPU cores and 2 runnable tasks (utilization: 100%).
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...

[-] Hmm, your system is configured to send core dump notifications to an
    external utility. This will cause issues: there will be an extended delay
    between stumbling upon a crash and having this information relayed to the
    fuzzer via the standard waitpid() API.

    To avoid having crashes misinterpreted as hangs, please log in as root
    and temporarily modify /proc/sys/kernel/core_pattern, like so:

    echo core >/proc/sys/kernel/core_pattern

[-] PROGRAM ABORT : Pipe at the beginning of 'core_pattern'
         Location : check_crash_handling(), afl-fuzz.c:7194
```

上記のようなエラーが出た場合はcoreファイル出力の設定が必要なので、以下のどちらかの手順で実行します。

### 環境変数`AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES`を有効にして`afl-fuzz`を実行する

```shell-session
$ AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=true afl-fuzz -i in -o out target/release/woothee
```

[ここに環境変数の一覧](https://github.com/mirrorer/afl/blob/master/docs/env_variables.txt)があり、色々動作を調整できそうです。

### `/proc/sys/kernel/core_pattern`を書き換えて適切にcoreファイルを出力できるように設定

```shell-session
$ echo "core" > /proc/sys/kernel/core_pattern
$ afl-fuzz -i in -o out target/release/woothee
```

## テスト実行が遅い

`cargo build --release`してリリースビルドでテストすると良さそう

## debug情報が必要？
[American Fuzzy Lop’ing Rust](http://blog.troutwine.us/2017/01/06/american-fuzzy-loping-rust/)あたりを見ると

```toml
[profile.release]
debug = true
```
を追加していたりしますね。本当に必要かどうかは不明。。。

# 参考
* [ご注文は American Fuzzy Lop ですか？ - Qiita](http://qiita.com/binzume/items/8e985e7bd01a6e4000d3)
* [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) ... AFLとは別のファザー[libFuzzer](http://llvm.org/docs/LibFuzzer.html)を使えるcargo拡張

# 最後に

以上です。よいファジングライフを!!