Enumerating shared libraries loaded via dlopen(RTLD_GLOBAL) - linux

Is there a way to determine at runtime which shared libraries have been loaded into the global symbol namespace of the current process? I'm primarily interested in anything that was loaded as a result of a dlopen() call that used the RTLD_GLOBAL flag.
I'm wanting to do this for auditing purposes -- it's important for an application I work on that dynamically-loaded shared libraries are loaded with dlopen's RTLD_LOCAL wherever possible so as not to conflict with third-party code; anything that's loaded into the global symbol namespace needs to be tightly controlled.
I've looked at the dl_iterate_phdr() API, but it doesn't seem to include this information.

You can try with
#define _GNU_SOURCE
#include <dlfcn.h>
typedef void *(*orig_dl)(const char *file, int mode);
void *dlopen(const char *file, int mode)
{
orig_dl o_dlopen;
o_dlopen = (orig_dl)dlsym(RTLD_NEXT, "dlopen");
return o_dlopen(file, mode);
}
Compile it using gcc -shared -fPIC dlo.c -o dlo.so -ldl
add LD_PRELOAD=dlo.so and here you go. You can log/trace/print any dlopen usage with specific mode

I think the suggestion to replace dlopen() using LD_PRELOAD is only a partial solution -- you won't catch dependencies of a library loaded with dlopen() that way.
In the end, I couldn't see any way of doing this without scraping the internal state of the dynamic linker itself. It found that there's a _rtld_global symbol exported from ld.so that has the information, but that you have to use private Glibc headers to interpret it.
The following is a Python snippet that will (assuming my reading of the Glibc sources is correct) print all the shared libraries in the global namespace in the order that they will be searched. Libraries loaded with RTLD_LOCAL will not be printed.
The fact that it relies on implementation details of Glibc means this approach is fraught with peril, but for my testing/auditing purposes I think it'll do nicely.
import ctypes
# Abridged type declarations pillaged from Glibc. See:
# - https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/generic/ldsodefs.h
# - https://sourceware.org/git/?p=glibc.git;a=blob;f=include/link.h
class link_map(ctypes.Structure):
_fields_ = [
("l_addr", ctypes.c_size_t),
("l_name", ctypes.c_char_p),
]
class r_scope_elem(ctypes.Structure):
_fields_ = [
("r_list", ctypes.POINTER(ctypes.POINTER(link_map))),
("r_nlist", ctypes.c_uint),
]
class rtld_global(ctypes.Structure):
_fields_ = [
("_ns_loaded", ctypes.POINTER(link_map)),
("_ns_nloaded", ctypes.c_uint),
("_ns_main_searchlist", ctypes.POINTER(r_scope_elem)),
]
_rtld_global = rtld_global.in_dll(ctypes.CDLL(None), "_rtld_global")
searchlist = _rtld_global._ns_main_searchlist[0]
print [searchlist.r_list[n][0].l_name for n in xrange(searchlist.r_nlist)]
On my CentOS 7 system, this prints:
['', '/lib64/libpython2.7.so.1.0', '/lib64/libpthread.so.0', '/lib64/libdl.so.2',
'/lib64/libutil.so.1', '/lib64/libm.so.6', '/lib64/libc.so.6',
'/lib64/ld-linux-x86-64.so.2']

Related

How to add own custom function in standard shared library (C) in linux?

I have downloaded libgcrypt library source code and I want to customize this standard shared library by adding my function inside one particular
source code file .
Although compilation/build process of customized shared library is successful, but it shows error at linking time.
Here is what I have done .
inside /src/visibility.c file, I have added my custom function,
void MyFunction(void)
{
printf("This is added just for testing purpose");
}
I have also include function prototype inside /src/gcrypt.h
void MyFunction(void);
#build process
./configure --prefix=/usr
sudo make install
nm command find this custom function.
nm /usr/lib/libgcrypt.so | grep MyFunction
000000000000dd70 t MyFunction
Here is my sample code to access my custom function.
//aes_gcrypt_example.c
#include <stdio.h>
#include <gcrypt.h>
#include <assert.h>
int main()
{
MyFunction();
return 0;
}
gcc aes_gcrypt_example.c -o aes -lgcrypt
/tmp/ccA0qgAB.o: In function `main':
aes_gcrypt_example.c:(.text+0x3a2): undefined reference to `MyFunction'
collect2: error: ld returned 1 exit status
I also tried by making MyFunction as extern inside gcrypt.h, but in that case also I am getting same error.
Why is this happening ?
Is the customization of standard library is not allowed ?
If YES, then is there any FLAG to disable to allow customization ?
If NO, what mistake I am making ?
It would be great help if someone provide some useful link/solution for the above mentioned problem. I am using Ubuntu16.04 , gcc 4.9.
Lower-case t for the symbol type?
nm /usr/lib/libgcrypt.so | grep MyFunction
000000000000dd70 t MyFunction
Are you sure that's a visible function? On my Ubuntu 16.04 VM, the linkable functions defined in an object file have T (not t) as the symbol type. Is there a stray static kicking around and causing confusion? Check a couple of other functions defined in libgcrypt.so (and documented in gcrypt.h) and see whether they have a t or a T. They will have a T and not t. You'll need to work out why your function gets a t — it is not clear from the code you show.
The (Ubuntu) man page for nm includes:
The symbol type. At least the following types are used; others
are, as well, depending on the object file format. If lowercase,
the symbol is usually local; if uppercase, the symbol is global
(external).
The line you show says that MyFunction is not visible outside its source file, and the linker agrees because it is not finding it.
Your problem now is to check that the object file containing MyFunction has a symbol type T — if it doesn't the problem is in the source code.
Assuming that the object file shows symbol type T but the shared object shows symbol type t, you have to find what happens during the shared object creation phase to make the symbol invisible outside the shared object. This is probably because of a 'linker script' that controls which symbols are visible outside the library (or maybe just compilation options). You can search on Google with 'linker script' and various extra words ('tutorial', 'provide', 'example', etc) and come up with links to the relevant documentation.
You may need to research documentation for LibTool, or for the linker BinUtils. LibTool provides ways of manipulating shared libraries. In a compilation command line that you show in a comment, there is the option -fvisibility=hidden. I found (mostly by serendipitous accident) a GCC Wiki on visibility. See also visibility attribute and code generation options.

Linux library calls ambiguously named function in executable - is this possible?

I have a problem with an embedded linux C++ application I've written that consists of an executable and a dynamically linked library. The executable calls a function that is one of the entry points in the library, but that function misbehaves. I've investigated using gdb, and find that the library function, which is supposed to make a call to another function xyz() within the library, actually calls a function of the same name xyz()within the executable.
I'm very surprised this can happen, so maybe I'm doing something stupid. Isn't the library linked within itself without reference to the executable? If the executable wrongly made a call to abc() in the library instead of abc() in the executable that would make slightly more sense, because it is at least linked with the library, although in that case would the linker spot the dual definition? Or prioritise the local function?
I could just rename my functions so none of them have matching names, but I'd like to understand what is going on. I don't have much experience in this area, or with the gcc tools. Firstly, is what I think is happening in the above scenario even possible?
Both the executable and the library make calls to another library.
The link command for the library I'm using is:
powerpc-unknown-linux-gnuspe-g++-4.9.3 aaa.o bbb.o [etc] -shared -o libmylibary.so -L ../otherlibpath -Wl,-rpath-link,../otherlibpath -lotherlibname
That is way how the dynamic linker works. The symbols in executable have higher priority then symbols in dynamic libraries. Dynamic library designer must be aware about it. She must do measures to avoid unwanted symbol mismatch. Most libraries use:
In case of C++ use namespaces. All symbols exported from library should be in a library namespace.
In case of C use a name prefix or suffix for all exported symbol. For example OpenSSL library uses the prefix SSL_ and the public functions have names like SSL_set_mode() so the unwanted symbol collision is avoided.
Do not export symbols from the library that are supposed to be private. If the symbol is not exported from the library then the dynamic linker use the local symbol in the library. #pragma visibility is your friend. See https://gcc.gnu.org/wiki/Visibility
If the library with duplicate symbols is a 3rd party library and its author does not follow the recommendations above then you have to rename your function or perhaps ask the author for a library update.
EDIT
Export/do not export may be controlled by #pragma visibility directive (gcc specific extension):
void exported_function1(int);
void exported_function2(int);
#pragma GCC visibility push(hidden)
void private_function1(int);
void private_function2(int);
#pragma GCC visibility pop
Detail at the link above.

