動的オブジェクトは、明示的に (「共有オブジェクトの依存関係の配置」を参照) あるいはフィルタを通して (「フィルタとしての共有オブジェクト」を参照)、依存関係を確立できます。それぞれの仕組みは「実行パス」で拡張できます。「実行パス」は実行時リンカーに、要求された依存関係を検索させ、読み込ませる指示を送ります。「動的ストリングトークン」で概説しているように、依存関係および「実行パス」の情報を記録するストリング名は、予約された動的ストリングトークンによって拡張できます。
$ISALIST
$OSNAME、$OSREL、および $PLATFORM
$ORIGIN
以降のセクションでは、これらのトークンの使用方法について具体的な例を示します。
動的トークン $ISALIST は、実行時に拡張され、このプラットフォームで実行可能なネイティブの命令セットを反映します。この様子はユーティリティ isalist(1) によって表されます。
$ISALIST トークンを持つあらゆるストリング名は、それぞれ使用できる命令セットの 1 つを割り当てられた複数の文字列に効率良くコピーされます。このトークンは、「フィルタ」あるいは「実行パス」指定でのみ使用できます。
次の例では、命令セット固有のフィルティー libfoo.so.1 にアクセスするように補助フィルタ libbar.so.1 を設計する方法を示します。
$ LD_OPTIONS='-f /opt/ISV/lib/$ISALIST/libbar.so.1' ¥ cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 -R. foo.c $ dump -Lv libfoo.so.1 | egrep "SONAME|AUXILIARY" [1] SONAME libfoo.so.1 [2] AUXILIARY /opt/ISV/lib/$ISALIST/libbar.so.1 |
あるいは、代わりに「実行パス」を使用することができます。
$ LD_OPTIONS='-f libbar.so.1' ¥ cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 -R'/ot/ISV/lib/$ISALIST' foo.c $ dump -Lv libfoo.so.1 | egrep "RPATH|AUXILIARY" [1] RPATH /opt/ISV/lib/$ISALIST [2] AUXILIARY libbar.so.1 |
どちらの場合でも、実行時リンカーはプラットフォームで使用可能な命令リストを使用して、複数の検索パスを構成します。たとえば、次のアプリケーションは libfoo.so.1 に依存関係があり、SUNW,Ultra-2 上で実行されます。
$ ldd -ls prog ..... find object=libbar.so.1; required by ./libfoo.so.1 search path=/opt/ISV/lib/$ISALIST (RPATH from file ./libfoo.so.1) trying path=/opt/ISV/lib/sparcv9+vis/libbar.so.1 trying path=/opt/ISV/lib/sparcv9/libbar.so.1 trying path=/opt/ISV/lib/sparcv8plus+vis/libbar.so.1 trying path=/opt/ISV/lib/sparcv8plus/libbar.so.1 trying path=/opt/ISV/lib/sparcv8/libbar.so.1 trying path=/opt/ISV/lib/sparcv8-fsmuld/libbar.so.1 trying path=/opt/ISV/lib/sparcv7/libbar.so.1 trying path=/opt/ISV/lib/sparc/libbar.so.1 |
また、同じ依存関係を持つアプリケーションは、MMX 設計の Pentium Pro で実行されます。
$ ldd -ls prog ..... find object=libbar.so.1; required by ./libfoo.so.1 search path=/opt/ISV/lib/$ISALIST (RPATH from file ./libfoo.so.1) trying path=/opt/ISV/lib/pentium_pro+mmx/libbar.so.1 trying path=/opt/ISV/lib/pentium_pro/libbar.so.1 trying path=/opt/ISV/lib/pentium+mmx/libbar.so.1 trying path=/opt/ISV/lib/pentium/libbar.so.1 trying path=/opt/ISV/lib/i486/libbar.so.1 trying path=/opt/ISV/lib/i386/libbar.so.1 trying path=/opt/ISV/lib/i86/libbar.so.1 |
補助フィルタ内で $ISALIST を使用すると、1 つあるいは複数のフィルティーが、フィルタ内で定義されたインタフェースの代替の実装を提供できます。
ただし、フィルタで定義されたインタフェースにフィルティーで定義された代替の実装がない場合は、要求されたインタフェースの場所を探すために、可能性のあるフィルティーすべてを徹底的に検索する結果となります。性能が重要となる機能を提供するためにフィルティーを使用する場合には、徹底的にフィルティーを検索することによって生産性が下がることがあります。
リンカーの -z endfiltee オプションを使用してフィルティーを作成し、それが使用可能な最後のフィルティーであると指定し、そのフィルタについてそれ以上のフィルティー検索を行わないようにできます。たとえば、前の SPARC の例で、sparcv9 フィルティーが存在し、-z endfiltee のタグが付いている場合、フィルティー検索は次のようになります。
$ ldd -ls prog ..... find object=libbar.so.1; required by ./libfoo.so.1 search path=/opt/ISV/lib/$ISALIST (RPATH from file ./libfoo.so.1) trying path=/opt/ISV/lib/sparcv9+vis/libbar.so.1 trying path=/opt/ISV/lib/sparcv9/libbar.so.1 |
動的トークン $OSNAME、$OSREL、および $PLATFORM は実行時に展開されて、システム固有の情報を提供します。$OSNAME は、ユーティリティ uname(1) にオプション -s を付けて実行した場合に表示されるように、オペレーティングシステムの名前を反映するよう展開されます。 $OSREL は、uname -r を実行した場合に表示されるように、オペレーティングシステムのリリースレベルを反映するよう展開され、$PLATFORM は、uname -i を実行した場合に表示されるように、基礎としているハードウェア実装を反映するよう展開されます。
次の例は、プラットフォーム固有のフィルティー libfoo.so.1 にアクセスするように補助フィルタ libbar.so.1 を設計する方法を示します。
$ LD_OPTIONS='-f /usr/platform/$PLATFORM/lib/libbar.so.1' ¥ cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 -R. foo.c $ dump -Lv libfoo.so.1 | egrep "SONAME|AUXILIARY" [1] SONAME libfoo.so.1 [2] AUXILIARY /usr/platform/$PLATFORM/lib/libbar.so.1 |
この仕組みは、共有オブジェクト /usr/lib/libc.so.1 に対してプラットフォーム固有の拡張を提供するために、Solaris 上で使用されます。
環境変数 LD_NOAUXFLTR
を設定して、実行時リンカーの「補助」フィルタ処理を無効にすることができます。補助フィルタはプラットフォーム固有の最適化に使用されることが多いので、フィルティーを使用する場合および性能インパクトを評価する場合にこのオプションが便利です。
通常、バンドルされていない製品は、独立した固有の場所にインストールされるように設計されています。この製品は、バイナリ、共有オブジェクト、および関連構成ファイルからなります。たとえば、バンドルされていない製品 ABC は、次の配置をとる場合があります。
製品が、/opt の元にインストールされるように設計されていると想定します。通常、ユーザーは、PATH に製品バイナリの位置を示す /opt/ABC/bin を追加する必要があります。各バイナリは、バイナリ内に直接記録された実行パスを使用して、その依存する相手を探します。アプリケーション abc
の場合、これは次のようになります。
% dump -Lv abc [1] NEEDED libA.so.1 [2] RPATH /opt/ABC/lib |
また、libA.so.1 の依存関係でも同様にこれは次のようになります。
% dump -Lv libA.so.1 [1] NEEDED libB.so.1 [2] RPATH /opt/ABC/lib |
この依存関係の表現は、製品が推奨されているデフォルト以外のディレクトリにインストールされるまで正常に作動します。異なるインストール環境が作成された場合、ユーザーは LD_LIBRARY_PATH を使用して、製品アプリケーションを実行しなければなりません。通常、これは、バイナリごとにラッパーを作って対応しますが、場合によっては、適切なオブジェクト内の実行パスを変更しようとするユーザーもいます。
動的トークン $ORIGIN は、オブジェクトが存在するディレクトリを表わします。この機能は、カーネルによってプロセス開始時に実行時リンカーに提供された新しい補助ベクトルに対応しています (getexecname(3C) のマニュアルページも参照)。この機構を使用すると、バンドルされていないアプリケーションを再定義して、$ORIGIN との相対位置で依存対象の位置を示すことができます。
% dump -Lv abc [1] NEEDED libA.so.1 [2] RPATH $ORIGIN/../lib |
また、$ORIGIN との関係で libA.so.1 の依存関係を定義することもできます。
% dump -Lv libA.so.1 [1] NEEDED libB.so.1 [2] RPATH $ORIGIN |
したがって、この製品が /usr/local/ABC の元にインストールされて、ユーザーの PATH に /usr/local/ABC/bin が追加された場合、アプリケーション abc
を呼び出すと次のように、パス名検索でその依存関係が探されます。
% ldd -s abc find object=libA.so.1; required by abc search path=$ORIGIN/../lib (RPATH from file abc) trying path=/usr/local/ABC/lib/libA.so.1 libA.so.1 => /usr/local/ABC/lib/libA.so.1 find object=libB.so.1; required by /usr/local/ABC/lib/libA.so.1 search path=$ORIGIN (RPATH from file /usr/local/ABC/lib/libA.so.1) trying path=/usr/local/ABC/lib/libB.so.1 libB.so.1 => /usr/local/ABC/lib/libB.so.1 |
依存関係の場所に関する次の問題としては、バンドルされていない製品が別のバンドルされていない製品の共有オブジェクトに対して依存関係を持つときの、基本となるモデルを作成する方法が挙げられます。
たとえば、バンドルされていない製品 XYZ は製品 ABC に対して依存関係を持つ場合があります。この依存関係は、図 C-2 に示すようにホストパッケージインストールスクリプトによって ABC 製品のインストール位置へのシンボルリンクを生成することで確立できます。
XYZ 製品のバイナリと共有オブジェクトは安定した参照位置としてシンボルリンクを使用して、ABC 製品への依存関係を表わします。アプリケーション xyz
の場合、次のようになります。
% dump -Lv xyz [1] NEEDED libX.so.1 [2] NEEDED libA.so.1 [3] RPATH $ORIGIN/../lib:$ORIGIN/../ABC/lib |
libX.so.1 の依存関係でも同様に、次のようになります。
% dump -Lv libX.so.1 [1] NEEDED libY.so.1 [2] NEEDED libC.so.1 [3] RPATH $ORIGIN:$ORIGIN/../ABC/lib |
したがって、この製品が /usr/local/XYZ の元にインストールされている場合は、次のシンボルリンクを確立するために、そのインストール後実行スクリプトが必要です。
% ln -s ../ABC /usr/local/XYZ/ABC |
ユーザーの PATH に /usr/local/XYZ/bin が追加される場合、アプリケーション xyz
の呼び出しによって、次のようにパス名検索でその依存関係が探されます。
% ldd -s xyz find object=libX.so.1; required by xyz search path=$ORIGIN/../lib:$ORIGIN/../ABC/lib (RPATH from file xyz) trying path=/usr/local/XYZ/lib/libX.so.1 libX.so.1 => /usr/local/XYZ/lib/libX.so.1 find object=libA.so.1; required by xyz search path=$ORIGIN/../lib:$ORIGIN/../ABC/lib (RPATH from file xyz) trying path=/usr/local/XYZ/lib/libA.so.1 trying path=/usr/local/ABC/lib/libA.so.1 libA.so.1 => /usr/local/ABC/lib/libA.so.1 find object=libY.so.1; required by /usr/local/XYZ/lib/libX.so.1 search path=$ORIGIN:$ORIGIN/../ABC/lib ¥ (RPATH from file /usr/local/XYZ/lib/libX.so.1) trying path=/usr/local/XYZ/lib/libY.so.1 libY.so.1 => /usr/local/XYZ/lib/libY.so.1 find object=libC.so.1; required by /usr/local/XYZ/lib/libX.so.1 search path=$ORIGIN:$ORIGIN/../ABC/lib ¥ (RPATH from file /usr/local/XYZ/lib/libX.so.1) trying path=/usr/local/XYZ/lib/libC.so.1 trying path=/usr/local/ABC/lib/libC.so.1 libC.so.1 => /usr/local/ABC/lib/libC.so.1 find object=libB.so.1; required by /usr/local/ABC/lib/libA.so.1 search path=$ORIGIN (RPATH from file /usr/local/ABC/lib/libA.so.1) trying path=/usr/local/ABC/lib/libB.so.1 libB.so.1 => /usr/local/ABC/lib/libB.so.1 |
セキュアプロセス (「セキュリティ」を参照) では、$ORIGIN 文字列の拡張は、それがトラストディレクトリに拡張されるときに限り許可されます。他の相対パス名は、セキュリティリスクを伴います。
一見すると、$ORIGIN/../lib のようなパスは一定の場所 (実行可能プログラムの場所で特定される) を指しているように見えますが、それは正しくありません。$ORIGIN を使ってセキュアプログラムを活用するために必要なものは、同じファイルシステム内の書き込み可能なディレクトリです。
次の例は、$ORIGIN がセキュアプロセス内で任意に拡張された場合、上記の事例がどのようにして起こるかを示しています。
% cd /worldwritable/dir/in/same/fs % mkdir bin lib % ln $ORIGIN/bin/program bin/program % cp ‾/crooked-libc.so.1 lib/libc.so.1 % bin/program ..... using crooked-libc.so.1 |
ユーティリティ crle(1) を使用すれば、$ORIGIN を使用するセキュアアプリケーションに適用されるトラストディレクトリを指定できます。この方法を使用する場合には、管理者は、ターゲットディレクトリを悪意のある侵入から適切に保護する必要があります。