Among the developers of the systemd system manager discussion is underway the issue of reducing dependencies of the libsystemd library, which links not only to systemd components, but also to many external applications. For example, in Fedora, more than 150 packages use libsystemd in their dependencies. The initiator of the discussion believes that adding additional third-party libraries to libsystemd that are not controlled by systemd developers significantly increases the attack surface in the event of third-party libraries being compromised, as happened with the liblzma library.
In addition to liblzma and glibc, libsystemd also loads libzstd, liblz4 and libgcrypt, the security of which becomes critical. libsystemd provides access to 12 basic APIs (sd-bus, sd-daemon, sd-device, sd-event, sd-hwdb, sd-id128, sd-journal, sd-login, sd-netlink, sd-network, sd -path and sd-resolve) and a situation arises where an application, for example, using libsystemd only for the sake of calling the sd_notify function to write data to the log, links with all other libraries and API handlers. As a way out, it is proposed to split libsystemd into several separate libraries responsible for separate APIs, which will allow third-party dependencies to be loaded only where they are needed.
systemd developers consider separation is not advisable, since the handlers included in libsystemd are interconnected and their separation will require a lot of work and will lead to either a loss of efficiency or the need for code duplication. To reduce memory footprint, libsystemd recently adopted change with the implementation of dynamic loading of the liblzma, libzstd and liblz4 libraries using the dlopen() call, in situations where their functions are really needed. Similar change starting next release will be implemented and for libgcrypt.
This decision has become the object of criticism, since instead of explicit and noticeable linking, loading of third-party libraries will now be done implicitly, which will complicate diagnostics, since the connection of libsystemd API calls with calls to functions from external libraries is not obvious. The switch to loading using dlopen() itself does not change the architecture, but only hides external components from maintainers and users.
Lenart Pottering expressed categorically disagree with the idea of splitting libsystemd into several libraries, since such a step will significantly complicate the sharing of code in systemd and will require transferring all internal handlers to the category of public ones or separately statically compiling them with each library. In the first case, there will be problems maintaining the stability of the API and namespaces, and in the second, it will increase in size due to code duplication.
Implemented for the next release, loading external libraries only when necessary is perceived by Lenart as the optimal strategy. It is proposed to solve the problem of increasing complexity in obtaining data about dynamically loaded libraries by adding additional fields to ELF files with information about such dynamic dependencies, which can be processed by debuggers and shown in the output of the readelf utility.
Regarding linking a large number of applications with libsystemd, Lenart recommended not trying to load libsystemd for the sake of one function, but implementing a protocol handler at the application level. For example, the implementation of the sd_notify() functionality is quite trivial and can be done in a few lines of code when using UNIX sockets (AF_UNIX). For example, a similar standalone implementation of sd_notify from 2017 available for OpenSSH and has recently been accepted into the portable branch of OpenSSH 9.8, the release of which is scheduled for mid-summer.
Thanks for reading: