Почему я не могу загрузить свой собственный libc.so.6 для запуска динамического исполняемого файла

Я пытаюсь запустить динамический исполняемый файл (xxx), но получаю следующую ошибку:

$ ./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)

Поскольку libc в системе в версии 2.12 и слишком стара для моего двоичного файла.

Я скопировал версию 2.27 libc, которая будет работать с этим конкретным двоичным файлом. Если я попытаюсь запустить его с помощью 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)

Система представляет собой сервер RedHat 6:

$ 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

Вместо этого те же шаги работают на моем компьютере с Ubuntu 18.10. Почему мне запрещено загружать мою собственную библиотеку libc? Кроме того, почему ld.so не может предоставить более подробное объяснение того, почему моя библиотека libc не может быть предварительно загружена?

Могу добавить, что следующее не работает:

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

Так что я предполагаю, что бинарный файл, который я использую, вероятно, каким-то образом несовместим с ядром RedHat.

Короткий ответ: потому что libc особенная, а не из-за ядра. Длинный ответ заключается в том, что libc особенная и требует гораздо большего, чем изменение libc. См. stackoverflow.com/questions/847179/… (например) для идей.

Cupcake Protocol 13.09.2018 20:32
2
1
1 096
2

Ответы 2

Мне удалось найти решение, но для этого потребовалась компиляция GLIBC 2.17 на сервере RedHat. Я опубликую инструкции, которые использовал, на случай, если это будет полезно другим:

$ 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

Мне также пришлось использовать новый динамический загрузчик, так как старый был несовместим с GLIBC 2.17:

$ LD_PRELOAD="./libc.so" ./xxx 
./xxx: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument

Проблема в том, что динамический загрузчик (/lib/ld-linux.so.2) связан со старой библиотекой libc и уже предварительно загружен. Чтобы загрузить новую libc, вам также необходимо взять новый ld-linux.so, связанный с этой libc. Эту программу можно запустить из командной строки:

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

Некоторые приложения могут работать таким образом некорректно, и им необходимо установить динамический загрузчик в его двоичном (elf) файле:

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

Путь к ld-linux.so может быть абсолютным или относительным относительно текущего каталога, но не с $ ORIGIN в качестве пути выполнения.

Другие вопросы по теме