通常,非绑定产品用于在唯一的位置上安装。此产品由二进制文件、共享库依赖项和关联的配置文件组成。例如,非绑定产品 ABC 可能具有下图所示的布局。
假定此产品适用于安装在 /opt 下。通常,您会向 PATH 中增加 /opt/ABC/bin,以定位产品的二进制代码。每个二进制代码均使用硬编码的运行路径在二进制代码内查找其依赖项。对于应用程序 abc,此运行路径将如下所示:
% cc -o abc abc.c -R/opt/ABC/lib -L/opt/ABC/lib -lA % dump -Lv abc [1] NEEDED libA.so.1 [2] RUNPATH /opt/ABC/lib |
类似地,对于依赖项 libA.so.1,它将显示为:
% cc -o libA.so.1 -G -Kpic A.c -R/opt/ABC/lib -L/opt/ABC/lib -lB % dump -Lv libA.so.1 [1] NEEDED libB.so.1 [2] RUNPATH /opt/ABC/lib |
此依赖项表示法将一直有效,直到将产品安装到除建议的缺省目录之外的某个目录中。
动态标记 $ORIGIN 扩展到目标文件的原始目录中。此标记可用于过滤器、运行路径或依赖项定义。可以使用此技术重新定义非绑定应用程序,根据 $ORIGIN 查找其依赖项:
% cc -o abc abc.c '-R$ORIGIN/../lib' -L/opt/ABC/lib -lA % dump -Lv abc [1] NEEDED libA.so.1 [2] RUNPATH $ORIGIN/../lib |
而依赖项 libA.so.1 也可以根据 $ORIGIN 进行定义:
% cc -o libA.so.1 -G -Kpic A.c '-R$ORIGIN' -L/opt/ABC/lib -lB % dump -Lv libA.so.1 [1] NEEDED libB.so.1 [2] RUNPATH $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。可以通过主机软件包安装脚本来建立此依赖性。此脚本生成一个指向 ABC 产品安装点的符号链接,如下图所示:
XYZ 产品的二进制代码和共享库可使用符号链接来表示其对于 ABC 产品的依赖性。此链接现在是一个稳定的参照点。对于应用程序 xyz,此运行路径将如下所示:
% cc -o xyz xyz.c '-R$ORIGIN/../lib:$ORIGIN/../ABC/lib' \ -L/opt/ABC/lib -lX -lA % dump -Lv xyz [1] NEEDED libX.so.1 [2] NEEDED libA.so.1 [3] RUNPATH $ORIGIN/../lib:$ORIGIN/../ABC/lib |
类似地,对于依赖项 libX.so.1,此运行路径将如下所示:
% cc -o libX.so.1 -G -Kpic X.c '-R$ORIGIN:$ORIGIN/../ABC/lib' \ -L/opt/ABC/lib -lY -lC % dump -Lv libX.so.1 [1] NEEDED libY.so.1 [2] NEEDED libC.so.1 [3] RUNPATH $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 的可信目录。使用此技术的管理员应确保已对目标目录进行了适当的保护,以防受到恶意入侵。