3.7. ダイナミックリンク・ライブラリ

プログラムを実行するには、実際ライブラリが必要となります。 Linux を含む最近の Unix ライクなシステムの大半は、プログラムはデフォルトで ダイナミックリンク・ライブラリ(DLL)を使って コンパイルしてあります。 つまりあるライブラリを更新すれば、そのライブラリを使っているプログラムすべて が新しい(うまくいけばより良い)バージョンになります。

普通ダイナミックリンク・ライブラリは、特別なディレクトリ数ヶ所に存在します。 通常は、/lib/usr/lib、 PAM モジュールの /lib/security、 X Window System の /usr/X11R6/lib/usr/local/lib がそれに当たります。 プログラムは、この標準的な慣例を使うようにしてください。デバッグ時を除い ては、カレントディレクトリからダイナミックリンク・ライブラリが存在する所を たどっていけるような値を使わないでください(攻撃者が好みの「ライブラリ」を 追加できてしまうかもしれません)。

ライブラリに名前を付けたり、シンボリックリンクを張る場合に特別な約束事が存在 します。 その結果として、ライブラリを新しくしても、古くて、バックワード・コンパチ ビリティがないバージョンのライブラリをサポートできます。 また、特定のライブラリや特別なプログラムを実行する時に、あるライブラリの特定 の関数だけを変更する方法も複数あります。 Unix ライクなシステムが Windows ライクなシステムと比べて、極めて優れている点 がこれです。Unix ライクなシステムはライブラリの更新を行う点では、より優れた システムだと思います。この優れた点が一因となり、Windows ベースのシステムより Unix や Linux システムの方が安定していると考えています。

Linux システムすべてを含む GNU glibc ベースのシステムでは、ディレクトリ の一覧は /etc/ld.so.conf に保存してあり、プログラムは起動する間に自動的に 検索しています。 Red Hat がベースとなっているディストリビューションでは、普通は /usr/local/lib/etc/ld.so.conf に記述してありません。 私はこれをバグの 1 つだと見なしています。/usr/local/lib/etc/ld.so.conf に追加するのは、プログラムの多くを 動かすのに必要な作業です。この作業は、Red Hat がベースとなっているシステムで 共通の「フィックス」作業になっています。 あるライブラリの関数をいくつかだけ変更したいが、その他はそのまま使いたい 場合は、優先して使いたいライブラリ(.o ファイル)の名前を /etc/ld.so.preload に記入してください。 この「先読み(preloading)」ライブラリは、標準で用意してあるものに先がけて ロードされます。 この先読みファイルは、緊急パッチ用によく使います。 ディストリビューションでは、配布時にはそのようなファイルは使用しません。 起動時にディレクトリをすべて検索するのはあまりに時間の無駄なので、実際には キャッシュを使って処理しています。 ldconfig(8)はデフォルトで /etc/ld.so.conf を読んで、ダイナミックリンク・ ライブラリのあるディレクトリにシンボリック・リンクを適切に張って設定し (したがって、標準的な慣例にしたがった方が良い)、キャッシュ情報を /etc/ld.so.cache に書きます。他のプログラムはそのキャッシュを利用します。 つまり、ldconfig は DLL が追加されたり、DLL が削除されたり、DLL の ディレクトリごと変更されたりした場合には必ず動かさなければいけません。 ライブラリをインストールした時にパッケージ・マネージャが作業の 1 つと して ldconfig を動かす場合がよくあります。 プログラムを起動すると、ダイナミック・ローダーを使って /etc/ld.so.cache を 読み、必要となるライブラリをロードします。

さまざまな環境変数がこの過程をコントロールできます。実際、この過程を変更して しまう環境変数も存在します(たとえば、一時的に別のライブラリに置き換えて、実行 できます)。 Linux では、環境変数 LD_LIBRARY_PATH はコロン(:)で区切って 記述してあるディレクトリの集まりで、ライブラリをまずここから検索し、その後に 標準的なディレクトリを検索します。 新しいライブラリをデバッグしたり、特定用途のために非標準のライブラリを 使用する時に役に立ちます。ただ、そのディレクトリを管理できる人間を信頼する ことになります。注意してください。 環境変数 LD_PRELOAD はオブジェクトファイルの一覧で、標準的なライブラリ から変更する関数を含んでいます。/etc/ld.so.preload がまさにそれです。 環境変数 LD_DEBUG はデバッグ情報を表示します。「all」と指定すると、 ダイナミックリンクしているプロセスについて、実行中に膨大な情報を表示します。

ユーザがダイナミックリンク・ライブラリをコントロールできるようになると、 何らかの手当てをしない限り、setuid や setgid したプログラムが面倒なことに なります。 そのため、GNU glibc の実装では、プログラムに setuid や setgid してあると これらの環境変数(加えて同じような変数も)を無視するか、動作に大幅な制限を かけます。 GNU glib ライブラリは、プログラムの権限をチェックして setuid もしくは setgid を判断しています。 uid と euid が違っているか、gid と egid が違っていれば、ライブラリはその プログラムが setuid もしくは setgid(もしくはそれを継承)していると仮定し、 その結果、機能を大幅に制限し、リンクを管理します。 GNU glib ライブラリをロードしてみればわかります。特に elf/rtld.c と sysdeps/generic/dl-sysdep.c を見てください。 uid と gid を euid と egid に等しくしてプログラムを呼び出せば、環境変数は 機能をすべて働かせます。 他の Unix ライクなシステムでは、理由は同様である点は別として、状況が変わり ます。setuid もしくは setgid したプログラムは環境変数にむやみに影響を受ける べきではありません。

Linux システムについては、私の著作である Program Library HOWTO から情報をさらに得られます。