Merge pull request #108032 from andir/systemd-dlopen

systemd: patch runtime dlopen calls
This commit is contained in:
Florian Klink 2021-01-03 13:33:09 +01:00 committed by GitHub
commit 4d36ba1d43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 0 deletions

View file

@ -13,6 +13,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("journalctl --grep=systemd")
machine.succeed(
"${pkgs.curl}/bin/curl -s localhost:19531/machine | ${pkgs.jq}/bin/jq -e '.hostname == \"machine\"'"
)

View file

@ -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" ];