NetBSD 2.0の新技術を理解する

NetBSDは、世界で最も移植性の高いOSとして知られている。現在、NetBSDは1つのソース・ツリーから派生した52のシステム・アーキテクチャをサポートしており、その他のアーキテクチャにも次々と移植されている。NetBSD 2.0では、これまでの伝統を維持しつつ、ファイル・システムとメモリ管理のパフォーマンスに大きな改善が加えられ、セキュリティ機能が大幅に拡張されたほか、多くの新しいプラットフォームと周辺機器がサポートされている。このリリースを記念し、NetBSD 2.0の新機能について著名なNetBSD開発者たちに聞いてみた。

NetBSD 2.0における変更および新機能の一覧は、「changes」ガイドで参照できるが、主なものをここで紹介しよう。

  • スケジューラ・アクティベーションに基づいたネイティブ・スレッドのサポートが追加された。ネイティブ・スレッドをサポートするアプリケーションは、NetBSDの高パフォーマンスなPOSIXスレッド実装をフル活用できるようになった。
  • カーネル・イベント通知フレームーワーク:kqueueが、ステートフルで効率的なイベント通知フレームワークを提供する。現在サポートされているイベントは、ソケット、ファイル、ディレクトリ、fifo、pipe、tty、デバイスの変更、そして、プロセスとシグナルの監視である。kqueueは、NetBSDツリー内のすべての書き込み可能なファイル・システム(Codaを除く)と、poll()をサポートしているすべてのデバイス・ドライバでサポートされている。
  • NetBSDのLinuxエミュレーションも改善され、最新のLinux用JDK/JREがサポートされている。テストでは、ネイティブなLinuxと同じように動作できることが確認されている。
  • NetBSD 2.0では、多くのプラットフォームで非実行マッピングを採用している。つまり、プロセス・スタックとヒープのマッピングはデフォルトで非実行になり、バッファ・オーバーフローが起きた場合にこれを悪用される可能性が低くなる。NetBSD 2.0は、ハードウェアが実行アクセスとデータアクセスを区別するすべてのプラットフォームにおいて、粒度が必ずしも1ページ単位でなくとも、mmap()を通じてPROT_EXECパーミッションをサポートしている。ハードウェアの粒度がページよりも大きいときには、より大きな単位の中のいずれかのページが実行可能な場合はその単位全体が実行可能であると判断され、そうでない場合はその単位は実行可能でないと判断される。
  • i386ポートがSMPをサポートし、IntelのACPI実装を活用できる、新しいACPIと電力管理フレームワークが加わった。
  • FreeBSDのUFS2がNetBSDに移植された。UFS2はFFSの拡張機能で、64ビットのブロック・ポインタと拡張ファイル・ストレージのサポートを追加する。また、UFS2では、1テラバイトを超えるファイル・システムが許可されている。
  • systraceフレームワークがシステムに追加された。systraceは、システムコールにアクセス・ポリシーを実装することで、アプリケーションからシステムへのアクセスを監視および制御する。systraceユーティリティは、アプリケーションからシステムへの信頼できないアクセスを追跡するのに利用できる。さらに、デーモンからシステムへのアクセスを制限することで、ソフトウェアのバグ(バッファ・オーバーフローなど)からシステムを保護するのにも役立つ。systraceの権限昇格の機能を使えば、昇格された権限を必要としているシステム・コールがたった数個である場合に、信頼できない大きなプログラムをルートとして実行する必要がなくなる。
  • このリリースでは、Verified Execサポートが追加されている。Verified Execは、バイナリやスクリプトの実行を許可する前に暗号ハッシュを検証する。これを使うと、悪意を持って改ざんまたはインストールされたバイナリやスクリプトをシステムが実行してしまうのを防げる。さらに、スクリプトのインタープリタの使用を、許可されたスクリプトのみに制限し、インタラクティブな使用を禁じることもできる。

2.0リリースについての詳細は、リリース声明で、さまざまな言語で読むことができる。

NetBSD開発者へのインタビュー

NetBSDのプログラマであるChristos Zoulas、Luke Mewburn, Ben Collver、Nathan J. Williams、Jaromir Dolecek、Chuck Silvers、Hubert Feyrer、Bret Lymn、Jan Schaumann、Roland Dowdeswell、そしてNiels Provosにインタビューを行った。NetBSDの新機能について彼らが語ってくれた内容を紹介する。

このリリースがメジャー・リリース番号である2.0になった理由の1つとして、SMPサポートの導入が挙げられます。それぞれが選択・開発したテクノロジを教えていただけますか?

Luke Mewburn:SMP(いわゆる「biglock」モデル)、カーネル補助のユーザランド・スレッド、およびpthreads(POSIXスレッド)APIです。

FreeBSD 4.x/5.x、DragonFlyBSD、OpenBSDのSMPテクノロジと比べてどのような特徴がありますか。

Luke Mewburn:私の記憶が確かならば、FreeBSD 4.xはbiglockだったはずです。FreeBSD 5.xとDragonFlyBSDでは、biglock SMPの問題を解決するために別のアプローチを採用しています。OpenBSDはbiglockで、以前のNetBSD SMPコードベースから派生したさまざまな部品を使っています。

i386 IntelのHyperThreadingテクノロジなど、特定のプラットフォーム向けの最適化は何か行われていますか?

Luke Mewburn:HTのサポートを有効にしました。また、それぞれの仮想CPUが別々に扱われるようになっています。スケジューラには現在のところ、HTについての特定の知識はないため、(仮想)CPUにおいてプロセスをスケジューリングする際にHT特有のアーキテクチャが活用されることはありません。

新しいコードは、シングルCPUシステムのパフォーマンスに影響しますか?

Luke Mewburn:SMPが有効になっているカーネルを実行していない限り、影響はないはずです。

ネイティブ・スレッドのサポートが追加されました。「ネイティブ」というのはどういうことですか?

Christos Zoulas:OSに対して「ネイティブ」である、ということです。言い換えれば、スレッド・ライブラリが利用する、スレッドを補助するための機能がOSに用意されているということです。これらの機能はベースのOSに含まれており、サードパーティのパッケージをインストールする必要はないので、ネイティブです。最後に、「ネイティブ」という言葉が意味するのは、それらがユーザランド・ベースであるだけでなく、本当のカーネル・スレッドであるということです。NetBSDの実装では、ユーザランド・スレッドとカーネル・スレッドの両方が使われています(これをn:mスレッド・モデルと呼びます)。

Ben Collver:NetBSD 2.0以前のリリースでは、ベース・システムにスレッドAPIがありませんでした。厳密に言うと例外はあります。たとえば、clone()システム・コールは、スレッド化されたLinuxアプリケーションを実行するためにLinuxエミュレーションに用意されていました。以前のNetBSDリリースにおいては、スレッド化されたアプリケーションの実行にはユーザランド・スレッドの実装だけで十分だったのです。pkgsrcではGNU PTHが使われており、これはおそらく最も広く使われている実装でしょう。

以前のスレッドはどのような仕組みだったのですか?

Nathan J. Williams:以前は、統合されたスレッドはありませんでした。スレッドを使う必要のあるアプリケーションは、GNU pthやPTL2のようなライブラリ内でリンクしていました。これらのライブラリは、文献などでは、カーネルが感知しないところですべてのスレッドの実装が行われることを意味する「ピュア・ユーザ空間(pure user-space)」システム、または、すべてのアプリケーションのスレッドがカーネル・プロセスに多重化されるという意味の「1:Nスレッド」と呼ばれています。このような形のライブラリには、スレッドの長所をすべて実装できないという問題があります。具体的には、カーネルはスレッドの存在を認識していないため、プロセス内のすべてのスレッドをブロックする演算やシステム・コールの一部に対して脆弱です。

Ben Collver:Ralf S. Engelschallによる論文「Portable Multithreading」で、GNU PTHの仕組みについて解説しています。

GNU PTHの短所は、スレッド化されたアプリケーションがマルチプロセッサ・マシンのメリットを享受できないということ、そして、スケジューリングがプリエンプティブでないことです。

POSIX標準への準拠によって変わったことは何ですか。

Christos Zoulas:プラットフォーム間でのアプリケーションの移植性が向上しました。ほかのOS上のPOSIX準拠のpthreadライブラリで利用できるスレッド化アプリケーションがすべて、NetBSDでも利用できます。

Nathan J. Williams:最近では、POSIXスレッドが唯一の選択肢です。

「スケジューラ・アクティベーション」が基になっているとのことですが、これは何ですか。

Nathan J. Williams:スケジューラ・アクティベーション(SA)は、Thomas Andersonが1992年の論文で発表したメカニズムで、which provides an interface between an OSカーネルとアプリケーションの間にインターフェイスを設け、並行処理のレベルを一定に保つというものです。このシステムでは、アプリケーションが並行処理の度合をカーネルに知らせます。たとえば、同時に演算を行っているスレッドの数などです。するとカーネルは、「アクティベーション」、つまり、ライブラリがアプリケーション演算を積み重ねるための、スケジューリング可能なエンティティを、特定の数に保ちます。これには、アプリケーションの演算割り当て調整と、カーネル内での操作のブロックおよび再開の通知のためのメッセージが含まれています。

POSIXスレッド実装でSAを使うメリットは、スケジューリング可能なカーネル・エンティティ、およびカーネル・リソース全般の数を、アプリケーション内のスレッドの合計数ではなく、並行処理されているスレッドの数に制限できることです。これにより、リソースを節約でき、スレッド間に不必要なスケジューリングの競合が起きることもありません。

これについては、USENIXの論文「An Implementation of Scheduler Activations on the NetBSD Operating System」で詳しく論じられています。

新しいkqueueフレームワークとは何ですか。

Jaromir Dolecek:従来のselect()/poll()は、記述子に限定されたものでした。重要なカーネルイベントは、シグナルやファイル・システムの変更など、他にもあります。

さらに、select()/poll()では、ウォッチされている記述子の数が多くなるとうまく対応できなくなります。効率が大きく低下してしまうのです。syscallが呼び出されるたびに、ウォッチされている一連の記述子すべてを渡す必要があるので、システムは、ユーザ/カーネルの境界を越えて2度もメモリ・コピーを行わなければならなくなります。こうなると、ほかの処理で利用できるメモリの帯域幅が少なくなります。内部カーネルの処理もスケーラブルだとは言えません。記述子が複数のプロセスまたはスレッドでウォッチされている場合、カーネルが、リストを何度もループしなければならず、やり取りがうまくいかなくなるからです。

kqueueには、イベントが発生したり条件が満たされたりした場合にユーザに通知を行うジェネリックな方法が用意されています。また、イベントについての詳細情報も提供されます。kqueueフレームワークはステートフルであり、アプリケーションはkqueue記述子経由で、関連のあるイベントをカーネルに登録し、いずれかのイベントが発生するのを待っていればよいのです。NetBSD 2.0では、select()/poll()で提供される従来どおりの機能だけでなく、Windowsディレクトリの通知やIRIXの/dev/imonと同様の、ファイルシステムのイベント(アンリンク、名前の変更、属性の変更など)の通知、シグナル、任意の数のタイマ、といったイベントがサポートされています。また、FIFO、ソケット、オープン・ファイル、その他のkqueue記述子など、あらゆる種類の記述子がサポートされています。すべての種類のオブジェクトに関して、登録されるイベントの数に制限はありません。

kqueueは通常、同期して使われます。kqueue記述子もpollableであるため、従来の非ブロッキングのアプリケーション・モデルと互換性があります。標準のO_ASYNCシグナルのセマンティクスをkqueue記述子で使用すれば、新しいイベントの非同期通知も利用可能です。

kqueueの仕組みはどのようになっているのですか。

Jaromir Dolecek:カーネル内部で、kqueueはカーネル・フィルタの概念を持ちます。アプリケーションがイベントを登録すると、適切なフィルタが呼び出され、そのイベントがすでに起こっているかどうかをチェックします。起こっていれば、そのイベントのデータがすぐに入手可能になります。一度登録されると、ウォッチ・セットは二度と評価されることはありません。ウォッチされている記述子が閉じられると、カーネルは自動的にアイテムをkqueueリストから削除します。

ウォッチされているイベントが起きると、条件と、それに関連する状態が、適切なkqueue structuresに記録され、アプリケーションはイベントを取得できるようになります。アプリケーションがイベント・データを読む前にイベントが複数回発生した場合には、最後のイベント・コンテキストだけがデータに反映されます。

ウォッチされているイベントに対するスケーラビリティは、select()/poll()ではO(n)ですが、kqueueでは、O(1)です。複数のプロセスまたはスレッドが同じ記述子をウォッチしても、パフォーマンスが低下することはありません。

kqueueを利用するようにアプリケーションを変換するのはとても簡単です。tail(1)syslogd(8)inetd(8)などのシステム・ユーティリティは、この機能を利用してより高いスケーラビリティとシンプルなイベント処理を実現できるよう変更されています。kqueueはサードパーティのコードでも使用されています。APIは、主要なオープンソースBSD(NetBSD、FreeBSD、OpenBSDなど)に含まれています。

