Home > Blockchain >  Qt5.9.6 do not follow RPATH to search openssl
Qt5.9.6 do not follow RPATH to search openssl

Time:06-25


I'm working on Qt based project on Linux based OS. We use Qt5.9.6. When we launch our application, we've got this log from Qt

qt.network.ssl: Incompatible version of OpenSSL

After a few research I found that Qt loads the version 1.1 of openssl whereas Qt5.9.6 needs the 1.0.2k version. So I put the right version of openssl next to our application and I set the RPATH accordingly. But it does not works. I'll try with LD_LIBRARY_PATH and that works.

I used LD_DEBUG=libs to see where the program try to load the dynamic library and it appears that for Qt, the RPATH is use partially or not at all.

I've created a docker image named eaglejoe/qtopenssl-bug with a minimal example. To compile the example launch

cmake --preset default
cmake --build build

and launch the program with build/testqt

Does someone kwow why the RPATH is not use completely here ?
(In the example it's the RUNPATH that is used but I have the same issue with a RPATH)

Thank you for your help

CodePudding user response:

So the thing is, Qt loads the OpenSSL library as a plugin, and the dynamic linker ld.so on Linux only takes into account the rpath of the executable and/or shared object that calls dlopen(). And because Qt itself doesn't have the rpath for your OpenSSL copy set, it won't load it.

The best way around that is (as long as you don't want to recompile Qt yourself with that rpath) to load OpenSSL manually before invoking any Qt function. So add the following to your code at the beginning of main():

void* crypto_handle = dlopen("libcrypto.so", RTLD_NOW | RTLD_GLOBAL);
if (!crypto_handle)
    std::cerr << "error loading libcrypto.so: " << dlerror() << std::endl;
void* ssl_handle = dlopen("libssl.so", RTLD_NOW | RTLD_GLOBAL);
if (!ssl_handle)
    std::cerr << "error loading libssl.so: " << dlerror() << std::endl;

Note that you must load libcrypto.so before libssl.so, otherwise libssl.so won't load, because libssl.so in your installation doesn't have an rpath set for itself, so it won't find the correct libcypto.so unless you load that yourself as well.

Further note: technically you could use the official SONAMEs libssl.so.1.0.0 and libcrypto.so.1.0.0 (yes, even for 1.0.2 those are the correct SONAMEs), but your Qt version is compiled against a weird version of OpenSSL that thinks its SONAME has 1.0.2k as the extension, not 1.0.0 as it should be, so it will only find the libraries by their generic names, and you have to load the libraries by their generic names (libssl.so, libcrypto.so) to make the dynamic linker aware that these are aliases.

If both of these are loaded, Qt will be able to work, because then the dynamic linker will see that the libraries in question have already been loaded into the program, and will hence reuse them, without looking for them in the filesystem.

Running your program will then give the following output:

build openssl: OpenSSL 1.0.2k-fips  26 Jan 2017
 load openssl: OpenSSL 1.0.2k  26 Jan 2017

That all said: OpenSSL 1.0.2 has not been supported for 2.5 years. And the version you're using, 1.0.2k is even older, that's from 5.5 years (!) ago. There are several security issues that have been fixed in OpenSSL since, and it is a really bad idea to write new code that relies on such outdated software when it comes to network communication.

Please, please use OpenSSL 1.1, which is still supported until September of next year. Qt has support for that since 5.12. From my experience the upgrade from 5.9 to 5.12 was completely painless. Though ideally I'd suggest that new code should use Qt6.

(Unfortunately not even Qt6 appears to work with OpenSSL 3.0 yet, but hopefully that'll change soon.)

  • Related