Shadow stack とは

コンピュータセキュリティでは、シャドウスタックは、スタックバッファのオーバーフローなど、プロシージャのストアされたリターンアドレスを保護するためのメカニズムです。シャドウスタック自体は、プログラムコールスタックを「シャドウ」にする別の2番目のスタックです。関数のプロローグでは、関数はその戻りアドレスを呼び出しスタックとシャドウスタックの両方に格納します。関数エピローグでは、関数が呼び出しスタックとシャドウスタックの両方から戻りアドレスをロードし、それらを比較します。戻りアドレスの2つのレコードが異なる場合、攻撃が検出されます。通常は、プログラムを終了するか、システム管理者に可能性のある侵入試行を警告するだけです。シャドウスタックは、両方のメカニズムが、攻撃の試み中に攻撃者によって格納されたリターンアドレスを改ざんする攻撃を検出することによって、保護されたプログラムの制御フローの完全性を維持することを目的としています。
シャドウスタックは、変更されたプロローグとエピローグを持つプログラムを再コンパイルすることによって、同じ効果を達成するための動的バイナリ書き換えテクニック、またはハードウェアサポートによって実装できます。ローカルプログラム変数、渡された引数、流出されたレジスタおよびその他のデータも格納するコールスタックとは異なり、シャドウスタックは通常、関数の戻りアドレスの2番目のコピーを格納します。
シャドースタックは、カナリア値の秘密に依存し、非連続書き込み攻撃に対して脆弱であるスタックカナリアよりも、リターンアドレスの保護が強化されています。シャドウスタック自体はガードページや情報隠蔽で保護することができ、攻撃者はそのシャドウスタックを検索してそこに格納されているリターンアドレスを上書きする必要があります。
スタック・カナリーのように、シャドウ・スタックはリターン・アドレス以外のスタック・データを保護しないため、メモリの安全性に起因するセキュリティ脆弱性に対する保護が不完全です。
インテルは、2016年に、制御フロー施行技術によりシャドウスタックのハードウェアサポートを発表しました。
シャドウスタックには互換性の問題がいくつかあります。プログラムが例外をスローするか、longjmpが発生した後、シャドウスタックの先頭にあるリターンアドレスは、コールスタックからポップされたリターンアドレスと一致しません。この問題の典型的な解決策は、一致するリターンアドレスが見つかるまでシャドウスタックからエントリをポップし、シャドウスタックで一致するものが見つからない場合にのみプログラムを終了することです。
実行スレッドごとにコールスタックを持つマルチスレッドプログラムは、各呼び出しスタックをシャドウイングするシャドウスタックも持っています。