Closed Mr-JingShi closed 3 years ago
Sorry,I thought I was wrong when I submit the issue, so I closed it, but after debugging, I found that I was right, so I reopened it.
https://github.com/kubo/plthook/blob/85dad5081b5ebdbeeea790aeef95eb60b3748dea/plthook_elf.c#L279 https://github.com/kubo/plthook/blob/85dad5081b5ebdbeeea790aeef95eb60b3748dea/plthook_elf.c#L305 https://github.com/kubo/plthook/blob/85dad5081b5ebdbeeea790aeef95eb60b3748dea/plthook_elf.c#L369
We should hold the hndl (the return value of dlopen) until pltook_close.
Can you reply me?
lmap
points to a node of a linked list maintained by the dynamic linker.
On the other hand, POSIX doesn't define actual type of a handle returned by dlopen
.
I think ... lmap is equal to hndl,
It is correct on Linux. However it isn't on other platforms using ELF.
Linux glibc chooses to reuse lmap
as a dlopen handle.
The following code prints same two addresses on Linux.
#include <stdio.h>
#include <string.h>
#include <link.h>
#include <dlfcn.h>
int main()
{
struct link_map *lmap = _r_debug.r_map; // See link.h
while (lmap != NULL) {
if (strstr(lmap->l_name, "libc.so.6") != NULL) {
printf("%p: link_map address of libc.so.6 searched from the global variable _r_debug\n", lmap);
}
lmap = lmap->l_next;
}
printf("%p: dlopen handle of libc.so.6\n", dlopen("libc.so.6", RTLD_LAZY));
}
so, if hndl is invalid after dlclose, lmap is invalid too.
No. lmap
is valid until the dynamic library is unloaded from the process.
Thanks for talking with me
test.c
#include <stdio.h>
#include <string.h>
#include <link.h>
#include <dlfcn.h>
void test() {
struct link_map *lmap = _r_debug.r_map; // See link.h
while (lmap != NULL) {
if (strstr(lmap->l_name, "libtest.so") != NULL) {
printf("%p: link_map address of libtest.so searched from the global variable _r_debug\n", lmap);
} else if (strstr(lmap->l_name, "libc.so.6") != NULL) {
printf("%p: link_map address of libc.so.6 searched from the global variable _r_debug\n", lmap);
}
lmap = lmap->l_next;
}
}
int main()
{
printf("-------------------\n");
test();
printf("-------------------\n");
void* handle = dlopen("libtest.so", RTLD_LAZY);
if (handle != NULL) {
printf("%p: dlopen handle of libtest.so\n", handle);
}
printf("-------------------\n");
test();
dlclose(handle);
printf("-------------------\n");
test();
printf("-------------------\n");
return 0;
}
gcc -o test test.c -ldl
ldd test
linux-vdso.so.1 (0x00007ffe6d3fa000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f72cc1fa000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f72cbe09000)
/lib64/ld-linux-x86-64.so.2 (0x00007f72cc600000)
./test
-------------------
0x7f18128ec4f0: link_map address of libc.so.6 searched from the global variable _r_debug
-------------------
0x55b015f49690: dlopen handle of libtest.so
-------------------
0x7f18128ec4f0: link_map address of libc.so.6 searched from the global variable _r_debug
0x55b015f49690: link_map address of libtest.so searched from the global variable _r_debug
-------------------
0x7f18128ec4f0: link_map address of libc.so.6 searched from the global variable _r_debug
-------------------
Sometimes dynamic libraries are used as plugins, if dlopen is used without linking libtest.so (such as my test.c/test), it is not ok. your's testprog is ok, because you have linked libtest.so.
In https://man7.org/linux/man-pages/man3/dlclose.3.html,
The function
dlclose()
decrements the reference count on the dynamically loaded shared object referred to by handle.If the object's reference count drops to zero and no symbols in this object are required by other objects, then the object is unloaded after first calling any destructors defined for the object.
https://github.com/kubo/plthook/blob/85dad5081b5ebdbeeea790aeef95eb60b3748dea/plthook_elf.c#L374
This code doesn't unload the shared library even when it is loaded by dlopen
.
if dlopen is used without linking libtest.so (such as my test.c/test), it is not ok.
In this situation, the reference count of libtest.so
increases to two at line 353
and decreases to one at line 374. The count doesn't drop to zero.
Thank you,I see
#include <stdio.h>
#include <string.h>
#include <link.h>
#include <dlfcn.h>
#include <plthook.h>
static double strtod_cdecl_hook_func(const char *str, char **endptr)
{
printf("strtod_cdecl_hook_func\n");
return 0;
}
int main()
{
plthook_t* plthook = NULL;
const char* filename = "libtest.so";
plthook_open(&plthook, filename);
unsigned int pos = 0;
const char* name = NULL;
void **addr = NULL;
const char* funcname = "strtod_cdecl";
unsigned int found = 0;
while (plthook_enum(plthook, &pos, &name, &addr) == 0) {
if (strcmp(funcname, name) == 0) {
found = 1;
break;
}
}
if (0 != found)
{
plthook_replace(plthook, funcname, (void*)strtod_cdecl_hook_func, NULL);
}
plthook_close(plthook);
// strtod_cdecl("3.7", NULL);
return 0;
}
gcc -o test test.c ../plthook_elf.c -ldl
My previous idea was not to link libtest.so when compiling, such as above. But i found i was wrong. (1) I can not call strtod_cdecl whitout linking libtest.so, Unless I explicitly call the dlopen and dlsym. (2) https://man7.org/linux/man-pages/man3/dlclose.3.html, RTLD_NOLOAD (since glibc 2.2) Don't load the shared object. This can be used to test if the object is already resident (dlopen() returns NULL if it is not, or the object's handle if it is resident). This flag can also be used to promote the flags on a shared object that is already loaded. For example, a shared object that was previously loaded with RTLD_LOCAL can be reopened with RTLD_NOLOAD | RTLD_GLOBAL. https://github.com/kubo/plthook/blob/85dad5081b5ebdbeeea790aeef95eb60b3748dea/plthook_elf.c#L353 If I do not link libtest.so, Line 353 hndl is NULL. (3) if i don't link libtest.so and don't call strtod_cdecl in main, strtod_cdecl doesn't appear in Dynamic Relocation Symbol Table. It's not PLT than delayed binding.
I see, Thank you
https://github.com/kubo/plthook/blob/85dad5081b5ebdbeeea790aeef95eb60b3748dea/plthook_elf.c#L374
I am working on 64-bit ubuntu20.04. I was learning ELF and hook recently, so I found pltkook. plthook is so cool,plthook is a very useful tool, I learned how to hook a dynamic library function, thanks.
but I found a fatal error, I think ... lmap is equal to hndl, so, if hndl is invalid after dlclose, lmap is invalid too.
I add memset into here:
lmap's l_addr and l_ld are invalid,then the program crashed
how about adding the hndl into struct plthook:
Can you reply me? thanks