Static vs. dynamic linking conflicts and duplication

I have a code A that is statically linked against one version of mpich. Now comes library B, which is used by A via dlopen(). B depends on mpich as well, but is linked dynamically against it.
The problem is that now, in order for B to take advantage of mpi distribution, needs to access the communicator currently handled by A. This communicator has been created by A static version of mpich, When B invokes MPI routines, it will use a dynamic version of MPI which is not guarateed to be compatible with the static version attached to A.
This is the overall picture. I think that the only solution is to have mpich dynamically linked for both A and B. What I am not fully understanding is however the following:
how does the linker handle shared objects dependencies when dlopening? Will I have two instances of mpich in VM also with dynamic linking, or is the linker smart enough to realize that the symbols required by the dlopened B are already in the address space and will resolve against those.
Is it possible to tell the linker: when you dlopen this library, don't go fetch the dynamic dependency, but resolve it with the static symbols that are already provided by A
In short: it depends on dlopen options. By default, if a symbol needed by the requested library already exists in the global scope, it will be reused (this is what you want). But you can bypass this behavior with RTLD_DEEPBIND, with this flag, the dependencies won't be reused from the global scope, and will be loaded a second time.
Here is some code to reproduce your situation and demo the effect of this flag.
Let's make a common library that will be used by both lib A and program B. This library will exist in two versions.
$ cat libcommon_v1.c
int common_func(int a)
{
return a+1;
}
$ cat libcommon_v2.c
int common_func(int a)
{
return a+2;
}
Now let's write lib A that uses libcommon_v2:
$ cat liba.c
int common_func(int a);
int a_func(int a)
{
return common_func(a)+1;
}
And finally program B that dynamically links to libcommon_v1 and dlopens lib A:
$ cat progb.c
#include <stdio.h>
#include <dlfcn.h>
int common_func(int a);
int a_func(int a);
int main(int argc, char *argv[])
{
void *dl_handle;
int (*a_ptr)(int);
char c;
/* just make sure common_func is registered in our global scope */
common_func(42);
printf("press 1 for global scope lookup, 2 for deep bind\n");
c = getchar();
if(c == '1')
{
dl_handle = dlopen("./liba.so", RTLD_NOW);
}
else if(c == '2')
{
dl_handle = dlopen("./liba.so", RTLD_NOW | RTLD_DEEPBIND);
}
else
{
printf("wrong choice\n");
return 1;
}
if( ! dl_handle)
{
printf("dlopen failed: %s\n", dlerror());
return 2;
}
a_ptr = dlsym(dl_handle, "a_func");
if( ! a_ptr)
{
printf("dlsym failed: %s\n", dlerror());
return 3;
}
printf("calling a_func(42): %d\n", (*a_ptr)(42));
return 0;
}
Let's build and run all the things:
$ export LD_LIBRARY_PATH=.
$ gcc -o libcommon_v1.so -fPIC -shared libcommon_v1.c
$ gcc -o libcommon_v2.so -fPIC -shared libcommon_v2.c
$ gcc -Wall -g -o progb progb.c -L. -lcommon_v1 -ldl
$ gcc -o liba.so -fPIC -shared liba.c -L. -lcommon_v2
$ ./progb
press 1 for global scope lookup, 2 for deep bind
1
calling a_func(42): 44
$ ./progb
press 1 for global scope lookup, 2 for deep bind
2
calling a_func(42): 45
We can clearly see that with default options, dlopen reuses the symbol common_func that was present in program B and that with RTLD_DEEPBIND, libcommon was loaded again and library A got its own version of common_func.
You did not say which Toolchain (GCC, LLVM, MSC, etc.) you are using, the most helpful answer will depend upon this information.
May I suggest you look at "GCC Exception Frames" http://www.airs.com/blog/archives/166 .
If that is helpful then the Gold Linker, which is available for GCC and LLVM, supports 'Link Time Optimization' and can run in "Make" with DLLTool http://sourceware.org/binutils/docs/binutils/dlltool.html .
Indeed it is possible to have both Static and Dynamic Code call each other, the Computer does not care; it will 'run' anything it is fed -- whether that ends up working exactly the way you want or HCFs depends on correct Code and correct Linker commands.
Using a Debugger will not be fun. It would be best to mangle the names prior to Linking so that when debugging you can see from which module the Code came. Once it is up and running you can undef the Mangle and have the same-named Functions Link (to ensure it still functions).
Compiler / Linker Bugs will not be your friend.
This sort of scenario (Static and Dynamic Linking) occurs more often with MinGW and Cygwin where some of the Libraries are Static yet a Library you download from the Internet is only available in Dynamic form (without Source).
If the Library is from two different Compiler Toolchains then other issues arise, see this StackOverflow Thread: " linking dilemma (undefined reference) between MinGW and MSVC. MinGW fails MSVC works ".
It would be best to simply get the newest version of the Library from the source and compile the whole thing yourself, rather than rely on trying to cobble together bits and pieces from different sources (though it is possible to do that).
You can even load the Dynamic Library and call it (statically) and then reload portions of it later.
How tight are you on Memory and how fast do you want Functions to run, if everything is in Memory your Program can transfer execution to called Functions straight away, if you are swapping a portion of your Code to VM your execution times will really take a hit.
Running a Profiler on your Code will help decide what portions of a Library to load if you want to do 'dynamic dynamic linking' (full control of your dyna-linking by loading a Dynamic Library so it can be used Statically). This is the stuff that headaches and nightmare are made of. GL.

