Назад | Перейти на главную страницу

Создание 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 и указать ее на свои сборки? Это безопасно?

Спасибо,

Здесь задействованы две разные операции компоновщика: время сборки (используется для поиска библиотек и «символов», выполняется 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 будет делать то же самое во время сборки, когда он отмечает потенциально конфликтующие библиотеки в зависимостях.

Для чистый build, без обмана среды выполнения, вы можете:

  1. построить OpenSSL, убедившись, что RPATH явный, потому что libssl.so ссылки против libcrypto.so, и установить по указанному пути
  2. собрать пакет (то есть 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. Вам может не повезти с символом или порядком загрузки, и вы получите две (или более!) Версии загруженной библиотеки.

Есть три способа обойти это:

  1. отключите все функции, которые вам не нужны при сборке, для curl придется как минимум LDAP и SSH2
  2. если это невозможно, создайте новые версии зависимых библиотек, которые также связаны с новым OpenSSL.
  3. если это невозможно, вы можете использовать .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, например, в <user> /.bashrc:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib