ShadowCallStack

ShadowCallStack(SCS)は、(スタック バッファ オーバーフローに似た)戻りアドレスの上書きを防ぐ LLVM インストゥルメンテーション モードです。そのために、非リーフ関数の関数プロローグで別個に割り当てられた ShadowCallStack に関数の戻りアドレスを保存し、関数エピローグの ShadowCallStack から返された戻りアドレスを読み込みます。戻りアドレスは、アンワインダーとの互換性のために通常のスタックにも格納されますが、それ以外では使用されません。これにより、通常スタックの戻りアドレスを変更する攻撃がプログラム制御フローに影響しないことが保証されます。

aarch64 では、インストゥルメンテーションは x18 レジスタを利用して ShadowCallStack を参照します。つまり、ShadowCallStack への参照をメモリ内に保存する必要はありません。これにより、任意のメモリを読み取れる攻撃者に ShadowCallStack のアドレスを開示しないランタイムを実装できます。

実装

Android は、カーネルとユーザー空間の両方で ShadowCallStack をサポートしています。

カーネルで SCS を有効化する

カーネルで ShadowCallStack を有効にするには、カーネル構成ファイルに次の行を追加します。

CONFIG_SHADOW_CALL_STACK=y

ユーザー空間で SCS を有効化する

ユーザー空間コンポーネントで ShadowCallStack を有効にするには、コンポーネントのブループリント ファイルに以下の行を追加します。

    sanitize: {
      scs: true
    }
    

SCS は、x18 レジスタが ShadowCallStack のアドレスを格納するために予約されており、他の目的に使用されないことを前提にしています。すべてのシステム ライブラリがコンパイルされて x18 レジスタが予約されると、プロセス内レガシーコードと相互作用するユーザー空間コンポーネント(たとえば、サードパーティ アプリによって読み込まれる可能性があるライブラリ)で SCS が有効になっている場合、x18 レジスタを上書きする可能性があるため、潜在的に問題となりえます。そのため、SCS はレガシー バイナリに読み込まれない自己完結型コンポーネントでのみ有効にすることをおすすめします。

検証

SCS 専用の CTS テストはありません。SCS がデバイスに影響しないことを確認するには、SCS を有効または無効にして CTS テストをパスするかどうかを検証してください。