【问题标题】:Code jumps into unreferenced shared object代码跳转到未引用的共享对象
【发布时间】:2021-12-18 19:54:57
【问题描述】:

我的静态链接 CryptoPP 代码(在 Linux 上通过 Matlab mex 调用时)跳转到 libmwflcryptocryptopp.so 二进制文件(然后冻结)。

我的代码如何跳转到外部 .so 而不是静态链接库?


从我的vcpkg_installed/.../cryptopp/filters.h:1443 中的函数CryptoPP::SourceTemplate<CryptoPP::FileStore>::PumpAll2 跳转到来自Matlabs 自己的libmwflcryptocryptopp.so 文件的CryptoPP::BufferedTransformation::TransferAllTo2

gdb 堆栈跟踪

#0  0x00007ffff02e6cab in CryptoPP::BufferedTransformation::Peek(unsigned char&) const () from /usr/local/MATLAB/R2020b/bin/glnxa64/libmwflcryptocryptopp.so
#1  0x00007ffff02e6c19 in CryptoPP::BufferedTransformation::AnyRetrievable() const () from /usr/local/MATLAB/R2020b/bin/glnxa64/libmwflcryptocryptopp.so
#2  0x00007ffff02e6ffe in CryptoPP::BufferedTransformation::TransferMessagesTo2(CryptoPP::BufferedTransformation&, unsigned int&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) () from /usr/local/MATLAB/R2020b/bin/glnxa64/libmwflcryptocryptopp.so
#3  0x00007ffff02e7129 in CryptoPP::BufferedTransformation::TransferAllTo2(CryptoPP::BufferedTransformation&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) () from /usr/local/MATLAB/R2020b/bin/glnxa64/libmwflcryptocryptopp.so
#4  0x00007fff9758aa4d in CryptoPP::SourceTemplate<CryptoPP::FileStore>::PumpAll2 (this=0x7fffdd87fbc0, blocking=<optimized out>)
    at /home/keinkoenig/build-o1/vcpkg_installed/x64-linux/include/cryptopp/filters.h:1443
#5  0x00007fff9758a130 in CryptoPP::Source::PumpAll (this=0x7fffdd87fbc0) at /home/keinkoenig/build-o1/vcpkg_installed/x64-linux/include/cryptopp/filters.h:1420
#6  CryptoPP::Source::SourceInitialize (parameters=warning: RTTI symbol not found for class 'CryptoPP::AlgorithmParameters'
..., pumpAll=true, this=0x7fffdd87fbc0) at /home/keinkoenig/build-o1/vcpkg_installed/x64-linux/include/cryptopp/filters.h:1420
#7  CryptoPP::FileSource::FileSource (attachment=0x7fffd6063160, pumpAll=true, in=..., this=0x7fffdd87fbc0) at /home/keinkoenig/build-o1/vcpkg_installed/x64-linux/include/cryptopp/files.h:102
#8  mexFunction (nlhs=<optimized out>, plhs=<optimized out>, nrhs=<optimized out>, prhs=<optimized out>) at /home/keinkoenig/src/CryptoppMinimal/CryptoppMinimal.cpp:18

最小示例代码

#include <mex.h>
#include <cryptopp/files.h>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <fstream>

unsigned char Key[CryptoPP::AES::DEFAULT_KEYLENGTH] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF };
unsigned char IV[CryptoPP::AES::BLOCKSIZE] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF };

extern "C" 
{
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
    {
        std::ifstream instream(mxArrayToString(prhs[0]));

        std::string decryptedString;
        CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption cfbDecryption(Key, sizeof(Key), IV);
        CryptoPP::FileSource(instream, true, new CryptoPP::StreamTransformationFilter( cfbDecryption, new CryptoPP::StringSink( decryptedString)));
    }
}

和 CMakeLists 链接

set(PROJECT_NAME CryptoppMinimal)
...
target_link_libraries(${PROJECT_NAME} PRIVATE cryptopp-static)

使用 gdb 启动控制台 matlab

/usr/local/MATLAB/R2020b/bin/matlab -nojvm -Dgdb

并在 Matlab 中运行测试 mex 函数

addpath ~/build-o1/bin
CryptoppMinimal('/home/keinkoenig/src/encrypted.dat')

【问题讨论】:

  • 值得注意的是,.so 似乎是 matlab 附带的,而不是来自“你的”版本的 cryptocpp 的。如果库是使用-fPIC 编译的,并且 Matlab 在加载代码之前将其 cryptocpp.so 加载到内存中,则会导致预加载的符号优先于项目中的符号。

标签: c++ linux matlab gcc crypto++


【解决方案1】:

TL;DR;即使它是静态链接的,您的 cryptocpp 也会被 Matlab LD_PRELOADed。

对正在发生的事情的一个重要提示是正在加载的 .so 的路径:

#3  0x00007ffff02e7129 [...] /usr/local/MATLAB/R2020b/bin/glnxa64/libmwflcryptocryptopp.so

与编译期间使用的标头相比:

#5 [...] /home/keinkoenig/build-o1/vcpkg_installed/x64-linux/include/cryptopp/filters.h:1420

这表明,cryptocpp 不仅在动态库中运行,而且在 .so 与您编译时所针对的不同.so 中运行!

怎么会这样?如果静态库使用与位置无关的代码进行编译,对库中函数的调用仍将按照与动态库相同的方式进行调度:使用跳转表。

和动态库很像,如果在代码加载时跳转表已经填充,现有的函数指针将被重用。

所以,如果:

  • crypto-cpp 是用-fPIC 编译的
  • Matlab 恰好在加载您的代码之前加载了 crypto-cpp .so

那么嵌入在你项目中的crypto-cpp的版本将被忽略,而将使用Matlab的版本。

快速浏览一下 crypto-cpp 项目,我们在 Makefile 中发现:

# Add -fPIC for targets *except* X86, X32, Cygwin or MinGW
ifeq ($(IS_X86)$(IS_CYGWIN)$(IS_MINGW),000)
  ifeq ($(findstring -fpic,$(CXXFLAGS))$(findstring -fPIC,$(CXXFLAGS)),)
    CRYPTOPP_CXXFLAGS += -fPIC
  endif
endif

这似乎证实了这是正在发生的事情。

您可以通过从 Matlab 外部加载和运行您的库来确认这一点,它应该会按预期调用静态库的代码。

【讨论】:

  • 在启动时预加载我的二进制文件会使 matlab 崩溃。所以似乎cryptopp版本不兼容。有没有办法解决这个问题?
  • 通过快速搜索,这似乎是该库的一些特定于 Matlab 的分支。您可以从这里开始:stackoverflow.com/questions/678254 进行修复。如果适合您,dlopen()/dlsym() 方法将是最简单的。
猜你喜欢
  • 2023-03-09
  • 2014-09-28
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多