リングプロテクション

リングプロテクション（Ring Protection または Protection Ring）は、複数の特権レベルの階層構造を持ったコンピュータアーキテクチャの一種。単にリングとも言う。また、階層保護ドメイン (hierarchical protection domains) とも呼ぶ。データや機能を障害から保護し（フォールトトレラント性）、悪意ある行為から保護する（コンピュータセキュリティ）。capability-based security とは対極の考え方に基づく。

概要

コンピュータのオペレーティングシステムは個々のリソースに対して様々なアクセスのレベル（アクセス権）を提供する。
リングとは図に示すように、円形の階層構造を示しており、各階層がアクセス権を示している。
リングプロテクションは、コンピュータ・アーキテクチャ内の権限の2つ以上の階層的「レベル」または「層」で構成される。これは一般に一部CPUアーキテクチャによってハードウェアで実施され、複数のCPUモードをハードウェアレベルかマイクロコードレベルで提供する。リングプロテクションは最も高い特権レベル（最も信頼され、番号0を与えられる）から最も低い特権レベル（最も信頼できず、大きな番号を与えられる）までの階層構造で形成される。多くのOSでは、リング0が最も特権が高く、最も直接ハードウェア（CPUやメモリ）とやりとりできる。
リング間には特別なゲート（門）があり、外側のリングから内側のリングのリソースに予め決められた方法でアクセスすることを可能にしており、任意の使用を許すことはない。ゲートによるリング間の正しいアクセスにより、あるリングのプログラムが別のリングのプログラム用のリソースを悪用することを防ぎ、セキュリティを強化することができる。例えば、ハードウェアアクセスはリング1のデバイスドライバで行う必要があり、ユーザプログラムとしてリング3で動作しているスパイウェアがユーザーに知られずにウェブカメラをONにすることはできない。より大きな番号のリングで動作するウェブブラウザなどのプログラムは、より小さい番号のリングからしかアクセスできないリソースであるネットワークへのアクセスを所定の方法で要求しなければならない。

実装

ハードウェアのサポートするリングプロテクションはMulticsオペレーティングシステム（UNIX系OSの先祖）の導入した様々な革新的コンセプトの中でも最も先進的であった。しかし、今日最も一般的なOSは2レベルのリングしか使っておらず、ハードウェアの提供するCPUモードの一部しか使用していないことが多い。例えば Windows XP およびそれ以降のOSは2つのリングしか使っていない。カーネルモードに対応するリング0とユーザーモードに対応するリング3である。
多くの最近のCPUアーキテクチャ（インテルx86アーキテクチャなど）は何らかのリングプロテクション機構を持っている。しかし、Windows NT 系OSもUnix系OSもそれを完全には利用していない。OS/2では3つのリングを使っていた。リング0はカーネルとデバイスドライバ、リング2は特権コード（I/Oアクセス特権を持ったユーザープログラム）、リング3は特権のないコード（ほぼ全てのユーザープログラム）となっていた。DOSでは、カーネルもドライバもアプリケーションもリング3で動作することが多く、EMM386などの386のメモリマネージャがリング0で動作していた。さらに、DR-DOSの EMM386 3.xx はオプションで一部モジュール（DPMSなど）をリング1で動作させることもできた。OpenVMSは4つのモードを使っており、特権の高い方から順に、カーネル、エグゼクティブ、スーパーバイザ、ユーザーと呼んでいる。
最近でもリングプロテクションに関して新たな動きがあった。XenのVMMソフトウェア、モノリシックカーネルとマイクロカーネルに関する議論、マイクロソフトのNGSCBイニシアティブによる「Ring-1」設計構造、Intel VT-x などのファームウェア組み込みのハイパーバイザなどである。
Multicsでは8レベルのリングを持っていたが、最近のシステムではもっと少ない。ハードウェアは現在走行中のスレッドが実行している命令列のリングレベルを特別なレジスタで監視している。システムによっては、仮想空間の一部領域とリング番号割り当てがハードウェアで連動している。例えば、データゼネラルの Eclipse MV/8000 では、プログラムカウンタ (PC) の最上位3ビットがリングレジスタを兼ねている。そのため、例えば仮想アドレス 0xE200000 をPCにセットしてコードを実行すると、自動的にリング7となり、仮想空間上の別のセクションにあるサブルーチンを呼び出すことは、リングからリングへの移行を自動的に伴うことになる。
ハードウェアは、あるリングから別のリングへの制御の移動を厳密に制限している。また、メモリアクセスも各リングのレベルに応じて制限している。予め設定されたエントリポイントを通して特別な gate 命令や call 命令を使って、より高い特権レベルのリングに制御を移す（これをコールゲート方式などと呼ぶ）。多くのOSでこれに類似したシステムコール方式を採用している。このようなハードウェアによる制限は偶然や故意によるセキュリティ違反からシステムを守るために設計されている。さらに、最も高い特権レベルのリングには特別な機能が与えられている。例えば、仮想記憶をバイパスして物理メモリ空間にアクセスするといったことが可能である。
リングプロテクションはシステムによってはCPUモードと密接な関係がある。両者をサポートするシステムで動作するオペレーティングシステムは、必ずしも両方を利用しているとは限らない。
リングプロテクションの効果的な利用にはハードウェアとオペレーティングシステムの緊密な協力が必要となる。複数のプラットフォームで動作するように設計されたオペレーティングシステムは、共通して使える一部のリングだけを使用する。そのため、ハードウェアが高度なリングプロテクション機能を持っていても「カーネル」と「ユーザー」に単純化したセキュリティモデルが採用されることが多い。

スーパーバイザモード

