ファジングはベータ版として利用可能に

Fuzzing is Beta Ready by Katie Hockman and Jay Conrod

ネイティブファジングがtip上でベータテストの準備が整ったことを発表できてうれしく思います。

ファジングは、パニックやバグなどの問題を見つけるために、プログラムへの入力を継続的に操作する自動テストの一種です。 この半ランダムなデータの変異によって、既存のユニットテストでは見逃してしまうような新しいコードカバレッジを 発見したり、そうでなければ気づかれないままになるエッジケースのバグを明らかにしたりできます。ファジングは こうしたエッジケースに到達できるため、ファズテストはセキュリティ上の攻撃可能な脆弱性を見つけるうえで 特に有用です。

この機能についての詳細は golang.org/s/draft-fuzzing-design を 参照してください。

はじめる

はじめるには、次のコマンドを実行します。

$ go install golang.org/dl/gotip@latest
$ gotip download

これによってmasterブランチからGoツールチェインがビルドされます。これを実行した後は、gotipgo コマンドの代替としてそのまま使えます。これで次のようなコマンドを実行できるようになります。

$ gotip test -fuzz=Fuzz

ファズテストを書く

ファズテストは *_test.go ファイル内に FuzzXxx という形式の関数として書く必要があります。この関数には、 TestXxx 関数に *testing.T 引数が渡されるのと同じように、*testing.F 引数を渡す必要があります。

以下は、net/urlパッケージの振る舞いをテストするファズテストの例です。

//go:build go1.18
// +build go1.18

package fuzz

import (
    "net/url"
    "reflect"
    "testing"
)

func FuzzParseQuery(f *testing.F) {
    f.Add("x=1&y=2")
    f.Fuzz(func(t *testing.T, queryStr string) {
        query, err := url.ParseQuery(queryStr)
        if err != nil {
            t.Skip()
        }
        queryStr2 := query.Encode()
        query2, err := url.ParseQuery(queryStr2)
        if err != nil {
            t.Fatalf("ParseQuery failed to decode a valid encoded query %s: %v", queryStr2, err)
        }
        if !reflect.DeepEqual(query, query2) {
            t.Errorf("ParseQuery gave different query after being encoded\nbefore: %v\nafter: %v", query, query2)
        }
    })
}

ファジングについての詳細はpkg.go.devで読めます。Goにおけるファジングの概要や、 新しいtesting.F型のgodocなどがあります。

期待されること

これはまだベータ版の新機能なので、いくつかのバグや機能の不足があることを想定しておいてください。既存の バグや不足している機能について最新情報を確認するには、「fuzz」ラベルが付いたissueを 確認してください。

ファジングは実行中に多くのメモリを消費し、マシンのパフォーマンスに影響を与える可能性があることに 注意してください。go test -fuzz はデフォルトで $GOMAXPROCS 個のプロセスを並列に実行してファジングを 行います。go test に明示的に -parallel フラグを指定することで、ファジング中に使用するプロセス数を 減らせます。詳しい情報が必要な場合は、gotip help testflag を実行して go test コマンドのドキュメントを 確認してください。

また、ファジングエンジンは実行中に、テストカバレッジを広げる値を $GOCACHE/fuzz 内のファズキャッシュ ディレクトリに書き込むことにも注意してください。現時点ではファズキャッシュに書き込まれるファイル数や 総バイト数に制限がないため、大量のストレージ(数GB程度)を占有する可能性があります。 gotip clean -fuzzcache を実行することでファズキャッシュをクリアできます。

この先の予定

この機能はGo 1.18から利用可能になる予定です。

問題が発生した場合や機能についてのアイデアがある場合は、issueを作成してください。

この機能についての議論や一般的なフィードバックについては、Gophers Slackの #fuzzingチャンネル にも参加できます。

楽しいファジングを!

By Katie Hockman and Jay Conrod