summary refs log tree commit diff
path: root/pkgs/os-specific/linux/systemd/default.nix
diff options
context:
space:
mode:
authorAndreas Rammhold <andreas@rammhold.de>2020-12-26 16:55:33 +0100
committerAndreas Rammhold <andreas@rammhold.de>2021-01-03 11:50:01 +0100
commit494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf (patch)
treee6e3347aae8441b62d0bc834a32c4d7d9fae892b /pkgs/os-specific/linux/systemd/default.nix
parentc2884c4011a9496b67ae2ccd8af126854628014b (diff)
downloadnixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.tar
nixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.tar.gz
nixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.tar.bz2
nixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.tar.lz
nixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.tar.xz
nixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.tar.zst
nixpkgs-494ed4d6ee6f3d3b25a0b5d45f3f9e8dd1c45ccf.zip
systemd: patch runtime dlopen calls
This ensures that all the features that are implemented via dlopen(3)
are available (or explicitly deactivated) by pointing dlopen to the
absolute store path instead of relying on the linkers runtime lookup
code.

All of the dlopen calls have to be handled. When new ones are introduced
by upstream (or one of our patches) those must be explicitly declared,
otherwise the build will fail.

As of systemd version 247 we've seen a few errors like `libpcre2.… not
found` when using e.g. --grep with journalctl. Those errors should
become less unexpected now.

There are generally two classes of dlopen calls. Those that we want to
support and those that should be deactivated / unsupported. This change
enforces that we handle all dlopen calls explicitly. Meaning: There is
not a single dlopen call in the code source tree that we did not
explicitly handle.

In order to do this I introduced a list of attributes that maps from
shared object name to the package that contains them. The package can be
null meaning the reference should be nuked and the shared object will
never be loadable during runtime (because it points at an invalid store
path location).
Diffstat (limited to 'pkgs/os-specific/linux/systemd/default.nix')
-rw-r--r--pkgs/os-specific/linux/systemd/default.nix84
1 files changed, 84 insertions, 0 deletions
diff --git a/pkgs/os-specific/linux/systemd/default.nix b/pkgs/os-specific/linux/systemd/default.nix
index e6cb589c9bf..2822bffdb51 100644
--- a/pkgs/os-specific/linux/systemd/default.nix
+++ b/pkgs/os-specific/linux/systemd/default.nix
@@ -160,6 +160,90 @@ stdenv.mkDerivation {
       --replace \
       "find_program('objcopy'" \
       "find_program('${stdenv.cc.bintools.targetPrefix}objcopy'"
+  '' + (let
+
+    # The folllowing dlopen patches ensure that all the features that are
+    # implemented via dlopen(3) are available (or explicitly deactivated) by
+    # pointing dlopen to the absolute store path instead of relying on the
+    # linkers runtime lookup code.
+    #
+    # All of the dlopen calls have to be handled. When new ones are introduced
+    # by upstream (or one of our patches) they must be explicitly declared,
+    # otherwise the build will fail.
+    #
+    # As of systemd version 247 we've seen a few errors like `libpcre2.… not
+    # found` when using e.g. --grep with journalctl. Those errors should
+    # become less unexpected now.
+    #
+    # There are generally two classes of dlopen(3) calls. Those that we want to
+    # support and those that should be deactivated / unsupported. This change
+    # enforces that we handle all dlopen calls explicitly. Meaning: There is
+    # not a single dlopen call in the source code tree that we did not
+    # explicitly handle.
+    #
+    # In order to do this we introduced a list of attributes that maps from
+    # shared object name to the package that contains them. The package can be
+    # null meaning the reference should be nuked and the shared object will
+    # never be loadable during runtime (because it points at an invalid store
+    # path location).
+    #
+    # To get a list of dynamically loaded libraries issue something like
+    # `grep -ri 'dlopen("lib' $src` and update the below list.
+    dlopenLibs = [
+      # We did never provide support for libxkbcommon & qrencode
+      { name = "libxkbcommon.so.0"; pkg = null; }
+      { name = "libqrencode.so.4"; pkg = null; }
+
+      # We did not provide libpwquality before so it is safe to disable it for
+      # now.
+      { name = "libpwquality.so.1"; pkg = null; }
+
+      # Only include cryptsetup if it is enabled. We might not be able to
+      # provide it during "bootstrap" in e.g. the minimal systemd build as
+      # cryptsetup has udev (aka systemd) in it's dependencies.
+      { name = "libcryptsetup.so.12"; pkg = if withCryptsetup then cryptsetup else null; }
+
+      # We are using libidn2 so we only provide that and ignore the others.
+      # Systemd does this decision during configure time and uses ifdef's to
+      # enable specific branches. We can safely ignore (nuke) the libidn "v1"
+      # libraries.
+      { name = "libidn2.so.0"; pkg = libidn2; }
+      { name = "libidn.so.12"; pkg = null; }
+      { name = "libidn.so.11"; pkg = null; }
+
+      # journalctl --grep requires libpcre so lets provide it
+      { name = "libpcre2-8.so.0"; pkg = pcre2; }
+    ];
+
+    patchDlOpen = dl: let
+      library = "${lib.makeLibraryPath [dl.pkg]}/${dl.name}";
+    in if dl.pkg == null then ''
+      # remove the dependency on the library by replacing it with an invalid path
+      for file in $(grep -lr 'dlopen("${dl.name}"' src); do
+        echo "patching dlopen(\"${dl.name}\", …) in $file to an invalid store path ("/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-not-implemented/${dl.name}")…"
+        substituteInPlace "$file" --replace 'dlopen("${dl.name}"' 'dlopen("/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-not-implemented/${dl.name}"'
+      done
+    '' else ''
+      # ensure that the library we provide actually exists
+      if ! [ -e ${library} ]; then
+        echo 'The shared library `${library}` does not exist but was given as subtitute for `${dl.name}`'
+        exit 1
+      fi
+      # make the path to the dependency explicit
+      for file in $(grep -lr 'dlopen("${dl.name}"' src); do
+        echo "patching dlopen(\"${dl.name}\", …) in $file to ${library}…"
+        substituteInPlace "$file" --replace 'dlopen("${dl.name}"' 'dlopen("${library}"'
+      done
+    '';
+  in # patch all the dlopen calls to contain absolute paths to the libraries
+  lib.concatMapStringsSep "\n" patchDlOpen dlopenLibs)
+  # finally ensure that there are no left-over dlopen calls that we didn't handle
+  + ''
+    if grep -qr 'dlopen("[^/]' src; then
+      echo "Found unhandled dlopen calls: "
+      grep -r 'dlopen("[^/]' src
+      exit 1
+    fi
   '';
 
   outputs = [ "out" "man" "dev" ];