Разделяемые библиотеки [102.3]

Рейтинг: 70.1% · 9 голосов
Полный курс LPIC-1 (экзамены 101-500 и 102-500): архитектура, загрузка, пакеты, команды и текст, ФС и права, шелл-скрипты, пользователи, сервисы, сеть, безопасность. Debian и RHEL.
Ответить
Аватара пользователя
Sergey_Sysadmin
Сообщения: 134
Зарегистрирован: 11 май 2026, 05:31

Разделяемые библиотеки [102.3]

Сообщение Sergey_Sysadmin »

Оглавление курса (41)
  1. Введение в LPIC-1 и как устроен путь администратора
  2. Железо, устройства и модули ядра [101.1]
  3. Загрузка системы: от BIOS до systemd [101.2]
  4. systemd, цели и уровни выполнения [101.3]
  5. План разметки диска и swap [102.1]
  6. Загрузчик GRUB 2 [102.2]
  7. Разделяемые библиотеки [102.3] (вы здесь)
  8. Управление пакетами в Debian: dpkg и apt [102.4]
  9. Управление пакетами RPM, DNF и Zypper [102.5]
  10. Linux как гость виртуализации [102.6]
  11. Командная строка Bash [103.1]
  12. Обработка текста фильтрами [103.2]
  13. Базовое управление файлами [103.3]
  14. Потоки, конвейеры и перенаправление [103.4]
  15. Процессы: создание, мониторинг, сигналы [103.5]
  16. Приоритеты выполнения процессов [103.6]
  17. Регулярные выражения [103.7]
  18. Редактор vi и vim [103.8]
  19. Разделы и создание файловых систем [104.1]
  20. Целостность и обслуживание ФС [104.2]
  21. Монтирование файловых систем [104.3]
  22. Урок 21. Права доступа и владение: rwx, chmod, umask и специальные биты
  23. Жёсткие и символические ссылки
  24. FHS и поиск файлов в системе [104.7]
  25. Окружение и кастомизация оболочки [105.1]
  26. Урок 25. Написание простых bash-скриптов [105.2]
  27. Графика, рабочие столы и доступность
  28. Учётные записи пользователей и групп
  29. Автоматизация задач: cron, at, таймеры [107.2]
  30. Локализация и интернационализация [107.3]
  31. Системное время и синхронизация [108.1]
  32. Системное логирование [108.2]
  33. Основы почтового агента (MTA) [108.3]
  34. Печать и CUPS [108.4]
  35. Основы интернет-протоколов [109.1]
  36. Постоянная конфигурация сети [109.2]
  37. Диагностика сети [109.3]
  38. DNS на стороне клиента [109.4]
  39. Задачи администрирования безопасности [110.1]
  40. Настройка безопасности хоста [110.2]
  41. Шифрование данных: SSH и GnuPG [110.3]
Урок 6. Разделяемые библиотеки [102.3]

Когда вы запускаете программу, она почти никогда не несет в себе весь код целиком. Функции вроде printf, открытия сокета или работы с UTF-8 лежат в общих библиотеках, которые подгружаются в момент запуска. Этот урок про то, как именно бинарник находит свои .so-файлы, кто ему в этом помогает, и почему сломанный кэш или неосторожно выставленная переменная окружения превращают рабочую систему в набор программ с ошибкой "cannot open shared object file". Администратор сталкивается с этим при установке софта мимо пакетного менеджера, при сборке из исходников и при разборе чужих инцидентов.

Изображение

Как это работает

Библиотеки бывают статические (.a) и разделяемые (.so, shared object). Статическая вшивается в бинарник на этапе линковки - программа становится толще, зато самодостаточна. Разделяемая существует одним файлом на диске, и десятки процессов отображают ее в память совместно. Экономится и диск, и оперативка, и - главное - обновление библиотеки (например, закрытие уязвимости в libssl) чинит сразу все программы, а не каждую по отдельности.

За загрузку отвечает динамический компоновщик ld.so (точнее, ld-linux-x86-64.so.2 на 64-битных системах). Это не обычная программа, а интерпретатор, прописанный прямо в заголовке ELF-бинарника. Ядро при exec видит, что файлу нужен интерпретатор, и передает управление ему. Компоновщик читает список нужных библиотек из секции бинарника, находит каждую на диске, проецирует в память и связывает символы.