inconsistent dll linkage & definition of dllimport static data member not allowed

Assuming I have these two files:
Header.h
class DLL ExportClass{
public:
ExportClass();
static int test;
};
Source.cpp
#ifdef EXPORT
#define DLL __declspec(dllexport)
#else
#define DLL __declspec(dllimport)
#endif
#include "Header.h"
int ExportClass::test = 0;
ExportClass::ExportClass(){
}
And I won't define EXPORT (to import a already exported class with a static member), why do I get these warnings:
1>source.cpp(11): warning C4273: 'test' : inconsistent dll linkage
1> header.h(4) : see previous definition of 'public: static int ExportClass::test'
1>source.cpp(13): warning C4273: 'ExportClass::ExportClass' : inconsistent dll linkage
1> header.h(3) : see previous definition of '{ctor}'
And this error:
1>source.cpp(11): error C2491: 'ExportClass::test' : definition of dllimport static data member not allowed
If I define EXPORT it works. I kind of understand the warnings, but I thought, that the static variable and the ctor could be ignored by the compiler, because the whole class is declared as __declspec(dllimport) anyway. I want to use the same codebase for the __declspec(dllexport) and __declspec(dllimport) - but it seems the compiler stll tries to define these symbols that are marked as __declspec(dllexport) in their declaration. What is the common practice to solve this problem?
You are expecting the compiler to ignore a very serious mishap. It encountered the __declspec(dllimport) attribute on the class declaration, that quite unequivocally states that the class implementation is present in different module that's going to bound at runtime. But then it encountered the definition as well, completely unexpected since the attribute contract says that it is compiled in an entirely different project.
The C4273 warning is generated to remind you that it is very unclear what function is actually going to execute at runtime. There are two, one that is busy compiling, another in the DLL. Which one will actually execute is a wild guess. C4273 is a level 1 warning, the kind that fit the "this is almost surely wrong" category. It is not entirely impossible to work okay since there's some expectation that the functions have at least the same code. The odds that will not cause trouble are however not great, it could only work if the function doesn't have any side effects that change the internal DLL state. Very hard to diagnose bug when it does btw.
Then it encountered the exported variable. Same case, there are two of them. This is where the compiler programmer put his foot down, having code randomly use one or the other is no longer something that can be ignored. That just cannot ever work, the variables cannot have the same value. So C2491 is a hard error.
No idea how you got in this pickle, clearly the road you're trying to travel will make you fall off a steep cliff.
The only way I can reproduce your problem is to do the following:
Create a Win32 DLL project, call it Project1
Add the source code as you described
Compile the DLL and LIB
Change the project properties to remove EXPORT from the preprocessor definitions
Attempt to compile again (then I see your errors/warnings)
If, instead of steps 4 and 5, I do the following, I do not see an error:
Create a Win32 console application, call it Project2
Add source code as follows:
#include "Project1.h"
#pragma comment(lib, "Project1.lib")
int _tmain(int argc, _TCHAR* argv[])
{
ExportClass pClass;
return 0;
}
I suspect you see those errors because you are doing everything from the same DLL project and it is overwriting the LIB that it previously created and then attempting to import it.
If I am correct in guessing what you did, can you try using your DLL/LIB from another project and see what happens?
Although it is an old thread, it will be probably read by others. Therefore, if you want to make this code cross-compilable, I would usually define a header "export.h" like:
export.h
#pragram once
#if ! defined(DLL_API)
# if defined(_WIN32) // for windows builds
# if defined(myDLL_EXPORTS)
# define DLL_API __declspec(dllexport)
# else
# define DLL_API __declspec(dllimport)
# endif
# else // for linux builds
# define DLL_API
# endif
#endif
and include it in all the classes (.h) you want to export from your dll. You will also have to define the variable myDLL_EXPORTS as a parameter of the compiler for the dll project.
The way it works is very simple, when you are compiling your dynamic library (dll/so), because the variable myDLL_EXPORTS is defined, the compiler will replace DLL_API with __declspec(dllexport) so that your class can be consumed by the user of your dll. Conversely, when you are including the header file where you want to use your class at, because the variable myDLL_EXPORTS is not defined in the consumer project (it is defined only in the DLL project), the compiler will replace myDLL_EXPORT with __declspec(dllimport), so it knows that your class symbols are defined somewhere else (in this case, defined in your dll/so).
Finally, as __declspec(...) is a Windows-only thing, for linux we replace DLL_API with nothing.

