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