Международная конференция разработчиков
и пользователей свободного программного обеспечения

Воспроизводимая сборка пакетов в сборочной инфраструктуре ALT Linux

Владимир Селезнев, Москва, Russian Federation

LVEE Winter 2018

Reproducible builds are important for various reasons, security among them. This talk explains what is done to check whether package build is reproducible in ALT Linux Team Build Infrastructure.

Введение

Что такое воспроизводимая сборка?

Сборка называется воспроизводимой[#rb], если в результате её из одних и тех же исходников в одинаковом сборочном окружении и при одинаковых инструкциях к сборке получается идентичный результат.

Воспроизводимость сборки является необходимым условием для доказательства того, что имеющееся скомпилированное программное обеспечение действительно получено из заявленных исходных кодов.

Что препятствует воспроизводимости сборки?

Сборка программного обеспечения — комплексный процесс, в котором может участвовать любое количество самого разнообразного программного обеспечения: компиляторы, компоновщики, библиотеки для линковки, генераторы кода/документации и любое другое программное обеспечение, невоспроизводимый результат любого из которых приведёт к невоспроизводимой сборке. На результат сборки также могут влиять условия, в которых работает сборочное программное обеспечение.

Основные причины, по которым сборка бывает невоспроизводима:

  • различные состояния сборочной системы — сборка программного обеспечения в окружениях, состоящих из разных версий, сборок или набора программного обеспечения, отличающихся переменными окружениями (например, задающих локаль, часовой пояс), с которыми запускается это программное обеспечение;
  • недетерминированные входные данные — например, зависимость от данных, получаемых при сборке по сети, или неоднозначный порядок входных данных (например, список файлов, взятых по маске);
  • метки времени — программное обеспечение, участвующее в сборке, может выставлять метки времени в результат;
  • случайный порядок выходных данных — сборочное программное обеспечение может выводить данные в случайном порядке;
  • использование случайных значений — сборочное программное обеспечение может использовать случайные значения во время сборки;
  • различные метаданные на сгенерированных файлах — хотя не влияют на содержимое файлов, однако затрудняют верификацию результата сборки в случае упаковки в архивы или пакеты.

Вышеприведённый список не является исчерпывающим.

Как добиться воспроизводимой сборки?

Для воспроизводимой сборки необходимо, чтобы каждый этап сборки был воспроизводим, в частности, должны быть соблюдены следующие условия:

  • одинаковое сборочное окружение (одинаковое программное обеспечение вплоть до бинарных сборок, переменные окружения, с которыми запускается процесс сборки, установленные файлы, смонтированные файловые системы и т.д.);
  • независимость сборки от сети, отсутствие изменчивых данных;
  • программному обеспечению, участвующему в процессе сборки, необходимо:
    • использовать метки времени на основе заранее определённой дате (для решения проблемы была введена переменная окружения SOURCE_DATE_EPOCH[#source_date_epoch])
    • генерировать выходные данные в строго определённом порядке
    • использовать псевдослучайные значения, полученных из генератора псевдослучайных чисел на основе заранее предопределённого значения
  • метаданные для файлов должны генерироваться воспроизводимым образом

Воспроизводимая сборка в терминах дистрибутивов Linux

Терминология

Обычно дистрибутивы Linux (или GNU/Linux) строятся вокруг пакетного менеджера. Пакетный менеджер решает задачи установки, удаления, обновления и проверки целостности установленных пакетов.

Пакет — это минимальная единица дистрибутива (форма распространения) программного обеспечения или каких-либо других ресурсов (например, шрифтов, пиктограмм, документации и т.д.), которые могут быть установлены в операционной системе с помощью пакетного менеджера. Пакет включает в себя помимо дистрибутива программного обеспечения или иных ресурсов (нередко в вида архива, который распаковывается в процессе установки в файловую систему) метаданные, содержащие в себе информацию о пакете (например, имя пакета, версию программного обеспечения, сайт разработчиков, контрольные суммы файлов, зависимости, список изменений и пр.), а также могу включать дополнительные скрипты, которые надо выполнить в определённый момент времени обработки пакета пакетным менеджером, например, при установке или удалении пакета.

Информация об установленных пакетах в системе хранится в базе данных пакетов, в которой каждому пакету ставится в соответствие список файлов на файловой системе, принадлежащих пакету, его мета-информация, как взятая из непосредственно пакета (по крайней мере та часть, которую пакетный менеджер считает нужной хранить в базе данных), так и полученная непосредственно в момент установки пакета, например, время установки пакета в систему.

Нередко в пакетные менеджеры включаются инструменты для сборки пакетов и для осуществления запросов в базу данных пакетов.

Как правило, в дистрибутивах Linux общего назначения все компоненты операционной системы представлены в виде пакетов программного обеспечения.

Пакеты делятся на два типа — исходные пакеты (source packages) и бинарные пакеты (binary packages), получаемые в результате сборки исходных пакетов.

Исходный пакет включает в себя исходники (исходные тексты и другие материалы) программного обеспечения и правила их сборки. Как правило, исходники предоставляются сообществом разработчиков (т.н. апстримом) этого программного обеспечения, обычно из некой ревизии системы контроля версий или архива, но состав исходного пакета также может включать дополнительные исходные материалы от сопровождающих пакет в операционной системе (мейнтейнеров), а также патчи, предоставленные как самими сопровождающими, так и взятые из других источников. Правила сборки пишутся мейнтейнерами.

Бинарные пакеты могут включать в себя архив файлов, необходимый для распаковки в файловую систему в случае установки пакета в систему, скрипты, вызываемые в случае установки/удаления пакета. Бинарные пакеты делятся на два типа: архитектурнозависимые и архитектурнонезависимые. Архитектурнозависимые пакеты привязаны к некой аппаратной архитектуре и могут быть установлены только на системы этой архитектуры, архитектурнонезависимые пакеты могут устанавливаться на системы любой архитектуры.

Воспроизводимая сборка пакетов

Сборка пакетов — это отображение исходного пакета и сборочного окружения в бинарные пакеты.

Сборочное окружение — среда, в котором происходит сборка, включающая в себя все установленное в него программное обеспечение (включая список установленных в него пакетов с их версиями и сборочный инструментарий), имеющиеся файлы, смонтированные файловые системы, переменные окружения, с которыми запускаются процессы сборки и др.

Сборка пакетов воспроизводима, когда такое отображение однозначно.

ALT Linux

Дистрибутивы ALT Linux являются основанными на пакетном менеджере RPM[#rpm] (RPM-based). RPM (RPM Package Manager, ранее Red Hat Package Manager) — пакетный менеджер, изначально разработанный для операционной системы Red Hat Linux, из которого развились многие другие системы, основанные на RPM, многие из которых потом самостоятельно дорабатывали RPM, образовывая по сути независимые проекты пакетных менеджеров. Альт также внёс существенные изменения и улучшения в свой пакетный менеджер.

Формат файла RPM-пакетов состоит из трёх секций:
  • ведущая секция, содержащая метки, определяющие, что файл является RPM-пакетом, и другую служебную информацию (архитектуру пакета, имя, версию, сигнатуру и др.);
  • заголовок RPM-пакета: содержит так называемые RPM-теги — именованные данные, содержащие некоторую информацию об RPM-пакете;
  • сжатый cpio-архив с содержимым RPM-пакета.

RPM-теги бывают разных типов (разного вида целочисленные, строковые, двоичные данные или массив из ранееперечисленного) и содержать некоторую информацию о пакете, его зависимостях и др. Как правило, имя RPM-тега является самоописывающим. Примеры тегов RPM: RPMTAG_NAME, RPMTAG_VERSION, RPMTAG_RELEASE, RPMTAG_LICENSE, RPMTAG_FILENAMES, RPMTAG_FILEMD5S, RPMTAG_FILEMODES.

Сборочная инфраструктура ALT Linux Team

Сборочная инфраструктура ALT Linux Team была спроектирована таким образом, чтобы обеспечить возможность верификации воспроизводимости сборки.
Сами сборочная инфраструктура довольно комплексна; в ней можно выделить следующий инструментарий:

  • rpmbuild — инструмент сборки RPM-пакетов;
  • hasher[#hasher] — инструмент для изолированной сборки пакетов, спроектированный таким образом, чтобы исключить влияние хостовой системы на сборочную среду (и наоборот);
  • gear[#gear] (Get Every Archive from git package Repository) — инструмент для хранения, поддержки и сборки RPM-пакетов из git-репозитория (как замены SourceRPM);
  • git.alt[#git.alt] — сервер совместной разработки Alt Linux Team;
  • girar — система, обеспечивающая функционирования хостинга git.alt, включающая в себя архив gear-репозиториев и систему сборки пакетов.

Помимо этого хранится архив ежедневных срезов репозиториев бинарных и исходных пакетов, архив репозиториев сборочных заданий, архив логов сборки каждого сборочного задания, индекс исходных пакетов, не ограничиваясь вышеперечисленным.

Сборка пакетов происходит в сборочных заданиях, в которых в подзаданиях собираются пакеты из заданного инициатором сборки подписанного мейнтейнером тега gear-репозитория или подписанного sourcerpm[#git.alt]. В случае, когда сборка успешно завершилось (сборка не является тестовой, прошли все проверки на неухудшаемость качества репозитория и нет запретов по ACL), то формируется новый репозиторий RPM-пакетов (новое состояние репозитория) для бранча, в который осуществлялась сборка, а также дополняется индекс исходных пакетов, включающий в себя дату сборки, номер задания и подзадания, откуда был собран пакет (репозиторий и git-тег в случае gear’а), ссылки на полученный репозиторий RPM-пакетов, логи сборки и др.. Для сборки каждого пакета сборочница с помощью hasher’а воссоздаёт с нуля изолированное сборочное окружение на основе текущего состояния репозитория RPM-пакетов бранча, для которого сборочное задание сформировано, в который устанавливаются только необходимые для сборки пакеты (сборочные зависимости) и в котором производится сборка. В процессе сборки сеть не участвует; исходные пакет и сборочные зависимости берутся из инфраструктуры ALT Linux Team (и только из неё) до начала непосредственно сборки.

Используя информацию из индекса исходных пакетов можно узнать, в каком задании и в каком окружении был собран определённый бинарный пакет. Из архива нужного среза репозитория можно легко воссоздать сборочное окружение, в котором был собран данный пакет, использовав этот срез в качестве репозитория для создания окружение hasher’ом, и собрать этот пакет из соответствующего исходного пакета, после чего сопоставить результат сборки с имеющимся пакетом. Например, сравнив побайтно содержимое пакетов[#altrb].

Сообщество по воспроизводимой сборке предлагает использовать в качестве одного из варианта характеристики сборки пакета контрольную сумму от результата сборки пакета. Однако в результате каждой сборки получаются немного разные бинарные RPM-пакеты, т.к. в их заголовки включены информация о времени сборки пакета, хосте, на котором производилась сборка, цифровая подпись и др. метаданные. Решением является брать контрольную сумму только от значимой части пакета. Значимой части является весь результат сборки, кроме незначимой. Т.к. все характеристики RPM-пакета записываются в соответствующие теги заголовка пакета, одним из решений является брать контрольную сумму от заголовка пакета, отфильтровав незначимые теги, т.е. те, которые не несут в себе существенной информации о получившемся результате, такие как RPMTAG_BUILDHOST, RPMTAG_BUILDDATE, и записать её в специально предназначенный для неё RPM-тег. Что в итоге и было сделано, новый тег назвали RPMTAG_IDENTITY (на момент публикации является ALT-специфичным тегом). Совпадение эначений этого тега у различных сборок пакета означает их существенную идентичность, т.е. показывает, что сборка является воспроизводимой. Также на основе этого тега появляется возможность генерировать более строгие межпакетные зависимости, что планируется сделать в будущем.

Также для обеспечения воспроизводимой сборки в ежедневнопубликуемый репозиторий Sisyphus были обновлено различное программное обеспечение, участвующее в сборке пакетов, с добавлением поддержки SOURCE_DATE_EPOCH. Также в конце 2017-начале 2018 года во все инструменты сборки пакетов, где это было необходимо, была добавлена поддержка SOURCE_DATE_EPOCH, а также поправлены некоторые места в rpmbuild, которые могли давать невоспроизводимый вывод.

Источники

notelist!.

note#rb. Reproducible builds

note#hasher. hasher: технология безопасной сборки дистрибутива

note#gear. От SRPMS к GEAR

note#git.alt. Сборочная система git.alt

note#source_date_epoch. SOURCE_DATE_EPOCH support in build infrastructure

note#rpm. RPM Package Manager

note#altrb. Воспроизводимая сборка

Abstract licensed under Creative Commons Attribution-ShareAlike 3.0 license

Назад