Skip to content

Commit

Permalink
For RAR load, check LD_LIBRARY_PATH before checking install path
Browse files Browse the repository at this point in the history
ClamAV initalization's rarload() function tries to load
libclamunrar_iface from the install path before checking under
LD_LIBRARY_PATH.
This means the unit tests will use the wrong unrar library if testing on
a system where ClamAV is already installed.
In the event there is an ABI break between versions, this will cause a
bunch of tests to fail.

This commit fixes the issue by checking for libclamunrar_iface under
LD_LIBRARY_PATH *first* before checking in the install lib directory.

Note in the previous version we were also checking LD_LIBRARY_PATH on
Windows, which is not a thing. I removed this.

Fixes: #1249

Also removed check for WARN_DLOPEN_FAIL define, which was not used, and
mistakenly set for the unrar library build target.
  • Loading branch information
val-ms committed May 6, 2024
1 parent 3809b2a commit 93699df
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 105 deletions.
205 changes: 101 additions & 104 deletions libclamav/others.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,106 +92,27 @@ static int is_rar_inited = 0;
#define PASTE2(a, b) a #b
#define PASTE(a, b) PASTE2(a, b)

static void *load_module(const char *name, const char *featurename)
{
#ifdef _WIN32
static const char *suffixes[] = {LT_MODULE_EXT};
#else
static const char *suffixes[] = {
LT_MODULE_EXT "." LIBCLAMAV_FULLVER,
PASTE(LT_MODULE_EXT ".", LIBCLAMAV_MAJORVER),
LT_MODULE_EXT,
"." LT_LIBEXT};
#endif

const char *searchpath;
static void *load_module(const char *name, const char *featurename)
{
HMODULE rhandle = NULL;
char modulename[128];
size_t i;
#ifdef _WIN32
HMODULE rhandle = NULL;
#else
void *rhandle;
#endif

#ifdef _WIN32
/*
* First try a standard LoadLibraryA() without specifying a full path.
* For Windows, just try a standard LoadLibraryA() with each of the different possible suffixes.
* For more information on the DLL search order, see:
* https://docs.microsoft.com/en-us/windows/desktop/Dlls/dynamic-link-library-search-order
* https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
*/
cli_dbgmsg("searching for %s\n", featurename);
#else
/*
* First search using the provided SEARCH_LIBDIR (e.g. "<prefix>/lib")
* Known issue: If an older clamav version is already installed, the clamav
* unit tests using this function will load the older library version from
* the install path first.
*/
searchpath = SEARCH_LIBDIR;
cli_dbgmsg("searching for %s, user-searchpath: %s\n", featurename, searchpath);
#endif

for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
#ifdef _WIN32
snprintf(modulename, sizeof(modulename), "%s%s", name, suffixes[i]);
rhandle = LoadLibraryA(modulename);
#else // !_WIN32
snprintf(modulename, sizeof(modulename), "%s" PATHSEP "%s%s", searchpath, name, suffixes[i]);
rhandle = dlopen(modulename, RTLD_NOW);
#endif // !_WIN32
if (rhandle) {
break;
}

cli_dbgmsg("searching for %s: %s not found\n", featurename, modulename);
}
snprintf(modulename, sizeof(modulename), "%s%s", name, LT_MODULE_EXT);

rhandle = LoadLibraryA(modulename);
if (NULL == rhandle) {
char *ld_library_path = NULL;
/*
* library not found.
* Try again using LD_LIBRARY_PATH environment variable for the path.
*/
ld_library_path = getenv("LD_LIBRARY_PATH");
if (NULL != ld_library_path) {
#define MAX_LIBRARY_PATHS 10
size_t token_index;
size_t tokens_count;
const char *tokens[MAX_LIBRARY_PATHS];

char *tokenized_library_path = NULL;

tokenized_library_path = strdup(ld_library_path);
tokens_count = cli_strtokenize(tokenized_library_path, ':', MAX_LIBRARY_PATHS, tokens);

for (token_index = 0; token_index < tokens_count; token_index++) {
cli_dbgmsg("searching for %s, LD_LIBRARY_PATH: %s\n", featurename, tokens[token_index]);

for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
snprintf(modulename, sizeof(modulename), "%s" PATHSEP "%s%s", tokens[token_index], name, suffixes[i]);
#ifdef _WIN32
rhandle = LoadLibraryA(modulename);
#else // !_WIN32
rhandle = dlopen(modulename, RTLD_NOW);
#endif // !_WIN32
if (rhandle) {
break;
}

cli_dbgmsg("searching for %s: %s not found\n", featurename, modulename);
}
char *err = NULL;

if (rhandle) {
break;
}
}
free(tokenized_library_path);
}
}

if (NULL == rhandle) {
#ifdef _WIN32
char *err = NULL;
DWORD lasterr = GetLastError();
if (0 < lasterr) {
FormatMessageA(
Expand All @@ -203,36 +124,112 @@ static void *load_module(const char *name, const char *featurename)
0,
NULL);
}
#else // !_WIN32
const char *err = dlerror();
#endif // !_WIN32

#ifdef WARN_DLOPEN_FAIL
if (NULL == err) {
cli_warnmsg("Cannot dlopen %s: Unknown error - %s support unavailable\n", name, featurename);
cli_dbgmsg("Cannot LoadLibraryA %s: Unknown error - %s support unavailable\n", name, featurename);
} else {
cli_warnmsg("Cannot dlopen %s: %s - %s support unavailable\n", name, err, featurename);
cli_dbgmsg("Cannot LoadLibraryA %s: %s - %s support unavailable\n", name, err, featurename);
LocalFree(err);
}

goto done;
}

cli_dbgmsg("%s support loaded from %s\n", featurename, modulename);

done:

return (void *)rhandle;
}

#else
if (NULL == err) {
cli_dbgmsg("Cannot dlopen %s: Unknown error - %s support unavailable\n", name, featurename);
} else {
cli_dbgmsg("Cannot dlopen %s: %s - %s support unavailable\n", name, err, featurename);

static void *load_module(const char *name, const char *featurename)
{
static const char *suffixes[] = {
LT_MODULE_EXT "." LIBCLAMAV_FULLVER,
PASTE(LT_MODULE_EXT ".", LIBCLAMAV_MAJORVER),
LT_MODULE_EXT,
"." LT_LIBEXT};
void *rhandle = NULL;
char *tokenized_library_path = NULL;
char *ld_library_path = NULL;
const char *err;

char modulename[128];
size_t i;

/*
* First try using LD_LIBRARY_PATH environment variable for the path.
* We do this first because LD_LIBRARY_PATH is intended as an option to override the installed library path.
*
* We don't do this for Windows because Windows doesn't have an equivalent to LD_LIBRARY_PATH
* and because LoadLibraryA() will search the executable's folder, which works for the unit tests.
*/
ld_library_path = getenv("LD_LIBRARY_PATH");
if (NULL != ld_library_path && strlen(ld_library_path) > 0) {
#define MAX_LIBRARY_PATHS 10
size_t token_index;
size_t tokens_count;
const char *tokens[MAX_LIBRARY_PATHS];

/*
* LD_LIBRARY_PATH may be a colon-separated list of directories.
* Tokenize the list and try to load the library from each directory.
*/
tokenized_library_path = strdup(ld_library_path);
tokens_count = cli_strtokenize(tokenized_library_path, ':', MAX_LIBRARY_PATHS, tokens);

for (token_index = 0; token_index < tokens_count; token_index++) {
cli_dbgmsg("searching for %s, LD_LIBRARY_PATH: %s\n", featurename, tokens[token_index]);

for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
snprintf(modulename, sizeof(modulename), "%s" PATHSEP "%s%s", tokens[token_index], name, suffixes[i]);

rhandle = dlopen(modulename, RTLD_NOW);
if (NULL != rhandle) {
cli_dbgmsg("%s support loaded from %s\n", featurename, modulename);
goto done;
}

cli_dbgmsg("searching for %s: %s not found\n", featurename, modulename);
}
}
#endif
}

#ifdef _WIN32
if (NULL != err) {
LocalFree(err);
/*
* Search in "<prefix>/lib" checking with each of the different possible suffixes.
*/
cli_dbgmsg("searching for %s, user-searchpath: %s\n", featurename, SEARCH_LIBDIR);

for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
snprintf(modulename, sizeof(modulename), "%s" PATHSEP "%s%s", SEARCH_LIBDIR, name, suffixes[i]);

rhandle = dlopen(modulename, RTLD_NOW);
if (NULL != rhandle) {
cli_dbgmsg("%s support loaded from %s\n", featurename, modulename);
goto done;
}
#endif
return rhandle;

cli_dbgmsg("searching for %s: %s not found\n", featurename, modulename);
}

cli_dbgmsg("%s support loaded from %s\n", featurename, modulename);
err = dlerror();
if (NULL == err) {
cli_dbgmsg("Cannot dlopen %s: Unknown error - %s support unavailable\n", name, featurename);
} else {
cli_dbgmsg("Cannot dlopen %s: %s - %s support unavailable\n", name, err, featurename);
}

done:

free(tokenized_library_path);

return (void *)rhandle;
}

#endif

#ifdef _WIN32

static void *get_module_function(HMODULE handle, const char *name)
Expand Down
1 change: 0 additions & 1 deletion libclamunrar/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Copyright (C) 2019-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.

add_compile_definitions(RARDLL)
add_compile_definitions(WARN_DLOPEN_FAIL)
add_compile_definitions(_FILE_OFFSET_BITS=64)

if(WIN32)
Expand Down

0 comments on commit 93699df

Please sign in to comment.