スーパーバイザモード (supervisor mode) という用語は、システムレベルのソフトウェアで動作するコードが変更できるハードウェアで実装されたフラグを意味する。システムレベルのタスクやスレッドが動作中はこのフラグがセットされており、ユーザ空間のアプリケーションが動作中はセットされていない。このフラグは、制御用のレジスタを書き換えたり、割り込みをマスクしたりといった特権命令を実行できるかどうかを決定する。2つの異なるモードを持たせるという考え方は「より多くの制御を得ると、より多くの責任も生じる」という考え方から来ている。特権命令を間違って使用するとシステム全体のクラッシュにつながる可能性があるので、スーパーバイザモードのプログラムは決して間違わないものとして信頼されている。
スーパーバイザモードは、「特権命令を含む全命令の実行を可能にする一部プロセッサが持つ実行モード。また、異なるアドレス空間へのアクセスを可能とされたり、メモリ管理ユニットや他の周辺機器へのアクセスも可能とされることもある。通常、オペレーティングシステムはこのモードで動作する。」と定義されている。
モノリシックカーネルのOSは、カーネルがスーパーバイザモードで動作し、アプリケーションがユーザーモードで動作する。マイクロカーネルなどでは、必ずしもこのような住み分けではない。
LinuxとWindowsはスーパーバイザモードとユーザーモードを使用している。ユーザーモードのコードが何らかの特別な機能を使いたい場合、システムコールによってスーパーバイザモードに移行し、カーネル空間にあるOSの信頼されているコードで処理を行い、結果をユーザ空間に返す。DOS（少なくともEMM386のような386のメモリマネージャをロードしていない場合）や他の単純なOSと同様、多くの組み込みシステムは常にスーパーバイザモードで動作しており、デバイスドライバとユーザプログラムのプログラミングに差がない。
多くのプロセッサは少なくとも2種類のモードを持つ。x86プロセッサは4つのモードを持ち4層のリングプロテクションになっている。リング0で動作するプログラムはあらゆることができ、リング3で動作するコードで障害が発生してもシステムの他の部分に影響を与えない。リング1とリング2は滅多に使われないが、それぞれ異なるアクセスレベルを構成できる。
ユーザーモードからカーネルモードへの切り替えは、多くのシステムで非常に高くつく。基本的なシステムコールであるgetpidを実測してみると、多くのマシンで1000から1500サイクルかかる。そのうち約100サイクルが実際のモード切替（ユーザからカーネル空間へは70サイクル、戻るのに40サイクル）で、残りはいわゆる「カーネルオーバーヘッド」である。L3 microkernel では、このオーバーヘッドを最小化しており、全体のコストは約150サイクルとなっている。
モーリス・ウィルクスは次のように記している。
… リングが提供する階層型プロテクションは、システムプログラマの要求とは正しくマッチしておらす、2つのモードだけを持つ単純なシステムにとってはほとんど全く改良にならなかったことが明らかとなった。リングプロテクションはハードウェアでの効率的実装に適していたが、それ以外に特に言うべきことはない。（中略）リングプロテクションが答えを提供しないことが明らかになった後でも、きめ細かいプロテクションという概念は魅力的だった。（中略）これはまた袋小路を裏付けた …
性能と決定性を向上させるため、一部システムはデバイスドライバ以外のアプリケーションのような機能をカーネルモードで提供している。例えば、セキュリティ関連機能（アクセス制御、ファイアウォールなど）やOSモニターなどがある。データベース管理システムをカーネルモードで実装してコンテキストスイッチを減らすという試みがなされた例もある。
また、逆方向の対処法もある。例えばLinuxカーネルは VDSO を使い、通常ならシステムコールで（リング間遷移を伴って）呼び出すような機能をプロセス側に持たせることができる。カーネルが提供する静的データを使い、リング間の遷移をすることなく軽量にシステムコールを実行できる。例えば gettimeofday はそのように提供できる。

ハイパーバイザモード

インテルおよびAMDの最近のCPUは、ハイパーバイザのためのx86仮想化命令を提供しており、ハイパーバイザがリング0のハードウェアアクセスを制御できる。Intel VT-x と AMD-V は相互に非互換だが、どちらも新たにリング0よりも特権レベルの高い状態を提供する。そのためゲストOSには全く修正を加えず、ゲストOSがリング0の命令を実行してもホストOSや他のゲストOSに影響を与えないようにできる。

CPUとOSの抽象化レベルの間の相互運用

多くのCPUアーキテクチャは、実際のオペレーティングシステムが利用する以上の柔軟性を提供している。複雑なCPUモード群をまともに活用しようとすると、OSとCPUの密接な協力が必要となり、OSがそのCPUアーキテクチャに依存することになる。OSとCPUが互いを意識して設計されている場合は問題ないが（それでも一部ハードウェア機能は利用されないことがある）、OSが複数のプラットフォーム（異なるCPUアーキテクチャ）で動作するよう設計されている場合、CPUモード機能の大部分は無視されることになる。例えば、Windows が2つのリング（リング0とリング3）しか使わないのは、かつてx86以外のアーキテクチャ（PowerPCやMIPS）もサポートしていたためで、最大公約数が2つの特権レベルだった。
Multicsは特定のCPUアーキテクチャ向けに設計されており、そのCPUアーキテクチャもMultics用に設計されている。そのため利用可能なCPUモード群を全て利用している。しかし、これは例外である。今日、OSとハードウェアが密接に相互依存することは、セキュリティと安定の観点からはよいことだが、費用効果が悪い。
マイクロカーネルは、主にセキュリティと簡潔さのために特権モードで実行するコード量を最小化しようとするが、そのために性能が犠牲になることが多い。