How to Check What Shared Libraries Are Loaded at Run Time for a Given Process

How to check what shared libraries are loaded at run time for a given process?

Other people are on the right track. Here are a couple ways.

cat /proc/NNNN/maps | awk '{print $6}' | grep '\.so' | sort | uniq

Or, with strace:

strace CMD.... 2>&1 | grep -E '^open(at)?\(.*\.so'

Both of these assume that shared libraries have ".so" somewhere in their paths, but you can modify that. The first one gives fairly pretty output as just a list of libraries, one per line. The second one will keep on listing libraries as they are opened, so that's nice.

And of course lsof...

lsof -p NNNN | awk '{print $9}' | grep '\.so'

How can I check a running process to see what shared libraries it is using?

If you want to know the library files a program have opened, you can try pmap.
For example, if we want to know the libraries that bash process 3860 have opened, the result could be:

3860:   bash
08048000 880K r-x-- /bin/bash
08124000 4K r---- /bin/bash
08125000 20K rw--- /bin/bash
0812a000 20K rw--- [ anon ]
099ae000 348K rw--- [ anon ]
b715c000 44K r-x-- /lib/i386-linux-gnu/libnss_files-2.15.so
b7167000 4K r---- /lib/i386-linux-gnu/libnss_files-2.15.so
b7168000 4K rw--- /lib/i386-linux-gnu/libnss_files-2.15.so
b7169000 88K r-x-- /lib/i386-linux-gnu/libnsl-2.15.so
b717f000 4K r---- /lib/i386-linux-gnu/libnsl-2.15.so
b7180000 4K rw--- /lib/i386-linux-gnu/libnsl-2.15.so
b7181000 8K rw--- [ anon ]
b7183000 28K r-x-- /lib/i386-linux-gnu/libnss_compat-2.15.so
b718a000 4K r---- /lib/i386-linux-gnu/libnss_compat-2.15.so
b718b000 4K rw--- /lib/i386-linux-gnu/libnss_compat-2.15.so
b71a1000 4K r---- /usr/lib/locale/locale-archive
b71a2000 1428K r---- /usr/lib/locale/locale-archive
b7307000 2048K r---- /usr/lib/locale/locale-archive
b7507000 4K rw--- [ anon ]
b7508000 1676K r-x-- /lib/i386-linux-gnu/libc-2.15.so
b76ab000 8K r---- /lib/i386-linux-gnu/libc-2.15.so
b76ad000 4K rw--- /lib/i386-linux-gnu/libc-2.15.so
b76ae000 16K rw--- [ anon ]
b76b2000 12K r-x-- /lib/i386-linux-gnu/libdl-2.15.so
b76b5000 4K r---- /lib/i386-linux-gnu/libdl-2.15.so
b76b6000 4K rw--- /lib/i386-linux-gnu/libdl-2.15.so
b76b7000 112K r-x-- /lib/i386-linux-gnu/libtinfo.so.5.9
b76d3000 8K r---- /lib/i386-linux-gnu/libtinfo.so.5.9
b76d5000 4K rw--- /lib/i386-linux-gnu/libtinfo.so.5.9
b76d8000 28K r--s- /usr/lib/i386-linux-gnu/gconv/gconv-modules.cache
b76df000 40K r-x-- /lib/i386-linux-gnu/libnss_nis-2.15.so
b76e9000 4K r---- /lib/i386-linux-gnu/libnss_nis-2.15.so
b76ea000 4K rw--- /lib/i386-linux-gnu/libnss_nis-2.15.so
b76eb000 8K rw--- [ anon ]
b76ed000 4K r-x-- [ anon ]
b76ee000 128K r-x-- /lib/i386-linux-gnu/ld-2.15.so
b770e000 4K r---- /lib/i386-linux-gnu/ld-2.15.so
b770f000 4K rw--- /lib/i386-linux-gnu/ld-2.15.so
bfbbf000 132K rw--- [ stack ]
total 7152K

Wish it would be of help for you.

Get all loaded shared libraries by a process

The kernel has no idea of loaded shared libraries, only memory mappings. You can get those from the vma list, and you can also see them from userspace in /proc/$pid/maps. On the other hand, an application can get a list of its own shared libraries via dl_iterate_phdr.

How to know which shared library my program is actually using at run time?

On Linux: One possible approach is to look into the corresponding entry in the /proc/ filesystem. For example for a program with PID X you can find info in /proc/X/maps similar to:

...
7f34a73d6000-7f34a73f8000 r--p 00000000 08:03 18371015 /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/libc-2.27.so
7f34a73f8000-7f34a7535000 r-xp 00022000 08:03 18371015 /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/libc-2.27.so
...

It clearly shows where my libc (the one used by this program) is.


Example (missing some error handling!) to show where fopen is coming from:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>

#define BSIZE 200

