Among the developers of the systemd system manager, there is a discussion about reducing the 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 inform systemd about a state change or sd_journal 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.
The systemd developers consider the separation inappropriate, since the handlers present in libsystemd are interconnected. Splitting would require a lot of work and would result in either loss of efficiency or the need for code duplication. To reduce memory footprint, libsystemd recently changed to dynamically load the liblzma, libzstd, and liblz4 libraries using a dlopen() call in situations where their functions are actually needed. A similar change will be implemented for libgcrypt starting from the next release.
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 strongly disagreed with the idea of splitting libsystemd into several libraries, since such a move would significantly complicate the sharing of code in systemd and would require making all internal handlers public or separately statically compiling them into 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 that application developers not try to load libsystemd for the sake of one function, but implement 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). A similar separate implementation of sd_notify has been available for OpenSSH since 2017 and was recently adopted into the portable branch of OpenSSH 9.8, the release of which is scheduled for mid-summer.
Source: opennet.ru