Strange symbols while linking shared library g++

I have a file with the void initGui() function in it. It does stuff.
I also have a .so shared library made with that file.
The problem is, when I try to launch a dlsym(..., "initGui"), dlerror() tells me that it didn't found the symbol (of course, I used dlopen to open it). So I tried to nm my shared lib. I "understood" that _Z7initGuiiii might be what I'm looking for. So I tried to dlsym it ... And it worked.
Please can someone tell me how to have clean symbols in my shared object library ?
I compile with g++ -Wall -Wextra -Werror -c -fPIC.
The usual practice when dlsym-ing inside some dlopen-ed shared library coded in C++ is to have the convention that those seeked symbols (those that you are dlsym-ing) are declared extern "C". Then their name is easily visible with dlsym. So you need to declare
extern "C" void initGui(void);
and then to do
typedef void initguiroutine_sig_t(void);
initguiroutine_sig_t* initguiptr = dlsym(dlhandle,"initGui");
if (!initguiptr) {
fprintf(stderr, "initGui not found: %s\n", dlerror());
exit (EXIT_FAILURE);
};
// later, call initguiptr like
(*initguiptr) ();
I don't recommend understanding in great details how your C++ name mangling works, it is not very well defined, and details depend upon particular version of the C++ libraries (notably the standard C++ library) and of the compiler version.

Resources