【发布时间】:2016-12-23 19:05:41
【问题描述】:
当尝试在共享库中使用 popen() 并通过 LD_PRELOAD 或 /etc/ld.so.preload 预加载它时,进程会陷入无限循环,并显示一条错误消息指出无法预加载共享库,或者系统只是冻结并需要重新启动,具体取决于代码。
请注意,不编译为共享库 (gcc test.c; ./a.out) 将不会出错。
如果有帮助,我正在 VirtualBox 上运行全新的 Debian 安装:
Linux debian 3.16.0-4-586 #1 Debian 3.16.36-1+deb8u2 (2016-10-19) i686 GNU/Linux
好的,所以这段代码:
#define _GNU_SOURCE
#include <stdio.h>
__attribute__((constructor, visibility("hidden")))
void init()
{
FILE *fp = popen("/usr/bin/id", "r");
pclose(fp);
}
第一种情况的结果:
root@debian:/mnt/group/hcfrk# gcc test.c -o test.so -std=c99 -shared -fPIC
root@debian:/mnt/group/hcfrk# LD_PRELOAD=./test.so whoami
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object './test.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
# For eternity.
这段代码:
...
#include <limits.h>
...
{
FILE *fp = popen("/usr/bin/id", "r");
if(!fp)
puts("Error.\n");
char buf[PATH_MAX];
while(fgets(buf, sizeof buf, fp))
printf("%s\n", buf);
pclose(fp); // Never gets here: VM just freezes.
}
导致第二种情况(系统冻结)。我怀疑这是因为 while 循环没有结束并导致 pclose() 没有被调用,因为第一个代码示例也会在没有 pclose() 的情况下冻结系统。
任何帮助将不胜感激。谢谢!
【问题讨论】:
-
我认为问题在于您的库在加载 libc 的其余部分之前已预加载,因此您无法在
init()函数中调用这些函数。 -
@Barmar 如果他的
init()函数链接到 libc,那么加载 libc 是否会成为预加载的一部分? -
OP 我很确定你必须在 .c 文件之前加上
-shared -fPIC -
另外,您是否尝试过将
init()的内容替换为简单的printf,以便推断它可能不是popen()破坏? -
-shared -fPIC之前没有更改输出。另外,是的,我已经尝试过printf和其他 libc 函数,并且效果很好。这是我的一个更大项目的一部分,我在其中挂钩 libc 和其他共享库中的函数。孤立的这个popen代码是有问题的(这不是我的项目引起的问题)。谢谢大家的帮助!
标签: c debian shared-libraries popen preload