我希望能够从我的库中控制是否允许加载或不使用异常,这意味着在某些情况下我想要dlopen(" mylib.so")返回NULL,只有在所有条件都正确的情况下才会成功。
很多人都在询问动机,在我的库中我多次使用dlopen,我想确保在加载我的库之前已经加载了所有需要的组件。
请记住,我必须使用标准解决方案,这意味着我无法使用外部插件或执行重写dlopen等操作。
答案 0 :(得分:3)
这可能是一些XY problem。我们无法猜测你的动机和目标(这些都是真正重要的)。您想要做的是在Linux上不可能。
但仔细阅读,并多次 dlopen(3) man
页面。您会注意到,由于"mylib.so"
没有/
,因此使用LD_LIBRARY_PATH
环境变量专门处理它。这就是我通常使用dlopen
的绝对文件路径的原因。参见例如realpath(3),glob(3),wordexp(3)。请注意,没有记录的方法使dlopen
失败超出所记录的失败案例,即:
成功后,
dlopen()
和dlmopen()
会返回非NULL
句柄 加载库。出错(无法找到文件,无法读取, 这些是格式错误,或在加载过程中导致错误) 函数返回NULL
。
然后您可以使用dlerror(3)来了解错误原因。
所以你可以用LD_LIBRARY_PATH
玩耍但你不应该。你可能很奇怪(实际上很疯狂),例如在其上使用putenv(3),或在该路径中添加由您的程序管理的某些FUSE文件系统中的目录,或者执行一些LD_PRELOAD
trick。但是 你真的不应该做这种疯狂的伎俩 。
所以合理:以其他方式解决您的实际需求。期望dlopen
表现得像记录(通常成功),如果你不想,不要调用它。编码时,使用常识很重要。
请注意rpath(可以在链接时明确设置),并仔细阅读Program Library HowTo和Drepper的How To Write Shared Libraries。另请阅读C++ dlopen minihowto并注意name mangling。
请注意,实际上dlopen
是Linux上C standard library的一部分,而libc
和ld-linux.so(8)通常是free software(例如GNU {{} 3}}或glibc)。因此,如果您对系统dlopen
不满意,原则上可以更改它(但我不建议这样做,因为libc
是每个Linux系统的基石。)
您可以考虑(可能不是一个好主意)使用一些ELF解析库(如musl-libc,libelf,...)或某些ELF分析程序(如libbfd或readelf(1) ...)在 dlopen
之前的共享对象上(但恶意进程或用户可能在分析后但dlopen
之前仍然会更改共享库)。您可以自己研究objdump(1)格式并手动进行这样的解析(可能更糟糕的想法)。
如果您正在编写mylib.so
库(在Linux上,也许还有其他一些类似的操作系统;但由于elf(5)中未指定,此行为是非标准的),您可能会感兴趣{ {3}} {{}}}和__attribute__((constructor))
& __attribute__((visibility))
(另见POSIX dlopen和function attributes)。如果你想从你的 dlopen
“拒绝”mylib.so
- ed(当满足某些条件时),你可以考虑让一些构造函数测试这些条件并调用{{ 1}}当他们失败时如果您的exit
是从其他可以改进的程序加载的插件,您可能只需要使用mylib.so
寻找一些初始化函数,在dlsym
之后调用它,如果主程序失败则初始化函数失败。 BTW,从这样的构造函数(或一些过时的dlopen
函数)抛出一些C ++异常是不明智的,因为_init
机制可能会消耗在这种情况下不会释放的内部资源。
最后,从理论上讲,您可以自己重新实施dlopen
(this以上,that等...并关注open(2) mmap(2)明确地)。这可能需要几年时间(并且是特定于处理器的)。研究适当的relocations。
你可以通过使用通常的dlopen
来实现你的(未说明的)目标,并在它之前做一些测试,也许在它之后进行一些测试(使用dlopen
)。大多数使用插件的程序都是这样做的。
也许你可能会让dlsym
的每个导出函数在运行时都进行适当的检查。也许你可以通过mylib.so
的某个函数设置一些静态布尔标志(所以它会在__attribute__((constructor))
时调用一次)并让其他公共函数检查该标志。
在最近的编辑中,您最后解释:
在我的库中我多次使用dlopen,我想确保在加载我的库之前已经加载了所有需要的组件。
无需使用dlopen
或其构造函数(您可能不需要在库中使用dlopen
;如果您这样做,则需要解释原因,如何,以及在哪里)。您只需将dlopen
与其使用的所有必需共享库相关联(请参阅ELF)。如果它们在mylib.so
时无法加载或无法访问,dlopen
的整个dlopen
都会失败(直观地说,在Linux上,x86 ABI会以某种方式“递归”。)
顺便说一句,如果您确实在mylib.so
内拨打了dlopen
,那么mylib.so
在 dlopen
mylib.so
之后发生 < - > ed(除非你从dlopen
的某个构造函数调用dlopen
,这很奇怪,但应该没问题并且提出不同的问题。)
答案 1 :(得分:2)
据我记得,不,你不能,至少以正常的方式。如果库存在于给定路径,则将加载它。 dlopen
dlopen2
并非旨在进行任何&#34;业务检查&#34;由您自行决定。最多,它将遵守任何文件系统权限/ etc,如果进程无权访问该文件,则会返回错误。
如果你可以完全控制将加载你的库的代码,那么像Atterson建议的那样包装它并使用dlopen2
并完成它。
如果您没有完全控制权,那么dlopen
仍然不会阻止任何人使用原始dlopen2
并绕过检查。你可以试着让它变得更聪明,例如,让你的dlopen
做一些可检测的事情,这样如果它被dlopen2
而不是dlopen
打开,那么图书馆可以拒绝工作,但随后。有人可以假装那些&#34;可检测的东西&#34;,然后使用dlopen
,完成。然后它归结为使那些&#34;可检测的东西&#34;很难被攻击者重现。
简单地说,它不打算做这些事情。如果操作系统允许(〜文件系统权限等),则意味着加载库。
对于任何其他&#34;访问检查&#34;喜欢&#34;你有执照吗?没有?然后走开&#34;你必须在库中实现它。让他们通过initialization
加载它,然后让库检查权限,例如,在每次调用它的函数时。使用异常,或只执行任何操作并返回NULL。或者甚至更好,您可能可以使用void
函数(请参阅https://stackoverflow.com/a/1602459/717732 + http://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html#INIT-AND-CLEANUP)并在加载lib时执行一次检查。请注意,此函数会返回dlopen
,因此仍然无法使extend
失败,但至少库可以暂停其功能。
答案 2 :(得分:1)
你总是可以把它包装成一个函数
BenchmarkName-8 500000 2453 ns/op
BenchmarkNotPool-8 200000 7984 ns/op
答案 3 :(得分:1)
处理这种情况的正确方法是使用 seccomp 并限制允许执行dlopen的操作。
http://man7.org/linux/man-pages/man3/seccomp_rule_add.3.html
当然,这种配置需要root权限。