From 94299500fe749e43a806a006973d8a50c4e36d97 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Thu, 21 Apr 2022 15:18:17 -0300 Subject: [PATCH] Adjust logic of POSIX DlfcnModule::findSymbol to avoid problems when same library is loaded through different file names (symbolic links / directly). --- src/common/os/mod_loader.h | 2 +- src/common/os/posix/mod_loader.cpp | 108 +++++++++++++++++------------ 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/common/os/mod_loader.h b/src/common/os/mod_loader.h index 933a4c896e..1c27966d91 100644 --- a/src/common/os/mod_loader.h +++ b/src/common/os/mod_loader.h @@ -73,7 +73,7 @@ public: const Firebird::PathName fileName; #ifdef LINUX - virtual bool getRealPath(Firebird::PathName& realPath) = 0; + virtual bool getRealPath(Firebird::PathName& path) = 0; #endif protected: diff --git a/src/common/os/posix/mod_loader.cpp b/src/common/os/posix/mod_loader.cpp index 9f87818e4a..ac0d61445c 100644 --- a/src/common/os/posix/mod_loader.cpp +++ b/src/common/os/posix/mod_loader.cpp @@ -46,18 +46,16 @@ class DlfcnModule : public ModuleLoader::Module { public: - DlfcnModule(MemoryPool& pool, const Firebird::PathName& aFileName, void* m) - : ModuleLoader::Module(pool, aFileName), - module(m) - {} - + DlfcnModule(MemoryPool& pool, const Firebird::PathName& aFileName, void* m); ~DlfcnModule(); - void* findSymbol(ISC_STATUS*, const Firebird::string&); - bool getRealPath(Firebird::PathName& realPath); + void* findSymbol(ISC_STATUS*, const Firebird::string&) override; + + bool getRealPath(Firebird::PathName& path) override; private: void* module; + Firebird::PathName realPath; }; static void makeErrorStatus(ISC_STATUS* status, const char* text) @@ -154,6 +152,47 @@ ModuleLoader::Module* ModuleLoader::loadModule(ISC_STATUS* status, const Firebir return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(*getDefaultMemoryPool(), linkPath, module); } +DlfcnModule::DlfcnModule(MemoryPool& pool, const Firebird::PathName& aFileName, void* m) + : ModuleLoader::Module(pool, aFileName), + module(m), + realPath(pool) +{ +#ifdef HAVE_DLINFO + char b[PATH_MAX]; + +#ifdef HAVE_RTLD_DI_ORIGIN + if (dlinfo(module, RTLD_DI_ORIGIN, b) == 0) + { + realPath = b; + realPath += '/'; + realPath += fileName; + + if (realpath(realPath.c_str(), b)) + { + realPath = b; + return; + } + } +#endif + +#ifdef HAVE_RTLD_DI_LINKMAP + struct link_map* lm; + if (dlinfo(module, RTLD_DI_LINKMAP, &lm) == 0) + { + if (realpath(lm->l_name, b)) + { + realPath = b; + return; + } + } +#endif + +#endif + + // Error getting real path. + realPath.clear(); +} + DlfcnModule::~DlfcnModule() { if (module) @@ -165,7 +204,7 @@ void* DlfcnModule::findSymbol(ISC_STATUS* status, const Firebird::string& symNam void* result = dlsym(module, symName.c_str()); if (!result) { - Firebird::string newSym ='_' + symName; + Firebird::string newSym = '_' + symName; result = dlsym(module, newSym.c_str()); } @@ -183,20 +222,28 @@ void* DlfcnModule::findSymbol(ISC_STATUS* status, const Firebird::string& symNam return NULL; } + const auto& libraryPath = realPath.isEmpty() ? fileName : realPath; + + char symbolPathBuffer[PATH_MAX]; + const char* symbolPath = symbolPathBuffer; + + if (!realpath(info.dli_fname, symbolPathBuffer)) + symbolPath = info.dli_fname; + const char* errText = "Actual module name does not match requested"; - if (PathUtils::isRelative(fileName) || PathUtils::isRelative(info.dli_fname)) + if (PathUtils::isRelative(libraryPath) || PathUtils::isRelative(symbolPath)) { // check only name (not path) of the library Firebird::PathName dummyDir, nm1, nm2; - PathUtils::splitLastComponent(dummyDir, nm1, fileName); - PathUtils::splitLastComponent(dummyDir, nm2, info.dli_fname); + PathUtils::splitLastComponent(dummyDir, nm1, libraryPath); + PathUtils::splitLastComponent(dummyDir, nm2, symbolPath); if (nm1 != nm2) { makeErrorStatus(status, errText); return NULL; } } - else if (fileName != info.dli_fname) + else if (libraryPath != symbolPath) { makeErrorStatus(status, errText); return NULL; @@ -206,38 +253,11 @@ void* DlfcnModule::findSymbol(ISC_STATUS* status, const Firebird::string& symNam return result; } -bool DlfcnModule::getRealPath(Firebird::PathName& realPath) +bool DlfcnModule::getRealPath(Firebird::PathName& path) { -#ifdef HAVE_DLINFO - char b[PATH_MAX]; + if (realPath.isEmpty()) + return false; -#ifdef HAVE_RTLD_DI_ORIGIN - if (dlinfo(module, RTLD_DI_ORIGIN, b) == 0) - { - realPath = b; - realPath += '/'; - realPath += fileName; - - if (realpath(realPath.c_str(), b)) - { - realPath = b; - return true; - } - } -#endif - -#ifdef HAVE_RTLD_DI_LINKMAP - struct link_map* lm; - if (dlinfo(module, RTLD_DI_LINKMAP, &lm) == 0) - { - if (realpath(lm->l_name, b)) - { - realPath = b; - return true; - } - } -#endif - -#endif - return false; + path = realPath; + return true; }