0

I'm trying to dynamically load a library from within a chroot. The said library depends on glibc and its version is different from my host (host has 2.26, chroot has 2.23).

Is there a way to achieve that?

Here is what I tried:

$ curl http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/ubuntu-base-16.04-core-amd64.tar.gz | tar -C ubuntu -xz

#include <unistd.h>                                                                                                                                                                                                 
#include <dlfcn.h>

int main(int argc, char *argv[])
{
        chdir("ubuntu");
        chroot(".");

        // 1. This will fail
        dlopen("libpthread.so.0", RTLD_NOW);

        // 2. This will crash
        dlmopen(LM_ID_NEWLM, "libpthread.so.0", RTLD_NOW);

        return 0;
}
  1. Obviously fails because there is a glibc mismatch:

    /lib/x86_64-linux-gnu/libpthread.so.0: symbol __libc_dl_error_tsd, version GLIBC_PRIVATE not defined in file libc.so.6 with link time reference
    
  2. Crashes with the following output from valgrind:

    ==19923== Process terminating with default action of signal 4 (SIGILL): dumping core
    ==19923==  Illegal opcode at address 0x401D41C
    ==19923==    at 0x401D41C: ??? (in /usr/lib/ld-2.26.so)
    ==19923==    by 0x4013932: dl_open_worker (in /usr/lib/ld-2.26.so)
    ==19923==    by 0x516EB63: _dl_catch_error (in /usr/lib/libc-2.26.so)
    ==19923==    by 0x4013279: _dl_open (in /usr/lib/ld-2.26.so)
    ==19923==    by 0x4E3A8CF: ??? (in /usr/lib/libdl-2.26.so)
    ==19923==    by 0x516EB63: _dl_catch_error (in /usr/lib/libc-2.26.so)
    ==19923==    by 0x4E3A586: ??? (in /usr/lib/libdl-2.26.so)
    ==19923==    by 0x4E3A9B6: dlmopen (in /usr/lib/libdl-2.26.so)
    
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
3XX0
  • 1,315
  • 1
  • 13
  • 25
  • Why are you `dlopen()`ing `libpthread`? And I don't think there is a way, but I am almost certain that you have a [X Y Problem](http://xyproblem.info), so please explain what your real goal is. – Iharob Al Asimi Mar 04 '18 at 11:13
  • 2
    Your executable needs a library version your environment doesn't have. There's little sense in trying to run it as is. In addition, dlopen'ing libpthread and using it in a program not built with -pthread in the first place is not the greatest idea and is very likely to crash your program regardless of the version of glibc. – n. m. could be an AI Mar 04 '18 at 11:28
  • If it helps, think of it as a plugin bundle that you wish to load and potentially has conflicting dependencies.`libpthread` is just for the sake of the example, it fails with any library really. As for the environment, all the requirements and dependencies are satisfied under the chroot, the question is how to bring those in the address space of the process safely. – 3XX0 Mar 04 '18 at 12:11

1 Answers1

1

You are trying to bring two separate versions of GLIBC into a single process.

The reasons this does not work are explained here:

you need to know that glibc consists of many pieces (200+ shared libraries) which all must match. One of the pieces is ld-linux.so.2, and it must match libc.so.6, or you'll see the errors you are seeing.

In your case the mismatch is between /usr/lib/ld-2.26.so (symlinked from ld-linux-x86-64.so.2 and loaded into the process by the kernel before your program executes a single instruction of its own) and ubuntu/libpthread.so.0.

If you fully statically link your test program with gcc -static ..., it will likely work. But that is not a mode of operation that GLIBC developers test or support, and is unlikely to work for any non-trivial program.

To fix this, you would need to re-execve the program inside chroot. If you can't copy the binary into your chroot, you may be able to escape from that difficulty with fexecve or using /proc/self/exe (both of these appear to require that /proc is mounted inside the chroot).

P.S.

The said library depends on glibc and its version is different from my host (host has 2.26, chroot has 2.23).

Due to libc backward compatibility, any library linked against GLIBC-2.23 should continue to work just fine against GLIBC-2.26.

So maybe you don't have a problem to solve in the first place?

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • While I agree with what you said, shouldn't `dlmopen` be able to handle that? `LD_DEBUG` shows that `ld-linux-x86-64.so.2` and `libc.so.6` are being pulled from the chroot until the crash occurs. If I try to `dlmopen("ld-linux-x86-64.so.")` it works but it's not really useful on its own. I could indeed rely on the glibc ABI for this but I would have to chroot, find the library path with `RTLD_NOLOAD/dlinfo` unchroot and then `dlopen` the fullpath. For this example it works but it would be nice to solve the general use case where potentially other dependencies conflict. – 3XX0 Mar 04 '18 at 23:20
  • @3XX0 "shouldn't dlmopen be able to handle that?" -- not really: there could only be one `ld-linux` in the process. – Employed Russian Mar 05 '18 at 00:41