views:

45

answers:

2

Hello. Am trying to find a way of knowing which shared lib is calling into my shared lib function. The scenario is like this.

I have used LD_PRELOAD to override malloc. Inside my malloc I forward the call directly to the real malloc but if the call came from a particular shared lib I want to do some processing before I forward the call.

Now, the shared lib whose calls to malloc I want to handle is loaded and called by an external executable in a kind of plugin architecture. I can tell which executable called my malloc by checking the global program_invocation_short_name variable, but I don't want to process malloc calls coming from the executable that provides the plugin architecture but only those that come from the plugin shared lib.

I have tried using backtrace() and backtrace_symbols() to see if I can get the plugin library name or part of it from the back trace but no luck with this. I never get the name there.

Could someone suggest how this can be done?

Regards,

Alex.

Edit: I forgot to mention. This is on Linux. My bad, I had assumed the LD_PRELOAD gave that away.

A: 

On Windows you could use special APIs like CreateToolhelp32Snapshot(), Module32First() to obtain the list of all the shared libraries loaded in your process.

Each such library will reside in a memory range, specified by modBaseAddr and modBaseSize members of the structure MODULEENTRY32 .

By checking the return address of the caller (can be done with some simple inline assembly) you can compare it with there ranges, that would identify exactly the caller.

ruslik
Am looking to use the same approach but on linux but no luck so far with finding equivalent system calls. Any ideas?
Alex
+1  A: 

There is no easy way to do that, but this approach might work for your needs.

I have coded 3 small applications so you can follow my instructions. They are:

  • app: the binary that will run on your system. Calls a function from libmiddleman.so that tries to allocate some memory through malloc()

source code: gcc app.c -o app -L. -lmiddle_man

//File: app.c
#include "libmiddle_man.h"    
#include <stdio.h>

int main()
{
    do_something();

    return 0;
}
  • libmiddle_man.so: exports a function that simply calls malloc()

source code: gcc libmiddle_man.c -o libmiddle_man.so -shared

//File: libmiddle_man.c
void do_something()
{
    int* tmp = malloc(sizeof(int));
}

and also:

//File: libmiddle_man.h
void do_something();
  • libfake_malloc.so: implements and exports our version of malloc() that prints something on the terminal

source code: gcc lbfake_malloc.c -o libfake_malloc.so -shared

//File: libfake_malloc.c
#include <stdio.h>
#include <unistd.h>

void* malloc(size_t size)
{
    printf("fake malloc()\n");

    printf("Process ID: %d\n", getpid());

    while(1)
    {
    }

    return NULL;
}

When you execute the application with LD_PRELOAD=libfake_malloc.so ./app it will output the following:

fake malloc()
Process ID: 14230    (the PID will be different each time you run the application)

and the application will hang there because we need it so. We will examine the process memory map and make sure that app has both loaded both of our libraries.

So leave it there for now and open another terminal. When you search for this PID on the process list it will show which application is using libfake_malloc.so. It's not what we are aiming for, but it's an interesting information.

ps -aux | grep 14230

outputs:

karl     14230 97.3  0.0   1648   396 pts/9    R+   13:57  10:20 ./app

Remember to change 14230 for whatever number the application returned to you. Next, we will examine the process memory and verify that both of out libraries were loaded.

cat /proc/14230/maps

displays:

00110000-00263000 r-xp 00000000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
00263000-00264000 ---p 00153000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
00264000-00266000 r--p 00153000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
00266000-00267000 rw-p 00155000 08:06 2158492    /lib/tls/i686/cmov/libc-2.11.1.so
00267000-0026a000 rw-p 00000000 00:00 0 
00584000-00585000 r-xp 00000000 08:07 2921104    /home/karl/workspace/shared_libs/who_called_my_shared/libmiddle_man.so
00585000-00586000 r--p 00000000 08:07 2921104    /home/karl/workspace/shared_libs/who_called_my_shared/libmiddle_man.so
00586000-00587000 rw-p 00001000 08:07 2921104    /home/karl/workspace/shared_libs/who_called_my_shared/libmiddle_man.so
00605000-00606000 r-xp 00000000 08:07 2921103    /home/karl/workspace/shared_libs/who_called_my_shared/libfake_malloc.so
00606000-00607000 r--p 00000000 08:07 2921103    /home/karl/workspace/shared_libs/who_called_my_shared/libfake_malloc.so
00607000-00608000 rw-p 00001000 08:07 2921103    /home/karl/workspace/shared_libs/who_called_my_shared/libfake_malloc.so
007e6000-007e7000 r-xp 00000000 00:00 0          [vdso]
0096a000-00985000 r-xp 00000000 08:06 2142529    /lib/ld-2.11.1.so
00985000-00986000 r--p 0001a000 08:06 2142529    /lib/ld-2.11.1.so
00986000-00987000 rw-p 0001b000 08:06 2142529    /lib/ld-2.11.1.so
08048000-08049000 r-xp 00000000 08:07 2921106    /home/karl/workspace/shared_libs/who_called_my_shared/app
08049000-0804a000 r--p 00000000 08:07 2921106    /home/karl/workspace/shared_libs/who_called_my_shared/app
0804a000-0804b000 rw-p 00001000 08:07 2921106    /home/karl/workspace/shared_libs/who_called_my_shared/app
b77b0000-b77b2000 rw-p 00000000 00:00 0 
b77c9000-b77cc000 rw-p 00000000 00:00 0 
bfb69000-bfb7e000 rw-p 00000000 00:00 0          [stack]

You will notice that the inode for libfake_malloc.so is 2921103 and the inode of the library that loaded it (i.e. libmiddle_man.so) is actually 2921103+1, which is 2921104.

I had the opportunity to test this on a few machines and some embedded devices also running Linux. To summarize, it seems possible to discover which library has loaded yours by parsing the information available on /proc/pid/maps.

karlphillip