I am using dlmopen in C to load shared libraries into an isolated namespace. My goal is to make symbols in that namespace all belong to the loaded libraries. So they can't access symbols in my main program. Flowing is the pseu·do·code of the main function to show the process.
// when first .so is loaded, load it into a new namespace and store that namespace
// function a() is defined in it
void* handle1 = dlmopen(LM_ID_NEWLM, new_so_name1, RTLD_NOW);
// store the namespace in lmid
dlinfo(handle1, RTLD_DI_LMID, &lmid);
// when second .so is loaded, load it in lmid
// function b() is defined in it
void* handle2 = dlmopen(lmid, new_so_name2, RTLD_NOW);
Works pretty good. And it seems that both a() and b() are loaded into the namespace. But When I load a third shared library, something strange happens:
// If I make a call a() in the third library
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
// call a() using dlsym()
The loading succeed and I can call that function a(). But if I make a call b() in the third library and load it into the same namespace:
void* handle3 = dlmopen(lmid, new_so_name3, RTLD_NOW);
printf("error:%s\n", dlerror());
It gives the following error:
erroe:undefined symbol: b
It seems that the second library weren't loaded in the namespace successfully. But As I've shown, the second load succeeded and a non-null handle2 is returned. So why does this happen, what's wrong with my loading process? I just want all loaded libraries can share symbols in that specific namespace, to avoid using symbols in my main program.
As suggested by @CharlieBurns. I post the smallest program below to show my problem.
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <dlfcn.h>
void* handle1;
void* handle2;
void* handle3;
Lmid_t lmid;
int main() {
// handle1 contains: int a(){return 0;}
handle1 = dlmopen(LM_ID_NEWLM, "/tmp/lib-o1i6Yd.so", RTLD_NOW);
dlinfo(handle1, RTLD_DI_LMID, &lmid);
// handle2 contains: int b(){return 1;}
handle2 = dlmopen(lmid, "/tmp/lib-vSyM4y.so", RTLD_NOW);
#ifdef RUN_A
int (*A)(void);
handle3 = dlmopen(lmid, "/tmp/lib-lAGjb2.so", RTLD_NOW);
A = (int(*)(void))dlsym(handle3, "__wrapper_lAGjb2");
/*
int __wrapper_lAGjb2() {
return a();
}
*/
printf("%d\n", (*A)()); // output 0 as expected
return 0;
#endif
#ifdef RUN_B
int (*B)(void);
handle3 = dlmopen(lmid, "/tmp/lib-CO1YAD.so", RTLD_NOW);
// error: /tmp/lib-CO1YAD.so: undefined symbol: b
printf("error: %s\n", dlerror());
B = (int(*)(void))dlsym(handle3, "__wrapper_CO1YAD");
// error: ./a.out: undefined symbol: __wrapper_CO1YAD
printf("error: %s\n", dlerror()); //
/*
int __wrapper_CO1YAD() {
return b();
}
*/
printf("%d\n", (*B)()); // segmentation fault (core dumped)
return 0;
#endif
}
This is test.c
file. I compile by using gcc test.c -ldl -DRUN_A/B
, then ./a.out
to run it.
/tmp/.so
filesThey are created manually. For example, to create /tmp/lib-o1i6Yd.so
file using gcc:
write code in /tmp/lib-o1i6Yd.c
:
int a(){return 0;}
compile to .o
object file:
gcc -c -fpic /tmp/lib-o1i6Yd.c -o /tmp/lib-o1i6Yd.o
then create .so
file:
gcc -shared -o /tmp/lib-o1i6Yd.so /tmp/lib-o1i6Yd.o
Manaul doesn't clearly state the namespace problem(or I didn't understand it clearly)
Newly loaded shared libraries using dlmopen()
will be in RTLD_LOCAL
state default. That is, the latest loaded function can't call functions or using variables that loaded previously. See this post for more information.