AddressSanitizer (ASan)
AddressSanitizer(ASan)は、ソフトウェアテスト、特にファジングで広く採用されているメモリエラー検出ツールです。バッファオーバーフロー、use-after-freeエラー、その他のメモリ安全性違反など、見過ごされがちなメモリ破壊バグを検出するのに役立ちます。
概要
ASanは、メモリの脆弱性を特定する効果の高さから、ファジングにおける標準的な手法です。コンパイル時にコードを計測してメモリの割り当てとアクセスを追跡し、実行時に不正な操作を検出します。
主要な概念
| 概念 | 説明 |
|---|---|
| 計測 (Instrumentation) | ASanはコンパイル中にメモリ操作に対するランタイムチェックを追加します |
| シャドウメモリ (Shadow Memory) | 20TBの仮想メモリをマッピングして割り当て状態を追跡します |
| パフォーマンスコスト | 非計測コードと比較して約2~4倍の速度低下 |
| 検出範囲 | バッファオーバーフロー、use-after-free、ダブルフリー、メモリリークを検出 |
適用タイミング
以下の場合にこの手法を適用します:
- C/C++コードをメモリ安全性の脆弱性についてファジングする場合
- unsafeブロックを含むRustコードをテストする場合
- メモリ破壊に関連するクラッシュをデバッグする場合
- メモリエラーが疑われるユニットテストを実行する場合
以下の場合はこの手法をスキップします:
- 本番コードを実行する場合(ASanはセキュリティを低下させる可能性があります)
- プラットフォームがWindowsまたはmacOSの場合(ASanのサポートが制限されています)
- パフォーマンスオーバーヘッドが許容できない場合
- FFIを使用しない純粋な安全言語(例:純粋なGo、純粋なJava)をファジングする場合
クイックリファレンス
| タスク | コマンド/パターン |
|---|---|
| ASanを有効にする (Clang/GCC) | -fsanitize=address |
| 冗長出力を有効にする | ASAN_OPTIONS=verbosity=1 |
| リーク検出を無効にする | ASAN_OPTIONS=detect_leaks=0 |
| エラー時に強制アボート | ASAN_OPTIONS=abort_on_error=1 |
| 複数のオプション | ASAN_OPTIONS=verbosity=1:abort_on_error=1 |
ステップバイステップ
ステップ1:ASanでコンパイルする
コードを-fsanitize=addressフラグでコンパイルおよびリンクします:
clang -fsanitize=address -g -o my_program my_program.c
-gフラグは推奨されます。ASanがエラーを検出したときにより良いスタックトレースを得るためです。
ステップ2:ASanオプションを設定する
ASAN_OPTIONS環境変数を設定してASanの動作を構成します:
export ASAN_OPTIONS=verbosity=1:abort_on_error=1:detect_leaks=0
ステップ3:プログラムを実行する
ASanで計測されたバイナリを実行します。メモリエラーが検出されると、ASanは詳細なレポートを出力します:
./my_program
ステップ4:ファザーのメモリ制限を調整する
ASanは約20TBの仮想メモリを必要とします。ファザーのメモリ制限を無効にします:
- libFuzzer:
-rss_limit_mb=0 - AFL++:
-m none
一般的なパターン
パターン:基本的なASan統合
使用例: ASanを使用した標準的なファジング設定
Before:
clang -o fuzz_target fuzz_target.c
./fuzz_target
After:
clang -fsanitize=address -g -o fuzz_target fuzz_target.c
ASAN_OPTIONS=verbosity=1:abort_on_error=1 ./fuzz_target
パターン:ASanとユニットテスト
使用例: ユニットテストスイートでASanを有効にする
Before:
gcc -o test_suite test_suite.c -lcheck
./test_suite
After:
gcc -fsanitize=address -g -o test_suite test_suite.c -lcheck
ASAN_OPTIONS=detect_leaks=1 ./test_suite
高度な使用法
ヒントとコツ
| ヒント | 役立つ理由 |
|---|---|
-gフラグを使用する | デバッグ用の詳細なスタックトレースを提供します |
verbosity=1を設定する | プログラム起動前にASanが有効であることを確認します |
| ファジング中はリーク検出を無効にする | リーク検出は即座のクラッシュを引き起こさず、出力を乱雑にします |
abort_on_error=1を有効にする | 一部のファザーは_exit()の代わりにabort()を必要とします |
ASanレポートの理解
ASanがメモリエラーを検出すると、詳細なレポートを出力します。これには以下が含まれます:
- エラータイプ: バッファオーバーフロー、use-after-freeなど
- スタックトレース: エラーが発生した場所
- 割り当て/解放トレース: メモリが割り当てられ/解放された場所
- メモリマップ: エラー周辺のシャドウメモリ状態
ASanレポートの例:
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000eff4 at pc 0x00000048e6a3
READ of size 4 at 0x60300000eff4 thread T0
#0 0x48e6a2 in main /path/to/file.c:42
サニタイザーの組み合わせ
ASanは他のサニタイザーと組み合わせて包括的な検出が可能です:
clang -fsanitize=address,undefined -g -o fuzz_target fuzz_target.c
プラットフォーム固有の考慮事項
Linux: ASanをフルサポート、最高のパフォーマンス macOS: サポートは限定的、一部の機能は動作しない可能性があります Windows: 実験的サポート、本番ファジングには推奨されません
アンチパターン
| アンチパターン | 問題 | 正しいアプローチ |
|---|---|---|
| 本番環境でASanを使用する | アプリケーションのセキュリティを低下させる可能性がある | ASanはテスト専用に使用する |
| メモリ制限を無効にしない | 20TBの仮想メモリによりファザーがプロセスを強制終了する可能性がある | -rss_limit_mb=0または-m noneを設定する |
| リークレポートを無視する | メモリリークはリソース管理の問題を示す | ファジングキャンペーンの終了時にリークレポートを確認する |
ツール固有のガイダンス
libFuzzer
ファザーとアドレスサニタイザーの両方でコンパイルします:
clang++ -fsanitize=fuzzer,address -g harness.cc -o fuzz
無制限のRSSで実行します:
./fuzz -rss_limit_mb=0
統合のヒント:
-fsanitize=fuzzerと-fsanitize=addressを常に組み合わせてください- クラッシュレポートの詳細なスタックトレースには
-gを使用します - より良いクラッシュ処理のために
ASAN_OPTIONS=abort_on_error=1を検討してください
参照: libFuzzer: AddressSanitizer
AFL++
AFL_USE_ASAN環境変数を使用します:
AFL_USE_ASAN=1 afl-clang-fast++ -g harness.cc -o fuzz
無制限メモリで実行します:
afl-fuzz -m none -i input_dir -o output_dir ./fuzz
統合のヒント:
AFL_USE_ASAN=1は適切なコンパイルフラグを自動的に追加します- AFL++のメモリ制限を無効にするには
-m noneを使用します - カバレッジマップが大きいプログラムには
AFL_MAP_SIZEを検討してください
cargo-fuzz (Rust)
--sanitizer=addressフラグを使用します:
cargo fuzz run fuzz_target --sanitizer=address
または、fuzz/Cargo.tomlで設定します:
[profile.release]
opt-level = 3
debug = true
統合のヒント:
- ASanはunsafeなRustコードやFFI境界のファジングに役立ちます
- 安全なRustコードはそれほど恩恵を受けない可能性があります(コンパイラが既に多くのエラーを防ぎます)
- unsafeブロック、生ポインタ、Cライブラリのバインディングに焦点を当ててください
参照: cargo-fuzz: AddressSanitizer
honggfuzz
ASanでコンパイルし、honggfuzzとリンクします:
honggfuzz -i input_dir -o output_dir -- ./fuzz_target_asan
ターゲットをコンパイルします:
hfuzz-clang -fsanitize=address -g target.c -o fuzz_target_asan
統合のヒント:
- honggfuzzはASanとそのまま動作します
- サニタイザーと併用する場合、カバレッジ駆動モードを使用してより良いカバレッジを得てください
- ASanはメモリフットプリントを増加させるため、メモリ使用量を監視してください
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
| ファザーが即座にプロセスを強制終了する | ASanの20TB仮想メモリに対してメモリ制限が低すぎる | -rss_limit_mb=0(libFuzzer)または-m none(AFL++)を使用する |