Как читать авторский курс и нормативные материалы
Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.
динамическая линковка
Почему это важно для SCA/OSA
Динамическая линковка — единственный слой состава C/C++, который остаётся читаемым в готовом бинаре без журнала сборки. Линкер не вшивает код библиотеки, а записывает в файл лишь её имя (soname), а реальное связывание выполняет загрузчик ld.so при старте процесса. Поэтому динамическую зависимость можно восстановить пост-фактум: имя .so лежит в бинаре, а на хосте оно резолвится в файл и далее — в системный пакет с версией. Это «лёгкая» часть инвентаризации, на которой держится автоматический скан.
Ровно поэтому здесь возникает ложное ощущение полноты: сканер уверенно перечисляет динамические библиотеки и молчит про всё остальное. Важно понимать границу — динамическая линковка показывает компонент, но не его точную версию, и не видит ничего, что вшито статически.
Как это проявляется
Резолвинг идёт по soname, а не по имени файла. В бинаре записан мажорный ABI (libssl.so.3), ld.so ищет совпадение через кэш и подставляет конкретный файл:
$ ldd ./app
libssl.so.3 => /usr/lib/x86_64-linux-gnu/libssl.so.3 (0x00007f...)
libz.so.1 => /usr/lib/x86_64-linux-gnu/libz.so.1 (0x00007f...)
$ ldconfig -p | grep libssl
libssl.so.3 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libssl.so.3
Имя libssl.so.3 фиксирует только мажорную ABI-версию — «какая-то OpenSSL 3.x». Чтобы получить точную версию (3.0.11), нужно перейти от файла к пакету (dpkg -S / rpm -qf), а от пакета — к его версии. Этот переход «soname → файл → DEB/RPM-пакет → версия» и есть рабочая логика динамической инвентаризации.
soname задаёт совместимость, не версию Мажор в soname (
.so.3) меняется при несовместимом изменении ABI, а патч-версии (3.0.11→3.0.13) живут под одним soname. Значит, по самому бинарю патч-версию узнать нельзя — её даёт только пакетный менеджер хоста, на котором собирали или будут запускать.
Слепая зона или приём
Слепая зона динамической линковки — RPATH/RUNPATH: бинарь может указывать загрузчику искать .so не в системных путях, а в каталоге поставки. Тогда libssl.so.3 по имени то же, но физически загрузится другая, vendored-копия с иной версией, чем системный libssl3. ldd покажет фактический путь и тем самым выдаст подмену; структура этих записей разбирается в ELF и разделы dynamic.
Приём — не доверять имени soname как версии. Имя даёт только идентичность компонента (мажорная ABI), точную версию подтверждает пакет хоста, а реальный файл — ldd/путь. Если путь ведёт не в системный каталог, компонент vendored и требует отдельной разметки.
Что делать на проекте
- Снимать динамический состав надёжным способом — из секции
.dynamic(readelf -d), не запуская бинарь;lddиспользовать как уточнение путей (детали в ldd readelf objdump). - Каждую
.soдоводить до версии:dpkg -S/rpm -qf→ имя пакета → версия пакета, а не останавливаться на soname. - Проверять фактический путь резолвинга:
.soвне системных каталогов (/opt/app/lib, рядом с бинарём) — признакRPATH/vendored-копии. - Фиксировать обе версии — soname (мажор ABI) и точную версию пакета: для матчинга на CVE нужны обе.
libc/libstdc++учитывать как системный runtime отдельно, не смешивая с прикладными компонентами.- Любую
.so, не привязанную к пакету, отправлять в реестр unresolved (см. unresolved libraries).
Связь
- Модуль: М09. C/C++ legacy
- Практики: П22. ELF dynamic dependencies
- Нормативка: CISA Minimum Elements for SBOM · BSI TR-03183-2 v2.1.0 · ГОСТ Р 56939-2024
- Смежные заметки 06: ELF и разделы dynamic · статическая линковка · ldd readelf objdump · dpkg apt metadata · unresolved libraries · CPE alias для libssl3