Using Interposition
The special handle RTLD_NEXT
enables
an application to locate the next symbol in a symbol scope. For
example, the application prog
can contain the
following code fragment.
if ((fptr = (int (*)())dlsym(RTLD_NEXT, "foo")) == NULL) { (void) printf("dlsym: %s\n", dlerror()); return (1); } return ((*fptr)());
In this case, foo
is searched for in the shared objects associated with prog
, which in this case is /lib/libc.so.1
. If this code fragment was contained in the file B.so.1
from the example that is shown in A Single dlopen Request, then foo
is searched for in C.so.1
only.
Use of RTLD_NEXT
provides a means to exploit symbol
interposition. For example, a function within an object can be
interposed upon by a preceding object, which can then augment the
processing of the original function. For example, the following code
fragment can be placed in the shared object
malloc.so.1
.
#include <sys/types.h> #include <dlfcn.h> #include <stdio.h> void * malloc(size_t size) { static void *(*fptr)() = 0; char buffer[50]; if (fptr == 0) { fptr = (void *(*)())dlsym(RTLD_NEXT, "malloc"); if (fptr == NULL) { (void) printf("dlopen: %s\n", dlerror()); return (NULL); } } (void) sprintf(buffer, "malloc: %#x bytes\n", size); (void) write(1, buffer, strlen(buffer)); return ((*fptr)(size)); }
malloc.so.1
can be interposed before the system library /lib/libc.so.1
where malloc
(3C) usually resides. Any calls to malloc
() are now interposed upon before the original function is called to complete the allocation.
$ cc -o malloc.so.1 -G -K pic malloc.c $ cc -o prog file1.o file2.o .... -R. malloc.so.1 $ prog malloc: 0x32 bytes malloc: 0x14 bytes ....
Alternatively, the same interposition can be achieved using the following commands.
$ cc -o malloc.so.1 -G -K pic malloc.c $ cc -o prog main.c $ LD_PRELOAD=./malloc.so.1 prog malloc: 0x32 bytes malloc: 0x14 bytes ....
Note:
Users of any interposition technique must be careful to handle any possibility of recursion. The previous example formats the diagnostic message usingsprintf
(3C), instead of using
printf
(3C) directly, to avoid any recursion caused by
printf
(3C) possibly using
malloc
(3C).
The use of RTLD_NEXT
within an executable or
preloaded object, provides a predictable interposition technique. Be
careful when using this technique in a generic object dependency, as
the actual load order of objects is not always predictable.