メモリエラーのデバッグと軽減

Android は、メモリエラーのデバッグ用の複数のツールをサポートしています。それぞれにトレードオフがあるため、以下の中からユースケースに最適なものを選択してください。このドキュメントには利用可能なツールの概要が記載されており、どのツールの詳細を確認するかは自身で判断できます。このドキュメントは簡潔であることを目的としているため、詳細については各ツールのドキュメントを参照してください。

要約

  • メモリエラーが発生しないように、可能な限りメモリセーフ言語を使用します
  • 常に PAC / BTI を使用して ROP / JOP 攻撃を軽減します
  • 常に GWP-ASan を使用して、本番環境でまれに発生するメモリエラーを検出します
  • HWASan を使用してテスト中にメモリエラーを検出します
  • MTE 対応デバイスは 2023 年には一般提供されていませんが、本番環境でエラーを検出できる場合は使用してください
  • テスト時に ASan を最後の手段としてのみ使用します

メモリセーフ言語

メモリセーフ言語は、メモリエラーを完全に回避し、軽減する唯一の方法です。このページで紹介するその他のツールは、メモリ安全でないコードの安全性と信頼性を向上させるのに役立ちますが、メモリセーフな言語を使用することで、問題全体が解消されます。

Android で公式にサポートされているメモリセーフ言語は Java と Kotlin です。ほとんどの Android アプリは、これらの言語のいずれかで開発するのが簡単です。

とはいえ、Rust で記述されたコードを提供するアプリ デベロッパーは存在します。このページをお読みの場合は、ネイティブ コード(ポータビリティ、パフォーマンス、またはその両方)を必要とする正当な理由があるはずです。Rust は、Android のメモリセーフのネイティブ コードに最適です。その場合ユーザーが直面する問題に関して、NDK チームは必ずしもサポートできるわけではありませんが、ぜひお聞かせいただきたいと考えています。

PAC / BTI

ポインタ認証とブランチ ターゲットの識別(PAC / BTI とも呼ばれます)は、本番環境での使用に適した軽減ツールです。これらは別個の技術ですが、同じコンパイラ フラグによって制御されるため、常に一緒に使用されます。

これらの機能には、サポートしていないデバイスとの下位互換性があります。使用される新しい命令は、以前のデバイスでは NoOps であるためです。また、カーネルと OS のバージョンが十分に新しいものであることも必要です。/proc/cpuinfopacabti を検索すると、ハードウェアとカーネルが十分に新しいかどうかを確認できます。Android 12(API 31)では、必要なユーザー空間がサポートされています。

長所:

  • 古いデバイスで問題を発生させることなく、すべてのビルドで有効化可能(ただし、サポートするデバイス / カーネル / OS の組み合わせで実際にテスト済みであることが必要)

短所:

  • 64 ビットアプリでのみ使用可能
  • サポートしないデバイスでのエラーは軽減されない
  • コードサイズのオーバーヘッド 1%

GWP-Asan

GWP-ASan を使用してフィールドのメモリエラーを検出できますが、サンプリング レートが低すぎるため、効果的に軽減することはできません。

長所:

  • 大きな CPU またはメモリのオーバーヘッドがない
  • デプロイが簡単: ネイティブ コードの再ビルドが不要
  • 32 ビットアプリで動作

短所:

  • サンプリング レートが低く、バグを効率的に見つけるために数多くのユーザーが必要
  • スタックエラーではなく、ヒープエラーのみを検出

HWASan

Hardware Address Sanitizer(HWASan とも呼ばれます)は、テスト中にメモリエラーを検出する場合に適しています。自動テストで使用するのが便利ですが(特にファズテストを実行する場合)、アプリのパフォーマンス ニーズによっては、dogfood 設定を使用するハイエンド スマートフォンでも使用できます。

長所:

  • 偽陽性なし
  • ASan では検出できない他のクラスのエラーを検出(返却後のスタック使用)
  • MTE よりも低い偽陰性率(16 分の 1 に対し、256 分の 1)
  • 最も近い代替手段である ASan よりもメモリのオーバーヘッドが少ない

短所:

  • かなりの CPU(約 100%)、コードサイズ(約 50%)、メモリ(10~35%)のオーバーヘッド
  • API 34 と NDK r26 までは、HWASan 互換イメージの書き込みが必要
  • 64 ビットアプリでのみ動作

MTE

メモリタグ付け拡張機能(MTE とも呼ばれます)は、HWASan に代わる低コストの代替手段です。デバッグとテストの機能に加えて、本番環境でのメモリ破損を検出して軽減することもできます。MTE ビルドをテストするハードウェアがある場合は、これを有効にする必要があります。

長所:

  • 多くのアプリの本番環境で許容されるレベルの少ないオーバーヘッド
  • 偽陽性なし
  • ヒープエラーを検出するためのコード再ビルドが不要(ただし、スタックエラーを検出するには必要)

短所:

  • 2024 年には、デフォルトで MTE が有効になっている市販デバイスはありませんが、Arm のドキュメントでは Google Pixel 8/Google Pixel 8 Pro でのテスト用に MTE を有効にする方法について説明しています。
  • HWASan の 256 分の 1 に対し、16 分の 1 の偽陰性率
  • 64 ビットアプリでのみ使用可能
  • MTE 対応デバイスと非 MTE 対応デバイスの両方を対象とするには、個別のライブラリのビルドが必要

ASan

AddressSanitizer(ASan とも呼ばれます)は、利用可能なツールで最も古いもので、最も広く使用されています。これは、他のツールが使用できない古いデバイスにのみ影響する問題のテストおよびデバッグ中に、メモリエラーを検出するのに役立ちます。可能であれば HWASan を優先します。

長所:

  • 広く使用可能KitKat と同程度に古いデバイスで動作する可能性あり
  • 正しく使用した場合は偽陽性または偽陰性なし

短所:

  • ビルドとパッケージ化が困難
  • 全オプションの中で最大のオーバーヘッド: CPU(約 100%)、コードサイズ(約 50%)、メモリ(約 100%)
  • サポートがすでに終了
  • 修正されない既知のバグあり