【问题标题】:Enumerating shared libraries loaded via dlopen(RTLD_GLOBAL)枚举通过 dlopen(RTLD_GLOBAL) 加载的共享库
【发布时间】:2018-03-23 04:41:23
【问题描述】:

有没有办法在运行时确定哪些共享库已加载到当前进程的全局符号命名空间中?我主要对由于使用RTLD_GLOBAL 标志的dlopen() 调用而加载的任何内容感兴趣。

我想这样做是出于审计目的——对于我工作的应用程序来说,动态加载的共享库尽可能地加载dlopenRTLD_LOCAL 很重要,以免与第三方冲突——党代号;加载到全局符号命名空间中的任何内容都需要严格控制。

我查看了dl_iterate_phdr() API,但它似乎没有包含此信息。

【问题讨论】:

  • 好吧,您可以使用例如带有 RTLD_NOLOAD 的 dlopen 检查库是否已加载(如果您有列表),这将返回 null 或句柄,具体取决于它是否已加载。可能对您有所帮助的东西可能是 /proc/PID/maps 解析/分析。这也可以帮助你link

标签: linux shared-libraries glibc dlopen


【解决方案1】:

你可以试试

#define _GNU_SOURCE
#include <dlfcn.h>

typedef void *(*orig_dl)(const char *file, int mode);
void *dlopen(const char *file, int mode)
{
    orig_dl o_dlopen;
    o_dlopen = (orig_dl)dlsym(RTLD_NEXT, "dlopen");
    return o_dlopen(file, mode);
}

使用gcc -shared -fPIC dlo.c -o dlo.so -ldl编译它 添加LD_PRELOAD=dlo.so 然后就可以了。您可以使用特定模式记录/跟踪/打印任何 dlopen 使用情况

【讨论】:

    【解决方案2】:

    我认为使用LD_PRELOAD 替换dlopen() 的建议只是部分解决方案——您不会以这种方式捕获加载有dlopen() 的库的依赖项

    最后,如果不抓取动态链接器本身的内部状态,我看不到任何方法。它发现有一个从ld.so 导出的_rtld_global 符号包含该信息,但是您必须使用私有Glibc 标头来解释它。

    以下是一个 Python sn-p,它将(假设我对 Glibc 源代码的阅读是正确的)按搜索顺序打印全局命名空间中的所有共享库。使用RTLD_LOCAL 加载的库将不会被打印。

    它依赖于 Glibc 的实现细节这一事实意味着这种方法充满危险,但出于我的测试/审计目的,我认为它会做得很好。

    import ctypes
    
    # Abridged type declarations pillaged from Glibc. See:
    # - https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/generic/ldsodefs.h
    # - https://sourceware.org/git/?p=glibc.git;a=blob;f=include/link.h
    
    class link_map(ctypes.Structure):
        _fields_ = [
            ("l_addr", ctypes.c_size_t),
            ("l_name", ctypes.c_char_p),
        ]
    
    
    class r_scope_elem(ctypes.Structure):
        _fields_ = [
            ("r_list", ctypes.POINTER(ctypes.POINTER(link_map))),
            ("r_nlist", ctypes.c_uint),
        ]
    
    
    class rtld_global(ctypes.Structure):
        _fields_ = [
            ("_ns_loaded", ctypes.POINTER(link_map)),
            ("_ns_nloaded", ctypes.c_uint),
            ("_ns_main_searchlist", ctypes.POINTER(r_scope_elem)),
        ]
    
    _rtld_global = rtld_global.in_dll(ctypes.CDLL(None), "_rtld_global")
    searchlist = _rtld_global._ns_main_searchlist[0]
    
    print [searchlist.r_list[n][0].l_name for n in xrange(searchlist.r_nlist)]
    

    在我的 CentOS 7 系统上,打印如下:

    ['', '/lib64/libpython2.7.so.1.0', '/lib64/libpthread.so.0', '/lib64/libdl.so.2',
     '/lib64/libutil.so.1', '/lib64/libm.so.6', '/lib64/libc.so.6',
     '/lib64/ld-linux-x86-64.so.2']
    

    【讨论】:

      猜你喜欢
      • 2011-06-30
      • 1970-01-01
      • 2015-03-02
      • 1970-01-01
      • 1970-01-01
      • 2012-09-27
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      相关资源
      最近更新 更多