HWASan のクラッシュを確認する方法については、HWASan レポートについてをご覧ください。
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(ASan と同じ)は UBSan と互換性があり、ターゲットで両方を同時に有効にできます。
実装の詳細と制限
HWASan はメモリのタグ付けアプローチに基づいており、小さなランダムタグ値がポインタとメモリアドレス範囲の両方に関連付けられます。メモリアクセスが有効になるには、ポインタとメモリタグが一致する必要があります。HWASan は ARMv8 の TBI(Top Byte Ignore)機能に依存します。この機能は仮想アドレスタグ付けとも呼ばれ、ポインタタグをアドレスの上位ビットに格納します。
HWASan の設計の詳細については、Clang のドキュメント サイトをご覧ください。
設計上、HWASan には、オーバーフローを検出する ASan のサイズ制限レッドゾーンと、解放後の使用を検出する ASan の容量制限検疫機能はありません。したがって、HWASan はオーバーフローのサイズ、またはメモリが割り当て解除されてからの経過時間に関係なくバグを検出できます。この点で HWASan には ASan よりも大きな利点があります。
ただし、HWASan では使用可能なタグ値が 256 個に制限されているため、プログラムの 1 回の実行でバグを見落とす確率が 0.4% あります。
要件
共通 Android カーネルの最近のバージョン(4.14 以降)は HWASan をサポートしており、すぐに利用できます。Android 10 固有のブランチは HWASan をサポートしていません。
HWASan 用のユーザー空間サポートは、Android 11 以降でご利用いただけます。
別のカーネルを使用している場合、HWASan はシステムコール引数でタグ付きポインタを受け入れる Linux カーネルを必要とします。このことに対するサポートは、次のアップストリーム パッチセットで実装されています。
- arm64 タグが付けられたアドレス ABI
- arm64: カーネルに渡されるユーザー ポインタのタグを解除する
- mm: brk()/mmap()/mremap() での仮想アドレス エイリアスの作成を回避する
- arm64: カーネル スレッドから呼び出される、access_ok() でタグ付けされたアドレスを検証する
カスタム ツールチェーンを使用してビルドする場合は、LLVM commit c336557f までのすべての要素が含まれていることを確認してください。
HWASan を使用する
HWASan を使用してプラットフォーム全体をビルドするには、次のコマンドを実行します。
lunch aosp_walleye-userdebug # (or any other product)
export SANITIZE_TARGET=hwaddress
m -j
便宜上、aosp_coral_hwasan の場合と同様に、SANITIZE_TARGET 設定をプロダクト定義に追加できます。
AddressSanitizer を使い慣れているユーザーは、ビルドに関する多くの複雑な作業から解放されます。
- make を 2 回実行する必要はありません。
- 増分ビルドをすぐに利用できます。
- ユーザーデータを書き込む必要はありません。
AddressSanitizer の制限も一部なくなります。
- 静的な実行可能ファイルがサポートされます。
- libc 以外のターゲットはサニタイズをスキップしても問題ありません。ASan と異なり、ライブラリがサニタイズされていれば、リンクする実行可能ファイルのサニタイズは必要ありません。
同じ(またはそれ以上の)ビルド番号で、HWASan と通常のイメージを自由に切り替えることができます。デバイスをワイプする必要はありません。
モジュールのサニタイズをスキップするには、LOCAL_NOSANITIZE := hwaddress
(Android.mk)または sanitize: { hwaddress: false }
(Android.bp)を使用します。
個々のターゲットをサニタイズする
HWASan は、libc.so
もサニタイズされていれば、通常の(サニタイズされていない)ビルドでターゲットごとに有効にできます。bionic/libc/Android.bp の "libc_defaults"
のサニタイズ ブロックに hwaddress: true
を追加します。次に、作業中のターゲットで同じ処理を行います。
libc をサニタイズすると、libc.so
内のメモリ オペレーションのタグのチェックだけでなく、システム全体のヒープメモリ割り当てのタグ付けが可能になります。これにより、不正なメモリアクセスが libc.so
にある場合に、HWASan が有効になっていないバイナリでもバグを検出できる可能性があります(例: delete()
されたミューテックスの pthread_mutex_unlock()
など)。
プラットフォーム全体が HWASan を使用してビルドされている場合は、ビルドファイルを変更する必要はありません。
フラッシュステーション
開発目的では、フラッシュステーションを使用しているロック解除されたブートローダーで Pixel デバイスに AOSP の HWASan 対応ビルドを書き込むことができます。_hwasan ターゲット(例: aosp_flame_hwasan-userdebug)を選択します。アプリ デベロッパー向けの詳細については、HWASan の NDK ドキュメントをご覧ください。
スタック トレースの向上
HWASan は、フレーム ポインタに基づく高速なアンワインダーを使用して、プログラム内のすべてのメモリ割り当ておよび割り当て解除イベントのスタック トレースを記録します。Android ではデフォルトで AArch64 コードのフレーム ポインタが有効になるため、これは実際に効果的に機能します。マネージド コードをアンワインドする必要がある場合は、プロセス環境で HWASAN_OPTIONS=fast_unwind_on_malloc=0
を設定してください。不適切なメモリアクセスのスタック トレースでは、デフォルトでは「遅い」アンワインダーが使用されます。この設定は、割り当てトレースと割り当て解除トレースにのみ影響します。このオプションでは、負荷によっては CPU 使用率が非常に高くなります。
シンボル化
「HWASan レポートについて」のシンボル化をご覧ください。
アプリでの HWASan
AddressSanitizer と同様に、HWASan は Java コードを調べることはできませんが、JNI ライブラリ内のバグは検出できます。Android 14 より前の場合、非 HWASan デバイスでの HWASan アプリの実行はサポートされていません。
HWASan デバイスでは HWASan を使用してアプリをチェックできます。そのためには、Make で SANITIZE_TARGET:=hwaddress
を指定するか、コンパイラ フラグで -fsanitize=hwaddress
を指定して、アプリのコードをビルドします。HWASan デバイス(Android 14 以降を搭載)の場合、wrap.sh ファイル設定 LD_HWASAN=1
を追加する必要があります。詳細については、アプリ デベロッパー向けドキュメントをご覧ください。