Чтобы не сканировать весь диск при каждом запуске, ld.so использует заранее построенный кэш - файл /etc/ld.so.cache. В нем лежит готовая таблица "имя библиотеки -> полный путь". Строит этот кэш утилита ldconfig. Она обходит стандартные каталоги (/lib, /usr/lib и их 64-битные варианты) плюс пути из конфигурации и записывает результат в кэш. Пока вы не выполнили ldconfig, свежеустановленная в нестандартное место библиотека компоновщику не видна.

Ключевое понятие версионирования - SONAME. Внутри .so-файла зашито "официальное" имя, например libssl.so.3. Программа на этапе сборки запоминает не имя файла, а именно SONAME, и при запуске ищет файл, чье SONAME совпадает. На диске обычно стоит цепочка символических ссылок: libssl.so -> libssl.so.3 -> libssl.so.3.0.14. Ссылка без версии (libssl.so) нужна только линковщику при сборке (флаг -lssl) и часто лежит в -dev/-devel пакете. Версия в SONAME (тройка) меняется только при несовместимых изменениях API - это и есть гарантия, что libssl.so.3 не подсунут программе несовместимую libssl.so.4.

Команды и примеры

Посмотреть, от каких библиотек зависит бинарник и нашлись ли они:

Код: Выделить всё

ldd /usr/bin/ssh
        linux-vdso.so.1 (0x00007ffd...)
        libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007f...)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f...)
        /lib64/ld-linux-x86-64.so.2 (0x00007f...)
Стрелка => показывает, куда реально разрешилось имя. Если видите "not found" - вот ваша проблема. Важно: ldd по сути запускает компоновщик в режиме трассировки, поэтому НЕ прогоняйте ее на бинарниках из ненадежного источника.

Узнать SONAME конкретного файла и посмотреть его зависимости без запуска - через readelf или objdump:

Код: Выделить всё

readelf -d /lib/x86_64-linux-gnu/libssl.so.3 | grep -E 'SONAME|NEEDED'
 0x000000000000000e (SONAME)   Library soname: [libssl.so.3]
 0x0000000000000001 (NEEDED)   Shared library: [libcrypto.so.3]
Перестроить кэш после установки библиотеки, посмотреть содержимое кэша и проверить пути:

Код: Выделить всё

sudo ldconfig            # перестроить /etc/ld.so.cache
sudo ldconfig -v         # то же, с подробным выводом обрабатываемых каталогов
ldconfig -p | grep libssl   # показать, что компоновщик знает о libssl
Добавить свой каталог с библиотеками постоянно. Создается отдельный файл в каталоге ld.so.conf.d, а не правится главный конфиг:

Код: Выделить всё