int main(void) {
char buffer[BSIZE];
int const pid = getpid();
snprintf(buffer, BSIZE, "/proc/%d/maps", pid);
FILE * const maps = fopen(buffer, "r");
while (fgets(buffer, BSIZE, maps) != NULL) {
unsigned long from, to;
int const r = sscanf(buffer, "%lx-%lx", &from, &to);
if (r != 2) {
puts("!");
continue;
}
if ((from <= (uintptr_t)&fopen) && ((uintptr_t)&fopen < to)) {
char const * name = strchr(buffer, '/');
if (name) {
printf("%s", name);
} else {
puts("?");
}
}
}
fclose(maps);
}

Get a list of all shared libraries that a running service is using in Ubuntu

libc.so.6 is present in the output of solutions 1, 2 and 4 but not in 3.

libc.so.6 is a symlink to libc-2.23.so so it is present, albeit in a different form.

and /lib64/ld-linux-x86-64.so.2 as well which no other solution reports.

Ditto, it's ld-2.23.so.

Also the output of solution 1 above reports inux-vdso.so.1

This is a dummy shared lib which does not exist but is emulated by kernel to increase performance of some library functions. I guess 3 has it in

ffffffffff600000 4K r-x-- [ anon ]

but it's not annotated.

which of these solutions should be taken as the accurate one.

2 and 4 are equivalent. They are inferior to 1 and 3 because they report only direct dependencies of your app (not transitive dependencies of it's dependants). Further, 1 is inferior to 3 because it won't report dynamically loaded libs (via dlopen).

Also, on demand a process can load any more shared libraries
when ever needed. Am I right or wrong here ?

Yup, that's used to implement e.g. plugins.

So, if I really need to know the shared libraries
being used by a process, will I need to poll the process
all the time to figure this out ?
(Am sure there is much better /elegant solution to this)

No, there is no easier solution. You could check whether app calls dlopen (by scanning output of readelf --dyn-syms -W) - if it doesn't you are most probably fine (some really clever apps may load libs themselves via mmap, etc. but this is so rare that is fine to ignore).

If app does call dlopen than the best thing you can do is use solution 3. This is obviously incomplete as app may load new libs at any time, depending on it's algorithm (and there's generally no way to figure it out statically as that would be equivalent to solving the halting problem).

One approximate solution for finding potentially dlopen-ed libs would be to scan all strings in app (by running strings on it) and extracting everything that looks like a library name. Of course this won't catch the situations where library name is generated dynamically (e.g. read from some config file).

Solution 1, the ldd approach, is something I would want
to avoid because of the inherent security risk it has
(depending on the version of the ldd being used) of
starting an executable itself to figure out it's shared libraries.

I don't think executable is started i.e. no app or libs code gets run.

So what is the best approach to figure out the shared libraries being
used by a process?

I'd got with no. 3 (which has many equivalent variants e.g. scanning /proc/PID/maps or lsof as suggested in other post). Depending on how inclined you are about dlopen, you can also scan strings for potentially loaded libs but IMHO that's an overkill in majority of cases.

How to know which shared object is used?

You should use the ldd utility. In the same environment you would load your executable (Same LD_LIBRARY_PATH, e.t.c.)

Programatically determine shared libraries in use by running application

Since it looks like you're using something UNIX-y, just use dlopen instead of dynamically linking your driver app against the missing symbol.

Full sequence is:

  1. iterate over all submitted .so library filenames somehow (maybe you have one directory with studentname.so or something)
  2. load each library
  3. get the entry point function
  4. call it
  5. unload library (optional, I guess)

like so:

void *lib = dlopen(filename, RTLD_LOCAL);
void *libfun = dlsym(lib, "doAction");
if (libfun == NULL)
cout << "student failed by not providing doAction() in " << filename << endl;
else {
void (*doAction)(void) = (void (*)(void)) libfun;
// no, I can't remember the correct syntax for casting to function pointer
cout << "calling " << filename << ":doAction()" << endl;
doAction();
// is there some way to tell if it succeeded?
cout << "unloading " << filename << endl;
dlclose(lib);
}

Notes:

  • if the interface is the same in each case (ie, void (*)()), you could make this configurable by directory name and symbol name, and it'd work for more than one test
  • in fact, if the interface is NOT what you expect, the function pointer cast will do horrible things, so careful with this
  • finally, if the student used C++, their function name symbol will be mangled. Tell them to declare the entry-point as extern "C" void doAction() to avoid that.
  • the RTLD_LOCAL flag should stop anything in one student's library interfering with another (if you don't unload), but there are other flags it may be sensible to add
    • specifically, RTLD_NOW will cause dlopen to fail if the student lib has an unresolved external reference it can't figure out (so you can handle it gracefully, by failing them): otherwise your program may just crash when you call doAction.

Although I think the above is better than the solution you're directly asking for help with, I did also find a reference to dl_iterate_phdr while double-checking the docs. If you're on Linux specifically, and if the dl_phdr_info.dlpi_name is actually the filename ... you might be able to get it that way.

I still think it's much uglier, though.



Related Topics



Leave a reply



Submit