0

After reading these questions, I'm looking for some more detail about how to control symbol resolution order.

In my problem, I have main executable exec. exec dynamically links to a.so and c.so. a.so dynamically links to b.so. b.so calls function foo, which is normally provided by c.so but in this case is also provided by exec. b.so only works with c.so's implementation of foo.

A diagram of the situation:

exec      (foo caller and provider)
   | \
a.so  |
   |  |
b.so  |   (foo caller)
   | /
c.so      (foo provider)

I can only control the compilation/source of a.so, and I link a.so to exec with LD_PRELOAD.

I'd like calls to foo in exec to resolve to exec's implementation, and calls in b.so to resolve to c.so's implementation. Is this type of thing with different symbol lookups in different objects possible?

Community
  • 1
  • 1

1 Answers1

0

Unfortunately there is no way to tweak symbol resolution at per-library level so there is not easy way to achieve this.

If foo is actually implemented in main executable (not just copy-relocated to it) there's nothing you can do because symbols from main executables get the highest priority during resolution (unless you are ok with ultimately hacky runtime-patching of GOT which you aren't).

But if

  • foo is implemented in c.so
  • and you are desperate enough

you could do the following:

  • get return address inside interceptor in a.so (use __builtin_return_address)
  • match it against boundaries of b.so (can be obtained from /proc/self/maps)
  • depending on result, either do special processing (if caller is in b.so) or forward call to RTLD_NEXT

This of course has obvious limitations e.g. won't work if b.so calls function from yet another d.so which then calls foo but it may be enough in many cases. And yes, I've seen this approach deployed in practice.

Community
  • 1
  • 1
yugr
  • 19,769
  • 3
  • 51
  • 96
  • How could I do this with ``dlsym``? I see how ``a.so`` can get reference to ``c.so``'s ``foo`` with ``dlsym``, but is there a way to use ``dlsym`` to make ``b.so`` use it? – Eric Martin Jan 06 '17 at 21:07
  • Sorry, misread the question. I've updated the answer, hopefully it's more helpful now. – yugr Jan 06 '17 at 21:40
  • thanks for the edit! However, all dependencies only go downwards in the diagram (``a.so`` only calls into ``b.so``), which means the ``__builtin_return_address`` trick won't work. Also, it is actually separate implementations of ``foo`` in ``exec`` and ``c.so``. Are there any resources on GOT hacking (which isn't a road I want to go down but is something I'd like to learn about)? – Eric Martin Jan 06 '17 at 22:48
  • "Are there any resources on GOT hacking" - [this one](http://vxheaven.org/lib/vrn00.html#c6) seems to be the most complete. Some parts will be irrelevant to you but parsing ELF and patching GOT seem to be quite generic. – yugr Jan 07 '17 at 05:41
  • BTW is `LD_PRELOAD` of a.so critical in your case (e.g. you use it to interpose some symbols in application)? If not, you could instead `dlopen` it with `RTLD_DEEPBIND` from `LD_PRELOAD`-ed intermediate a_forwarder.so. Deep binding will force b.so to prefer symbols from a.so. – yugr Jan 07 '17 at 05:52
  • I do have some symbols I want to interpose. Does ``dlopen`` not interpose symbols? From reading about ``RTLD_DEEPBIND``, it sounds like a solution to my problem. – Eric Martin Jan 08 '17 at 18:15
  • "Does dlopen not interpose symbols" - no, `dlopen` appends library to the end of search list so it won't interpose symbols provided by libraries that were loaded at program startup. "From reading about RTLD_DEEPBIND, it sounds like a solution to my problem" - unfortunately there's no equivalent of `RTLD_DEEPBIND` for `LD_PRELOAD`-ed libraries. – yugr Jan 08 '17 at 18:20
  • Thanks. I think I still have a possible fix by ``LD_PRELOAD``ing ``a_forwarder.so`` which defines the few symbols I want to interpose and then forwards calls to ``dlopen``'d ``a.so``. – Eric Martin Jan 09 '17 at 17:52
  • Yes, sounds doable. – yugr Jan 09 '17 at 18:28
  • Note that it's possible to auto-generate forwarding for all interesting functions. I once did it in a rather cynical way [here](https://github.com/yugr/sigcheck/blob/master/src/interceptors.c) (the cynical part being not using `dlsym`) but "proper" approach is straightforward as well. – yugr Jan 09 '17 at 19:02