メモリ保護は、コンピュータ上のメモリアクセス権限を制御する方法であり、最新の命令セットアーキテクチャやオペレーティングシステムのほとんどに組み込まれています。メモリ保護の主な目的は、プロセスが自身に割り当てられていないメモリにアクセスするのを防ぐことです。これにより、プロセス内のバグやマルウェアが他のプロセスやオペレーティングシステム自体に影響を与えるのを防ぎます。保護は、指定されたメモリ領域へのすべてのアクセス、書き込みアクセス、またはその領域の内容を実行しようとする試みを対象とする場合があります。許可されていないメモリにアクセスしようとすると、ハードウェア障害(セグメンテーション違反、ストレージ違反例外など)が発生し、通常は問題のあるプロセスが異常終了します。コンピュータセキュリティのためのメモリ保護には、アドレス空間配置ランダム化や実行可能領域保護などの追加の技術が含まれます。
セグメンテーションとは、コンピュータのメモリをセグメントに分割することを指します。メモリ位置への参照には、セグメントを識別する値と、そのセグメント内のオフセットが含まれます。セグメント記述子は、読み取り専用、特定のリングからのみアクセス可能など、アクセス権を制限することができます。
x86アーキテクチャには複数のセグメンテーション機能があり、このアーキテクチャで保護されたメモリを使用するのに役立ちます。[ 1 ] x86アーキテクチャでは、グローバル記述子テーブルとローカル記述子テーブルを使用して、コンピュータのメモリ内のセグメントを参照できます。x86プロセッサのメモリセグメントへのポインタは、プロセッサのセグメントレジスタに格納することもできます。当初、x86プロセッサには、CS(コードセグメント)、SS(スタックセグメント)、DS(データセグメント)、ES(エクストラセグメント)の4つのセグメントレジスタがありましたが、後にFSとGSの2つのセグメントレジスタが追加されました。[ 1 ]
ページングでは、メモリのアドレス空間またはセグメントが、ページと呼ばれる等しいサイズのブロック[ b ]に分割されます。仮想メモリハードウェアを使用すると、各ページはコンピュータの物理メモリの適切な境界内の任意の場所に配置したり、保護対象としてフラグを付けたりすることができます。仮想メモリにより、線形の仮想メモリアドレス空間を持ち、それを使用して物理メモリアドレス空間に断片化されたブロックにアクセスすることが可能になります。
ページングをサポートするほとんどのコンピュータアーキテクチャは、メモリ保護の基盤としてもページを使用しています。
ページテーブルは、仮想メモリを物理メモリにマッピングする役割を果たします。アーキテクチャやOSによって、ページテーブルは1つだけの場合もあれば、プロセスごとに1つ、セグメントごとに1つ、あるいは階層構造になっている場合もあります。通常、ページテーブルはプロセスからは見えません。ページテーブルを使うことで、物理メモリ内のどこからでも新しいページを割り当てることができるため、メモリの追加が容易になります。システムによっては、ページテーブルのエントリによってページを読み取り専用として指定することもできます。
一部のオペレーティングシステムでは、プロセスごとに異なるアドレス空間が設定され、これによりハードメモリ保護境界が提供されます。[ 2 ] 特権のない[ c ]アプリケーションが明示的に割り当てられていないページにアクセスすることは不可能です。なぜなら、すべてのメモリ アドレスは、そのアプリケーションに割り当てられたページを指すか、ページ フォルトと呼ばれる割り込みを生成するかのいずれかだからです。割り当てられていないページ、および他のアプリケーションに割り当てられたページは、アプリケーションの観点からはアドレスを持ちません。
ページフォールトは必ずしもエラーを示すものではありません。ページフォールトはメモリ保護のためだけに用いられるわけではありません。オペレーティングシステムは、以前に二次記憶装置[ d ]にページアウトされたページへの参照がページフォールトを引き起こすようにページテーブルを管理することがあります。オペレーティングシステムはページフォールトをインターセプトし、必要なメモリページをロードし、アプリケーションはフォールトが発生しなかったかのように動作を続行します。この方式は一種の仮想メモリであり、現在使用されていないメモリ内のデータをアプリケーションに透過的に移動して、メモリ全体の容量を増やすことができます。
システムによっては、仮想ストレージの要求によって、ページフレームが割り当てられていない仮想アドレスのブロックが割り当てられる場合があり、ページフォールトが発生した場合にのみ、システムがページフレームを割り当てて初期化します。システムによっては、エラー検出のため、またはデータ構造を自動的に拡張するために、ガードページが使用される場合があります。
一部のシステムでは、 W^Xなどの実行可能領域保護のためにページフォールトメカニズムも使用されます。
メモリ保護キー(MPK)[ 3 ]メカニズムは、物理メモリを特定のサイズ(例:4 KiB)のブロックに分割し、各ブロックには保護キーと呼ばれる数値が関連付けられています。各プロセスにも保護キーの値が関連付けられています。メモリへのアクセス時に、ハードウェアは現在のプロセスの保護キーがアクセス対象のメモリブロックに関連付けられた値と一致するかどうかを確認します。一致しない場合は、例外が発生します。このメカニズムはSystem/360アーキテクチャで導入されました。現在でもSystem zメインフレームで利用可能であり、 System zオペレーティングシステムとそのサブシステムで広く使用されています。
上記で説明したSystem/360の保護キーは、物理アドレスに関連付けられています。これは、仮想アドレスに関連付けられ、プロセスごとに複数のキーを使用できるHewlett-Packard / Intel IA-64やHewlett-Packard PA-RISCなどのアーキテクチャで使用される保護キーのメカニズムとは異なります。
Itanium および PA-RISC アーキテクチャでは、変換 ( TLBエントリ)には、キー(Itanium) またはアクセス ID (PA-RISC) が関連付けられています。実行中のプロセスには、複数の保護キー レジスタ (Itanium では 16 個、[ 4 ] PA-RISC では 4 個[ 5 ] ) があります。仮想アドレスによって選択された変換のキーは、それぞれの保護キー レジスタと比較されます。いずれかが一致すれば (他の可能なチェックも含む)、アクセスが許可されます。一致しない場合は、障害または例外が発生します。必要に応じて、ソフトウェア障害ハンドラは、不足しているキーをソフトウェアによって管理されているキーのリストと比較することができます。したがって、プロセッサ内の保護キー レジスタは、プロセスに関連付けられたキーのリストのソフトウェア管理キャッシュとして扱うことができます。
PA-RISCは15~18ビットの鍵を持ち、Itaniumは少なくとも18ビットを必須としている。鍵は通常、ライブラリやモジュールなどの保護ドメインに関連付けられる。
x86アーキテクチャでは、保護キー[ 6 ]アーキテクチャにより、ユーザーページの仮想アドレスに16個の保護キーのいずれかをタグ付けできます。同じ保護キーでタグ付けされたすべてのページは、保護ドメインを構成します。新しいレジスタには、各保護ドメインに関連付けられたアクセス許可が格納されます。ロードおよびストア操作は、仮想アドレスの保護ドメインに関連付けられたページテーブルのアクセス許可と保護キーのアクセス許可の両方に対してチェックされ、両方のアクセス許可がアクセスを許可している場合にのみ許可されます。保護キーのアクセス許可はユーザー空間から設定できるため、アプリケーションはOSの介入なしにアプリケーションデータへのアクセスを直接制限できます。保護キーは仮想アドレスに関連付けられているため、保護ドメインはアドレス空間ごとに存在し、異なるアドレス空間で実行されているプロセスはそれぞれ16個のドメインすべてを使用できます。
Multicsおよびそこから派生したシステムでは、各セグメントは読み取り、書き込み、実行のための保護リングを持ちます。セグメントのリング番号よりも高いリング番号を持つプロセスがアクセスしようとすると、障害が発生します。低いリングで実行されているプロシージャを安全に呼び出し、高いリングに戻るためのメカニズムがあります。低いリング番号で実行されているルーチンが、自身のリングと呼び出し元のリングのうち大きい方のリングを使用してパラメータにアクセスするためのメカニズムがあります。
シミュレーションとは、監視プログラムを使用して、一部のコンピュータアーキテクチャのマシンコード命令を解釈することです。このような命令セットシミュレータは、セグメンテーションのようなスキームを使用し、各命令のターゲットアドレスと長さをリアルタイムで検証してから実際に実行することで、メモリ保護を提供できます。シミュレータは、ターゲットアドレスと長さを計算し、スレッドの開始以降に取得した動的メモリブロックや有効な共有静的メモリスロットなど、スレッドの環境に関する有効なアドレス範囲のリストと比較する必要があります。「有効」の意味は、スレッドのライフサイクルを通じてコンテキストに応じて変化する可能性があります。現在の実行モードによっては、静的ストレージブロックの変更が許可される場合と許可されない場合があり、これはストレージキーやスーパーバイザの状態に依存する場合と依存しない場合があります。
CPUに適切なメモリ保護機能が搭載されている場合、この方法を使用することは一般的に推奨されません。なぜなら、コンピュータの処理能力を無駄に消費してしまうからです。しかし、この方法はデバッグやテストの目的でよく使用され、一般的なストレージ違反に対してより詳細な情報を提供し、保護されていないストレージと同じストレージキーを持つ可能性のある特定のストレージ領域を上書きしようとしている命令を正確に特定することができます。
機能ベースのアドレッシングは、現代の商用コンピュータでは使用されていないメモリ保護方式です。この方式では、ポインタは保護されたオブジェクト(機能と呼ばれる)に置き換えられ、カーネルまたは実行を許可された他のプロセスのみが実行できる特権命令を使用してのみ作成できます。これにより、カーネルは、個別のアドレス空間やコンテキストスイッチを使用する必要なく、どのプロセスがメモリ内のどのオブジェクトにアクセスできるかを効果的に制御できます。機能ベースのセキュリティを使用した商用製品は、 Plessey System 250、IBM System/38、Intel iAPX 432アーキテクチャ、KeyKOSなどごく少数です。機能アプローチは、 EROSやCombex DARPAブラウザなどの研究システムで広く使用されています。概念的には、 SmalltalkやJavaなどの仮想マシンの基盤として使用されています。現在、ケンブリッジ大学のDARPA資金提供によるCHERIプロジェクトは、レガシーソフトウェアもサポートする最新の機能マシンを作成するために取り組んでいます。
動的汚染は、不正なメモリアクセスからプログラムを保護するための手法です。実行時にメモリが割り当てられると、この手法はメモリと対応するポインタの両方を同じ汚染マークで汚染します。汚染マークはプログラムの実行中に適切に伝播され、ポインタpを介してメモリ アドレスmにアクセスするたびにチェックされます。mとpに関連付けられた汚染マークが異なる場合、実行は停止され、不正アクセスが報告されます。[ 7 ] [ 8 ]
SPARC M7プロセッサ(およびそれ以降のプロセッサ)は、ハードウェアで動的汚染を実装しています。Oracleはこの機能をシリコンセキュアメモリ(SSM)(以前はアプリケーションデータインテグリティ(ADI)というブランド名でした)として販売しています。[ 9 ]
特定の実装の保護レベルは、最小限の特権の原則にどれだけ忠実に従っているかによって測定できます。[ 11 ]
異なるオペレーティングシステムは、異なる形式のメモリ保護または分離を使用します。メモリ保護は1960年代のほとんどのメインフレームや多くのミニコンピュータシステムで一般的でしたが、真のメモリ分離は、1987年にOS/2(およびRISC OS)がリリースされるまで、ホームコンピュータのオペレーティングシステムでは使用されていませんでした。以前のシステムでは、このような保護の欠如は、プロセス間でポインタを送信することによって、プロセス間通信の一形態としてさえ使用されていました。Windows 9xファミリーのオペレーティングシステムでは、プロセスがシステムメモリにアクセスすることが可能です。[ 12 ]
メモリ保護機能を実装しているオペレーティングシステムには、以下のようなものがあります。