Среди разработчиков системного менеджера systemd ведётся обсуждение вопроса сокращения зависимостей у библиотеки libsystemd, которая связывается не только с компонентами systemd, но и со многими внешними приложениями. Например, в Fedora более 150 пакетов используют libsystemd в зависимостях. Инициатор обсуждения считает, что подтягивание в libsystemd дополнительных сторонних библиотек, которые не контролируют разработчики systemd, существенно увеличивает поверхность атаки в случае компрометации сторонних библиотек, как это произошло с библиотекой liblzma.
Помимо liblzma и glibc в libsystemd также загружаются библиотеки libzstd, liblz4 и libgcrypt, поддержание безопасности в которых становится критически важной задачей. В libsystemd предоставляется доступ к 12 базовым API (sd-bus, sd-daemon, sd-device, sd-event, sd-hwdb, sd-id128, sd-journal, sd-login, sd-netlink, sd-network, sd-path и sd-resolve) и возникает ситуация, когда приложение, например, использующее libsystemd только ради вызова функции sd_notify для информирования systemd об изменении состояния или sd_journal для записи данных в лог, связывается со всеми остальными библиотеками и обработчиками API. В качестве выхода предлагается разделить libsystemd на несколько отдельных библиотек, отвечающих за отдельные API, что позволит подгружать сторонние зависимости только там, где они необходимы.
Разработчики systemd считают разделение не целесообразным, так как присутствующие в libsystemd обработчики взаимосвязаны. Разделение потребует огромной работы и приведёт либо к потере эффективности, либо к необходимости дублирования кода. Для сокращения занимаемой памяти в libsystemd недавно принято изменение c реализацией динамической загрузки библиотек liblzma, libzstd и liblz4 при помощи вызова dlopen() в ситуациях, когда их функции действительно необходимы. Аналогичное изменение начиная со следующего выпуска будет реализовано и для libgcrypt.
Подобное решение стало объектом критики, так как вместо явного и заметного связывания, загрузка сторонних библиотек теперь будет производиться неявно, что усложнит диагностику, так как не очевидна связь API-вызовов libsystemd c вызовом функций из внешних библиотек. Сам по себе переход на загрузку при помощи dlopen() не меняет архитектуру, а лишь скрывает внешние компоненты от сопровождающих и пользователей.
Ленарт Поттеринг выразил категорическое несогласие с идеей разделения libsystemd на несколько библиотек, так как такой шаг существенно усложнит совместное использование кода в systemd и потребует перевести все внутренние обработчики в разряд публичных или отдельно статически вкомпилировать их в каждую библиотеку. В первом случае возникнут проблемы с поддержанием стабильности API и пространствами имён, а во втором - к увеличению размера из-за дублирования кода.
Реализованная для следующего выпуска загрузка внешних библиотек только по необходимости воспринимается Ленартом как оптимальная стратегия. Проблему с усложнением получения данных о динамически загружаемых библиотеках предлагается решить через добавление в файлы ELF дополнительных полей с информацией о подобных динамических зависимостях, которые могут обрабатываться отладчиками и показываться в выводе утилиты readelf.
Что касается связывания c libsystemd большого числа приложений, то Ленарт порекомендовал разработчикам приложений не пытаться загружать libsystemd ради одной функции, а реализовать обработчик протокола на уровне приложения. Например, реализация функциональности sd_notify() достаточно тривиальна и может уложиться в несколько строк кода при использовании UNIX-сокетов (AF_UNIX). Подобная обособленная реализация sd_notify с 2017 года доступна для OpenSSH и на днях принята в состав переносимой ветки OpenSSH 9.8, релиз которой намечен на середину лета.
>>> Подробности