echo "/opt/myapp/lib" | sudo tee /etc/ld.so.conf.d/myapp.conf
sudo ldconfig
ldconfig -p | grep myapp
Главный файл /etc/ld.so.conf обычно содержит лишь строку include /etc/ld.so.conf.d/*.conf - то есть реальная настройка раскидана по отдельным файлам каталога.

В Debian/Ubuntu принадлежность файла пакету и поиск -dev пакета:

Код: Выделить всё

dpkg -S /lib/x86_64-linux-gnu/libssl.so.3   # какой пакет дал файл
apt-get install libssl-dev                  # заголовки и .so-ссылка для сборки
В RHEL/Fedora то же самое через rpm и dnf (на RHEL 10 / Fedora 41 это dnf5):

Код: Выделить всё

rpm -qf /usr/lib64/libssl.so.3              # какой пакет владеет файлом
dnf install openssl-devel                   # devel-пакет с заголовками и ссылкой
Обратите внимание на пути: в Debian-семействе библиотеки лежат в /lib/<арх-триплет>/ (multiarch), а в RHEL-семействе - просто в /lib64 и /usr/lib64.

Переменная LD_LIBRARY_PATH добавляет каталоги в поиск для одного запуска, минуя кэш:

Код: Выделить всё

LD_LIBRARY_PATH=/opt/test/lib ./mybinary
Это удобно при отладке и тестировании несистемной сборки. Но как постоянное решение - плохая идея (см. грабли).

Частые грабли
  • Поставили библиотеку (скопировали .so в /usr/local/lib) и забыли ldconfig - программа падает с "cannot open shared object file", хотя файл на месте. Кэш просто про него не знает.
  • LD_LIBRARY_PATH прописали глобально в /etc/environment или в профиль "чтобы заработало". Теперь эта переменная наследуется всеми процессами, перекрывает системные библиотеки и ломает совсем другой софт. Она еще и опасна с setuid-бинарниками (для них ld.so ее игнорирует, и люди удивляются, почему "не работает").
  • Скопировали один файл libfoo.so.1.2.3 без символической ссылки libfoo.so.1. Компоновщик ищет по SONAME (libfoo.so.1), а ссылки нет - "not found". ldconfig сам создает versioned-ссылку по SONAME, но только в каталогах, которые он обходит.
  • Перепутали роли ссылок: думают, что для запуска нужна libfoo.so (без версии). Нет - она для сборки. Для запуска нужна именно versioned (libfoo.so.N).
  • Запустили ldd на скачанном непонятно откуда бинарнике. Поскольку ldd может выполнять код через компоновщик, это потенциальный вектор атаки - для недоверенных файлов берите readelf -d или objdump -p.
  • Подняли мажорную версию (libssl.so.1.1 -> libssl.so.3) и ждут, что старый софт подхватит новую. Не подхватит: разные SONAME - это намеренно несовместимые ABI, нужна пересборка или старый пакет совместимости.
Мини-лаба
  • Выберите любой системный бинарник (например, /usr/bin/curl) и выполните ldd на нем. Запишите, сколько библиотек он тянет и где они лежат.
  • Через readelf -d на одной из этих библиотек найдите ее SONAME и сравните с именем файла на диске.
  • Создайте каталог /opt/lab/lib и скопируйте туда любую системную .so (например libz). Запустите ldconfig -p | grep libz - убедитесь, что нового пути там нет.
  • Создайте файл /etc/ld.so.conf.d/lab.conf с путем /opt/lab/lib, выполните ldconfig и снова проверьте ldconfig -p.
  • Сравните результат запуска программы с переменной LD_LIBRARY_PATH=/opt/lab/lib и без нее, посмотрите через ldd, какой путь выбирается.
  • Уберите файл lab.conf, выполните ldconfig и проверьте, что кэш вернулся к исходному состоянию.
Контрольные вопросы
  • Чем отличается статическая библиотека от разделяемой и в чем выигрыш разделяемой при выпуске security-обновления?
  • Какой файл является кэшем компоновщика и какая команда его перестраивает?
  • Что такое SONAME и почему программа ищет библиотеку по нему, а не по имени файла?
  • Где правильно прописать дополнительный каталог поиска библиотек постоянно и какие два шага для этого нужны?
  • Почему глобальное использование LD_LIBRARY_PATH считается плохой практикой и как она ведет себя с setuid-программами?
  • Чем безопаснее заменить ldd при анализе недоверенного бинарника?
👍3 ❤️2 🔥1 😄 🤔1
Аватара пользователя
elixir6
Сообщения: 1
Зарегистрирован: 15 май 2026, 21:49

Re: Разделяемые библиотеки [102.3]

Сообщение elixir6 »

А зачем тогда нужна ссылка libfoo.so без версии, если для запуска берется versioned? Я ее снес чтобы место освободить и сборка соседнего проекта отвалилась с -lfoo not found, теперь понял
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
saubear
Сообщения: 1
Зарегистрирован: 13 май 2026, 10:37

Re: Разделяемые библиотеки [102.3]

Сообщение saubear »

Поймал реальный кейс: скопировал .so в /usr/local/lib, бинарник падает cannot open shared object. ldconfig -p его не видит. Один sudo ldconfig и все ожило, спасибо за раздел про кэш
👍2 ❤️ 🔥 😄 🤔1
Ответить
← Предыдущая глава
Загрузчик GRUB 2 [102.2]
Следующая глава →
Управление пакетами в Debian: dpkg и apt [102.4]

Все главы курса «LPIC-1: администратор Linux (101 + 102)»

Поделиться темой: ✈ Telegram VK

Вернуться в «LPIC-1: администратор Linux»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость