BSD界隈四方山話

第9回 カーネル内部のセキュリティを強化,ネストカーネルでメモリ区画化

この記事を読むのに必要な時間:およそ 2 分

ネストカーネル - カーネル内メモリアクセスを区画化

2015年6月10日,カナダのオタワで開催されたFreeBSD開発者らによるデベロッパサミットFreeBSD Developer Summit, June, 2015において,カーネルモードにおけるメモリアクセスを区画化し,カーネルモードでの動作をより安全にする取り組み「ネストカーネル(Nested Kernel)⁠が紹介されました。イリノイ大学アーバナ・シャンペーン校の研究者らによって取り組まれたものです。FreeBSD 9.0を対象に実施されており面白いものでした。開発も活発で今後FreeBSD本家へ取り込まれる可能性もありそうです。

UNIX系オペレーティングシステムはソフトウェアをプロセッサの特権モードのうち,2つのモードのどちらかで実行します。すべての機能を使用できるスーパバイザモードか,機能が制限されたユーザモードかです。通常,カーネルがスーパバイザモードで動作し,それ以外のソフトウェアがユーザモードで動作します。システムに影響を与えるような処理はカーネルにまとめておき,ユーザモードで動作するソフトウェアがそれらの機能を必要とした場合には,システムコールを呼び出してカーネルに処理をお願いします。

このような仕組みにすることで,一般のソフトウェアがほかのソフトウェアに与える影響を抑え,バグや,または故意に組まれた悪意あるコードによってシステムがおかしくなることを防いでいます。しかしこれは反面,カーネル自体はなにも保護されていない,ということも意味しています。

ユーザモードで動作しているソフトウェアはシステムコールを呼ぶことでカーネルに処理を依頼できるわけですが,さまざまな仕組みを使うことで故意にカーネルに誤った処理をさせることができる可能性があります。バグがあればそこが使われますし,最終的にバッファオーバーフローなどを引き起こさせて任意のコードを実行させたり,機密性の高い情報が抜き出されるなどの恐れがあります。カーネルという最後のリゾートが突破されてしまうと,セキュリティもなにもないわけです。

ゼウス・カーネル故のもろさ

カーネルの何が問題かといえば,カーネルは全メモリのどこにでも自由にアクセスできてしまう,というのが問題です。カーネルにバグがあれば,またはセキュリティ脆弱性を突かれてしまえば,あとはメモリ上のデータをやりたい放題に書き換えることができますので,もうそこにリソース保護やセキュリティといったものはないわけです。

近年,特にセキュリティへの高い必要性から,こうしたモノリシック指向のカーネルにおいて,どうやってセキュリティを向上させるかといった研究が盛んに行われています。研究内容は多岐に渡りますが,今回カナダのデベロッパサミットで発表された「ネストカーネル(Nested Kernel)⁠は,MMUやプロセッサの機能を使ってカーネルがアクセスするメモリ領域を区画化および保護化し,特権を超えた処理ができないようにしよう,というものです。

カーネル内メモリアクセスを区画化またはモニタリングして,不適切なアクセスを防止するという取り組みはほかにもありますが,ネストカーネルは既存のモノリシックカーネルと相性が良いこと,カーネルの変更が少ないこと,ネステッドカーネルのコードもかなり短いこと,といった特徴があります。さらにカーネルサイズもほとんど変わらず,パフォーマンスの低下も目をつぶれるほど小さいという特徴があります。

FreeBSDカーネルをベースとしたメモリ区画化の研究はネストカーネルに限らないため,この技術が最終的にマージされるとは限りませんが,今後さらに高まるセキュリティへの需要を受けて,将来どこかのタイミングでこうした機能がマージされることは間違いのないように思います。

ネストカーネルの抜本的なアイディア

ネストカーネルでは,次の過程がアイディアの根幹をなしています。

メモリ管理ユニット(MMU:Memory Management Unit)のページテーブルへのアクセスを規制することができれば,カーネル内部においてもメモリの区画化を実現できるのではないか。たとえそれが単一のハードウェア特権レベルで動作しているのであったとしても。

カーネルはこれまでスーパバイザモードで動作し,その世界はすべての特権を持つものでした。ネストカーネルのアイディアは,このスーパバイザモードで動作するカーネルを仮想化して,そこでのメモリアクセスをより細かに規制して保護すればよいのではないか,というものです。

ここで従来のカーネルは次の2つのカーネルに分かれます。従来のカーネルに相当するものは「アウタカーネル」と呼ばれ,新しく追加されるカーネルが「ネストカーネル」と呼ばれています。そして,ユーザランドからシステムコールが呼ばれると,カーネルは次のような処理をするようになります。

  1. システムコールが呼ばれる
  2. アウタカーネルが呼ばれる
  3. アウタカーネルはネストカーネルを呼ぶ
  4. ネストカーネルが処理を実施する

処理は「アウタカーネル」「ネストカーネル」の2つに分かれています。そして従来と異なり,それぞれ次のような規制が加わります。

  • アウタカーネル
    • ページテーブルは常にリードオンリー
  • ネストカーネル
    • カーネルコードはリードオンリー
    • カーネルデータは実行不可能(Non-executable)
    • ユーザコードはSMEP(Supervisor Mode Execution Protection)
    • ユーザデータはSMEP(Supervisor Mode Execution Protection)
    • ページテーブルは常にリードオンリー

アウタカーネルもネストカーネルも動作するのは同じ特権レベルであるスーパバイザモードですが,今までなんでも操作できたカーネルと異なり,自ら規制を敷いて,操作できる内容を限定化しています。このようにすることでメモリアクセスや変更できる領域または特権を区画化し,従来よりも悪さがしにくい構造にしています。

なお,ネストカーネル側では書き込みへの介入およびチェック,書き込みのロギングなども実施し,不正な処理を検出するようになっています。

コメント

コメントの記入