Bundled-зависимости и supply chain
Почему bundled-библиотеки опасны и как с ними работать.
На этой странице
Многие проекты включают копии сторонних библиотек прямо в свои исходники (bundling). Это создаёт серьёзные проблемы безопасности.
Что такое bundling
Bundled-зависимость — это копия сторонней библиотеки, включённая в исходники проекта:
myproject/
├── src/
│ └── main.c
├── third_party/ ← Bundled!
│ ├── zlib/
│ ├── openssl/
│ └── json-c/
└── Makefile
Почему это плохо
Проблема безопасности
Если в zlib найдена CVE:
- Системный zlib — обновляется одним пакетом, сразу для всех
- Bundled zlib — нужно пересобрать каждый пакет, который его bundled
На практике bundled-копии часто забывают обновить → уязвимости остаются.
Проблема обновлений
Системная libfoo: 1.5.0 (с исправлениями CVE)
Bundled libfoo: 1.2.0 (старая, уязвимая)
Проблема дублирования
Одна и та же библиотека в 10 пакетах — это 10 копий в памяти и на диске.
Как определить bundled-зависимости
# Распаковать и поискать типичные паттерны
tar xf myproject-1.0.tar.gz
find myproject-1.0 -name "*.c" -path "*/third_party/*" | head
find myproject-1.0 -name "*.c" -path "*/vendor/*" | head
find myproject-1.0 -name "*.c" -path "*/external/*" | head
# Для Python
grep -r "bundled" myproject-1.0/setup.py
ls myproject-1.0/vendor/
# Для Rust
ls myproject-1.0/vendor/
Стратегии работы с bundling
Стратегия 1: Использовать системную библиотеку (предпочтительно)
BuildRequires: pkgconfig(zlib)
BuildRequires: pkgconfig(json-c)
%build
%cmake -DUSE_SYSTEM_ZLIB=ON \
-DUSE_SYSTEM_JSON=ON
%cmake_build
%install
%cmake_install
# Удалить bundled-копии, если они всё ещё устанавливаются
rm -rf %{buildroot}%{_libdir}/myproject/third_party/
Стратегия 2: Если системная библиотека недоступна
Иногда bundling неизбежен (например, форк с несовместимыми изменениями):
# Явно укажите, что библиотека bundled
Provides: bundled(libfoo) = 1.2.0
Provides: bundled(...) — это документация для аудита. Она показывает, что пакет содержит встроенную копию библиотеки определённой версии.
Стратегия 3: Vendoring (Rust, Go)
Для Rust и Go vendoring — стандартная практика, потому что эти языки не используют системные библиотеки для своих зависимостей:
# Rust: vendor-архив
Source1: %{name}-%{version}-vendor.tar.xz
# Указать bundled-зависимости
Provides: bundled(crate(serde)) = 1.0.195
Provides: bundled(crate(tokio)) = 1.35.1
Для Rust/Go vendoring допустим, но для C/C++ — используйте системные библиотеки.
Аудит bundled-зависимостей
# Для Rust
cargo license
cargo deny check
# Для Python
pip show mypackage | grep -i requires
# Для Go
go list -m all
Рекомендации
- Предпочитайте системные библиотеки всегда, когда возможно
- Документируйте bundled-зависимости через
Provides: bundled(...) - Отслеживайте CVE не только для основного проекта, но и для bundled-библиотек
- Сообщайте upstream о необходимости использования системных библиотек
- Для Rust/Go vendoring допустим, но лицензии зависимостей должны быть учтены
Проверьте понимание
- Почему bundled-библиотеки — проблема безопасности?
- Как найти bundled-зависимости в проекте?
- Когда vendoring допустим?
- Зачем указывать
Provides: bundled(...)?
Следующий модуль: Лицензирование