コンピュータセキュリティにおいて、実行可能領域保護とは、メモリ領域を実行不可としてマークし、これらの領域でマシンコードを実行しようとすると例外が発生するようにする技術です。これは、 NXビット(実行不可ビット)などのハードウェア機能、またはハードウェアによるサポートが利用できない場合はソフトウェアエミュレーションに依存します。ソフトウェアエミュレーションは、多くの場合、パフォーマンスコスト、つまりオーバーヘッド(追加の処理時間やリソース)を伴いますが、ハードウェアベースのNXビット実装は、パフォーマンスに目立った影響を与えません。
1961年に発表されたBurroughs 5000を皮切りに、Burroughsの大型システムは、タグ付きアーキテクチャを使用して実行可能領域の保護を実現しました。コードとデータへのすべてのアクセスはディスクリプタを介して行われ、ディスクリプタには変更を防止するメモリタグが付与されていました。コード用のディスクリプタはコードの変更を許さず、データ用のディスクリプタはデータをコードとして実行することを許しませんでした。
現在、オペレーティングシステムは実行可能領域保護機能を用いて、スタックやヒープなどの書き込み可能なメモリ領域を実行不可能な領域としてマークし、バッファオーバーフロー攻撃を防いでいます。これらの攻撃は、メモリの一部(通常はスタック)が書き込み可能かつ実行可能であることを前提としており、そうでない場合は攻撃は失敗します。
多くのオペレーティングシステムは、実行可能領域保護ポリシーを実装しているか、または備えています。以下に、そのようなシステムをアルファベット順にリストアップし、各システムにおける技術を新しいものから古いものへと順に示します。
アーキテクチャに依存しないエミュレーションを提供する技術は、ハードウェアでサポートされていないすべてのプロセッサで機能します。「その他サポート対象」の項目は、明示的なNXビットは存在しないものの、ハードウェアで何らかの方法でエミュレーションが可能な、グレーゾーン的な方法をサポートするプロセッサ向けです。
Android 2.3以降では、これをサポートするアーキテクチャでは、実行不可能なページがデフォルトで用意されており、実行不可能なスタックとヒープも含まれます。[ 1 ] [ 2 ] [ 3 ]
NXビットの初期サポートは、対応するx86-64およびIA-32プロセッサにおいて、2004年6月8日にFreeBSD -CURRENTで初めて登場しました。FreeBSD 5.3以降のリリースでは、この機能が引き続き搭載されています。
Linuxカーネルは、AMD、Intel、Transmeta、VIA製の最新の64ビットプロセッサなど、NXビットをサポートするx86-64およびIA-32プロセッサでNXビットをサポートしています。x86-64 CPUの64ビットモードでのこの機能のサポートは、2004年にAndi Kleenによって追加され、同年後半にはIngo Molnárが64ビットCPUの32ビットモードでのサポートを追加しました。これらの機能は、 2004年8月にカーネルバージョン2.6.8がリリースされて以来、Linuxカーネルのメインラインの一部となっています。 [ 4 ]
32ビットx86カーネルでNXビットが利用可能になることは重要です。32ビットx86カーネルは、32ビットx86 CPUと64ビットIA-32互換CPUの両方で動作する可能性があります。これは、32ビットx86カーネルは通常、AMD64またはIA-64が提供するNXビットを想定していないためです。NXイネーブラーパッチは、これらのカーネルがNXビットが存在する場合にそれを使用することを保証します。
Fedora、Ubuntu、openSUSEなどの一部のデスクトップLinuxディストリビューションでは、デフォルトのカーネルでHIGHMEM64オプションがデフォルトで有効になっていません。このオプションは、32ビットモードでNXビットにアクセスするために必要なものです。これは、NXビットを使用するために必要なPAEモードが、NXをサポートしていないPentium Pro以前のプロセッサ(Pentium MMXを含む)およびCeleron MとPentium Mプロセッサで起動エラーを引き起こすためです。PAEをサポートしていない他のプロセッサには、 AMD K6以前、Transmeta Crusoe、VIA C3以前、Geode GXおよびLXがあります。VMware Workstationバージョン4.0より前のバージョン、Parallels Workstationバージョン4.0より前のバージョン、およびMicrosoft Virtual PCとVirtual Serverは、ゲストOS上でPAEをサポートしていません。Fedora Core 6およびUbuntu 9.10以降では、PAEとNXをサポートするkernel-PAEパッケージが提供されています。
NXメモリ保護は、対応するハードウェアを備え、64ビットカーネルまたは32ビットサーバーカーネルを実行しているシステムであれば、Ubuntuで常に利用可能でした。Ubuntu 9.10以降の32ビットPAEデスクトップカーネル(linux-image-generic-pae)は、NX CPU機能を搭載したハードウェアに必要なPAEモードも提供します。NXハードウェアを搭載していないシステムの場合、32ビットカーネルはソフトウェアエミュレーションによってNX CPU機能の近似値を提供し、スタックメモリやヒープメモリから攻撃者が実行する可能性のある多くのエクスプロイトをブロックするのに役立ちます。
非実行機能は、この機能をサポートする他の非x86プロセッサにおいても、多くのリリースで既に存在しています。
Red Hatカーネル開発者のIngo Molnár氏は、 32 ビットx86 CPU上で NX 機能を近似的に利用するためのExec Shieldという Linux カーネルパッチをリリースしました。Exec Shield パッチは 2003 年 5 月 2 日にLinux カーネルのメーリングリストに公開されましたが、エミュレーションの複雑な部分を処理するためにコアコードに侵襲的な変更が必要だったため、ベースカーネルへのマージは拒否されました。Exec Shield のレガシー CPU サポートは、コードセグメントの上限を追跡することで NX エミュレーションを近似的に実現します。これにより、コンテキストスイッチ時にわずか数サイクルのオーバーヘッドが発生するだけで、これは事実上測定不可能です。NX ビットを持たないレガシー CPU の場合、Exec Shield はコードセグメントの上限以下のページを保護できません。スタックなどの上位メモリを実行可能としてマークする mprotect() 呼び出しは、その上限以下のすべてのメモリも実行可能としてマークします。したがって、このような状況では Exec Shield の仕組みは機能しません。これが Exec Shield の低オーバーヘッドの代償です。 Exec Shield は、スタックまたはヒープが実行可能である必要があるかどうかを示す 2 つのELFヘッダーマーキングをチェックします。これらはそれぞれ PT_GNU_STACK と PT_GNU_HEAP と呼ばれます。Exec Shield では、これらの制御をバイナリ実行ファイルとライブラリの両方に設定できます。実行ファイルが特定の制限の緩和を必要とするライブラリをロードする場合、実行ファイルはそのマーキングを継承し、その制限が緩和されます。
PaX NXテクノロジーは、NX機能をエミュレートするか、ハードウェアのNXビットを使用できます。PaXは、32ビットx86など、NXビットを持たないx86 CPUでも動作します。Linuxカーネルには(2007年5月現在)まだPaXは同梱されておらず、パッチを手動でマージする必要があります。
PaX は、SEGMEXEC と PAGEEXEC という 2 つの NX ビット エミュレーション方法を提供します。SEGMEXEC メソッドは、実行とデータ アクセスの分離に使用される仮想メモリ ミラーリングによって発生する定数スカラーである、測定可能だが低いオーバーヘッド (通常 1% 未満) を課します。[ 5 ] SEGMEXEC はまた、タスクの仮想アドレス空間を半分にする効果があり、タスクが通常よりも少ないメモリにアクセスできるようにします。タスクが通常のアドレス空間の半分を超えるアクセスを必要とする場合を除いて、これは問題になりませんが、そのようなことはまれです。SEGMEXEC は、プログラムがより多くのシステム メモリ (つまり RAM) を使用するようにするものではなく、アクセスできる量を制限するだけです。32 ビット CPU では、これは 3 GB ではなく 1.5 GBになります 。
PaX は、高速化のために PAGEEXEC で Exec Shield の近似に似た方法を提供しますが、メモリ領域が実行可能としてマークされると、この方法は保護を失います。このような場合、PaX は PAGEEXEC が CS 制限以下のページを保護するために使用する、より古い可変オーバーヘッドの方法にフォールバックします。この方法は、特定のメモリ アクセス パターンでは非常に高いオーバーヘッドを伴う操作になる可能性があります。ハードウェア NX ビットを提供する CPU で PAGEEXEC メソッドを使用する場合、ハードウェア NX ビットが使用されるため、大きなオーバーヘッドは発生しません。
PaXは、潜在的な脆弱性を悪用するためにメモリをマークするプログラムを防止するmprotect()制限を提供します。このポリシーにより、一部のアプリケーションは動作しなくなりますが、影響を受けるプログラムに対しては無効にすることができます。
PaXでは、各バイナリ実行ファイルごとに、テクノロジーの以下の機能を個別に制御できます。
PaX は PT_GNU_STACK と PT_GNU_HEAP の両方を無視します。以前は、これらの設定を尊重する構成オプションがありましたが、セキュリティ上の理由から、そのオプションは不要と判断され削除されました。通常、プログラムはロード時にスタックを mprotect() するため、mprotect() の制限を無効にすることで PT_GNU_STACK と同じ結果が得られます。ただし、常にそうとは限りません。この方法がうまくいかない場合は、PAGEEXEC と SEGMEXEC の両方を無効にするだけで、実行可能領域の制限がすべて解除され、タスクは PaX 以外のシステムと同様に実行可能領域を保護されます。
Intel 版macOS は、Apple がサポートするすべての CPU で NX ビットをサポートしています (Mac OS X 10.4.4 (Intel 版の最初のリリース) 以降)。Mac OS X 10.4 では、NX スタック保護のみがサポートされていました。Mac OS X 10.5 では、すべての 64 ビット実行ファイルで NX スタックおよびヒープ、W^X 保護がサポートされます。これには、x86-64 (Core 2 以降) およびG5 Macの64 ビットPowerPC が含まれます。
NetBSD 2.0以降(2004年12月9日)では、これをサポートするアーキテクチャは実行不可能なスタックとヒープを備えています。[ 6 ]
ページ単位の粒度を持つアーキテクチャは、alpha、amd64、hppa、i386 ( PAE付き)、powerpc(ibm4xx)、sh5、sparc(sun4m、sun4d)、sparc64です。
領域粒度でのみこれらをサポートできるアーキテクチャは、i386(PAEなし)、その他のPowerPC(macppcなど)です。
他のアーキテクチャでは、非実行可能スタックやヒープの恩恵を受けることはありません。NetBSDはデフォルトでは、これらのアーキテクチャ上でこれらの機能を提供するためのソフトウェアエミュレーションを使用しません。
OpenBSDオペレーティングシステムに搭載されているW^Xと呼ばれる技術は、対応するプロセッサにおいて、書き込み可能なページをデフォルトで実行不可能なページとしてマークします。32ビットx86プロセッサでは、コードセグメントはアドレス空間の一部のみを含むように設定され、実行可能領域をある程度保護します。
OpenBSD 3.3は2003年5月1日に出荷され、W^Xを初めて搭載したバージョンでした。
Solarisは、Solaris 2.6(1997年)以降、SPARCプロセッサ上でのスタック実行のグローバル無効化をサポートしており、Solaris 9(2002年)では、実行ファイルごとにスタック実行を無効化する機能が追加されました。
Windows (NT 4.0、2000、XP) 用の非実行可能スタックの最初の実装は、PaX の研究に基づいて SecureWave が 2001 年に SecureStack 製品を通じて公開しました。[ 7 ] [ 8 ]
Windows XP Service Pack 2 (2004) およびWindows Server 2003 Service Pack 1 (2005)以降、NX 機能がx86アーキテクチャに初めて実装されました。Windows における実行可能ファイルの保護は、「データ実行防止 (DEP)」と呼ばれています。
Windows XPまたはServer 2003では、NX保護はデフォルトで重要なWindowsサービスのみに適用されていました。x86プロセッサがハードウェアでこの機能をサポートしている場合、Windows XP/Server 2003ではNX機能がデフォルトで自動的に有効になっていました。x86プロセッサがこの機能をサポートしていない場合は、保護は適用されませんでした。
DEP の初期実装ではアドレス空間レイアウトランダム化(ASLR) が提供されていなかったため、攻撃中に DEP を無効にするために実際に使用できるlibc へのリターン攻撃が可能でした。 [ 9 ] PaXのドキュメントでは、ASLR が必要な理由が詳しく説明されています。[ 10 ] ASLR がない場合に DEP を回避できる方法を詳述した概念実証が作成されました。[ 11 ]破損した画像やMP3 などの準備されたデータのアドレスが攻撃者にわかっている場合、攻撃を成功させる可能性があります。
Microsoft はWindows VistaおよびWindows Server 2008に ASLR 機能を追加しました。このプラットフォームでは、 32 ビット Windows ではPAEカーネルの自動使用、64 ビット カーネルではネイティブ サポートによって DEP が実装されています。Windows Vista の DEP は、メモリの特定の部分をデータのみを保持するようにマークすることで機能し、NX ビットまたは XD ビットが有効になっているプロセッサはそれを実行不可能なものとして認識します。[ 12 ] Windows では、Vista 以降のバージョンで、特定のプロセスに対して DEP が有効か無効かは、 Windows タスク マネージャーの[プロセス] / [詳細]タブで確認できます。
Windows は、Microsoft の「Safe Structured Exception Handling 」(SafeSEH)を通じて、ソフトウェア DEP( NX ビットを使用せずに)を実装しています。適切にコンパイルされたアプリケーションの場合、SafeSEH は、プログラムの実行中に例外が発生したときに、例外ハンドラがアプリケーションが最初にコンパイルされたときに定義されたものであることを確認します。この保護の効果は、攻撃者がチェックされていないプログラム入力によってデータ ページに格納した独自の例外ハンドラを追加できないことです。[ 12 ] [ 13 ]
NX がサポートされている場合、デフォルトで有効になります。Windows では、APIおよびPE ファイルのセクション ヘッダーを介して、プログラムが実行を禁止するページを制御できます。API では、 Win32 API 呼び出しVirtualAlloc[Ex]およびVirtualProtect[Ex]を介して、NX ビットへのランタイム アクセスが公開されます。各ページは、個別に実行可能または実行不可としてフラグ付けできます。以前の x86 ハードウェア サポートがなかったにもかかわらず、実行可能および実行不可のページ設定は最初から提供されていました。NX 以前の CPU では、「executable」属性の存在は効果がありません。機能するかのように文書化されていたため、ほとんどのプログラマはそれを正しく使用していました。PE ファイル フォーマットでは、各セクションで実行可能性を指定できます。実行フラグはフォーマットの最初から存在しており、標準リンカはNX ビットよりもずっと前からこのフラグを正しく使用していました。このため、Windows は古いプログラムに対して NX ビットを強制できます。プログラマーが「ベストプラクティス」に従っていれば、NXが実際に強制適用された現在、アプリケーションは正しく動作するはずです。問題が発生したケースはごくわずかで、Microsoft自身の.NETランタイムがNXビットに問題があり、アップデートされました。
MicrosoftのXboxでは、CPUにNXビットは搭載されていませんが、新しいバージョンのXDKでは、コードセグメントの制限がカーネルの.dataセクションの先頭に設定されています(通常、この位置より後にコードは存在しないはずです)。バージョン51xx以降、この変更は新しいXboxのカーネルにも実装されました。これにより、古いエクスプロイトが使用していた、終了して常駐するプログラムになる手法は無効になりました。しかし、Xboxカーネルの根本的な脆弱性は影響を受けなかったため、この新しいカーネルバージョンをサポートする新しいエクスプロイトがすぐにリリースされました。
コードが実行時に記述され実行される場合(JITコンパイラはその代表的な例)、コンパイラは実行フラグが立てられ、したがってトラップされないエクスプロイトコード(JIT Sprayなどを使用)を生成するために使用される可能性がある。[ 14 ] [ 15 ]
戻り値指向プログラミングでは、実行可能領域保護が有効になっている場合でも、攻撃者が任意のコードを実行できてしまう可能性がある。