2

I am trying to run a dynamic executable (xxx) but I am getting the following error:

$ ./xxx
./xxx: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./xxx)
./xxx: /lib64/libc.so.6: version `GLIBC_2.17' not found (required by ./xxx)

As the libc in the system in version 2.12 and is too old for my binary.

I have copied version 2.27 of libc which would work with this particular binary. If I try to run it using LD_PRELOAD:

$ LD_PRELOAD="./libc.so.6" ./xxx
ERROR: ld.so: object './libc.so.6' from LD_PRELOAD cannot be preloaded: ignored.
./xxx: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./xxx)
./xxx: /lib64/libc.so.6: version `GLIBC_2.17' not found (required by ./xxx)

The system is a RedHat 6 server:

$ uname -a
Linux platinum 2.6.32-754.3.5.el6.x86_64 #1 SMP Thu Aug 9 11:56:22 EDT 2018 x86_64 GNU/Linux

The same steps work instead on my Ubuntu 18.10 machine. Why am I prevented from proloading my own libc? Also, why couldn't ld.so provide a more comprehensive explanation as of why my libc cannot be preloaded?

I might add that the following fails:

$ /lib64/ld-linux-x86-64.so.2 ./libc.so.6 
Segmentation fault (core dumped)

So I am guessing the binary I am using is likely incompatible with the RedHat kernel somehow.

melpomene
  • 84,125
  • 8
  • 85
  • 148
Giulio Genovese
  • 2,761
  • 1
  • 15
  • 12
  • 1
    Short answer is because libc is special, not because of the kernel. Long answer is because libc is special and needs a lot more than libc changed. See https://stackoverflow.com/questions/847179/multiple-glibc-libraries-on-a-single-host (eg) for ideas. – Cupcake Protocol Sep 13 '18 at 18:32

2 Answers2

1

I was able to find a solution, but it required compiling GLIBC 2.17 on the RedHat server. I will post the instructions I have used, in case this is of use to others:

$ cd /tmp
$ wget https://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.gz
$ tar xzvf glibc-2.17.tar.gz
$ mkdir build-glibc
$ cd build-glibc
$ ../glibc-2.17/configure --disable-sanity-checks
$ make
$ cd -
$ cp /tmp/build-glibc/libc.so /tmp/build-glibc/elf/ld-linux-x86-64.so.2 .
$ LD_PRELOAD="./libc.so:/lib64/libpthread.so.0:/lib64/libkrb5.so.3:/lib64/libk5crypto.so.3:/lib64/libdl.so.2:/lib64/libm.so.6:/lib64/libcom_err.so.2:/lib64/libkrb5support.so.0:/lib64/libkeyutils.so.1:/lib64/libresolv.so.2:/lib64/libselinux.so.1" ./ld-linux-x86-64.so.2 ./xxx

I also had to use the new dynamic loader, as the old one was incompatible with the GLIBC 2.17:

$ LD_PRELOAD="./libc.so" ./xxx 
./xxx: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
Stefan Lasiewski
  • 17,380
  • 5
  • 28
  • 35
Giulio Genovese
  • 2,761
  • 1
  • 15
  • 12
1

The problem is that dynamic loader (/lib/ld-linux.so.2) is linked with the old libc and it already pre-loaded. To load the new libc, you also need to take the new ld-linux.so linked with this libc. This program can be launched from command line:

$ LD_LIBRARY_PATH="." ./ld-linux.so.2 ./xxx

Some applications may incorrectly work this way and need to set dynamnic loader in its binary (elf) file:

$ patchelf --set-interpreter ./ld-linux.so.2 --set-rpath '$ORIGIN' ./xxx
$ ./xxx

The path to ld-linux.so may be absolute or relative the current directory but not with $ORIGIN as runpath.

sercxjo
  • 328
  • 2
  • 12