Christos Zoulas:これはFreeBSDのJonathan Lemonによるものです。

非実行スタック、非実行ヒープ、propolice、W^Xなどのメモリ保護についてお聞きします。2.0リリースではこれらのテクノロジがどのように扱われているか、簡単に説明していただけますか。

Chuck Silvers:NetBSD 2.0では、プロセス・スタックとヒープはいずれも、ハードウェアがこれをサポートしているプラットフォームならばデフォルトで非実行です。propoliceはNetBSDには統合されていません。その他のOpenBSD W^Xの変更も、まだ統合されていません。

これらの保護はどのハードウェアでサポートされていますか。

Chuck Silvers:非実行マッピングを完全にサポートしているハードウェア・プラットフォームは、AMD64、SPARC64、SPARC(sun4m、sun4d)、PowerPC(IBM4xx)、Alpha、SH5、HPPAです。

非実行マッピングを部分的にサポートしているハードウェア・プラットフォームは、i386およびPowerPC OEA(macppcなど)です。詳細についてはこのドキュメントを参照してください。

Verified Execのアイデアは良いと思いますが、この環境のセットアップにはどの程度の時間が必要なのでしょうか。

Brett Lymn:それほど長くはかかりません。Verified Execを含めてカーネルをビルドする必要があります。最も時間がかかるのは、フィンガープリント・ファイルの生成です。これに役立つスクリプトが、/usr/share/examples/veriexecctl/にいくつかあります。これらのスクリプトは、システムをスキャンして、適応するすべてのファイルに対してフィンガープリントを生成します。マシンの種類によっては、多少時間がかかるかもしれません。生成されたシグネチャ・ファイルを/etcに配置すると、ロードできます。

検証プロセスの仕組みはどのようになっているのですか。

Brett Lymn:ブート・プロセスの前半で、すべての実行可能ファイルと共有ライブラリのフィンガープリントのリスト(md5またはsha1ハッシュ)がカーネル・メモリに読み込まれます。いずれかの実行可能ファイルが実行されるか、共有ライブラリが参照されると、実行可能ファイルまたはファイルのハッシュが計算され、リストと照合されます。ハッシュが合致すれば、実行またはアクセスが許可されます。合致しなければブロックされます。このアイデアは、トロイの木馬がシステム・ユーティリティ内に挿入されることや、未確認のバイナリが実行されることを防ぐためのものです。詳細はここを参照してください。

systraceがついにベース・システムに含まれましたが、デフォルトでsystraceされるアプリケーションはあるのですか。

Niels Provos:現時点では、デフォルトでsystraceされるアプリケーションはありません。systraceは、被害妄想気味のシステム管理者が、セキュリティを確実にするために利用することができます。たとえば、小規模ISPであるmonkey.orgは、systraceを実行して、ユーザに対し制限付きのシェル・アクセスを提供しています。systraceによって悪用を未然に防ぐことが可能になったようです。

NetBSDはFreeBSD-5からUFSv2を移植しています。移植の際に、何らかの改善や新機能は加えられているのでしょうか。

Christos Zoulas:いいえ、何も加えていません。ブロックレベルでのスナップショット・メカニズム(/dev/{r,}fss*)を採用していますが、あくまで実験的なものです。

サポートされているアーキテクチャのうち、ポータビリティの問題が起きたものはありましたか。

Christos Zoulas:UFS2に関して、ということであれば、ブート・ブロックとUFS1ファイル・システムでは互換性の問題がありましたが、これらは解決しました。全般的なコードのポータビリティについてであれば、次の3種類の問題がありました。

  • エンディアンネスの条件
  • 配置制約の違反
  • 型サイズの条件

問題のほとんどは、こちらのソースではなく、pkgsrcでした。しかし、i386(リトルエンディアン、32ビット、配置制約なし)とSPARC64(ビッグエンディアン、64ビット、配置制約あり)の両方でコードが動くようにできるなら、ポータビリティに関するバグのほとんどは解決されたも同然です。

最後に、OS機能のポータビリティがありますが、最近では多くのOSがPOSIX準拠なので、これは難しくなくなってきています。

NetBSD/xenのステータスはどうなっていますか。

Luke Mewburn:動作します。われわれはプロジェクト内でこれを使用して、1台の物理マシン上に複数の仮想マシンを作成し、内部の管理に役立てています。

