8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 08:03:04 +01:00

Frontported CORE-3443: Races in UDF library lookup

This commit is contained in:
alexpeshkoff 2011-05-30 14:05:30 +00:00
parent 070718bea2
commit 931f1afd51
2 changed files with 58 additions and 134 deletions

View File

@ -173,7 +173,7 @@ namespace Jrd
FPTR_INT Module::lookup(const char* module, const char* name, DatabaseModules& interest) FPTR_INT Module::lookup(const char* module, const char* name, DatabaseModules& interest)
{ {
// Try to find loadable module // Try to find loadable module
Module m = lookupModule(module, true); Module m = lookupModule(module);
if (! m) if (! m)
{ {
return 0; return 0;
@ -193,24 +193,11 @@ namespace Jrd
return (FPTR_INT)rc; return (FPTR_INT)rc;
} }
FPTR_INT Module::lookup(const TEXT* module, const TEXT* name)
{
// Try to find loadable module
Module m = lookupModule(module, false);
if (! m)
{
return 0;
}
Firebird::string symbol;
terminate_at_space(symbol, name);
return (FPTR_INT)(m.lookupSymbol(symbol));
}
// flag 'udf' means pass name-path through UdfDirectoryList // flag 'udf' means pass name-path through UdfDirectoryList
Module Module::lookupModule(const char* name, bool udf) Module Module::lookupModule(const char* name)
{ {
Firebird::MutexLockGuard lg(modulesMutex); Firebird::MutexLockGuard lg(modulesMutex);
Firebird::PathName initialModule; Firebird::PathName initialModule;
terminate_at_space(initialModule, name); terminate_at_space(initialModule, name);
@ -248,53 +235,37 @@ namespace Jrd
return Module(im); return Module(im);
} }
if (udf) // UdfAccess verification
Firebird::PathName path, relative;
// Search for module name in UdfAccess restricted
// paths list
PathUtils::splitLastComponent(path, relative, fixedModule);
if (path.length() == 0 && PathUtils::isRelative(fixedModule))
{ {
// UdfAccess verification path = fixedModule;
Firebird::PathName path, relative; if (! iUdfDirectoryList().expandFileName(fixedModule, path))
// Search for module name in UdfAccess restricted
// paths list
PathUtils::splitLastComponent(path, relative, fixedModule);
if (path.length() == 0 && PathUtils::isRelative(fixedModule))
{ {
path = fixedModule; // relative path was used, but no appropriate file present
if (! iUdfDirectoryList().expandFileName(fixedModule, path)) continue;
{
// relative path was used, but no appropriate file present
continue;
}
}
// The module name, including directory path,
// must satisfy UdfAccess entry in config file.
if (! iUdfDirectoryList().isPathInList(fixedModule))
{
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("UDF/BLOB-filter module") <<
Arg::Str(initialModule));
}
ModuleLoader::Module* mlm = ModuleLoader::loadModule(fixedModule);
if (mlm)
{
im = FB_NEW(*getDefaultMemoryPool())
InternalModule(*getDefaultMemoryPool(), mlm, initialModule, fixedModule);
loadedModules().add(im);
return Module(im);
} }
} }
else
// The module name, including directory path,
// must satisfy UdfAccess entry in config file.
if (! iUdfDirectoryList().isPathInList(fixedModule))
{ {
// try to load permanent module ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("UDF/BLOB-filter module") <<
ModuleLoader::Module* mlm = ModuleLoader::loadModule(fixedModule); Arg::Str(initialModule));
if (mlm) }
{
im = FB_NEW(*getDefaultMemoryPool()) ModuleLoader::Module* mlm = ModuleLoader::loadModule(fixedModule);
InternalModule(*getDefaultMemoryPool(), mlm, initialModule, fixedModule); if (mlm)
loadedModules().add(im); {
im->acquire(); // make permanent im = FB_NEW(*getDefaultMemoryPool())
return Module(im); InternalModule(*getDefaultMemoryPool(), mlm, initialModule, fixedModule);
} loadedModules().add(im);
return Module(im);
} }
} }
@ -302,29 +273,22 @@ namespace Jrd
return Module(); return Module();
} }
Module::~Module() Module::InternalModule::~InternalModule()
{ {
if (interMod) delete handle;
Firebird::MutexLockGuard lg(modulesMutex);
for (size_t m = 0; m < loadedModules().getCount(); m++)
{ {
interMod->release(); if (loadedModules()[m] == this)
if (! interMod->inUse())
{ {
Firebird::MutexLockGuard lg(modulesMutex); loadedModules().remove(m);
for (size_t m = 0; m < loadedModules().getCount(); m++) return;
{
if (loadedModules()[m] == interMod)
{
loadedModules().remove(m);
delete interMod;
return;
}
}
fb_assert(false);
// In production server we delete interMod here
// (though this is not normal case)
delete interMod;
} }
} }
fb_assert(false);
} }
} // namespace Jrd } // namespace Jrd

View File

@ -31,20 +31,20 @@
#include "../common/classes/objects_array.h" #include "../common/classes/objects_array.h"
#include "../common/os/mod_loader.h" #include "../common/os/mod_loader.h"
#include "../common/classes/RefCounted.h"
namespace Jrd namespace Jrd
{ {
class Module class Module
{ {
private: private:
class InternalModule class InternalModule : public Firebird::RefCounted
{ {
private: private:
InternalModule(const InternalModule &im); InternalModule(const InternalModule &im);
void operator=(const InternalModule &im); void operator=(const InternalModule &im);
public: public:
long useCount;
ModuleLoader::Module* handle; ModuleLoader::Module* handle;
Firebird::PathName originalName, loadName; Firebird::PathName originalName, loadName;
@ -57,59 +57,30 @@ namespace Jrd
return handle->findSymbol(name); return handle->findSymbol(name);
} }
/* explicit InternalModule(MemoryPool& p)
: useCount(0), handle(0),
originalName(p), loadName(p)
{ }
*/
InternalModule(MemoryPool& p, InternalModule(MemoryPool& p,
ModuleLoader::Module* h, ModuleLoader::Module* h,
const Firebird::PathName& on, const Firebird::PathName& on,
const Firebird::PathName& ln) const Firebird::PathName& ln)
: useCount(0), handle(h), : handle(h),
originalName(p, on), loadName(p, ln) originalName(p, on), loadName(p, ln)
{ } { }
~InternalModule() ~InternalModule();
{
fb_assert(useCount == 0);
delete handle;
}
bool operator==(const Firebird::PathName &pn) const bool operator==(const Firebird::PathName &pn) const
{ {
return originalName == pn || loadName == pn; return originalName == pn || loadName == pn;
} }
bool inUse() const
{
return useCount > 0;
}
void acquire()
{
fb_assert(handle);
++useCount;
}
void release()
{
fb_assert(useCount > 0);
--useCount;
}
}; };
InternalModule* interMod; Firebird::RefPtr<InternalModule> interMod;
Module(InternalModule* h) : interMod(h) Module(InternalModule* h)
{ : interMod(h)
if (interMod) { }
{
interMod->acquire();
}
}
static Module lookupModule(const char*, bool); static Module lookupModule(const char*);
static InternalModule* scanModule(const Firebird::PathName& name); static InternalModule* scanModule(const Firebird::PathName& name);
@ -118,32 +89,21 @@ namespace Jrd
Module() : interMod(0) { } Module() : interMod(0) { }
explicit Module(MemoryPool&) : interMod(0) { } explicit Module(MemoryPool&)
: interMod(NULL)
{ }
Module(MemoryPool&, const Module& m) : interMod(m.interMod) Module(MemoryPool&, const Module& m)
{ : interMod(m.interMod)
if (interMod) { }
{
interMod->acquire();
}
}
Module(const Module& m) : interMod(m.interMod) Module(const Module& m)
{ : interMod(m.interMod)
if (interMod) { }
{
interMod->acquire();
}
}
virtual ~Module();
// used for UDF/BLOB Filter // used for UDF/BLOB Filter
static FPTR_INT lookup(const char*, const char*, Firebird::SortedObjectsArray<Module>&); static FPTR_INT lookup(const char*, const char*, Firebird::SortedObjectsArray<Module>&);
// used in y-valve
static FPTR_INT lookup(const char*, const char*);
bool operator>(const Module &im) const; bool operator>(const Module &im) const;
void *lookupSymbol(const Firebird::string& name) void *lookupSymbol(const Firebird::string& name)