Hardware Assisted AddressSanitizer(HWASan)は AddressSanitizer(ASan)に似たメモリエラー検出ツールです。HWASan は ASan と比較して RAM の使用量がはるかに少ないため、システム全体のサニタイズに適しています。HWASan は Android 10 以降および AArch64 ハードウェアでのみ使用できます。
HWASan は主に C/C++ コードに有用ですが、Java インターフェースの実装に使用される C/C++ でクラッシュを引き起こす Java コードのデバッグにも役立ちます。クラッシュ発生時にメモリエラーが検出されるため、レスポンス コードを直接確認することができます。
ci.android.com からサポート対象の Pixel デバイスにビルド済みの HWASan イメージを書き込めます(詳細な設定手順)。
従来の ASan と比較した HWASan の特徴を次に示します。
- CPU オーバーヘッドは同程度(~2 倍)
- コードサイズ オーバーヘッドは同程度(40~50%)
- RAM オーバーヘッドは大幅に少ない(10~35%)
HWASan は ASan と同じ種類のバグを検出します。
- スタックとヒープのバッファ オーバーフロー / アンダーフロー
- 解放後のヒープ使用
- スコープ外のスタック使用
- 二重解放 / ワイルド解放
さらに、HWASan は返却後のスタック使用を検出します。
実装の詳細と制限
HWASan はメモリのタグ付けアプローチに基づいており、小さなランダムタグ値がポインタとメモリアドレス範囲の両方に関連付けられます。メモリアクセスが有効になるには、ポインタとメモリタグが一致する必要があります。HWASan は ARMv8 の TBI(Top Byte Ignore)機能に依存します。この機能は仮想アドレスタグ付けとも呼ばれ、ポインタタグをアドレスの上位ビットに格納します。
HWASan の設計の詳細については、Clang のドキュメント サイトをご覧ください。
設計上、HWASan には、オーバーフローを検出する ASan のサイズ制限レッドゾーンと、解放後の使用を検出する ASan の容量制限検疫機能はありません。したがって、HWASan はオーバーフローのサイズ、またはメモリが割り当て解除されてからの経過時間に関係なくバグを検出できます。この点で HWASan には ASan よりも大きな利点があります。
ただし、HWASan では使用可能なタグ値が 256 個に制限されているため、プログラムの 1 回の実行でバグを見落とす確率が 0.4% あります。
要件
HWASan は、システムコール引数でタグ付きポインタを受け入れる Linux カーネルを必要とします。このことに対するサポートは、次のアップストリーム パッチセットで実装されています。
- arm64 タグが付けられたアドレス ABI
- arm64: カーネルに渡されるユーザー ポインタのタグを解除する
- mm: brk()/mmap()/mremap() での仮想アドレス エイリアスの作成を回避する
- arm64: カーネル スレッドから呼び出される、access_ok() でタグ付けされたアドレスを検証する
これらのパッチは、android-4.14 以降のブランチの共通 Android カーネルでバックポートとして使用できますが、Android 10 固有のブランチ(android-4.14-q など)では使用できません。
HWASan 用のユーザー空間サポートは、Android 11 以降でご利用いただけます。
カスタム ツールチェーンを使用してビルドする場合は、LLVM commit c336557f までのすべての要素が含まれていることを確認してください。
HWASan の使用
HWASan を使用してプラットフォーム全体をビルドするには、次のコマンドを実行します。
lunch aosp_walleye-userdebug # (or any other product)
export SANITIZE_TARGET=hwaddress
m -j
便宜上、aosp_coral_hwasan の場合と同様に、SANITIZE_TARGET 設定をプロダクト定義に追加できます。
ASan と異なり、HWASan では 2 回のビルドは必要ありません。増分ビルドは正常に機能します。特別なフラッシュ命令またはワイプの要件はありません。静的な実行可能ファイルがサポートされます。libc
以外のすべてのライブラリのサニタイズはスキップしてかまいません。
また、ライブラリをサニタイズする場合、ライブラリにリンクされている実行可能ファイルもサニタイズする必要はありません。
モジュールのサニタイズをスキップするには、LOCAL_NOSANITIZE := hwaddress
または sanitize: { hwaddress: false }
を使用します。
HWASan では個別のモジュールをサニタイズできますが、libc
にも HWASan が使用されることに注意してください。サニタイズするには、個別の Android.bp
モジュール定義に sanitize: { hwaddress: true }
を追加します。_hwasan
接尾辞が付いたビルド(libc
を含む)を使用すると、Android プラットフォーム全体が HWASan でビルドされます。つまり、HWASan ビルドでは libc
を手動でサニタイズする必要はありません。
スタック トレースの向上
HWASan は、フレーム ポインタに基づく高速なアンワインダーを使用して、プログラム内のすべてのメモリ割り当ておよび割り当て解除イベントのスタック トレースを記録します。Android ではデフォルトで AArch64 コードのフレーム ポインタが有効になるため、これは実際に効果的に機能します。マネージド コードをアンワインドする必要がある場合は、プロセス環境で HWASAN_OPTIONS=fast_unwind_on_malloc=0
を設定してください。不適切なメモリアクセスのスタック トレースでは、デフォルトでは「遅い」アンワインダーが使用されます。この設定は、割り当てトレースと割り当て解除トレースにのみ影響します。このオプションでは、負荷によっては CPU 使用率が非常に高くなります。
シンボル化
ASan ドキュメントのシンボル化をご覧ください。
アプリでの HWASan
AddressSanitizer と同様に、HWASan は Java コードを調べることはできませんが、JNI ライブラリ内のバグは検出できます。ASan と異なり、非 HWASan デバイスでの HWASan アプリの実行はサポートされていません。
HWASan デバイスでは HWASan を使用してアプリをチェックできます。そのためには、Make で SANITIZE_TARGET:=hwaddress
を指定するか、コンパイラ フラグで -fsanitize=hwaddress
を指定して、アプリのコードをビルドします。
詳細については、アプリ デベロッパー向けドキュメントをご覧ください。