5

freeRedHat Linux 5.0には、関数とmalloc以下を提供する社内共有ライブラリがあります。

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

この共有ライブラリは、プロセスのメモリ消費に関する情報を提供する役割を果たします。残念ながら、この共有ライブラリをApacheで使用すると、問題が発生しhttpdます。このライブラリでApachehttpdを実行すると、コアダンプが表示さlibc::freeれ、ポインタが無効であるというメッセージが表示されます。問題は、によってロードされるlibphp5.soによってロードされる共有ライブラリであるhttp.soにあるようですhttpd

実際、http.soすべてをロードしなくても問題はなく、コアダンプはありません。(ロードするかしないかはhttp.so、構成ファイルのディレクティブによって管理されます:extension = http.so)http.sohttpdプロセスのコアダンプをロードするとき。

httpdこのように起動されます:

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

終了時にコアダンプします。

LD_BIND_NOW = 1を設定しhttp.soてロードすると、(gdbの下で)http.soが他のロードされたライブラリ(たとえば)をfree@plt指していることがわかります。どうしてそれが可能でしょうか?libc::freelibphp5.sofree@pltlibmem_consumption.so::free

ちなみに、LD_DEBUG = allをエクスポートして出力をファイルに保存すると、libphp5.so(これもロードされます)の次の行が表示されます。

 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では完全に異なります:

 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'

見上げるとLD_PRELOAD=./libmem_consumption.so使われていないhttp.soようです。freeLD_PRELOADが無視されるのはなぜですか?

4

1 に答える 1

8

http.soにRTLD_DEEPBINDフラグがロードされているように見えるため、共有ライブラリの1つでLD_PRELOADが無視されます。

これはhttp://linux.die.net/man/3/dlopenからです:

RTLD_DEEPBIND(glibc 2.3.4以降)このライブラリ内のシンボルのルックアップスコープをグローバルスコープの前に配置します。これは、自己完結型ライブラリが、すでにロードされているライブラリに含まれている同じ名前のグローバルシンボルよりも、独自のシンボルを使用することを意味します。このフラグはPOSIX.1-2001では指定されていません。

テスト共有ライブラリを作成しました。

  #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、プログラム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すべて問題ありません。

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

これは、UNSET_RTLD_DEEPBINDのLD_DEBUG=allを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'
于 2012-11-14T06:49:42.537 に答える