address-sanitizer について
AddressSanitizer(ASan)は、テストやファジングでメモリエラーを検出するコンパイル時インストルメンテーション技術です。実行時レポートで、バッファーオーバーフローや解放後使用などを特定できます。
主な機能
- 01メモリー操作へのコンパイル時インストルメンテーション
- 02オーバーフローや解放後使用の検出
- 03割り当て情報とスタックトレースの報告
- 04ASAN_OPTIONSによる動作設定
- 05複数のファザーとの連携
活用シーン
- 01C/C++プログラムのメモリエラー検出
- 02unsafeコードを含むRustプロジェクトのテスト
- 03ユニットテストでのメモリー破損の特定
- 04ファジングで見つかったクラッシュの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills --skill address-sanitizerインストール後、Claude Code で/address-sanitizerを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlassets/trail-of-bits-mark.svg
詳細
AddressSanitizer(ASan)
AddressSanitizer(ASan)は、ソフトウェアテスト、特にファジングで広く使用されている、メモリエラー検出ツールです。バッファーオーバーフロー、解放後使用エラー、その他のメモリー安全性違反など、見過ごされる可能性のあるメモリー破損のバグを検出できます。
概要
ASan はメモリー脆弱性の特定に効果的なため、ファジングで標準的に使用されています。コンパイル時にコードを計測し、メモリー割り当てとアクセスを追跡することで、実行時に不正な操作を検出します。
主な概念
| 概念 | 説明 |
|---|---|
| 計測 | ASan はコンパイル時にメモリー操作へ実行時チェックを追加します |
| シャドーメモリー | 割り当て状態を追跡するために、20TB の仮想メモリーをマッピングします |
| パフォーマンスコスト | 計測されていないコードと比較して約 2〜4 倍遅くなります |
| 検出範囲 | バッファーオーバーフロー、解放後使用、二重解放、メモリーリークを検出します |
適用するタイミング
この手法を適用する場合:
- メモリー安全性の脆弱性を探すために 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
ASan がエラーを検出した際に、より詳しいスタックトレースを取得するため、-g フラグの使用を推奨します。
ステップ 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 を使用する標準的なファジング設定
変更前:
clang -o fuzz_target fuzz_target.c
./fuzz_target
変更後:
clang -fsanitize=address -g -o fuzz_target fuzz_target.c
ASAN_OPTIONS=verbosity=1:abort_on_error=1 ./fuzz_target
パターン:単体テストでの ASan
用途: 単体テストスイートで ASan を有効にする
変更前:
gcc -o test_suite test_suite.c -lcheck
./test_suite
変更後:
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 がメモリーエラーを検出すると、次の情報を含む詳細なレポートを出力します。
- エラーの種類:バッファーオーバーフロー、解放後使用など
- スタックトレース:エラーが発生した場所
- 割り当て/解放のトレース:メモリーが割り当て/解放された場所
- メモリーマップ:エラー周辺のシャドーメモリーの状態
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の使用を検討します
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 ブロック、raw ポインター、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++)を使用します |
| 「ASan runtime not initialized」 | リンク順序が間違っているか、ランタイムがありません | コンパイル時とリンク時の両方で -fsanitize=address が使われていることを確認します |
| リークレポートで出力が埋まる | LeakSanitizer がデフォルトで有効になっています | ASAN_OPTIONS=detect_leaks=0 を設定します |
| パフォーマンスが低い(4 倍以上の速度低下) | デバッグモードまたは最適化されていないビルドです | -fsanitize=address とともに -O2 または -O3 を指定してコンパイルします |
| ASan が明らかなバグを検出しない | バイナリが計測されていません | ASAN_OPTIONS=verbosity=1 を指定し、ASan が起動情報を出力することを確認します |
| 誤検知 | インターセプターの競合です | 特定のライブラリで既知の問題がないか、ASan FAQ を確認します |
関連スキル
この手法を使用するツール
| スキル | 適用方法 |
|---|---|
| libfuzzer | -fsanitize=fuzzer,address を指定してコンパイルすると、メモリエラー検出機能を備えたファジングを統合できます |
| aflpp | コンパイル時に AFL_USE_ASAN=1 環境変数を使用します |
| cargo-fuzz | --sanitizer=address フラグを使用して、Rust のファズターゲットで ASan を有効にします |
| honggfuzz | ASan で計測されたファジングを行うには、-fsanitize=address を指定してターゲットをコンパイルします |
関連手法
| スキル | 関係 |
|---|---|
| undefined-behavior-sanitizer | 包括的なバグ検出(未定義動作とメモリエラー)のために、ASan と併用されることがよくあります |
| fuzz-harness-writing | ハーネスは、ASan が検出したクラッシュを処理し、誤検知を避けられるように設計する必要があります |
| coverage-analysis | カバレッジガイド付きファジングは、ASan がメモリエラーを検出できるコードパスの実行に役立ちます |
リソース
主な外部リソース
Google Sanitizers Wiki の AddressSanitizer
ASan の公式ドキュメントでは、以下の内容を扱っています:
- アルゴリズムと実装の詳細
- 検出されるエラータイプの完全なリスト
- パフォーマンス特性とオーバーヘッド
- プラットフォーム固有の動作
- 既知の制限と非互換性
すべてのサニタイザーで共有される共通の設定フラグ:
verbosity:診断出力レベルを制御しますlog_path:サニタイザーの出力をファイルにリダイレクトしますsymbolize:レポート内のシンボル解決を有効化/無効化しますexternal_symbolizer_path:カスタムシンボライザーを使用します
ASan 固有の設定オプション:
detect_leaks:メモリリーク検出を制御しますabort_on_error:エラー時にabort()を呼び出すか_exit()を呼び出すかを指定しますdetect_stack_use_after_return:スタックの use-after-return バグを検出しますcheck_initialization_order:初期化順序のバグを検出します
よくある落とし穴と解決策:
- リンク順序の問題
- 他のツールとの競合
- プラットフォーム固有の問題
- パフォーマンスチューニングのヒント
Clang 固有のガイダンス:
- コンパイルフラグとオプション
- 他の Clang 機能との相互作用
- サポートされているプラットフォームとアーキテクチャ
GCC 固有の ASan ドキュメント:
- GCC 固有のフラグと動作
- Clang 実装との違い
- GCC におけるプラットフォームサポート
AddressSanitizer: A Fast Address Sanity Checker (USENIX 論文)
技術的な詳細を含む原著論文:
- シャドウメモリのアルゴリズム
- 仮想メモリ要件(歴史的には 16TB、現在は約 20TB)
- パフォーマンスベンチマーク
- 設計上の決定とトレードオフ