Exploring $ORIGIN - 探索 $ORIGIN

https://www.technovelty.org/linux/exploring-origin.html

Anyone who works with building something with a few libraries will quickly become familiar with rpath's; that is the ability to store a path inside a binary for finding dependencies at runtime. Slightly less well known is that the dynamic linker provides some options for this path specification; one in particular is a path with the special variable $ORIGIN. ld.so man page has the following to say about the an $ORIGIN appearing in the rpath:
任何使用几个库来构建东西的人都会很快熟悉 rpath 的知识。这是将路径存储在二进制文件中以在运行时查找依赖项的能力。鲜为人知的是,动态链接器为此路径规范提供了一些选项。特别是一个带有特殊变量 $ORIGIN 的路径。ld.so 手册页对在 rpath 中出现的 $ORIGIN 进行了以下说明:

ld.so understands the string $ORIGIN (or equivalently ${ORIGIN}) in an rpath specification to mean the directory containing the application executable. Thus, an application located in somedir/app could be compiled with gcc -Wl,-rpath,'$ORIGIN/../lib' so that it finds an associated shared library in somedir/lib no matter where somedir is located in the directory hierarchy.
ld.so 理解 rpath 规范中的字符串 $ORIGIN (或等效的 ${ORIGIN}) 来表示包含应用程序可执行文件的目录。因此,位于 somedir/app 中的应用程序可以使用gcc -Wl,-rpath,'$ORIGIN/../lib' 进行编译,以便无论 somedir 在何处都可以在 somedir/lib 中找到关联的共享库。somedir 位于目录层次结构中。

As a way of a small example, consider the following:

$ cat Makefile
main: main.c lib/libfoo.sogcc -g -Wall -o main -Wl,-rpath='$$ORIGIN/lib' -L ./lib -lfoo main.clib/libfoo.so: lib/foo.cgcc -g -Wall -fPIC -shared -o lib/libfoo.so lib/foo.c$ cat main.c
void function(void);int main(void)
{function();return 0;
}$ cat lib/foo.c
#include <stdio.h>void function(void)
{printf("called!\n");
}$ make
gcc -g -Wall -fPIC -shared -o lib/libfoo.so lib/foo.c
gcc -g -Wall -o main -Wl,-rpath='$ORIGIN/lib' -L ./lib -lfoo main.c$ ./main
called!

Now, wherever you should choose to locate main, as long as the library is in the right relative location it will be found correctly. If you are wondering how this works, examining the back-trace from the linker function that expands it is helpful:
现在,无论您应该选择放置 main 的任何位置,只要库位于正确的相对位置,都可以正确找到它。如果您想知道这是如何工作的,请检查链接器函数的后向跟踪是否有用:

$ gdb ./main
(gdb) break _dl_get_origin
Function "_dl_get_origin" not defined.
Make breakpoint pending on future shared library load? (y or [n]) yBreakpoint 1 (_dl_get_origin) pending.
(gdb) r
Starting program: /tmp/test-origin/mainBreakpoint 1, _dl_get_origin () at ../sysdeps/unix/sysv/linux/dl-origin.c:37
37  ../sysdeps/unix/sysv/linux/dl-origin.c: No such file or directory.in ../sysdeps/unix/sysv/linux/dl-origin.c
(gdb) bt
#0  _dl_get_origin () at ../sysdeps/unix/sysv/linux/dl-origin.c:37
#1  0x00007ffff7de61f4 in expand_dynamic_string_token (l=0x7ffff7ffe128,s=<value optimized out>) at dl-load.c:331
#2  0x00007ffff7de62ea in decompose_rpath (sps=0x7ffff7ffe440,rpath=0xffffffc0 <Address 0xffffffc0 out of bounds>, l=0x0,what=0x7ffff7df780a "RPATH") at dl-load.c:554
#3  0x00007ffff7de7051 in _dl_init_paths (llp=0x0) at dl-load.c:722
#4  0x00007ffff7de2124 in dl_main (phdr=0x7ffff7ffe6b8,phnum=<value optimized out>, user_entry=0x7ffff7ffeb28) at rtld.c:1391
#5  0x00007ffff7df3647 in _dl_sysdep_start (start_argptr=<value optimized out>, dl_main=0x7ffff7de14e0 <dl_main>)at ../elf/dl-sysdep.c:243
#6  0x00007ffff7de0423 in _dl_start_final (arg=0x7fffffffe7c0) at rtld.c:338
#7  _dl_start (arg=0x7fffffffe7c0) at rtld.c:564
#8  0x00007ffff7ddfaf8 in _start () from /lib64/ld-linux-x86-64.so.2

Just from a first look we can divine that this has found the RPATH header in the dynamic section and has decided to expand the string $ORIGIN.
乍一看,我们可以发现这已经在动态部分找到了 RPATH 头,并决定扩展字符串 $ORIGIN

$ readelf --dynamic ./mainDynamic section at offset 0x7d8 contains 23 entries:Tag        Type                         Name/Value0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/lib]0x000000000000000c (INIT)               0x4004d80x000000000000000d (FINI)               0x4006f8

At this point it proceeds to do a readlink on /proc/self/exe to get the path to the currently running binary, effectively does a basename on it and replaces the value of $ORIGIN. Interestingly, if this should fail, it will fall back on the environment variable LD_ORIGIN_PATH for unknown reasons. This might be useful if you were in a bad situation where /proc was not mounted and you still had to run your binary, although you could probably achieve the same thing via the use of LD_LIBRARY_PATH just as well.
在这一点上,它继续在 /proc/self/exe 上执行一个 readlink 来获取当前正在运行的二进制文件的路径,在其上有效地执行一个 basename 并替换 $ORIGIN 的值。有趣的是,如果失败,它将以未知原因退回到环境变量 LD_ORIGIN_PATH 上。如果您处于无法挂载 /proc 并且仍然必须运行二进制文件的情况下,这可能很有用,尽管您也可以通过使用 LD_LIBRARY_PATH 来实现相同的目的。

This feature should be used with some caution to avoid turning your application in a mess that can’t be packaged in any standard manner. One common example of use is probably your java virtual machine to find its implementation libraries.
使用此功能时应格外小心,以免使您的应用程序混乱,无法以任何标准方式打包。一个常见的使用示例是您的 Java 虚拟机来查找其实现库。

$ readelf --dynamic /usr/lib/jvm/java-6-sun/bin/javaDynamic section at offset 0x9a28 contains 25 entries:Tag        Type                         Name/Value0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]0x0000000000000001 (NEEDED)             Shared library: [libjli.so]0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]0x000000000000000e (SONAME)             Library soname: [lib.so]0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/../lib/amd64/jli:$ORIGIN/../jre/lib/amd64/jli]...

There is a small but interesting security issue. If an attacker can hardlink to your binary that is using $ORIGIN then any path expansion is now relative to the attackers directory. Hence it is possible to make the linker read in arbitrary libraries and hence run arbitrary code. Clearly if your program is running setuid as someone else, such as root, you’ve just given up the keys to the house!
有一个小而有趣的安全问题。如果攻击者可以使用 $ORIGIN 硬链接到您的二进制文件,则任何路径扩展现在都相对于攻击者目录。因此,可以使链接器在任意库中读取,从而运行任意代码。显然,如果您的程序正在以 root 等其他身份运行 setuid,你就已经放弃了房子的钥匙!

Luckily, the dynamic linker will not let you shoot yourself in the foot like this, and prevents expansion of the $ORIGIN field if the program is running setuid.
幸运的是,如果程序正在运行 setuid,动态链接器将不允许您像这样搬起石头砸自己的脚,并防止扩展 $ORIGIN 字段。

shoot oneself in the foot:搬起石头砸自己的脚,自讨苦吃
$ sudo chown root ./main
$ sudo chmod +s ./main
$ ./main
./main: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

However, this is a good example of why you might want to keep users home and temp directories on separate file systems away from where binaries live.
但是,这是一个很好的示例,说明了为什么您可能希望将用户的主目录和临时目录保留在远离二进制文件所在的单独文件系统上。

There is also a similar variable $PLATFORM, which describes the current running system. This is gained via the auxiliary vector, which I have written about here and here. Setting LD_SHOW_AUXV=1 will allow you to examine this value.
还有一个类似的变量 $PLATFORM,它描述了当前正在运行的系统。这是通过辅助向量获得的,我在这里已经写过。设置 LD_SHOW_AUXV=1 将允许您检查该值。

$ LD_SHOW_AUXV=1 ls
...
AT_PLATFORM:     x86_64
...

References

https://www.technovelty.org/linux/a-little-tour-of-linux-gateso.html
https://www.technovelty.org/linux/poking-around-in-auxv-part-2.html

Exploring $ORIGIN - 探索 $ORIGIN相关推荐

  1. matlab与origin关联,origin与matlab

    哈哈哈 MATLAB 显示正炫余炫图:plot(x,y1,'* r',x,y2,'o b') 定义[..._origin]=floor((size(se)+1)/2); image_dilation= ...

  2. 【Origin】Origin准确标注某点

    先随便添加一个点 对象管理器右键要定位的点 绘图细节里重新命名点的位置坐标(如3311)即可精确定位点

  3. 浅显易懂 Makefile 入门 (07)— 其它函数(foreach 、if、call、origin )

    1. foreach 函数 foreach 函数定义如下: $(foreach <var>,<list>,<text>) 函数的功能是:把参数 <list&g ...

  4. 【Git】Git 分支管理 ( 删除远程分支 | 查看远程分支 git branch -a | 删除远程分支 git push origin --delete feature1 )

    文章目录 一.查看远程分支 二.远程分支分析 三.删除远程分支 一.查看远程分支 执行 git branch -a 命令 , 可以查看当前 本地仓库 对应的 远程仓库 的所有分支 ; 远程分支内容 : ...

  5. github中origin和upstream的区别(转)

    Fork,本身并不是git工具中的一个命令,也不是对git的扩展,它是在GitHub上的概念,是另一种clone方式--在服务器端的clone. 而我们通常意义上的clone,是将远程repo 复制一 ...

  6. git学习:关于origin和master,自己增加一部分

    git的服务器端(remote)端包含多个repository,每个repository可以理解为一个项目.而每个repository下有多个branch."origin"就是指向 ...

  7. 【转】github中origin和upstream的区别

    Fork,本身并不是git工具中的一个命令,也不是对git的扩展,它是在GitHub上的概念,是另一种clone方式--在服务器端的clone. 而我们通常意义上的clone,是将远程repo 复制一 ...

  8. Git 的origin和master解析

    首先要明确一点,对git的操作是围绕3个大的步骤来展开的(其实几乎所有的SCM都是这样) 1.     从git取数据(git clone) 2.     改动代码 3.     将改动传回git(g ...

  9. 文件打开特别慢_“Origin进不去、下载慢”的解决办法合集

    玩儿烂橘子的游戏,喜闻乐见会见到下面这句话: 呃,发生了些意料之外的事情.其实,这还挺意料之中的.▌进不去方法①:挂加速器. 加速器挂Steam或者Origin大厅一般是免费的,没效果就换一个节点.模 ...

  10. origin如何绘制双y轴曲线_Origin对曲线进行多峰拟合

    点击上方关注点击下方点赞 ORIGIN教程 Origin对任意曲线进行多峰拟合 01 数据表 我们以11B NMR 核磁共振谱数据为例. 02 多峰拟合 为了增加教程的可参考性,本文以目前常用的最低版 ...

最新文章

  1. window.location.href如何多次请求_RabbitMQ如何保证幂等性?
  2. 浙江大数据交易中心正式上线
  3. hadoop设置ssh免密码登录
  4. 深入理解Activity启动流程(二)–Activity启动相关类的类图
  5. JSOUP 教程—— Java爬虫,简易入门,秒杀htmlparser
  6. 中职生计算机专业600分,来了!超全盘点高职分类中500-600分及以上的高中生能报的专业和院校名单!...
  7. python五子棋人机对战_Python:游戏:五子棋之人机对战
  8. LeetCode刷题开源手册
  9. 算法:移除数组中的数字,不用额外空间27. Remove Element
  10. 单片机烧录文件格式转换(1)
  11. Linux 系统安装中文语言包
  12. Liunx 安装redis
  13. c++ HDC 写一个简单的不需要bmp图片的progressbar
  14. 一、Docker 容器
  15. Python操控鼠标和键盘
  16. 网友们碰到过的最难调试的 Bug
  17. OpenCV-透视变换及对二维点求透视变换之后的坐标
  18. BOOT模式选择启动、Error -6311 PRSC modulefailedtowritetoa register。
  19. 区块链在中国(3):区块链场景漫谈
  20. 实现某位置附近距离【Redis的GEO】

热门文章

  1. Eclipse多国语言包的安装
  2. 服务器不能用pe安装win7系统安装,WinPE无法安装win7系统的完美解决方案
  3. java+ElementUI前后端分离旅游项目第五天 移动端开发上
  4. 如何使用patch命令打补丁
  5. 计算机上有哪些操作系统?
  6. 数据挖掘十大经典算法
  7. 论文的中期报告怎么写?
  8. 密码编码学与网络安全笔记(第7版)
  9. 联想Y7000P 安装黑苹果到外置移动机械硬盘
  10. 企业如何安装linux软件下载,linux系统安装软件方法大全