ノートPCでNetBSDを実行するユーザには、ACPIが採用されているこのリリースが適していると思われますが、具体的なメリットとしてはどのようなものがありますか。

Luke Mewburn:サーマル・ゾーンのサポート含め、最新のラップトップがサポートされています。しかし、現時点ではACPIサスペンド/レジュームはサポートされていません。

Hubert Feyrer:コホン。私は、NetBSDをノートPCで利用する動機がACPIしかないとは思いませんよ。PCMCIAおよびCardbus用の優れたフレームワークのためだけでも、NetBSDを試す価値はあると思います。最近のラップトップやノートPCで使われている多数のUSBデバイスや最近のPCIデバイスのサポートも、すぐに利用可能です。NetBSDのUSBおよびPCMCIA/Cardbusシステムは、ほかのシステムの実装の基礎にもなっているのです。

WPA、WiFi-Max、802.11a/b/g/iなど、ワイヤレス通信に新しい標準がいくつか登場しましたが、どれがサポートされているのですか。

Hubert Feyrer:これは、ワイヤレス通信機能を実現するカードや、そのドライバによって異なります。Atherosのカードでは、WAPは利用できません。WiFi-Maxは専門用語ではなく、おそらくAtherosの「Turbo」(108Mps)モードに相当すると思われますが、これはNetBSDで完全に動作します。NetBSD 2.0がサポートしている802.11標準は、「b」、「a」、そして「g」です(「i」がすでに発表されているかどうかはわかりません)。

Luke Mewburn:802.11a/b/gは、Atherosベースのデバイスを含めさまざまなカードでサポートされています。WPAのサポートは現在対応中です。WiFi-Maxについてはわかりません。

ラップトップのユーザにとって興味深い機能として暗号化ディスク・ドライバがありますが、これはどのような仕組みですか。

Roland Dowdeswell:詳しくは論文とmanページ(私のWebページにあります)で説明されていますが、簡単に言うと、CGDはディスク、またはディスク内のパーティションに付随して、OSのほかの部分に対しては擬似ディスクとして振舞います。これが、移行する情報を暗号化および復号します。つまり、CGDを/dev/wd0eに追加した場合、/dev/cgd0[a-h]に読み書きすると、/dev/wd0eの内容が復号されたものが得られます。/dev/cgd0[a-h]を使えば、通常のディスクで行うことのできる処理はすべて可能です(主にファイル・システムとスワップですが、データベースのバックエンドのような使い方も可能です)。

予期しないシステムのシャットダウンがあった場合、それはどの程度影響しますか。

Christos Zoulas:何の影響もありません。ブロックレベルのドライバなので、通常のディスクの上にあるもう1つのレイヤとして動作します。

Roland Dowdeswell:基底のディスク・デバイスの原子性はすべて保持されているので、CGDを利用することで、予期せぬシステムのシャットダウンに対するOSの振る舞いが変わることはありません。

これはOpenBSDから移植されたものですか。

Roland Dowdeswell:いいえ。私は、CGDの作成時に、すでに同じようなものがないかどうか探しましたが、実用的で、かつ暗号の面でも満足のいくオープンソースのディスク暗号化システムはありませんでした。OpenBSDでは、vnd(4)に暗号化を追加して同様の機能を実現することができますが、1種類の暗号(blowfish)しかサポートされておらず、鍵の生成も強力とは言えません。実際のデータ保護に利用できるものではないでしょう。

以上の理由で、私は1からCGDを作成することにしたのです。

CGDはその一部が、Ted UnangstによってOpenBSDに移植されていますが、私が最後にチェックした段階では、標準リリースには含まれていませんでした。

NetBSDには、1.6リリースをベースとしたLiveCDがあったと記憶しています。2.0のコードを基にして、アップデート版を作成する計画はあるのでしょうか。

Jan Schaumann:計画についてはわかりませんが、pkgsrcにあるsysutils/mklivecdを使うと、ユーザが自分でLiveCDを作成できます。覚えておくといいかもしれません(実際、ACM主催の地元のプログラミング・コンテストでは、2.0ベースのLiveCDを使う予定です)。

Hubert Feyrer:あります。ドイツ語版の、2.0ベースLiveCDが、ドイツのFreeX magazineで配布されています。このCDはKDEでブートし、KOffice、Sodipodiなど数多くのアプリケーションが利用できます。このCDの国際化バージョンは、FreeXのエディタJoerg Braunの好意によって、2.0のリリースにあわせて入手可能になる予定です。

原文