Пиков / КАПО
Как читать авторский курс и нормативные материалы

Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.

П23. Статическая линковка как слепая зона

Цель

На одном и том же коде показать разницу между динамической и статической сборкой: для динамической библиотека видна в DT_NEEDED, для статической — исчезает из секции .dynamic, и её присутствие приходится доказывать косвенно (по символам и строкам). Проверяемый результат: два бинаря из одного исходника и доказательство, что поздний скан статического бинаря НЕ даёт версию вшитой библиотеки.

Команда или действие

# 1. собрать один и тот же код дважды: динамика и статика
g++ main.cpp -o app_dyn -lssl -lcrypto -lz
g++ main.cpp -o app_static -l:libssl.a -l:libcrypto.a -l:libz.a -static-libstdc++

# 2. сравнить динамические зависимости
readelf -d ./app_dyn    | grep NEEDED      # OpenSSL виден
readelf -d ./app_static | grep NEEDED      # OpenSSL НЕ виден

# 3. косвенный поиск вшитого кода: символы и строки версий
nm -C ./app_static 2>/dev/null | grep -i -E 'SSL_|OPENSSL' | head
strings ./app_static | grep -iE 'OpenSSL [0-9]+\.[0-9]+'

Главный тезис практики Поздний скан готового бинаря не равен build-scan. У статически слинкованной библиотеки нет ни DT_NEEDED, ни DEB-пакета, ни (в stripped-бинаре) символов. Версию приходится угадывать по строке вида OpenSSL 3.0.11 — если она вообще осталась. Это и есть слепая зона C/C++ SCA.

Что вы должны увидеть

Динамический бинарь — OpenSSL в NEEDED:

$ readelf -d ./app_dyn | grep NEEDED
 0x0000000000000001 (NEEDED) Shared library: [libssl.so.3]
 0x0000000000000001 (NEEDED) Shared library: [libcrypto.so.3]

Статический бинарь — тех же записей нет (остаётся только libc/libstdc++ или вообще пусто при -static):

$ readelf -d ./app_static | grep NEEDED
 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

Косвенное доказательство присутствия (не всегда есть!): строка версии в strings:

$ strings ./app_static | grep -iE 'OpenSSL [0-9]'
OpenSSL 3.0.11 19 Sep 2023

Ориентир: разница между app_dyn и app_static — минус 2+ записи NEEDED. Если в stripped-сборке nm пуст и strings не нашёл версию, итог практики — «компонент присутствует, версия из бинаря недоступна», и это правильный, честный результат.

Если не получилось

Критерий зачёта

Показать преподавателю: два бинаря из одного исходника, side-by-side вывод readelf -d ... | grep NEEDED для обоих (видно исчезновение библиотеки) и письменный вывод одной фразой — почему поздний скан статического бинаря не заменяет build-scan и где здесь риск false negative при поиске уязвимостей.

Нормативная связка

Статическая линковка — каноничный пример, почему полнота SBOM достигается на этапе сборки (PS.3.2, PW.4 NIST SP 800-218 SSDF), а не поздним сканом; управляемость этого этапа требует ГОСТ Р 56939-2024. Невидимая вшитая библиотека = пропуск компонента = false negative при матчинге, что напрямую снижает качество SBOM по BSI TR-03183-2 v2.1.0 и связано с alias/identity-проблемой модуля М04. Смежные практики модуля М09: П19. C C++ make build inventory, П22. ELF dynamic dependencies, П25. CPE alias worklist. Шаблон: Порядок работы с неопознанной библиотекой.