为什么LD_PRELOAD对已加载的共享库之一不起作用? [英] Why LD_PRELOAD doesn't work for one of loaded shared libraries?

查看:377
本文介绍了为什么LD_PRELOAD对已加载的共享库之一不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在RedHat Linux 5.0上有一个内部共享库,其中提供了功能freemalloc:

I have an in-house shared library on RedHat Linux 5.0 that provides functions free and malloc:

>nm ./libmem_consumption.so | grep -P -e "\bfree\b|\bmalloc\b"
0000000000006540 T free
00000000000088a0 T malloc

此共享库负责提供有关进程的内存消耗的信息. 不幸的是,与Apache httpd一起使用时,此共享库存在问题. 当使用该库运行Apache httpd时,我在libc::free中得到一个coredump,并显示一条消息,指出指针无效. 问题似乎出在http.so中,它是由libphp5.so加载的共享库,由httpd加载.

This shared library is responsible for providing information about memory consumption of a process. Unfortunatelly there is a problem with this shared library when it is used with Apache httpd. When Apache httpd is run with this library I get a coredump in libc::free and a message that the pointer is invalid. The problem seems to be in http.so which is a shared library loaded by libphp5.so that is loaded by the httpd.

实际上,当我不加载http.so时,一切都很好,也没有coredump. (加载或不加载http.so由配置文件中的指令管理:extension = http.so) 当我加载http.so时,httpd进程会发生核心转储.

Actually when I do not load http.so everything is OK and there is no coredump. (Loading or not loading http.so is managed by the directive in a configuration file: extension=http.so) When I load http.so the httpd process coredumps.

httpd以这种方式启动:

LD_PRELOAD=./libmem_consumption.so ./bin/httpd -f config

和退出时的核心转储.

当我设置LD_BIND_NOW = 1并且加载了http.so时,我(在gdb下)看到http.so的free@plt指向libc::free并在其他加载中 库(例如libphp5.so)free@plt指向libmem_consumption.so::free. 怎么可能?

When I set LD_BIND_NOW=1 and http.so is loaded I see (under gdb) that http.so has free@plt pointing to libc::free and in in other loaded libraries (for example libphp5.so) free@plt points to libmem_consumption.so::free. How that could be possible?

顺便说一下,当我导出LD_DEBUG = all并将输出保存到文件中时,我看到libphp5.so的这些行(也已加载):

By the way when I export LD_DEBUG=all and save output to a file I see these lines for libphp5.so (which is also loaded):

 25788: symbol=free;  lookup in file=/apache2/bin/httpd [0]
 25788: symbol=free;  lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
 25788: binding file /apache2/modules/libphp5.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free' [GLIBC_2.2.5]

与http.so完全不同:

And completely different for http.so:

 25825: symbol=free;  lookup in file=/apache2/ext/http.so [0]
 25825: symbol=free;  lookup in file=/apache2/ps/lib/libz.so.1 [0]
 25825: symbol=free;  lookup in file=/apache2/ps/lib/libcurl.so.4 [0]
 25825: symbol=free;  lookup in file=/lib64/libc.so.6 [0]
 25825: binding file /apache2/ext/http.so [0] to /lib64/libc.so.6 [0]: normal symbol `free'

当查找free时,似乎LD_PRELOAD=./libmem_consumption.so不用于http.so.为什么LD_PRELOAD被忽略?

It seems that LD_PRELOAD=./libmem_consumption.so is not used for http.so when free is looked up. Why LD_PRELOAD is ignored?

推荐答案

似乎http.so加载了RTLD_DEEPBIND标志,这就是为什么共享库之一忽略LD_PRELOAD的原因.

It seeems that http.so is loaded with the RTLD_DEEPBIND flag and that is why LD_PRELOAD is ignored for one of shared libraries.

这来自 http://linux.die.net/man/3/dlopen:

RTLD_DEEPBIND(自glibc 2.3.4起) 将符号的查找范围放在此库中的全局范围之前.这意味着一个自包含的库将使用其 拥有自己的符号优先于具有相同名称的全局符号 包含在已经加载的库中.这个标志不是 在POSIX.1-2001中指定.

RTLD_DEEPBIND (since glibc 2.3.4) Place the lookup scope of the symbols in this library ahead of the global scope. This means that a self-contained library will use its own symbols in preference to global symbols with the same name contained in libraries that have already been loaded. This flag is not specified in POSIX.1-2001.

我写了一个测试共享库:

I wrote a test shared library:

  #include <dlfcn.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>

  static void initialize_my_dlopen(void) __attribute__((constructor));

  void* (*real_dlopen)(const char *, int flag);
  static int unset_RTLD_DEEPBIND=0;
  static int _initialized = 0;

  static void initialize_my_dlopen(void)
  {
    if (_initialized)
        return;
    real_dlopen  = (void *(*)(const char *,int))dlsym(RTLD_NEXT, "dlopen");
    unset_RTLD_DEEPBIND = atoi(getenv("UNSET_RTLD_DEEPBIND") ? getenv("UNSET_RTLD_DEEPBIND") : "0");
    printf("unset_RTLD_DEEPBIND: %d\n", unset_RTLD_DEEPBIND);
    _initialized = 1;
  }

  extern "C" {

    void *dlopen(const char *filename, int flag)
    {
      int new_flag = unset_RTLD_DEEPBIND == 0 ? flag : flag & (~RTLD_DEEPBIND);
      return (*real_dlopen)(filename, new_flag);
    }
  }

并构建它:

  gcc -shared -fPIC -g -m64 my_dlopen.cpp -o libmy_dlopen.so -ldl

当我将UNSET_RTLD_DEEPBIND设置为0并运行httpd程序核心转储时.

When I set UNSET_RTLD_DEEPBIND to 0 and run httpd the program coredumps.

export UNSET_RTLD_DEEPBIND=0
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config  

当我将UNSET_RTLD_DEEPBIND设置为1并运行httpd时,一切正常.

When I set UNSET_RTLD_DEEPBIND to 1 and run httpd everything is OK.

export UNSET_RTLD_DEEPBIND=1
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config  

这是LD_DEBUG = all的输出,用于UNSET_RTLD_DEEPBIND到1:

And this is the output of LD_DEBUG=all for the UNSET_RTLD_DEEPBIND to 1:

 10678: symbol=free;  lookup in file=/apache2/bin/httpd [0]
 10678: symbol=free;  lookup in file=/apache2/libmy_dlopen.so [0]
 10678: symbol=free;  lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
 10678: binding file /apache2/ext/http.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free'

这篇关于为什么LD_PRELOAD对已加载的共享库之一不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