微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

dlsym() + RTLD_NEXT 在 Ubuntu 20.04 上无法正常工作

如何解决dlsym() + RTLD_NEXT 在 Ubuntu 20.04 上无法正常工作

我在 Ubuntu 20.04 (gcc v 9.3.0) 上使用 dlsym() 调用时遇到了奇怪的运行时行为。

请看下面一个简单的例子:

#include <iostream>
#include <dlfcn.h>
#include <execinfo.h>
#include <typeinfo>
#include <string>
#include <memory>
#include <cxxabi.h>
#include <cstdlib>

extern "C"
{
    void __cxa_throw(void *ex,void *info,void (*dest)(void *))
    {
        std::cout << "__cxa_throw() invoked \n";

        static void (*const rethrow)(void *,void *,void (*)(void *)) __attribute__((noreturn))
            = (void (*)(void *,void (*)(void *)))dlsym(RTLD_NEXT,"__cxa_throw");

        std::cout << "addr in lib=" << &rethrow << "\n";

        rethrow(ex,info,dest);

        std::terminate();
    }
}

#include <iostream>

void foo()
{
  throw std::runtime_error("error");
}

int main()
{
    foo();
    return 0;
}

构建这两个文件如下:

g++ -fPIC -std=c++17 test.cpp -g -c -o test.o
g++ -shared ./test.o -o libtest.so
g++ main.cpp -std=c++17 -g -pedantic -L./ -ltest -ldl

将 ldd 输入 ./a.out 得到:

ldd a.out 
    linux-vdso.so.1 (0x00007ffe01186000)
    /usr/local/lib/AppProtection/libAppProtection.so (0x00007f1dbd738000)
    libtest.so (0x00007f1dbd733000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1dbd708000)
    libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1dbd526000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1dbd50b000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1dbd319000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1dbd2f4000)
    libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007f1dbd1b7000)
    libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f1dbd18d000)
    libXi.so.6 => /lib/x86_64-linux-gnu/libXi.so.6 (0x00007f1dbd17b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f1dbd964000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1dbd02c000)
    libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007f1dbd024000)
    libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f1dbd01c000)
    libXext.so.6 => /lib/x86_64-linux-gnu/libXext.so.6 (0x00007f1dbd007000)
    libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007f1dbcfed000)

我们可以看到 libtest.solibstdc++.so 之前被解析。 我期望这段代码应该如何工作:

  • __cxa_throw() 在 2 个共享库中定义:libtest.solibstdc++.so
  • foo() 调用中抛出异常时,__cxa_throw 将从 libtest.so 解析并调用
  • 调用 dlsym(RTLD_NEXT,"__cxa_throw"); 在共享库列表中进一步查找 __cxa_throw,在 libstdc++.so 中找到并调用

这在除 Ubuntu 20.04 之外的所有平台上都按预期工作,其中 rethrow 引用来自 __cxa_throw(但不是 libtest.so)的 libstc++.so,从而导致无休止的递归。>

请帮助我,因为我对运行时行为感到困惑。

解决方法

Citrix ICA 客户端的“应用程序保护”组件安装库 /usr/local/lib/AppProtection/libAppProtection.so 并将其条目添加到 /etc/ld.so.preload,使其加载到每个动态链接的进程中。除其他外,这个库用它自己的函数替换了 dlsym 函数。 (如果您很好奇这并不总是通过进入无限循环来破坏所有内容,请参阅 How can I intercept dlsym calls using LD_PRELOAD?。实际上,Citrix 的代码似乎是直接从该答案中复制和粘贴的。)问题是由于 RTLD_NEXT 依赖于能够检查返回地址,因此需要特别注意避免在挂钩 dlsym 时破坏它,而他们没有特别注意。因此,RTLD_NEXT 将在 libAppProtection.so 之后的下一个库中查找符号,而不是在您的代码之后的下一个库中查找符号,这正是您遇到的问题。

这里有一些关于如何处理它的选择:

  • 向 Citrix 支持部门投诉,直到他们修复有问题的库
  • sudo apt-get purge icaclient(之后可以选择重新安装,但choosing no when asked about the app protection component
  • 修改您的程序以从 dlsym 加载真正的 libdl.so,然后将其用于任何使用 RTLD_NEXT 的调用
,

如评论中所述,该问题是由 Citrix ICA 客户端完成的钩子引起的,该钩子钩住 dlsym(),从而导致调用错误的 dlsym()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?