Discussion:
Using dlsym to load a function inside a shared library?
(too old to reply)
milewis1
2006-01-18 18:43:23 UTC
Permalink
I'm having trouble using dlsym, specifically it crashes with a SIGSEGV
when I try to do something like the following (please keep in mind that
this is a overly simplified example and I have plenty of reasons why I
think doing it this way is best -- but I don't want to get into that
here).

I have an application that loads a library called ip.so. When the
application runs I specify what function in ip.so I want it to run on
the command line. ex: app Function1.

The application code looks like this:

app.c
-----------------------------------------------------------------------------
int main(int argc, char** argv)
{
...

handle = dlopen("ip.so",RTLD_LAZY|RTLD_GLOBAL);
entryfunc = (entryfuncptr)dlsym(handle,"Entry");

/* run a function */
(entryfunc)(argv[1]);

return 0;
}


ip.c:
------------------------------------------------------------------------------
void FindWithdladdr(void) { return; }

void Function1(void)
{
/* do something here */
}

void Function2(void)
{
/* do something else here */
}


void Entry(char* funcname)
{
Dl_info dli;
...

dladdr((const void*)FindWithdladdr,&dli);
dlsym(dli_fbase,funcname);

...
}

-----------------------------
Using gdb I find that I get the SIGSEGV inside the dlsym call,
specifically in do_lookup_x(). From what I've read and know this should
be possible, but it's obviously not working. I've also tried using
RTLD_DEFAULT in the dlsym call, but then it looks for the funcname in
the application and not the library and thusly can't find it.

Does anyone have any idea what I'm doing wrong? or if I'm trying to do
something impossible?

Thanks,
Mike
Roger Leigh
2006-01-18 20:52:56 UTC
Permalink
Post by milewis1
I have an application that loads a library called ip.so. When the
application runs I specify what function in ip.so I want it to run
on the command line.
Have you considered the security implications of allowing user access
to arbitrary symbols?

(Example: the recent Microsoft WMF vulnerabilities were partly due to
the fact that the WMF format allowed calling arbitrary functions
within a particular DLL.)
Post by milewis1
Using gdb I find that I get the SIGSEGV inside the dlsym call,
specifically in do_lookup_x(). From what I've read and know this should
be possible, but it's obviously not working. I've also tried using
RTLD_DEFAULT in the dlsym call, but then it looks for the funcname in
the application and not the library and thusly can't find it.
Did you compile with -fpic/-fPIC and link with -shared? Can you see
the symbols in the dynamic symbol table (nm -D)?

You didn't check if dlsym returned NULL, BTW. That's an obvious cause
of a segfault.


Regards,
Roger

- --
Roger Leigh
Printing on GNU/Linux? http://gutenprint.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
milewis1
2006-01-18 21:09:39 UTC
Permalink
Yes, I have considered the security implications. As I mentioned, this
is the simpliest example of what's causing me trouble that I could
think of.

I did compile with -fPIC and I linked it with -shared. Also, I can see
the symbols using nm -D. I realize in the code I posted I don't check
for NULL. I do in the real program, but that doesn't matter since it
crashes inside the dlsym call (meaning that dlsym never returns at all).
milewis1
2006-01-18 21:59:42 UTC
Permalink
I wanted to add another side note. It turns out that if I look at the
variable "handle" returned by dlopen in app.c and then at dli.dli_fbase
return from dladdr they are different. I suspect this is what's causing
my problem. However, I'm not sure how to get around this. Any
suggestions?
Roger Leigh
2006-01-18 23:42:27 UTC
Permalink
Post by milewis1
I did compile with -fPIC and I linked it with -shared. Also, I can see
the symbols using nm -D. I realize in the code I posted I don't check
for NULL. I do in the real program, but that doesn't matter since it
crashes inside the dlsym call (meaning that dlsym never returns at all).
You really need to post a /minimal, compilable example/ if you want us
to look at your code.

If you add full error checking to your code, the fault will quickly
become apparent. Hint: it's before dlsym, and dlerror will tell you
about failures. You might want to ask yourself why you specifically
need RTLD_LAZY *and* RTLD_GLOBAL, and what you do if dlopen fails.


Regards,
Roger

- --
Roger Leigh
Printing on GNU/Linux? http://gutenprint.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
Paul Pluzhnikov
2006-01-19 04:42:40 UTC
Permalink
Post by milewis1
void Entry(char* funcname)
{
Dl_info dli;
...
dladdr((const void*)FindWithdladdr,&dli);
dlsym(dli_fbase,funcname);
Presumably this is actually

dlsym(dli.dli_fbase,funcname);
Post by milewis1
...
}
-----------------------------
Using gdb I find that I get the SIGSEGV inside the dlsym call,
Naturally: from "man dlsym":

The function dlsym() takes a "handle" of a dynamic library
returned by dlopen

Since you didn't give dlsym() valid input parameter (something
returned from dlopen()), dlsym() is free to crash.
Post by milewis1
From what I've read and know this should be possible
Passing dli_fbase to dlsym() might work on some systems, but that's
extremely non-portable, and almost certainly will not work on
any Linux.
Post by milewis1
if I'm trying to do something impossible?
Not impossible, and in fact quite easy.

The simplest and most portable approach is to have the main
application pass "handle" into the Entry:

handle = dlopen(...);
entryfunc = dlsym(...);
entryfunc(handle, argv[1]);

If for whatever reason you don't want to do that, then a
linux-specific solution is (error checking omitted):

Entry(const char *funcname)
{
Dl_info dli;
struct link_map *lm = (struct link_map *)dlopen(0, RTLD_LAZY);
const char *tail;

dladdr(&Entry, &dli);
tail = strrchr(dli.dli_fname, '/');
if (!tail) tail = dli.dli_fname;
for (lm = lm->l_next; lm; lm = lm->l_next) {
const char *tail2 = strrchr(lm->l_name, '/');
if (!tail2) tail2 = lm->l_name;
if (!strcmp(tail, tail2)) break;
}
func = dlsym(lm, funcname);
}

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Loading...