Сборка curl, httpd и других с пользовательской сборкой openssl, избегая при этом системной openssl по умолчанию
Я пытался обновить некоторые программы на старой версии Linux (Debian 7.5 wheezy). Я бы хотел оставить системные библиотеки по умолчанию нетронутыми и добавить несколько пользовательских сборок вместе с ними. Он отлично работает для большинства библиотек, только OpenSSL доставляет мне неприятности (libssl.so + libcrypt.so).
Вот моя строка конфигурации OpenSSL:
# ./config --prefix=/usr/local --openssldir=/usr/local/openssl no-gost shared zlib no-ssl2 -fPIC
Тогда для других программ, например cURL:
# ./configure LDFLAGS="-L/usr/local/ssl/lib -ldl" --with-ssl --enable-shared
Но тогда я получаю неправильную версию OpenSSL:
# curl --version
curl 7.44.0 (x86_64-unknown-linux-gnu) libcurl/7.44.0 OpenSSL/1.0.1e
Я знаю, что libssl.so имеет копии в следующих папках в этой системе:
/usr/lib/libssl.so
/usr/lib/x86_64-linux-gnu/libssl.so
/usr/local/lib/libssl.so
/usr/local/ssl/lib/libssl.so
Все они представляют собой одну и ту же скомпилированную версию, за исключением /usr/lib/x86_64-linux-gnu/libssl.so, которая, похоже, является моей системной библиотекой по умолчанию (v1.0.5e).
Я хотел бы знать, как я могу дать команду настроить скрипты, чтобы не заглядывать внутрь / lib / x86_64-linux-gnu? Могу ли я просто изменить /usr/lib/x86_64-linux-gnu/libssl.so символическую ссылку и указать ее для моих сборок? Это безопасно?
Спасибо,
2 ответа
Здесь задействованы две разные операции компоновщика: время сборки (используется для поиска библиотек и "символы", выполняемые
ld
или эквивалент), и время выполнения (выполняется
ld.so
), который загружает библиотеки в память процесса и выполняет перемещения.
Когда вы используете
-L
во время сборки,
ld
только подтверждает, что библиотеки и необходимые символы (обычно функции, составляющие API) доступны. Во время выполнения можно использовать библиотеки с разными путями.
LD_LIBRARY_PATH
,
LD_PRELOAD
и RPATH (-R
или же
-rpath
) являются одними из способов управления этим - последний способ указать это во время сборки (так что это свойство двоичного файла и меньше зависит от пользовательской среды).
В любой библиотеке функции, API и ABI могут измениться, что приведет к ошибкам или нестабильности, если компоновщик найдет или загрузит "неправильный" двоичный файл. Даже если символы могут совпадать, как ожидалось (или вы получите ошибку перед выполнением), колеса могут оторваться во время выполнения процесса. Есть решения для этого, управление версиями имени файла библиотеки и версиями символов в библиотеке, хотя здесь они не будут иметь большого смысла.
(Сложность в том, что
SHLIB_MAJOR
/SHLIB_MINOR
во всей серии OpenSSL 1.0.x стоит "1.0.0", поэтому эти библиотеки нельзя будет легко отличить, если вы не взломаете
Makefile
.)
Curl сам проверяет наличие такого рода проблем, он сравнивает время сборки
libcurl
версия к версии времени выполнения и может выдать:
ВНИМАНИЕ: версии curl и libcurl не совпадают. Это может повлиять на функциональность.
Современный
ld
будет делать то же самое во время сборки, когда он отмечает потенциально конфликтующие библиотеки в зависимостях.
Для чистой сборки без уловок среды выполнения вы можете:
- построить OpenSSL, убедившись, что RPATH явный, потому что
libssl.so
ссылки противlibcrypto.so
, и установить по указанному пути - собрать пакет (т.е. curl) с правильной спецификацией времени компоновки и времени выполнения, чтобы он находил конкретный
libssl.so
/libcrypto.so
Дешевый и неприятный способ решить проблему - это usr
chrpath
чтобы изменить ELF RPATH в двоичных файлах после сборки, я не рекомендую это вообще, и определенно не для curl, читайте дальше.
Теперь о сложностях: curl поддерживает множество протоколов, некоторые из этих протоколов предоставляются через другие библиотеки, и там, где протокол поддерживает TLS (или использует криптографические функции), он будет также связываться с
libssl.so
и / или
libcrypto.so
, например, для LDAP и SSH. Чего вы не хотите:
curl ↦ libcurl.so → libldap.so → libssl.so
↦ lib...
↦ libcrypto.so
↳ libssl.so
где
curl
сам использовал бы одну версию, но
libldap.so
может ожидать загрузки другой версии; это также может дать сбой во время выполнения, если есть несовместимость ABI. Вам может не повезти с символом или порядком загрузки, и вы получите две (или более!) Версии загруженной библиотеки.
Обычно есть три способа обойти это:
- отключите все функции, которые вам не нужны при сборке, для curl придется как минимум LDAP и SSH2
- если это невозможно, создайте новые версии зависимых библиотек, которые также связаны с новым OpenSSL.
- если это невозможно, вы можете использовать
.a
библиотеки для статической компоновки. Для curl это не то же самое, что просто использовать--enable-static
. Это может работать, я делал это в далеком прошлом, но здесь может не сработать, поэтому я не буду упоминать об этом дальше; и это может вызвать много головных болей, не в последнюю очередь с PIC / PIE.
GnuTLS может еще больше запутать ситуацию, хотя одновременное использование обеих библиотек не проблема (по крайней мере, я не видел этого до сих пор); это не относится к другим библиотекам, которые нацелены на совместимость с ABI, например LibreSSL. У Curl есть проблемы с использованием только одной библиотеки SSL в своей сборке (в настоящее время он поддерживает 8, AFAIK), но он не знает, что, например,
libssh2
может быть связано с.
Итак, в зависимости от версии, вы можете попробовать собрать OpenSSL и curl соответственно:
# OpenSSL
./config --prefix=/usr/local --openssldir=/usr/local/openssl no-gost \
shared zlib no-ssl2 -fPIC -Wl,-R,/usr/local/openssl
make depend && make && make install_sw
# curl
./configure --with-ssl=/usr/local/openssl --enable-shared \
--enable-ldap=no --without-libssh2 \
CFLAGS=-Wl,-R,/usr/local/openssl/lib
make && make install
(Несмотря на документацию об обратном,
--with-ldap=no
и
--without-ldap
не имеют полезного эффекта, используйте
--enable-ldap=no
.
libssh2
(для scp) обычно не включен по умолчанию.)
После установки
ldd /usr/local/bin/curl
не должно содержать сюрпризов: ровно одна ссылка на каждый из ожидаемых
libssl.so
и
libcrypto.so
.
Сборка OpenSSL (не autoconf) установит
RPATH
правильно на
openssl
двоичный, но он не устанавливает его в библиотеках по умолчанию. Существуют специфические для платформы варианты расположения библиотек (большая часть обработки RPATH в сборке OpenSSL является уловкой: она применяется к платформам, отличным от Linux). Это может не потребоваться для curl, но не вызовет проблем.
Когда вы используете autoconf
configure
нет гарантии, что расположение библиотеки, отличное от заданного по умолчанию, приведет к совпадению RPATH в двоичных файлах,
CFLAGS
/LDFLAGS
обычно можно это исправить. Однако здесь, в двухэтапном процессе OpenSSL,
config
не совсем ладит с такими переменными, как
LDFLAGS
, поэтому добавьте в конце
config
линия вместо этого, и
Configure
правильно обрабатывает это при создании
Makefile
.
Вы можете проверить исполняемый файл ELF или путь выполнения библиотеки с помощью:
readelf --dynamic elfbinary | grep PATH
Вы можете отладить загрузку библиотеки с помощью:
LD_DEBUG=files,libs /usr/local/bin/curl ...
(Обратите внимание, что исходный вопрос устарел, и OpenSSL 1.0.x больше не поддерживается официально, хотя дистрибутивы могут различаться. Приведенные здесь инструкции обычно применимы для создания специальных версий OpenSSL 1.0.x для конкретных целей.
stunnel
двоичный код для обратного прокси-сервера старого сетевого устройства, чтобы оно могло работать с современным браузером, является хорошим примером.)
Вы можете найти дальнейшие объяснения и инструкции в моем ответе на этот вопрос: Заставьте ld выбрать правильную библиотеку.
Я попытался сделать то, что вы предлагаете, что привело к ошибке сегментации! Так что не безопасно!
/usr/lib/i686/cmov$ sudo ln -s /usr/lib/libssl.so.1.0.0 libssl.so.0.9.8
/usr/lib/i686/cmov$ ls -la
total 1684
drwxr-xr-x 2 root root 4096 Jun 16 14:15 .
drwxr-xr-x 3 root root 4096 Oct 22 2012 ..
-rw-r--r-- 1 root root 1393308 Feb 11 2013 libcrypto.so.0.9.8
lrwxrwxrwx 1 root root 24 Jun 16 14:15 libssl.so.0.9.8 -> /usr/lib/libssl.so.1.0.0
-rw-r--r-- 1 root root 310296 Feb 11 2013 libssl.so.0.9.8.bk
:/usr/lib/i686/cmov$ sudo /etc/init.d/nginx restart
Restarting nginx: nginx/usr/sbin/nginx: /usr/lib/i686/cmov/libssl.so.0.9.8: no version information available (required by /usr/sbin/nginx)
Segmentation fault
Я нашел одно решение, которое было помечено как "не лучший способ сделать это", но сработало для меня, - это отредактировать системную переменную LD_LIBRARY_PATH, например, в
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib