Linux のセキュリティ機能についてのガイドラインを検討する前に、プログラマ の観点でそれらの機能を理解しておきましょう。 このセクションではそれらの機能について概観します。すでに理解されている場合 は読み飛ばしてください。
プログラミング・ガイドの多くは、Linux のセキュリティ関連の項目を軽く 済ましてしまい、大切な情報を省いてしまっています。 特に「どうやって使用するのか」をかいつまんで説明する場合が多く、 その機能を使用することによって生じるセキュリティ上の問題については、 うわべの説明にしか行っていません。 逆に個々の機能については、マニュアルの該当するページに詳細な情報がたくさん 書かれています。しかし、マニュアルページの記述は詳細すぎて全体像の把握を 困難にしがちです。 このセクションでは、そのギャップを埋めようと思います。プログラマが使いそう な Linux におけるセキュリティのしくみを概観します。 一般的なプログラミング・ガイドよりもう少し深くセキュリティに関する事項に 焦点を当て、さらに詳細な情報が得られるよう、参考文献をあげたいと思います。 UNIX でプログラミングをされた方々にとっては、すでにおなじみのことですが、 Linux で拡張された機能や固有の機能もいくつかあります。その機能にびっくり するかもしれません。 このセクションではそれらの相違点を明らかにしていきます。
まずは基本的なところから。 本来 Linux とは 2 つの部分から成り立っていて、それぞれ Linux カーネル (及びカーネル・モジュール)と「ユーザー空間」と呼ばれています。ユーザ空間は カーネル上にあり、そこで様々なプログラムが動いています。 ユーザがログインすると、ユーザ名はそのユーザが属している uid(ユーザ ID)と gid(グループ ID)を表す整数値に割り当てられます。 uid が 0 のユーザは特別な権限(役割)を持っていて、「root」と言われています。 root はセキュリティ・チェックをほとんど受けることがなく、システム管理を 行う場合に使用されるユーザです。 セキュリティから見て唯一「対象」となるもの、それがプロセスです(つまり、 いろいろなことを実行している正体は、プロセスそのものなのです)。 プロセスは様々なデータにアクセスします。それはファイルシステム(FSO)で あったり、System V のプロセス間通信(IPC)であったり、ネットワーク・ポート であったりします。 もう少しこの点について、詳しく見ていくことにしましょう。
Linux ではユーザ・レベルでの動作をプロセスを動かすことで実現しています。 独立した「スレッド」をサポートするシステムが多いのですが、Linux では スレッドそれぞれを複数のプロセスとして走らせて実現しているようです(Linux カーネルは最適化をはかることによって、スレッド並の実行速度を稼いでいます)。
訳註:Linux のスレッドはユーザ・レベルではなく、カーネル・レベル のスレッドで、カーネルがスレッドの制御を行っています。fork() と同じく 子プロセスを起こしますが、コンテキストの何を親プロセスと共有できるかを 指定できます。
それぞれのプロセスは、次のようなセキュリティ関連の属性を持っています。
訳註:ここで述べられている「カウンタ」とは、プロセスの実行履歴 を計測するために用いられるカウンタを意味します。
属性とプロセスが実際どのように関連しているのかを知りたければ、Linux の ソース・コードを参照してください。include/linux/sched.h で定義されている 構造体の task_struct がキーポイントです。
Linux カーネル 2.2 の機能として「POSIX ケイパビリティ」がサポートされて います。 POSIX のケイパビリティは、通常 root が持っている権限をいくつかに分割して、 独自に権限の体系を再構成しています。 POSIX ケイパビリティは、IEEE(米国電気電子通信学会)標準のドラフトで定義されて います。したがって Linux 固有の機能ではありませんが、他の UNIX ライクなシス テムで広く採用されているわけではありません。 Linux のドキュメント(このドキュメントも含め)の中で、「root の権限が必要で ある」と書いてあった場合、「ケイパビリティが必要である」とほぼ同じ意味に なる、とケイパビリティについてのドキュメントに述べられています。 個々のケイパビリティについて知りたい場合は、下記のケイパビリティに関する ドキュメントを読んでください。
ファイルシステム上にある各ファイル毎にケイパビリティが適用されることが 最終的な目標なのですが、このドキュメントを書いている時点ではまだサポート されていません。 転送機能に対するケイパビリティはサポートされていますが、デフォルトでは無効 になっています。 カーネル 2.2.11 ではケイパビリティを更に身近に使いやすくするしくみである 「ケイパビリティ・バウンディング・セット(capability bounding set)」が取り 入れられました。 このしくみは、システム上で稼動しているすべてのプロセスが利用できるケイパ ビリティのリストを用意します(特別な init プロセスだけが利用できるケイパ ビリティもあります)。 あるケイパビリティがリストにない場合、権限がどうであれ、どのプロセスもその ケイパビリティを利用できません。 この機能を使っている例として、カーネルモジュールの読み込みを無効にする場合 があげられます。 またうまくこの機能を活用しているツールとして、 http://pweb.netcom.com/~spoon/lcap/ にある LCAP があげられます。
訳註:LCAP は、カーネルがサポートしているケイパビリティを無効にする ことによって、システムをより安全にするしくみです。
POSIX ケイパビリティの詳細については、 ftp://linux.kernel.org/pub/linux/libs/security/linux-privs を参照してください。
訳註:上記 ftp サーバーは anonymous ユーザの利用を認めていません。 ftp://ftp.kernel.org/pub/linux/libs/security/linux-privs を利用してください。
プロセスは fork(2)もしくは vfork(2)(使用しない方がよい)、clone(2)(Linux 独自) を使って作成します。これらのシステムコールすべては、既存のプロセスを コピーして、2 つのプロセスを生成します。 プロセスは execve(2)やそのフロントエンドをコールして、別々のプログラムを実行 できます(フロントエンドとして、exec(3)、system(3)、popen(3)を参照してくだ さい)。
あるプログラムを実行する時にファイルに setuid ビットが立っていると、 そのプロセスの euid にはファイルの uid が設定されます。 setgid が立っていると egid にファイルの gid が設定されます。 Linux 上では、シェルスクリプトのようなスクリプト全般に対して、このような ビットの設定はされないことを忘れないでください。 このようなことがスクリプトで設定できてしまうと、セキュリティ上非常に危険な ことになるからです(UNIX ライクなシステムの中には setuid されているスクリプト が動くものもあります)。 例外として、 Perl は特別な設定をほどこすと、setuid されている Perl スクリプト が実行できるようになります。
場合によって、プロセスはいくつかある uid や gid の値を変更できます。 setuid(2)、seteuid(2)、setreuid(2)、setfsuid(2)を参照してください。 特に suid の場合は、信頼できるプログラムが一時的にその uid 値を変更できます。 ruid の変更もしくは euid が ruid と異なる値にした場合は suid には新しい euid の値が設定されます。 特権をもたないユーザは、自分の suid から自分の euid を、ruid から euid を、 euid から ruid を設定できます。
fsuid プロセス属性は、NFS サーバのようなプログラムの権限を、指定された いくつかの UID のファイルシステム権限に制限できるようにするためのものです。 この際、その UID にはプロセスへシグナルを送れる許可は与えません。 euid が変更されると fsuid は新しい euid の値に変更されます。fsuid は setfsuid(2)という Linux 固有のシステムコールを使って設定することもできます。 root 以外から呼び出された場合は、fsuid には現在の ruid 値、euid 値、seuid 値、 あるいは現在の fsuid 値しか設定できません。
ファイルシステムの構成要素(FSO)は、通常のファイル、ディレクトリ、シンボリック リンク、名前付きパイプ(FIFO)、ソケット、キャラクタスペシャル(デバイス) ファイル、ブロックスペシャル(デバイス)ファイルがあります(find(1)コマンドに その一覧があります)。 これらはファイルシステムによって制御され、ファイルシステムを構成するディレ クトリ上でマウント/アンマウントして利用します。 ファイルシステム自身は、これら構成要素とは多少異なるアクセス制限の属性を 持っていて、マウント時にオプションを設定することによって、アクセス制限を かけることが可能です。
今のところ Linux では ext2 が最も一般的なファイルシステムです。ファイルシス テムの構成要素が持っている属性は下記の通りです。
訳註:ファイルのロック機能には、強制ロック(mandatory locking)と アドバイザリ・ロック(advisory locking)があります。違いは、前者が カーネルがプロセスを監視しロック操作を行うので、プロセス間の依存 関係を越えてロックが可能です。 これに対して後者は、プロセス自身がロック操作を行うので、その プロセスの制御外のものに対してはロックが無効となります。 詳しくは、カーネル付属のドキュメントの mandatory.txt を参照してください。
上記の値の多くは、マウント時に適用されます。したがって、あるビット値がすでに 値(媒体上の値が何であれ)を持っていたかのように扱われる場合もあります。 詳しいことは mount(1)を参照してください。 ファイルシステムも中にはこれらのアクセス制御値のいくつかをサポートしていない 場合がありますので、くどいようですが mount(1)を見て、ファイルシステムが何を サポートしているのかを確認してください。
アクセス制御リスト(ACL、access control list)と POSIX ケイパビリティの値を ファイルシステムへ実装する作業が続けられていますが、標準の Linux 2.2 には まだ入っていません。
訳註:ACL は従来の所有者、グループ等によるファイルへのアクセス 制御方法にかわって更に細かな制御を可能とするしくみです。ネットワーク上 のサーバーに対するアクセス制限についてもこの用語が使用されています (RFC 1983)。
作成する時には次のルールが適用されます。 あるファイルシステムの構成要素(FSO)が作られると(たとえば creat(2)を使って)、 FSO の uid はプロセスの fsuid に設定されます。普通、FSO の gid はプロセスの fsuid が設定されますが、ディレクトリに setgid ビットが立っていたり、ファイル システムの「grpid」が設定してあったりすると FSO の gid には、ディレクトリの gid が設定されます。 この特殊なケースを利用することによって、いわゆる「プロジェクト」のための ディレクトリを作ることができます。「プロジェクト用」のディレクトリを作る には次のようにします。まずプロジェクト用に専用のグループを作ります。それから そのグループが所有者であるプロジェクト用のディレクトリを作成し、setgid します。こうすると、何かファイルをそこのディレクトリに置くと、自動的にその プロジェクトが所有者となります。 同様に、新しいサブディレクトリを setgid ビットを立てたディレクトリの配下に 作成すると(ファイルシステムの grpid も設定されていない)、新しいディレクトリ も setgid ビットが立てられます(したがってプロジェクトのサブディレクトリは、 「期待通りの正しい動作」をします。その他のケースは、新しいファイルに setgid はかけられていません。基本となる FSO のアクセス制限(読み込み、 書き込み、実行)は、(要求された値に umask 値を &(ビット反転) ~(論理積))して求められます。 ファイルが新規に作成された状態では、常に sticky ビットも setuid ビットも クリアされています。
アクセス制御の属性の大部分は、chmod(2)か chmod(1)で設定できますが、chown(1)、 chgrp(1)、chattr(1)も参照してください。
注意して欲しいことがあります。それは Linux では root だけがファイルの所有者 を変更することができるということです。 UNIX ライクなシステムの中には、一般ユーザも所有者の変更が行えるものがあり ますが、これは厄介事を引き起こします。たとえばディスク使用量を制限しようと したとします。その時、一般ユーザに所有者の変更を許していると、ユーザの誰かが 自分の大きなファイルを他人の所有に変更して、その人を「被害者」にしたててしま えます。
Linux と UNIX ライクなシステムのほとんどで、読み込みや書き込みの属性 の値はファイルがオープンされた時にだけチェックされます。読み書きする度 にチェックされるわけではありません。システム・コールの大多数が、これらの 属性を利用しています。というのも、ファイルシステムというものが Linux の中枢をなしているからです。 これらのシステム・コールには、open(2)、creat(2)、link(2)、unlink(2)、 rename(2)、 mknod(2)、symlink(2)、socket(2)等があります。
長年の慣例で、「何のファイルはどこに置く」という約束事ができています。 きまりを守って、ディレクトリ階層の中に情報を格納してください。 概略については、hier(5)を参照してください。 さらに詳しく知りたければ、Filesystem Hierarchy Standard (FHS) http://www.pathname.com/fhs を見てください。FHS は従来の Filesystem Structure standard (FSSTND)を新たに書き換えたものです。
Linux は System V 由来の IPC である、メッセージ・キュー、セマフォ、共有メモリ をサポートしています。 それぞれのサービスは、下記の属性を持っています。
下記のルールにもとづいて IPC オブジェクトアクセスします。
root もしくは 所有者や作成者の euid を持つプロセスは、所有者の uid や gid を 設定でき、また削除も可能であることを忘れないでください。詳しくは ipc(5)を 参照してください。
ソケットは、情報を伝える手段として特にネットワーク越しの通信に使用されて います。 socket(2)は情報を伝えるための接続ポイントを作成し、それを表わすディスクリプタ を返します。さらに詳しいことは、socket(2)やそこから相互に参照できる関連情報を 見てください。 Linux の場合、TCP や UDP で 1024 以下のローカルなポートに接続するには、root の権限が必要であることを覚えておいてください。 (リモートにある 1024 以下のポートへの接続については、特別な権限は必要ありま せん)。
Linux には、ファイルシステムの割り当て制限(quota)とプロセスのリソース制限 を行なう機能があります。 この機能には、「ハードな制限」(hard limit)と「ソフトな制限」(soft limit)両方 の意味があり、多少意味が異なるので、注意が必要です。
記憶装置(ファイルシステム)の割り当て制限は、マウントポイント毎に設定が可能で、 特定のユーザやグループがそこで使用できるブロック数やファイル数(inode数)に 制限をかけられます。 「ハードな」ものが制限を越えることができないのに対して、「ソフトな」ものは 一時的に制限を越えることが許されています。 quota(1)、quotactl(2)、quotaon(8)を参照してください。
rlimit は、プロセスに対する数々の割り当て制限を実現するしくみで、ファイル サイズ、子プロセス数、オープンできるファイル数などを扱えます。「ソフトな」 制限(現状の制限(current limit)とも言う)と「ハードな制限」 (上限(upper limit)とも言う)があります。 ソフトな制限を超えることは決してできませんが、システムコールによってハード な制限の上限まであげることができます。 getrlimit()、setrlimit()、getrusage()を参照してください。
現在もっとも一般的な「監査」のしくみは、syslogd(8)です。 wtmp(5)、utmp(5)、lastlog(8)、acct(2)も参照することをお勧めします。 サーバー・プログラム(Apache Web サーバーのようなもの)の中には、独自に痕跡を監査 するしくみを持っているものもあります。
認証が必要な時に Linux システムの大部分は Pluggable Authentication Modules (PAM: 差し替え可能な認証モジュール)を使用します。このしくみを使うと、認証 方法の構成を変更できるようになります(たとえばパスワードやスマートカード等 の使用)。 PAM については、後でさらに論じます。
訳註:スマートカード(smart card)とは、プラスティックのカード上に IC やメモリなどのチップを載せたカードを指します。日本では IC カードと 呼ぶケースが多いようです。 従来の磁気カードと比べると、より多くの情報を格納できるだけではなく、 プログラムをインストールして実行することが可能である点が大きく異なり ます。